예제 #1
0
        internal void CallFunction(CallingConvention callingConvention, IntPtr functionAddress, params ulong[] parameters)
        {
            // Write the shellcode used to call the function into the remote process

            var shellcode = _assembler.AssembleFunctionCall(callingConvention, functionAddress, IntPtr.Zero, parameters);

            var shellcodeBuffer = _memoryManager.AllocateVirtualMemory(shellcode.Length);

            _memoryManager.WriteVirtualMemory(shellcodeBuffer, shellcode);

            // Create a thread to call the shellcode in the remote process

            var ntStatus = RtlCreateUserThread(Process.SafeHandle, IntPtr.Zero, false, 0, IntPtr.Zero, IntPtr.Zero, shellcodeBuffer, IntPtr.Zero, out var threadHandle, IntPtr.Zero);

            if (ntStatus != NtStatus.Success)
            {
                ExceptionHandler.ThrowWin32Exception("Failed to create a thread in the remote process");
            }

            WaitForSingleObject(threadHandle, int.MaxValue);

            threadHandle.Dispose();

            _memoryManager.FreeVirtualMemory(shellcodeBuffer);
        }
예제 #2
0
        internal void CallFunction(IntPtr functionAddress, ulong[] parameters, CallingConvention callingConvention = CallingConvention.StdCall)
        {
            // Write the shellcode used to call the function into the remote process

            var shellcode = callingConvention == CallingConvention.FastCall
                          ? _assembler.AssembleFastCallFunctionCall(functionAddress, IntPtr.Zero, parameters.ToArray())
                          : _assembler.AssembleStandardFunctionCall(functionAddress, IntPtr.Zero, parameters.ToArray());

            var shellcodeBuffer = _memoryManager.AllocateVirtualMemory(shellcode.Length);

            _memoryManager.WriteVirtualMemory(shellcodeBuffer, shellcode);


            // Create a thread in the remote process to call the shellcode

            var ntStatus = PInvoke.RtlCreateUserThread(Process.SafeHandle, IntPtr.Zero, false, 0, IntPtr.Zero, IntPtr.Zero, shellcodeBuffer, IntPtr.Zero, out var threadHandle, out _);

            if (ntStatus != Enumerations.NtStatus.Success)
            {
                ExceptionHandler.ThrowWin32Exception("Failed to create a thread in the remote process");
            }

            PInvoke.WaitForSingleObject(threadHandle, int.MaxValue);

            threadHandle.Dispose();

            _memoryManager.FreeVirtualMemory(shellcodeBuffer);
        }
예제 #3
0
        internal IntPtr InitialiseDllPath()
        {
            // Write the DLL path into the remote process

            var dllPathAddress = MemoryManager.AllocateVirtualMemory(ProcessManager.Process.SafeHandle, IntPtr.Zero, DllPath.Length, MemoryProtectionType.ReadWrite);

            MemoryManager.WriteVirtualMemory(ProcessManager.Process.SafeHandle, dllPathAddress, Encoding.Unicode.GetBytes(DllPath));

            // Write a UnicodeString representing the DLL path into the remote process

            IntPtr dllPathUnicodeStringAddress;

            if (ProcessManager.IsWow64)
            {
                var dllPathUnicodeString = new UnicodeString32(DllPath, dllPathAddress);

                dllPathUnicodeStringAddress = MemoryManager.AllocateVirtualMemory(ProcessManager.Process.SafeHandle, IntPtr.Zero, Marshal.SizeOf <UnicodeString32>(), MemoryProtectionType.ReadWrite);

                MemoryManager.WriteVirtualMemory(ProcessManager.Process.SafeHandle, dllPathUnicodeStringAddress, dllPathUnicodeString);
            }

            else
            {
                var dllPathUnicodeString = new UnicodeString64(DllPath, dllPathAddress);

                dllPathUnicodeStringAddress = MemoryManager.AllocateVirtualMemory(ProcessManager.Process.SafeHandle, IntPtr.Zero, Marshal.SizeOf <UnicodeString64>(), MemoryProtectionType.ReadWrite);

                MemoryManager.WriteVirtualMemory(ProcessManager.Process.SafeHandle, dllPathUnicodeStringAddress, dllPathUnicodeString);
            }

            return(dllPathUnicodeStringAddress);
        }
