//Event Calls
 internal void PreControllerCheck(HttpRequest request, CallDescriptor desc)
 {
     if (OnPreController != null)
     {
         OnPreController(request, desc);
     }
 }
        public ControllerDescriptor(Type t, HttpServer server, bool wrapped = false)
        {
            if (server == null || t == null)
            {
                throw new ArgumentNullException("Type and Server parameter cannot be null");
            }
            UseWrap        = wrapped;
            Server         = server;
            ControllerType = t;
            List <MethodInfo> ms = t.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly)
                                   .Where(x => !IgnoreControllerMethodAttribute.HasAttribute(x)).ToList();

            foreach (MethodInfo m in ms)
            {
                CallDescriptor desc = new CallDescriptor(this, m);
                string         name = m.Name.ToLower();
                if (desc.Descriptor != null && !string.IsNullOrEmpty(desc.Descriptor.MethodName))
                {
                    name = desc.Descriptor.MethodName;
                }
                Calls.Add(m.Name.ToLower(), desc);
                if (desc.Descriptor != null && desc.Descriptor.IsDefault && !Calls.ContainsKey(""))
                {
                    Calls.Add("", desc);
                }
            }
        }
Esempio n. 3
0
        internal static Span <byte> AssembleCall32(CallDescriptor <int> callDescriptor)
        {
            var shellcode = new List <byte>();

            foreach (var argument in callDescriptor.Arguments.Reverse())
            {
                switch (argument)
                {
                case >= sbyte.MinValue and <= sbyte.MaxValue:
                {
                    // push argument

                    shellcode.AddRange(new byte[] { 0x6A, unchecked ((byte)argument) });

                    break;
                }

                default:
                {
                    // push argument

                    shellcode.Add(0x68);

                    shellcode.AddRange(BitConverter.GetBytes(argument));

                    break;
                }
                }
            }

            // mov eax, Address

            shellcode.Add(0xB8);

            shellcode.AddRange(BitConverter.GetBytes(callDescriptor.Address.ToInt32()));

            // call eax

            shellcode.AddRange(new byte[] { 0xFF, 0xD0 });

            if (callDescriptor.ReturnAddress != IntPtr.Zero)
            {
                // mov ReturnAddress, eax

                shellcode.Add(0xA3);

                shellcode.AddRange(BitConverter.GetBytes(callDescriptor.ReturnAddress.ToInt32()));
            }

            // xor eax, eax

            shellcode.AddRange(new byte[] { 0x33, 0xC0 });

            // ret

            shellcode.Add(0xC3);

            return(CollectionsMarshal.AsSpan(shellcode));
        }
