Beispiel #1
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);
        }
Beispiel #2
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);
        }