예제 #4
0
        internal TStructure CallFunction <TStructure>(CallingConvention callingConvention, IntPtr functionAddress, params long[] parameters) where TStructure : struct
        {
            var returnAddress = MemoryManager.AllocateVirtualMemory(Marshal.SizeOf <TStructure>(), MemoryProtectionType.ReadWrite);

            CallFunctionInternal(new FunctionCall(functionAddress, callingConvention, parameters, returnAddress));

            try
            {
                return(MemoryManager.ReadVirtualMemory <TStructure>(returnAddress));
            }

            finally
            {
                MemoryManager.FreeVirtualMemory(returnAddress);
            }
        }
예제 #5
0
        internal TStructure CallFunction <TStructure>(IntPtr functionAddress, params ulong[] parameters) where TStructure : struct
        {
            // Allocate a buffer in the remote process to store the returned value of the function

            var returnBuffer = _memoryManager.AllocateVirtualMemory <TStructure>();

            // Write the shellcode used to call the function into the remote process

            var shellcode = _assembler.AssembleFunctionCall(functionAddress, returnBuffer, parameters);

            var shellcodeBuffer = _memoryManager.AllocateVirtualMemory(shellcode.Length);

            _memoryManager.WriteVirtualMemory(shellcodeBuffer, shellcode);

            // Create a thread in the remote process to call the shellcode

            SafeThreadHandle threadHandle;

            var ntStatus = _windowsVersion == WindowsVersion.Windows7
                         ? PInvoke.NtCreateThreadEx(out threadHandle, Enumerations.ThreadAccessMask.AllAccess, IntPtr.Zero, Process.SafeHandle, shellcodeBuffer, IntPtr.Zero, Enumerations.ThreadCreationType.HideFromDebugger, 0, 0, 0, IntPtr.Zero)
                         : PInvoke.RtlCreateUserThread(Process.SafeHandle, IntPtr.Zero, false, 0, IntPtr.Zero, IntPtr.Zero, shellcodeBuffer, IntPtr.Zero, out threadHandle, out _);

            if (ntStatus != Enumerations.NtStatus.Success)
            {
                ExceptionHandler.ThrowWin32Exception("Failed to create a thread in the remote process");
            }

            PInvoke.WaitForSingleObject(threadHandle, int.MaxValue);

            threadHandle.Dispose();

            _memoryManager.FreeVirtualMemory(shellcodeBuffer);

            try
            {
                // Read the returned value of the function from the buffer

                return(_memoryManager.ReadVirtualMemory <TStructure>(returnBuffer));
            }

            finally
            {
                _memoryManager.FreeVirtualMemory(returnBuffer);
            }
        }
        internal override void Inject()
        {
            // Write the DLL path into the remote process

            var dllPathUnicodeStringAddress = InitialiseDllPath();

            // Create a thread to call LdrLoadDll in the remote process

            var ldrLoadDllAddress = ProcessManager.GetFunctionAddress("ntdll.dll", "LdrLoadDll");

            var moduleHandleAddress = MemoryManager.AllocateVirtualMemory(ProcessManager.Process.SafeHandle, IntPtr.Zero, IntPtr.Size, MemoryProtectionType.ReadWrite);

            var ntStatus = ProcessManager.CallFunction <int>(CallingConvention.StdCall, ldrLoadDllAddress, 0, 0, (long)dllPathUnicodeStringAddress, (long)moduleHandleAddress);

            if ((NtStatus)ntStatus != NtStatus.Success)
            {
                throw new RemoteFunctionCallException("Failed to call LdrLoadDll", (NtStatus)ntStatus);
            }

            // Ensure the DLL is loaded before freeing any memory

            while (ProcessManager.Modules.TrueForAll(module => module.FilePath != DllPath))
            {
                ProcessManager.Refresh();
            }

            var dllPathAddress = ProcessManager.IsWow64 ? (IntPtr)MemoryManager.ReadVirtualMemory <UnicodeString32>(ProcessManager.Process.SafeHandle, dllPathUnicodeStringAddress).Buffer
                                                        : (IntPtr)MemoryManager.ReadVirtualMemory <UnicodeString64>(ProcessManager.Process.SafeHandle, dllPathUnicodeStringAddress).Buffer;

            MemoryManager.FreeVirtualMemory(ProcessManager.Process.SafeHandle, dllPathAddress);

            MemoryManager.FreeVirtualMemory(ProcessManager.Process.SafeHandle, dllPathUnicodeStringAddress);

            // Read the address of the DLL that was loaded in the remote process

            DllBaseAddress = MemoryManager.ReadVirtualMemory <IntPtr>(ProcessManager.Process.SafeHandle, moduleHandleAddress);

            MemoryManager.FreeVirtualMemory(ProcessManager.Process.SafeHandle, moduleHandleAddress);

            if (InjectionFlags.HasFlag(InjectionFlags.HideDllFromPeb))
            {
                // Hide the DLL from the PEB of the remote process

                HideDllFromPeb();
            }

            if (InjectionFlags.HasFlag(InjectionFlags.RandomiseDllHeaders))
            {
                // Randomise the DLL headers

                RandomiseDllHeaders(DllBaseAddress);
            }
        }