Esempio n. 4
0
        internal static byte[] AssembleCallDescriptor(CallDescriptor callDescriptor)
        {
            var assembledBytes = new List <byte>();

            if (callDescriptor.IsWow64Call)
            {
                if (callDescriptor.CallingConvention == CallingConvention.FastCall)
                {
                    // Move the first parameter into the ECX register

                    if (callDescriptor.Parameters.Length > 0)
                    {
                        var parameter = callDescriptor.Parameters[0];

                        if (parameter == 0)
                        {
                            // xor ecx, ecx

                            assembledBytes.AddRange(new byte[] { 0x31, 0xC9 });
                        }

                        else
                        {
                            // mov ecx, parameter

                            assembledBytes.Add(0xB9);

                            assembledBytes.AddRange(BitConverter.GetBytes((int)parameter));
                        }
                    }

                    // Move the second parameter into the EDX register

                    if (callDescriptor.Parameters.Length > 1)
                    {
                        var parameter = callDescriptor.Parameters[1];

                        if (parameter == 0)
                        {
                            // xor edx, edx

                            assembledBytes.AddRange(new byte[] { 0x31, 0xD2 });
                        }

                        else
                        {
                            // mov edx, parameter

                            assembledBytes.Add(0xBA);

                            assembledBytes.AddRange(BitConverter.GetBytes((int)parameter));
                        }
                    }

                    // Push the remaining parameters onto the stack in reverse order

                    if (callDescriptor.Parameters.Length > 2)
                    {
                        foreach (var parameter in callDescriptor.Parameters[2..].Reverse())
Esempio n. 5
0
        internal T CallRoutine <T>(IntPtr routineAddress, params dynamic[] arguments) where T : unmanaged
        {
            var returnAddress = Process.AllocateBuffer(Unsafe.SizeOf <T>(), ProtectionType.ReadWrite);

            try
            {
                // Assemble the shellcode used to call the routine

                Span <byte> shellcodeBytes;

                if (Process.GetArchitecture() == Architecture.X86)
                {
                    var callDescriptor = new CallDescriptor <int>(routineAddress, Array.ConvertAll(arguments, argument => (int)argument), returnAddress);
                    shellcodeBytes = Assembler.AssembleCall32(callDescriptor);
                }

                else
                {
                    var callDescriptor = new CallDescriptor <long>(routineAddress, Array.ConvertAll(arguments, argument => (long)argument), returnAddress);
                    shellcodeBytes = Assembler.AssembleCall64(callDescriptor);
                }

                // Write the shellcode into the process

                var shellcodeAddress = Process.AllocateBuffer(shellcodeBytes.Length, ProtectionType.ExecuteRead);

                try
                {
                    Process.WriteSpan(shellcodeAddress, shellcodeBytes);

                    // Create a thread to execute the shellcode

                    Process.CreateThread(shellcodeAddress);
                }

                finally
                {
                    Executor.IgnoreExceptions(() => Process.FreeBuffer(shellcodeAddress));
                }

                return(Process.ReadStruct <T>(returnAddress));
            }

            finally
            {
                Executor.IgnoreExceptions(() => Process.FreeBuffer(returnAddress));
            }
        }
Esempio n. 6
0
    internal T CallRoutine <T>(IntPtr routineAddress, params dynamic[] arguments) where T : unmanaged
    {
        var returnSize    = typeof(T) == typeof(IntPtr) ? Architecture == Architecture.X86 ? sizeof(int) : sizeof(long) : Unsafe.SizeOf <T>();
        var returnAddress = Process.AllocateBuffer(returnSize, ProtectionType.ReadWrite);

        try
        {
            // Assemble the shellcode used to call the routine

            Span <byte> shellcodeBytes;

            if (Architecture == Architecture.X86)
            {
                var descriptor = new CallDescriptor <int>(routineAddress, Array.ConvertAll(arguments, argument => (int)argument), returnAddress);
                shellcodeBytes = Assembler.AssembleCall32(descriptor);
            }

            else
            {
                var descriptor = new CallDescriptor <long>(routineAddress, Array.ConvertAll(arguments, argument => (long)argument), returnAddress);
                shellcodeBytes = Assembler.AssembleCall64(descriptor);
            }

            ExecuteShellcode(shellcodeBytes);

            // Read the return value

            if (typeof(T) != typeof(IntPtr))
            {
                return(Process.ReadStruct <T>(returnAddress));
            }

            var pointer = Architecture == Architecture.X86 ? UnsafeHelpers.WrapPointer(Process.ReadStruct <int>(returnAddress)) : UnsafeHelpers.WrapPointer(Process.ReadStruct <long>(returnAddress));

            return(Unsafe.As <IntPtr, T>(ref pointer));
        }

        finally
        {
            Executor.IgnoreExceptions(() => Process.FreeBuffer(returnAddress));
        }
    }
Esempio n. 7
0
    internal void CallRoutine(IntPtr routineAddress, params dynamic[] arguments)
    {
        // Assemble the shellcode used to call the routine

        Span <byte> shellcodeBytes;

        if (Architecture == Architecture.X86)
        {
            var descriptor = new CallDescriptor <int>(routineAddress, Array.ConvertAll(arguments, argument => (int)argument), IntPtr.Zero);
            shellcodeBytes = Assembler.AssembleCall32(descriptor);
        }

        else
        {
            var descriptor = new CallDescriptor <long>(routineAddress, Array.ConvertAll(arguments, argument => (long)argument), IntPtr.Zero);
            shellcodeBytes = Assembler.AssembleCall64(descriptor);
        }

        ExecuteShellcode(shellcodeBytes);
    }
Esempio n. 8
0
        internal static void AssembleStdCallParameters(CallDescriptor callDescriptor, ref List <byte> shellcode)
        {
            foreach (var parameter in callDescriptor.Parameters.Select(p => p).Reverse())
            {
                if (parameter <= 0x7F)
                {
                    // push parameter

                    shellcode.AddRange(new byte[] { 0x6A, (byte)parameter });
                }

                else
                {
                    // push parameter

                    shellcode.Add(0x68);

                    shellcode.AddRange(BitConverter.GetBytes((int)parameter));
                }
            }
        }
        //Handling
        private static void HandleRazor(HttpRequest request, CallDescriptor call, object result)
        {
            if (call.Descriptor == null)
            {
                throw new Exception("MethodDescriptor cannot be null for Razor views");
            }

            if (!call.Descriptor.IsRazor)
            {
                throw new ArgumentNullException("RazorView parameter for MethodDescriptor cannot be null");
            }

            string view = call.Descriptor.RazorView;

            if (!request.Server.RazorCache.Contains(view))
            {
                throw new ArgumentException("Given RazorView does not exist");
            }

            request.Response.ContentType = "text/html";
            request.Write(request.Server.RazorCache.Render(view, result));
            request.Close();
        }
Esempio n. 10
0
        internal T CallRoutine <T>(IntPtr routineAddress, params dynamic[] arguments) where T : unmanaged
        {
            var returnAddress = Memory.AllocateBuffer(Unsafe.SizeOf <T>(), ProtectionType.ReadWrite);

            try
            {
                // Assemble the shellcode used to call the routine

                Span <byte> shellcodeBytes;

                if (Process.GetArchitecture() == Architecture.X86)
                {
                    var callDescriptor = new CallDescriptor <int>(routineAddress, Array.ConvertAll(arguments, argument => (int)argument), returnAddress);

                    shellcodeBytes = ShellcodeAssembler.AssembleCall32(callDescriptor);
                }

                else
                {
                    var callDescriptor = new CallDescriptor <long>(routineAddress, Array.ConvertAll(arguments, argument => (long)argument), returnAddress);

                    shellcodeBytes = ShellcodeAssembler.AssembleCall64(callDescriptor);
                }

                // Execute the shellcode

                ExecuteShellcode(shellcodeBytes);

                return(Memory.ReadStructure <T>(returnAddress));
            }

            finally
            {
                Memory.FreeBuffer(returnAddress);
            }
        }
        public bool ExecuteController(string methodName, HttpRequest request)
        {
            string mn = methodName.ToLower();

            if (Calls.ContainsKey(methodName))
            {
                if (request.IsClosed)
                {
                    return(true);
                }

                BodyType responseType = Server.DefaultResponseType;

                //Header override
                string accept = request.GetHeader("Accept");
                if (!string.IsNullOrEmpty(accept))
                {
                    switch (accept.ToLower())
                    {
                    case "text/json":
                    case "application/json":
                        responseType = BodyType.JSON;
                        break;

                    case "text/xml":
                    case "application/xml":
                        responseType = BodyType.XML;
                        break;

                    default:
                        //Not supported ResponseType
                        break;
                    }
                }

                try
                {
                    CallDescriptor call = Calls[methodName];

                    //Pre-Controller logic
                    request.Server.PreControllerCheck(request, call);
                    if (request.IsClosed)
                    {
                        return(true);
                    }

                    //With descriptor
                    if (call.Descriptor != null)
                    {
                        responseType = call.Descriptor.ResponseType;
                        if (responseType == BodyType.Undefined)
                        {
                            responseType = Server.DefaultResponseType;
                        }

                        if (call.Descriptor.HasParameters)
                        {
                            foreach (string enforced in call.Descriptor.Parameters)
                            {
                                if (!request.Parameters.ContainsKey(enforced))
                                {
                                    throw new ArgumentException($"Missing parameter {enforced}");
                                }
                            }
                        }
                    }

                    object    result = null;
                    Exception ex     = null;

                    try
                    {
                        if (call.TokenRequirements != null)
                        {
                            if (!request.Authenticated || call.TokenRequirements.LevelRequired > request.AuthenticationLevel)
                            {
                                throw new ForbiddenException("You don't have permission to access this API method");
                            }
                            if (call.TokenRequirements.RequestAttributes != null && call.TokenRequirements.RequestAttributes.Length > 0)
                            {
                                foreach (string attr in call.TokenRequirements.RequestAttributes)
                                {
                                    if (!request.Attributes.Contains(attr))
                                    {
                                        throw new ForbiddenException("You don't have permission to access this API method at this moment");
                                    }
                                }
                            }
                        }
                        //Caching
                        if (call.CacheHeader != null)
                        {
                            switch (call.CacheHeader.Cache)
                            {
                            case CachingType.Cache:
                                request.Response.Headers.Add("cache-control", "max-age=" + call.CacheHeader.Validity.ToString());
                                break;

                            case CachingType.Prevent:
                                request.Response.Headers.Add("cache-control", "no-cache, no-store, must-revalidate");
                                request.Response.Headers.Add("Pragma", "no-cache");
                                request.Response.Headers.Add("Expires", "0");
                                break;
                            }
                        }

                        //Parse Parameters
                        object[] paras = GetParameters(call, request);

                        //Handling
                        result = call.Info.Invoke(GetInstance(request), paras.ToArray());
                        if (request.DisableAutoHandling)
                        {
                            return(true);
                        }
                    }
                    catch (TargetInvocationException tx)
                    {
                        ex = tx.InnerException;
                    }
                    catch (Exception x)
                    {
                        ex = x;
                    }

                    if (!request.IsClosed && (result != null || ex != null))
                    {
                        Type resultType;
                        if (ex != null)
                        {
                            resultType = typeof(Exception);
                            result     = new APIWrap(ex);
                            if (!Server.Debug)
                            {
                                ((APIWrap)result).Exception.StackTrace = "";
                            }
                            if (responseType == BodyType.Raw || responseType == BodyType.Razor)
                            {
                                responseType = Server.DefaultResponseType;
                            }
                            HandleResult(Server, request, call, responseType, result, false);
                        }
                        else
                        {
                            HandleResult(Server, request, call, responseType, result, UseWrap);
                        }
                    }
                }
                catch (Exception ex)
                {
                    if (responseType == BodyType.Razor)
                    {
                        responseType = Server.DefaultResponseType;
                    }

                    request.Write(new APIWrap(ex), responseType);
                }

                if (!request.IsClosed)
                {
                    request.Close();
                }

                return(true);
            }
            else
            {
                return(false);
            }
        }
Esempio n. 12
0
        private static byte[] AssembleShellcode(CallDescriptor callDescriptor)
        {
            var shellcode = new List <byte>();

            if (callDescriptor.IsWow64Call)
            {
                // Assemble the function parameters

                if (callDescriptor.CallingConvention == CallingConvention.FastCall)
                {
                    ParameterAssembler.AssembleFastCallParameters(callDescriptor, ref shellcode);
                }

                else
                {
                    ParameterAssembler.AssembleStdCallParameters(callDescriptor, ref shellcode);
                }

                // mov eax, functionAddress

                shellcode.Add(0xB8);

                shellcode.AddRange(BitConverter.GetBytes((int)callDescriptor.FunctionAddress));

                // call eax

                shellcode.AddRange(new byte[] { 0xFF, 0xD0 });

                if (callDescriptor.ReturnAddress != IntPtr.Zero)
                {
                    // mov [returnAddress], eax

                    shellcode.Add(0xA3);

                    shellcode.AddRange(BitConverter.GetBytes((int)callDescriptor.ReturnAddress));
                }

                // xor eax, eax

                shellcode.AddRange(new byte[] { 0x33, 0xC0 });

                // ret

                shellcode.Add(0xC3);
            }

            else
            {
                // Assemble the function parameters

                ParameterAssembler.AssembleFastCallParameters(callDescriptor, ref shellcode);

                // mov rax, functionAddress

                shellcode.AddRange(new byte[] { 0x48, 0xB8 });

                shellcode.AddRange(BitConverter.GetBytes((long)callDescriptor.FunctionAddress));

                // sub rsp, 0x28

                shellcode.AddRange(new byte[] { 0x48, 0x83, 0xEC, 0x28 });

                // call rax

                shellcode.AddRange(new byte[] { 0xFF, 0xD0 });

                // add rsp, 0x28

                shellcode.AddRange(new byte[] { 0x48, 0x83, 0xC4, 0x28 });

                if (callDescriptor.ReturnAddress != IntPtr.Zero)
                {
                    // mov [returnAddress], rax

                    shellcode.AddRange(new byte[] { 0x48, 0xA3 });

                    shellcode.AddRange(BitConverter.GetBytes((long)callDescriptor.ReturnAddress));
                }

                // xor eax, eax

                shellcode.AddRange(new byte[] { 0x31, 0xC0 });

                // ret

                shellcode.Add(0xC3);
            }

            return(shellcode.ToArray());
        }
        private object[] GetParameters(CallDescriptor call, HttpRequest request)
        {
            List <object> paras = new List <object>();

            foreach (ParameterDescriptor para in call.Parameters)
            {
                string name          = para.Info.Name;
                Type   parameterType = para.Info.ParameterType;
                if ((para.Descriptor != null && para.Descriptor.Type == ParameterType.Body) || name == call.Descriptor?.PostParameter)
                {
                    BodyType bType = BodyType.Undefined;

                    if (para.Descriptor != null)
                    {
                        bType = para.Descriptor.BodyType;
                    }

                    if (call.Descriptor != null && bType == BodyType.Undefined)
                    {
                        bType = call.Descriptor.RequestType;
                    }

                    if (bType == BodyType.Undefined)
                    {
                        bType = Server.DefaultRequestType;
                        string contentType = request.GetHeader("Content-Type");
                        if (contentType != null)
                        {
                            switch (contentType.ToLower())
                            {
                            case "text/json":
                            case "application/json":
                                bType = BodyType.JSON;
                                break;

                            case "text/xml":
                            case "application/xml":
                                bType = BodyType.XML;
                                break;

                            case "application/x-www-form-urlencoded":
                                bType = BodyType.UrlEncoded;
                                break;

                            case "multipart/form-data":
                                bType = BodyType.MultipartStream;
                                break;
                            }
                        }
                    }

                    paras.Add(request.GetDataObject(parameterType, bType, call));
                }
                else
                {
                    if (para.Descriptor != null)
                    {
                        if (!string.IsNullOrEmpty(para.Descriptor.Name))
                        {
                            name = para.Descriptor.Name;
                        }

                        if (!para.Descriptor.Optional && request.Parameters.ContainsKey(name))
                        {
                            throw new ArgumentException($"Parameter {name} missing");
                        }
                    }

                    string data = null;
                    request.Parameters.TryGetValue(name, out data);

                    if (data != null)
                    {
                        paras.Add(ParameterConverter.Static.Parse(parameterType, request.Parameters[name]));
                    }
                    else
                    {
                        paras.Add((parameterType.IsValueType) ? Activator.CreateInstance(parameterType) : null);
                    }
                }
            }
            return(paras.ToArray());
        }
        private static void HandleResult(HttpServer server, HttpRequest request, CallDescriptor call, BodyType responseType, object result, bool useWrap)
        {
            Type resultType = result.GetType();

            if (useWrap && responseType != BodyType.Raw && responseType != BodyType.Razor)
            {
                result = new APIWrap(result);
            }

            if (!server?.IsAllowedResponse(responseType) ?? false)
            {
                throw new Exceptions.ConfigurationException("Requested response type is not allowed");
            }
            switch (responseType)
            {
            case BodyType.Razor:
                HandleRazor(request, call, result);
                break;

            case BodyType.Raw:
                if (resultType == typeof(byte[]))
                {
                    request.Response.ContentType = "application/octet-stream";
                    request.Write((byte[])result);
                }
                else
                {
                    request.Response.ContentType = "text/plain";
                    request.Write(result.ToString());
                }
                break;

            case BodyType.JSON:
                request.Response.ContentType = "application/json";

                JsonSerializerSettings settings = call.JsonSerialization?.Response;
                if (settings != null)
                {
                    request.Write(JsonConvert.SerializeObject(result, settings));
                }
                else
                {
                    request.Write(JsonConvert.SerializeObject(result));
                }
                break;

            case BodyType.XML:
                if (useWrap)
                {
                    XmlParser.AddSubType(typeof(APIWrap), resultType);
                }
                request.Response.ContentType = "application/xml";
                request.Write(XmlParser.Serialize(result));
                break;

            case BodyType.UrlEncoded:
                throw new NotSupportedException();

            case BodyType.MultipartStream:
                throw new NotSupportedException();
            }
        }
Esempio n. 15
0
        internal static Span <byte> AssembleCall64(CallDescriptor <long> callDescriptor)
        {
            var shellcode       = new List <byte>();
            var shadowSpaceSize = Constants.ShadowSpaceSize + sizeof(long) * Math.Max(0, callDescriptor.Arguments.Count - 4);

            // sub rsp, shadowSpaceSize

            shellcode.AddRange(new byte[] { 0x48, 0x83, 0xEC, (byte)shadowSpaceSize });

            if (callDescriptor.Arguments.Count > 0)
            {
                var argument = callDescriptor.Arguments[0];

                switch (argument)
                {
                case 0:
                {
                    // xor ecx, ecx

                    shellcode.AddRange(new byte[] { 0x31, 0xC9 });

                    break;
                }

                case >= int.MinValue and <= uint.MaxValue:
                {
                    // mov ecx, argument

                    shellcode.Add(0xB9);
                    shellcode.AddRange(BitConverter.GetBytes((int)argument));

                    break;
                }

                default:
                {
                    // mov rcx, argument

                    shellcode.AddRange(new byte[] { 0x48, 0xB9 });
                    shellcode.AddRange(BitConverter.GetBytes(argument));

                    break;
                }
                }
            }

            if (callDescriptor.Arguments.Count > 1)
            {
                var argument = callDescriptor.Arguments[1];

                switch (argument)
                {
                case 0:
                {
                    // xor edx, edx

                    shellcode.AddRange(new byte[] { 0x31, 0xD2 });

                    break;
                }

                case >= int.MinValue and <= uint.MaxValue:
                {
                    // mov edx, argument

                    shellcode.Add(0xBA);
                    shellcode.AddRange(BitConverter.GetBytes((int)argument));

                    break;
                }

                default:
                {
                    // mov rdx, argument

                    shellcode.AddRange(new byte[] { 0x48, 0xBA });
                    shellcode.AddRange(BitConverter.GetBytes(argument));

                    break;
                }
                }
            }

            if (callDescriptor.Arguments.Count > 2)
            {
                var argument = callDescriptor.Arguments[2];

                switch (argument)
                {
                case 0:
                {
                    // xor r8, r8

                    shellcode.AddRange(new byte[] { 0x4D, 0x31, 0xC0 });

                    break;
                }

                case >= int.MinValue and <= uint.MaxValue:
                {
                    // mov r8d, argument

                    shellcode.AddRange(new byte[] { 0x41, 0xB8 });
                    shellcode.AddRange(BitConverter.GetBytes((int)argument));

                    break;
                }

                default:
                {
                    // mov r8, argument

                    shellcode.AddRange(new byte[] { 0x49, 0xB8 });
                    shellcode.AddRange(BitConverter.GetBytes(argument));

                    break;
                }
                }
            }

            if (callDescriptor.Arguments.Count > 3)
            {
                var argument = callDescriptor.Arguments[3];

                switch (argument)
                {
                case 0:
                {
                    // xor r9, r9

                    shellcode.AddRange(new byte[] { 0x4D, 0x31, 0xC9 });

                    break;
                }

                case >= int.MinValue and <= uint.MaxValue:
                {
                    // mov r9d, argument

                    shellcode.AddRange(new byte[] { 0x41, 0xB9 });
                    shellcode.AddRange(BitConverter.GetBytes((int)argument));

                    break;
                }

                default:
                {
                    // mov r9, argument

                    shellcode.AddRange(new byte[] { 0x49, 0xB9 });
                    shellcode.AddRange(BitConverter.GetBytes(argument));

                    break;
                }
                }
            }

            if (callDescriptor.Arguments.Count > 4)
            {
                foreach (var argument in callDescriptor.Arguments.Skip(4).Reverse())
                {
                    switch (argument)
                    {
                    case >= sbyte.MinValue and <= sbyte.MaxValue:
                    {
                        // push argument

                        shellcode.AddRange(new byte[] { 0x6A, unchecked ((byte)argument) });

                        break;
                    }

                    case >= int.MinValue and <= int.MaxValue:
                    {
                        // push argument

                        shellcode.Add(0x68);
                        shellcode.AddRange(BitConverter.GetBytes((int)argument));

                        break;
                    }

                    default:
                    {
                        // mov rax, argument

                        shellcode.AddRange(new byte[] { 0x48, 0xB8 });
                        shellcode.AddRange(BitConverter.GetBytes(argument));

                        // push rax

                        shellcode.Add(0x50);

                        break;
                    }
                    }
                }
            }

            // mov rax, Address

            shellcode.AddRange(new byte[] { 0x48, 0xB8 });
            shellcode.AddRange(BitConverter.GetBytes(callDescriptor.Address.ToInt64()));

            // call rax

            shellcode.AddRange(new byte[] { 0xFF, 0xD0 });

            if (callDescriptor.ReturnAddress != IntPtr.Zero)
            {
                // mov [ReturnAddress], rax

                shellcode.AddRange(new byte[] { 0x48, 0xA3 });
                shellcode.AddRange(BitConverter.GetBytes(callDescriptor.ReturnAddress.ToInt64()));
            }

            // xor eax, eax

            shellcode.AddRange(new byte[] { 0x31, 0xC0 });

            // add rsp, shadowSpaceSize

            shellcode.AddRange(new byte[] { 0x48, 0x83, 0xC4, (byte)shadowSpaceSize });

            // ret

            shellcode.Add(0xC3);

            return(CollectionsMarshal.AsSpan(shellcode));
        }
Esempio n. 16
0
        public void CallFunction(CallDescriptor callDescriptor)
        {
            // Write the shellcode used to perform the function call into a buffer

            var shellcode = AssembleShellcode(callDescriptor);

            var shellcodeBuffer = _memory.AllocateBlock(IntPtr.Zero, shellcode.Length, ProtectionType.ReadWrite);

            _memory.WriteBlock(shellcodeBuffer, shellcode);

            _memory.ProtectBlock(shellcodeBuffer, shellcode.Length, ProtectionType.ExecuteRead);

            // Create a suspended thread with a spoofed start address

            var ntStatus = Ntdll.NtCreateThreadEx(out var threadHandle, AccessMask.SpecificRightsAll | AccessMask.StandardRightsAll, IntPtr.Zero, _process.SafeHandle, _process.MainModule.BaseAddress, IntPtr.Zero, ThreadCreationFlags.CreateSuspended | ThreadCreationFlags.HideFromDebugger, 0, 0, 0, IntPtr.Zero);

            if (ntStatus != NtStatus.Success)
            {
                throw new Win32Exception($"Failed to call NtCreateThreadEx with error code {ntStatus}");
            }

            if (callDescriptor.IsWow64Call)
            {
                // Get the context of the thread

                var threadContext = new Wow64Context {
                    ContextFlags = Wow64ContextFlags.Integer
                };

                if (!Kernel32.Wow64GetThreadContext(threadHandle, ref threadContext))
                {
                    throw new Win32Exception($"Failed to call Wow64GetThreadContext with error code {Marshal.GetLastWin32Error()}");
                }

                // Change the spoofed start address to the address of the shellcode

                threadContext.Eax = (int)shellcodeBuffer;

                // Update the context of the thread

                if (!Kernel32.Wow64SetThreadContext(threadHandle, ref threadContext))
                {
                    throw new Win32Exception($"Failed to call Wow64GetThreadContext with error code {Marshal.GetLastWin32Error()}");
                }
            }

            else
            {
                // Get the context of the thread

                var threadContext = new Context {
                    ContextFlags = ContextFlags.Integer
                };

                var threadContextBuffer = Marshal.AllocHGlobal(Unsafe.SizeOf <Context>());

                Marshal.StructureToPtr(threadContext, threadContextBuffer, false);

                if (!Kernel32.GetThreadContext(threadHandle, threadContextBuffer))
                {
                    throw new Win32Exception($"Failed to call GetThreadContext with error code {Marshal.GetLastWin32Error()}");
                }

                threadContext = Marshal.PtrToStructure <Context>(threadContextBuffer);

                // Change the spoofed start address to the address of the shellcode

                threadContext.Rcx = (long)shellcodeBuffer;

                Marshal.StructureToPtr(threadContext, threadContextBuffer, false);

                // Update the context of the thread

                if (!Kernel32.SetThreadContext(threadHandle, threadContextBuffer))
                {
                    throw new Win32Exception($"Failed to call SetThreadContext with error code {Marshal.GetLastWin32Error()}");
                }

                Marshal.FreeHGlobal(threadContextBuffer);
            }

            // Resume the thread

            if (Kernel32.ResumeThread(threadHandle) == -1)
            {
                throw new Win32Exception($"Failed to call ResumeThread with error code {Marshal.GetLastWin32Error()}");
            }

            if (Kernel32.WaitForSingleObject(threadHandle, int.MaxValue) == -1)
            {
                throw new Win32Exception($"Failed to call WaitForSingleObject with error code {Marshal.GetLastWin32Error()}");
            }

            threadHandle.Dispose();

            _memory.FreeBlock(shellcodeBuffer);
        }
Esempio n. 17
0
        private static byte[] AssembleShellcode(CallDescriptor callDescriptor, IntPtr completionFlagBuffer)
        {
            var shellcode = new List <byte>();

            if (callDescriptor.IsWow64Call)
            {
                // pushf

                shellcode.Add(0x9C);

                // pusha

                shellcode.Add(0x60);

                // Assemble the function parameters

                if (callDescriptor.CallingConvention == CallingConvention.FastCall)
                {
                    ParameterAssembler.AssembleFastCallParameters(callDescriptor, ref shellcode);
                }

                else
                {
                    ParameterAssembler.AssembleStdCallParameters(callDescriptor, ref shellcode);
                }

                // mov eax, functionAddress

                shellcode.Add(0xB8);

                shellcode.AddRange(BitConverter.GetBytes((int)callDescriptor.FunctionAddress));

                // call eax

                shellcode.AddRange(new byte[] { 0xFF, 0xD0 });

                if (callDescriptor.ReturnAddress != IntPtr.Zero)
                {
                    // mov [returnAddress], eax

                    shellcode.Add(0xA3);

                    shellcode.AddRange(BitConverter.GetBytes((int)callDescriptor.ReturnAddress));
                }

                // mov BYTE PTR [completionFlagBuffer], 0x01

                shellcode.AddRange(new byte[] { 0xC6, 0x05 });

                shellcode.AddRange(BitConverter.GetBytes((int)completionFlagBuffer));

                shellcode.Add(0x01);

                // popa

                shellcode.Add(0x61);

                // popf

                shellcode.Add(0x9D);

                // ret

                shellcode.Add(0xC3);
            }

            else
            {
                // pushf

                shellcode.Add(0x9C);

                // push rax

                shellcode.Add(0x50);

                // push rbx

                shellcode.Add(0x53);

                // push rcx

                shellcode.Add(0x51);

                // push rdx

                shellcode.Add(0x52);

                // push r8

                shellcode.AddRange(new byte[] { 0x41, 0x50 });

                // push r9

                shellcode.AddRange(new byte[] { 0x41, 0x51 });

                // push r10

                shellcode.AddRange(new byte[] { 0x41, 0x52 });

                // push r11

                shellcode.AddRange(new byte[] { 0x41, 0x53 });

                // Assemble the function parameters

                ParameterAssembler.AssembleFastCallParameters(callDescriptor, ref shellcode);

                // mov rax, functionAddress

                shellcode.AddRange(new byte[] { 0x48, 0xB8 });

                shellcode.AddRange(BitConverter.GetBytes((long)callDescriptor.FunctionAddress));

                // sub rsp, 0x28

                shellcode.AddRange(new byte[] { 0x48, 0x83, 0xEC, 0x28 });

                // call rax

                shellcode.AddRange(new byte[] { 0xFF, 0xD0 });

                // add rsp, 0x28

                shellcode.AddRange(new byte[] { 0x48, 0x83, 0xC4, 0x28 });

                if (callDescriptor.ReturnAddress != IntPtr.Zero)
                {
                    // mov [returnAddress], rax

                    shellcode.AddRange(new byte[] { 0x48, 0xA3 });

                    shellcode.AddRange(BitConverter.GetBytes((long)callDescriptor.ReturnAddress));
                }

                // mov rax, completionFlagBuffer

                shellcode.AddRange(new byte[] { 0x48, 0xB8 });

                shellcode.AddRange(BitConverter.GetBytes((long)completionFlagBuffer));

                // mov BYTE PTR [rax], 0x01

                shellcode.AddRange(new byte[] { 0xC6, 0x00, 0x01 });

                // pop r11

                shellcode.AddRange(new byte[] { 0x41, 0x5B });

                // pop r10

                shellcode.AddRange(new byte[] { 0x41, 0x5A });

                // pop r9

                shellcode.AddRange(new byte[] { 0x41, 0x59 });

                // pop r8

                shellcode.AddRange(new byte[] { 0x41, 0x58 });

                // pop rdx

                shellcode.Add(0x5A);

                // pop rcx

                shellcode.Add(0x59);

                // pop rbx

                shellcode.Add(0x5B);

                // pop rax

                shellcode.Add(0x58);

                // popf

                shellcode.Add(0x9D);

                // ret

                shellcode.Add(0xC3);
            }

            return(shellcode.ToArray());
        }
Esempio n. 18
0
        public void CallFunction(CallDescriptor callDescriptor)
        {
            var completionFlagBuffer = _memory.AllocateBlock(IntPtr.Zero, sizeof(bool), ProtectionType.ReadWrite);

            // Write the shellcode used to perform the function call into a buffer

            var shellcode = AssembleShellcode(callDescriptor, completionFlagBuffer);

            var shellcodeBuffer = _memory.AllocateBlock(IntPtr.Zero, shellcode.Length, ProtectionType.ReadWrite);

            _memory.WriteBlock(shellcodeBuffer, shellcode);

            _memory.ProtectBlock(shellcodeBuffer, shellcode.Length, ProtectionType.ExecuteRead);

            // Open a handle to the first thread

            var firstThreadHandle = Kernel32.OpenThread(AccessMask.SpecificRightsAll | AccessMask.StandardRightsAll, false, _process.Threads[0].Id);

            if (firstThreadHandle.IsInvalid)
            {
                throw new Win32Exception($"Failed to call OpenThread with error code {Marshal.GetLastWin32Error()}");
            }

            if (callDescriptor.IsWow64Call)
            {
                // Suspend the thread

                if (Kernel32.Wow64SuspendThread(firstThreadHandle) == -1)
                {
                    throw new Win32Exception($"Failed to call Wow64SuspendThread with error code {Marshal.GetLastWin32Error()}");
                }

                // Get the context of the thread

                var threadContext = new Wow64Context {
                    ContextFlags = Wow64ContextFlags.Control
                };

                if (!Kernel32.Wow64GetThreadContext(firstThreadHandle, ref threadContext))
                {
                    throw new Win32Exception($"Failed to call Wow64GetThreadContext with error code {Marshal.GetLastWin32Error()}");
                }

                // Write the original instruction pointer of the thread into the top of its stack

                threadContext.Esp -= sizeof(int);

                _memory.Write((IntPtr)threadContext.Esp, threadContext.Eip);

                // Overwrite the instruction pointer of the thread with the address of the shellcode

                threadContext.Eip = (int)shellcodeBuffer;

                // Update the context of the thread

                if (!Kernel32.Wow64SetThreadContext(firstThreadHandle, ref threadContext))
                {
                    throw new Win32Exception($"Failed to call Wow64SetThreadContext with error code {Marshal.GetLastWin32Error()}");
                }
            }

            else
            {
                // Suspend the thread

                if (Kernel32.SuspendThread(firstThreadHandle) == -1)
                {
                    throw new Win32Exception($"Failed to call SuspendThread with error code {Marshal.GetLastWin32Error()}");
                }

                // Get the context of the thread

                var threadContext = new Context {
                    ContextFlags = ContextFlags.Control
                };

                var threadContextBuffer = Marshal.AllocHGlobal(Unsafe.SizeOf <Context>());

                Marshal.StructureToPtr(threadContext, threadContextBuffer, false);

                if (!Kernel32.GetThreadContext(firstThreadHandle, threadContextBuffer))
                {
                    throw new Win32Exception($"Failed to call GetThreadContext with error code {Marshal.GetLastWin32Error()}");
                }

                threadContext = Marshal.PtrToStructure <Context>(threadContextBuffer);

                // Write the original instruction pointer of the thread into the top of its stack

                threadContext.Rsp -= sizeof(long);

                _memory.Write((IntPtr)threadContext.Rsp, threadContext.Rip);

                // Overwrite the instruction pointer of the thread with the address of the shellcode

                threadContext.Rip = (long)shellcodeBuffer;

                Marshal.StructureToPtr(threadContext, threadContextBuffer, false);

                // Update the context of the thread

                if (!Kernel32.SetThreadContext(firstThreadHandle, threadContextBuffer))
                {
                    throw new Win32Exception($"Failed to call SetThreadContext with error code {Marshal.GetLastWin32Error()}");
                }

                Marshal.FreeHGlobal(threadContextBuffer);
            }

            // Send a message to the thread to ensure it executes the shellcode

            if (!User32.PostThreadMessage(_process.Threads[0].Id, MessageType.Null, IntPtr.Zero, IntPtr.Zero))
            {
                throw new Win32Exception($"Failed to call PostThreadMessage with error code {Marshal.GetLastWin32Error()}");
            }

            // Resume the thread

            if (Kernel32.ResumeThread(firstThreadHandle) == -1)
            {
                throw new Win32Exception($"Failed to call ResumeThread with error code {Marshal.GetLastWin32Error()}");
            }

            while (!_memory.Read <bool>(completionFlagBuffer))
            {
                Thread.Sleep(1);
            }

            firstThreadHandle.Dispose();

            _memory.FreeBlock(shellcodeBuffer);

            _memory.FreeBlock(completionFlagBuffer);
        }
Esempio n. 19
0
        internal static void AssembleFastCallParameters(CallDescriptor callDescriptor, ref List <byte> shellcode)
        {
            var stackParameters = new List <byte>();

            var parameterIndex = 0;

            if (callDescriptor.IsWow64Call)
            {
                foreach (var parameter in callDescriptor.Parameters)
                {
                    switch (parameterIndex)
                    {
                    case 0:
                    {
                        if (parameter == 0)
                        {
                            // xor ecx, ecx

                            shellcode.AddRange(new byte[] { 0x31, 0xC9 });
                        }

                        else
                        {
                            // mov ecx, parameter

                            shellcode.Add(0xB9);

                            shellcode.AddRange(BitConverter.GetBytes((int)parameter));
                        }

                        parameterIndex += 1;

                        break;
                    }

                    case 1:
                    {
                        if (parameter == 0)
                        {
                            // xor edx, edx

                            shellcode.AddRange(new byte[] { 0x31, 0xD2 });
                        }

                        else
                        {
                            // mov edx, parameter

                            shellcode.Add(0xBA);

                            shellcode.AddRange(BitConverter.GetBytes((int)parameter));
                        }

                        parameterIndex += 1;

                        break;
                    }

                    default:
                    {
                        if (parameter <= 0x7F)
                        {
                            // push parameter

                            stackParameters.InsertRange(0, new byte[] { 0x6A, (byte)parameter });
                        }

                        else
                        {
                            // push parameter

                            var operation = new List <byte> {
                                0x68
                            };

                            operation.AddRange(BitConverter.GetBytes((int)parameter));

                            stackParameters.InsertRange(0, operation);
                        }

                        break;
                    }
                    }
                }
            }

            else
            {
                foreach (var parameter in callDescriptor.Parameters)
                {
                    switch (parameterIndex)
                    {
                    case 0:
                    {
                        if (parameter == 0)
                        {
                            // xor ecx, ecx

                            shellcode.AddRange(new byte[] { 0x31, 0xC9 });
                        }

                        else
                        {
                            // mov rcx, parameter

                            shellcode.AddRange(new byte[] { 0x48, 0xB9 });

                            shellcode.AddRange(BitConverter.GetBytes(parameter));
                        }

                        parameterIndex += 1;

                        break;
                    }

                    case 1:
                    {
                        if (parameter == 0)
                        {
                            // xor edx, edx

                            shellcode.AddRange(new byte[] { 0x31, 0xD2 });
                        }

                        else
                        {
                            // mov rdx, parameter

                            shellcode.AddRange(new byte[] { 0x48, 0xBA });

                            shellcode.AddRange(BitConverter.GetBytes(parameter));
                        }

                        parameterIndex += 1;

                        break;
                    }

                    case 2:
                    {
                        if (parameter == 0)
                        {
                            // xor r8, r8

                            shellcode.AddRange(new byte[] { 0x4D, 0x31, 0xC0 });
                        }

                        else
                        {
                            // mov r8, parameter

                            shellcode.AddRange(new byte[] { 0x49, 0xB8 });

                            shellcode.AddRange(BitConverter.GetBytes(parameter));
                        }

                        parameterIndex += 1;

                        break;
                    }

                    case 3:
                    {
                        if (parameter == 0)
                        {
                            // xor r9, r9

                            shellcode.AddRange(new byte[] { 0x4D, 0x31, 0xC9 });
                        }

                        else
                        {
                            // mov r9, parameter

                            shellcode.AddRange(new byte[] { 0x49, 0xB9 });

                            shellcode.AddRange(BitConverter.GetBytes(parameter));
                        }

                        parameterIndex += 1;

                        break;
                    }

                    default:
                    {
                        if (parameter <= 0x7F)
                        {
                            // push parameter

                            stackParameters.InsertRange(0, new byte[] { 0x6A, (byte)parameter });
                        }

                        else
                        {
                            var operation = new List <byte>();

                            if (parameter < int.MaxValue)
                            {
                                // push parameter

                                operation.Add(0x68);

                                operation.AddRange(BitConverter.GetBytes((int)parameter));
                            }

                            else
                            {
                                // mov rax, parameter

                                operation.AddRange(new byte[] { 0x48, 0xB8 });

                                operation.AddRange(BitConverter.GetBytes(parameter));

                                // push rax

                                operation.Add(0x50);
                            }

                            stackParameters.InsertRange(0, operation);
                        }

                        break;
                    }
                    }
                }
            }

            shellcode.AddRange(stackParameters);
        }
        //Data
        public object GetDataObject(Type type, BodyType body = BodyType.Undefined, CallDescriptor call = null)
        {
            if (body == BodyType.Undefined)
            {
                char firstCharacter = DataString.Trim().FirstOrDefault();
                switch (firstCharacter)
                {
                case '{':
                case '[':
                    body = BodyType.JSON;
                    break;

                case '<':
                    body = BodyType.XML;
                    break;

                default:
                    if (DataString.Contains("="))
                    {
                        body = BodyType.UrlEncoded;
                    }
                    break;
                }
            }

            switch (body)
            {
            case BodyType.JSON:
                JsonSerializerSettings settings = call?.JsonSerialization?.Request;
                if (settings != null)
                {
                    return(JsonConvert.DeserializeObject(DataString, type, settings));
                }
                else
                {
                    return(JsonConvert.DeserializeObject(DataString, type));
                }

            case BodyType.XML:
                return(XmlConvert.DeserializeObject(DataString, type));

            case BodyType.UrlEncoded:
                object targetObj = Activator.CreateInstance(type);
                foreach (PropertyInfo info in type.GetPropertiesCached())
                {
                    if (DataUrlEncoded.ContainsKey(info.Name))
                    {
                        info.SetValue(targetObj,
                                      ParameterConverter.Static.Parse(info.PropertyType, DataUrlEncoded[info.Name]));
                    }
                }
                return(targetObj);

            case BodyType.Raw:
                if (type == typeof(string))
                {
                    return(DataString);
                }
                else if (type == typeof(byte[]))
                {
                    return(Data);
                }
                else
                {
                    return(null);
                }

            case BodyType.MultipartStream:
                return(new MultiPartStream(DataStream));

            default:
                return(null);
            }
        }