예제 #7
0
        internal override void Inject()
        {
            // Store the DLL in the local process

            _localDllAddress = Marshal.AllocHGlobal(DllBytes.Length);

            Marshal.Copy(DllBytes, 0, _localDllAddress, DllBytes.Length);

            // Allocate memory for the DLL in the remote process

            try
            {
                DllBaseAddress = MemoryManager.AllocateVirtualMemory(ProcessManager.Process.SafeHandle, (IntPtr)PeImage.PeHeaders.PEHeader.ImageBase, PeImage.PeHeaders.PEHeader.SizeOfImage, MemoryProtectionType.ReadWrite);
            }

            catch (PInvokeException)
            {
                DllBaseAddress = MemoryManager.AllocateVirtualMemory(ProcessManager.Process.SafeHandle, IntPtr.Zero, PeImage.PeHeaders.PEHeader.SizeOfImage, MemoryProtectionType.ReadWrite);
            }

            // Build the import table of the DLL in the local process

            BuildImportTable();

            // Relocate the DLL in the local process

            RelocateImage();

            // Map the sections of the DLL into the remote process

            MapSections();

            // Map the headers of the DLL into the remote process

            MapHeaders();

            // Enable exception handling within the DLL

            EnableExceptionHandling();

            // Call the init routines

            CallInitRoutines();
        }
        internal override void Inject()
        {
            // Write the DLL path into the remote process

            var dllPathUnicodeStringAddress = InitialiseDllPath();

            // Write the shellcode used to call LdrLoadDll into the remote process

            var ldrLoadDllAddress = ProcessManager.GetFunctionAddress("ntdll.dll", "LdrLoadDll");

            var moduleHandleAddress = MemoryManager.AllocateVirtualMemory(ProcessManager.Process.SafeHandle, IntPtr.Zero, IntPtr.Size, MemoryProtectionType.ReadWrite);

            var shellcodeReturnAddress = MemoryManager.AllocateVirtualMemory(ProcessManager.Process.SafeHandle, IntPtr.Zero, sizeof(int), MemoryProtectionType.ReadWrite);

            var shellcode = Assembler.AssembleThreadFunctionCall(new FunctionCall(ProcessManager.IsWow64, ldrLoadDllAddress, CallingConvention.StdCall, new[] { 0, 0, (long)dllPathUnicodeStringAddress, (long)moduleHandleAddress }, shellcodeReturnAddress));

            var shellcodeAddress = MemoryManager.AllocateVirtualMemory(ProcessManager.Process.SafeHandle, IntPtr.Zero, shellcode.Length, MemoryProtectionType.ReadWrite);

            MemoryManager.WriteVirtualMemory(ProcessManager.Process.SafeHandle, shellcodeAddress, shellcode);

            MemoryManager.ProtectVirtualMemory(ProcessManager.Process.SafeHandle, shellcodeAddress, shellcode.Length, MemoryProtectionType.ExecuteRead);

            // Open a handle to the first thread in the remote process

            var firstThreadHandle = Kernel32.OpenThread(Constants.ThreadAllAccess, false, ProcessManager.Process.Threads[0].Id);

            if (firstThreadHandle is null)
            {
                throw new PInvokeException("Failed to call OpenThread");
            }

            if (ProcessManager.IsWow64)
            {
                // Suspend the thread

                if (Kernel32.Wow64SuspendThread(firstThreadHandle) == -1)
                {
                    throw new PInvokeException("Failed to call Wow64SuspendThread");
                }

                // Get the context of the thread

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

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

                Marshal.StructureToPtr(threadContext, threadContextBuffer, false);

                if (!Kernel32.Wow64GetThreadContext(firstThreadHandle, threadContextBuffer))
                {
                    throw new PInvokeException("Failed to call Wow64GetThreadContext");
                }

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

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

                threadContext.Esp -= sizeof(int);

                MemoryManager.WriteVirtualMemory(ProcessManager.Process.SafeHandle, (IntPtr)threadContext.Esp, threadContext.Eip);

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

                threadContext.Eip = (int)shellcodeAddress;

                Marshal.StructureToPtr(threadContext, threadContextBuffer, false);

                // Update the context of the thread

                if (!Kernel32.Wow64SetThreadContext(firstThreadHandle, threadContextBuffer))
                {
                    throw new PInvokeException("Failed to call Wow64SetThreadContext");
                }

                Marshal.FreeHGlobal(threadContextBuffer);
            }

            else
            {
                // Suspend the thread

                if (Kernel32.SuspendThread(firstThreadHandle) == -1)
                {
                    throw new PInvokeException("Failed to call SuspendThread");
                }

                // Get the context of the thread

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

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

                Marshal.StructureToPtr(threadContext, threadContextBuffer, false);

                if (!Kernel32.GetThreadContext(firstThreadHandle, threadContextBuffer))
                {
                    throw new PInvokeException("Failed to call GetThreadContext");
                }

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

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

                threadContext.Rsp -= sizeof(long);

                MemoryManager.WriteVirtualMemory(ProcessManager.Process.SafeHandle, (IntPtr)threadContext.Rsp, threadContext.Rip);

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

                threadContext.Rip = (long)shellcodeAddress;

                Marshal.StructureToPtr(threadContext, threadContextBuffer, false);

                // Update the context of the thread

                if (!Kernel32.SetThreadContext(firstThreadHandle, threadContextBuffer))
                {
                    throw new PInvokeException("Failed to call SetThreadContext");
                }

                Marshal.FreeHGlobal(threadContextBuffer);
            }

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

            User32.PostThreadMessage(ProcessManager.Process.Threads[0].Id, MessageType.Null, IntPtr.Zero, IntPtr.Zero);

            // Resume the thread

            if (Kernel32.ResumeThread(firstThreadHandle) == -1)
            {
                throw new PInvokeException("Failed to call ResumeThread");
            }

            firstThreadHandle.Dispose();

            var shellcodeReturn = MemoryManager.ReadVirtualMemory <int>(ProcessManager.Process.SafeHandle, shellcodeReturnAddress);

            if ((NtStatus)shellcodeReturn != NtStatus.Success)
            {
                throw new RemoteFunctionCallException("Failed to call LdrLoadDll", (NtStatus)shellcodeReturn);
            }

            // Ensure the DLL is loaded before freeing any memory

            while (ProcessManager.Modules.TrueForAll(module => module.FilePath != DllPath))
            {
                ProcessManager.Refresh();
            }

            var dllPathAddress = ProcessManager.IsWow64 ? (IntPtr)MemoryManager.ReadVirtualMemory <UnicodeString32>(ProcessManager.Process.SafeHandle, dllPathUnicodeStringAddress).Buffer
                                                        : (IntPtr)MemoryManager.ReadVirtualMemory <UnicodeString64>(ProcessManager.Process.SafeHandle, dllPathUnicodeStringAddress).Buffer;

            MemoryManager.FreeVirtualMemory(ProcessManager.Process.SafeHandle, dllPathAddress);

            MemoryManager.FreeVirtualMemory(ProcessManager.Process.SafeHandle, dllPathUnicodeStringAddress);

            MemoryManager.FreeVirtualMemory(ProcessManager.Process.SafeHandle, shellcodeReturnAddress);

            // Read the address of the DLL that was loaded in the remote process

            DllBaseAddress = MemoryManager.ReadVirtualMemory <IntPtr>(ProcessManager.Process.SafeHandle, moduleHandleAddress);

            MemoryManager.FreeVirtualMemory(ProcessManager.Process.SafeHandle, moduleHandleAddress);

            if (InjectionFlags.HasFlag(InjectionFlags.HideDllFromPeb))
            {
                // Hide the DLL from the PEB of the remote process

                HideDllFromPeb();
            }

            if (InjectionFlags.HasFlag(InjectionFlags.RandomiseDllHeaders))
            {
                // Randomise the DLL headers

                RandomiseDllHeaders(DllBaseAddress);
            }
        }
        private void CallFunctionInternal(FunctionCall functionCall)
        {
            // Write the shellcode used to perform the function call into the remote process

            var shellcode = Assembler.AssembleFunctionCall(functionCall);

            var shellcodeAddress = MemoryManager.AllocateVirtualMemory(Process.SafeHandle, IntPtr.Zero, shellcode.Length, MemoryProtectionType.ReadWrite);

            MemoryManager.WriteVirtualMemory(Process.SafeHandle, shellcodeAddress, shellcode);

            MemoryManager.ProtectVirtualMemory(Process.SafeHandle, shellcodeAddress, shellcode.Length, MemoryProtectionType.ExecuteRead);

            // Create a thread to execute the shellcode in the remote process

            var ntStatus = Ntdll.NtCreateThreadEx(out var threadHandle, Constants.ThreadAllAccess, IntPtr.Zero, Process.SafeHandle, Modules[0].BaseAddress, IntPtr.Zero, ThreadCreationFlags.CreateSuspended | ThreadCreationFlags.HideFromDebugger, 0, 0, 0, IntPtr.Zero);

            if (ntStatus != NtStatus.Success)
            {
                throw new PInvokeException("Failed to call NtCreateThreadEx", ntStatus);
            }

            if (IsWow64)
            {
                // Get the context of the thread

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

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

                Marshal.StructureToPtr(threadContext, threadContextBuffer, false);

                if (!Kernel32.Wow64GetThreadContext(threadHandle, threadContextBuffer))
                {
                    throw new PInvokeException("Failed to call Wow64GetThreadContext");
                }

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

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

                threadContext.Eax = (int)shellcodeAddress;

                Marshal.StructureToPtr(threadContext, threadContextBuffer, false);

                // Update the context of the thread

                if (!Kernel32.Wow64SetThreadContext(threadHandle, threadContextBuffer))
                {
                    throw new PInvokeException("Failed to call Wow64SetThreadContext");
                }

                Marshal.FreeHGlobal(threadContextBuffer);
            }

            else
            {
                // Get the context of the thread

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

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

                Marshal.StructureToPtr(threadContext, threadContextBuffer, false);

                if (!Kernel32.GetThreadContext(threadHandle, threadContextBuffer))
                {
                    throw new PInvokeException("Failed to call GetThreadContext");
                }

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

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

                threadContext.Rcx = (long)shellcodeAddress;

                Marshal.StructureToPtr(threadContext, threadContextBuffer, false);

                // Update the context of the thread

                if (!Kernel32.SetThreadContext(threadHandle, threadContextBuffer))
                {
                    throw new PInvokeException("Failed to call SetThreadContext");
                }

                Marshal.FreeHGlobal(threadContextBuffer);
            }

            Kernel32.ResumeThread(threadHandle);

            Kernel32.WaitForSingleObject(threadHandle, int.MaxValue);

            threadHandle.Dispose();

            MemoryManager.FreeVirtualMemory(Process.SafeHandle, shellcodeAddress);
        }
예제 #10
0
 /// <summary>
 /// Allocates a region of virtual memory in the remote process
 /// </summary>
 public IntPtr AllocateVirtualMemory(IntPtr baseAddress, int allocationSize, MemoryProtection protectionType = MemoryProtection.ExecuteReadWrite)
 {
     return(_memoryManager.AllocateVirtualMemory(baseAddress, allocationSize, protectionType));
 }