Beispiel #1
0
        internal void Call(IntPtr remoteDllAddress)
        {
            if (_injectionMethod == InjectionMethod.ManualMap || _injectionFlags.HasFlag(InjectionFlags.HideDllFromPeb))
            {
                // Call the entry point of the DLL with DllProcessDetach

                if (!_process.CallFunction <bool>(CallingConvention.StdCall, remoteDllAddress + _peImage.PeHeaders.PEHeader.AddressOfEntryPoint, (long)remoteDllAddress, Constants.DllProcessDetach, 0))
                {
                    throw new RemoteFunctionCallException("Failed to call the entry point of the DLL");
                }

                // Remove the entry for the DLL from the LdrpInvertedFunctionTable

                var rtRemoveInvertedFunctionTableAddress = _process.PdbFile.Value.Symbols["RtlRemoveInvertedFunctionTable"];

                _process.CallFunction(CallingConvention.FastCall, rtRemoveInvertedFunctionTableAddress, (long)remoteDllAddress);

                // Decrease the reference count of the DLL dependencies

                var freeLibraryAddress = _process.GetFunctionAddress("kernel32.dll", "FreeLibrary");

                if (_peImage.ImportedFunctions.Value.GroupBy(importedFunction => importedFunction.Dll).Select(dll => _process.Modules.Find(module => module.Name.Equals(dll.Key, StringComparison.OrdinalIgnoreCase)).BaseAddress).Any(dependencyAddress => !_process.CallFunction <bool>(CallingConvention.StdCall, freeLibraryAddress, (long)dependencyAddress)))
                {
                    throw new RemoteFunctionCallException("Failed to call FreeLibrary");
                }

                // Free the memory allocated for the DLL

                if (_injectionMethod == InjectionMethod.ManualMap)
                {
                    _process.MemoryManager.FreeVirtualMemory(remoteDllAddress);
                }

                else
                {
                    Ntdll.NtUnmapViewOfSection(_process.Process.SafeHandle, remoteDllAddress);
                }
            }

            else
            {
                var freeLibraryAddress = _process.GetFunctionAddress("kernel32.dll", "FreeLibrary");

                if (!_process.CallFunction <bool>(CallingConvention.StdCall, freeLibraryAddress, (long)remoteDllAddress))
                {
                    throw new RemoteFunctionCallException("Failed to call FreeLibrary");
                }
            }
        }
Beispiel #2
0
        public IntPtr Inject()
        {
            // Write the DLL path into the remote process

            var dllPathAddress = _process.MemoryManager.AllocateVirtualMemory(_dllPath.Length, MemoryProtectionType.ReadWrite);

            _process.MemoryManager.WriteVirtualMemory(dllPathAddress, Encoding.Unicode.GetBytes(_dllPath));

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

            IntPtr dllPathUnicodeStringAddress;

            if (_process.IsWow64)
            {
                var dllPathUnicodeString = new UnicodeString32(_dllPath, dllPathAddress);

                dllPathUnicodeStringAddress = _process.MemoryManager.AllocateVirtualMemory(Marshal.SizeOf <UnicodeString32>(), MemoryProtectionType.ReadWrite);

                _process.MemoryManager.WriteVirtualMemory(dllPathUnicodeStringAddress, dllPathUnicodeString);
            }

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

                dllPathUnicodeStringAddress = _process.MemoryManager.AllocateVirtualMemory(Marshal.SizeOf <UnicodeString64>(), MemoryProtectionType.ReadWrite);

                _process.MemoryManager.WriteVirtualMemory(dllPathUnicodeStringAddress, dllPathUnicodeString);
            }

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

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

            var moduleHandleAddress = _process.MemoryManager.AllocateVirtualMemory(IntPtr.Size, MemoryProtectionType.ReadWrite);

            var shellcodeReturnAddress = _process.MemoryManager.AllocateVirtualMemory(sizeof(int), MemoryProtectionType.ReadWrite);

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

            var shellcodeAddress = _process.MemoryManager.AllocateVirtualMemory(shellcode.Length, MemoryProtectionType.ReadWrite);

            _process.MemoryManager.WriteVirtualMemory(shellcodeAddress, shellcode);

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

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

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

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

            if (_process.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);

                _process.MemoryManager.WriteVirtualMemory((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);

                _process.MemoryManager.WriteVirtualMemory((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(_process.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 = _process.MemoryManager.ReadVirtualMemory <int>(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 (_process.Modules.TrueForAll(module => module.FilePath != _dllPath))
            {
                _process.Refresh();
            }

            _process.MemoryManager.FreeVirtualMemory(dllPathAddress);

            _process.MemoryManager.FreeVirtualMemory(dllPathUnicodeStringAddress);

            _process.MemoryManager.FreeVirtualMemory(shellcodeReturnAddress);

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

            var remoteDllAddress = _process.MemoryManager.ReadVirtualMemory <IntPtr>(moduleHandleAddress);

            _process.MemoryManager.FreeVirtualMemory(moduleHandleAddress);

            if (!_injectionFlags.HasFlag(InjectionFlags.RandomiseDllHeaders))
            {
                return(remoteDllAddress);
            }

            // Write over the header region of the DLL with random bytes

            var randomBuffer = new byte[_peImage.PeHeaders.PEHeader.SizeOfHeaders];

            new Random().NextBytes(randomBuffer);

            _process.MemoryManager.WriteVirtualMemory(remoteDllAddress, randomBuffer);

            return(remoteDllAddress);
        }
Beispiel #3
0
        private void BuildImportTable()
        {
            if (_peImage.ImportedFunctions.Value.Count == 0)
            {
                return;
            }

            // Group the imported functions by the DLL they are imported from

            var groupedFunctions = _peImage.ImportedFunctions.Value.GroupBy(importedFunction => importedFunction.Dll).ToList();

            // Ensure the dependencies of the DLL are loaded in the remote process

            var systemFolderPath = _process.IsWow64 ? Environment.GetFolderPath(Environment.SpecialFolder.SystemX86) : Environment.GetFolderPath(Environment.SpecialFolder.System);

            foreach (var dll in groupedFunctions)
            {
                var module = _process.Modules.Find(m => m.Name.Equals(dll.Key, StringComparison.OrdinalIgnoreCase));

                if (module != null)
                {
                    // Increase the reference count of the dependency

                    var ldrAddRefDllAddress = _process.GetFunctionAddress("ntdll.dll", "LdrAddRefDll");

                    var ntStatus = _process.CallFunction <int>(CallingConvention.StdCall, ldrAddRefDllAddress, 0, (long)module.BaseAddress);

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

                    continue;
                }

                // Load the dependency into the remote process

                using (var injector = new Injector(_process.Process.Id, Path.Combine(systemFolderPath, dll.Key), InjectionMethod.HijackThread))
                {
                    injector.InjectDll();
                }

                _process.Refresh();
            }

            // Build the import table in the local process

            foreach (var function in groupedFunctions.SelectMany(dll => dll.Select(f => f)))
            {
                var importedFunctionAddress = function.Name is null
                                            ? _process.GetFunctionAddress(function.Dll, function.Ordinal)
                                            : _process.GetFunctionAddress(function.Dll, function.Name);

                if (_process.IsWow64)
                {
                    Marshal.WriteInt32(_localDllAddress + function.Offset, (int)importedFunctionAddress);
                }

                else
                {
                    Marshal.WriteInt64(_localDllAddress + function.Offset, (long)importedFunctionAddress);
                }
            }
        }
Beispiel #4
0
        internal void Call()
        {
            if (_process.IsWow64)
            {
                foreach (var(entryAddress, entry) in _process.Peb.GetWow64PebEntries())
                {
                    // Read the file path of the entry

                    var entryFilePathBytes = _process.MemoryManager.ReadVirtualMemory((IntPtr)entry.FullDllName.Buffer, entry.FullDllName.Length);

                    var entryFilePath = Encoding.Unicode.GetString(entryFilePathBytes);

                    if (entryFilePath != _dllPath)
                    {
                        continue;
                    }

                    // Remove the entry from the InLoadOrder, InMemoryOrder and InInitializationOrder linked lists

                    RemoveDoublyLinkedListEntry(entry.InLoadOrderLinks);

                    RemoveDoublyLinkedListEntry(entry.InMemoryOrderLinks);

                    RemoveDoublyLinkedListEntry(entry.InInitializationOrderLinks);

                    // Remove the entry from the LdrpHashTable

                    RemoveDoublyLinkedListEntry(entry.HashLinks);

                    // Remove the entry from the LdrpModuleBaseAddressIndex

                    var rtlRbRemoveNodeAddress = _process.GetFunctionAddress("ntdll.dll", "RtlRbRemoveNode");

                    var ldrpModuleBaseAddressIndex = _process.PdbFile.Value.Symbols["LdrpModuleBaseAddressIndex"];

                    _process.CallFunction(CallingConvention.StdCall, rtlRbRemoveNodeAddress, (long)ldrpModuleBaseAddressIndex, (long)(entryAddress + (int)Marshal.OffsetOf <LdrDataTableEntry32>("BaseAddressIndexNode")));
                }
            }

            else
            {
                foreach (var(entryAddress, entry) in _process.Peb.GetPebEntries())
                {
                    // Read the file path of the entry

                    var entryFilePathBytes = _process.MemoryManager.ReadVirtualMemory((IntPtr)entry.FullDllName.Buffer, entry.FullDllName.Length);

                    var entryFilePath = Encoding.Unicode.GetString(entryFilePathBytes);

                    if (entryFilePath != _dllPath)
                    {
                        continue;
                    }

                    // Remove the entry from the InLoadOrder, InMemoryOrder and InInitializationOrder linked lists

                    RemoveDoublyLinkedListEntry(entry.InLoadOrderLinks);

                    RemoveDoublyLinkedListEntry(entry.InMemoryOrderLinks);

                    RemoveDoublyLinkedListEntry(entry.InInitializationOrderLinks);

                    // Remove the entry from the LdrpHashTable

                    RemoveDoublyLinkedListEntry(entry.HashLinks);

                    // Remove the entry from the LdrpModuleBaseAddressIndex

                    var rtlRbRemoveNodeAddress = _process.GetFunctionAddress("ntdll.dll", "RtlRbRemoveNode");

                    var ldrpModuleBaseAddressIndex = _process.PdbFile.Value.Symbols["LdrpModuleBaseAddressIndex"];

                    _process.CallFunction(CallingConvention.StdCall, rtlRbRemoveNodeAddress, (long)ldrpModuleBaseAddressIndex, (long)(entryAddress + (int)Marshal.OffsetOf <LdrDataTableEntry64>("BaseAddressIndexNode")));
                }
            }
        }
Beispiel #5
0
        public IntPtr Call()
        {
            // Write the DLL path into the remote process

            var dllPathAddress = _process.MemoryManager.AllocateVirtualMemory(_dllPath.Length, MemoryProtectionType.ReadWrite);

            _process.MemoryManager.WriteVirtualMemory(dllPathAddress, Encoding.Unicode.GetBytes(_dllPath));

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

            IntPtr dllPathUnicodeStringAddress;

            if (_process.IsWow64)
            {
                var dllPathUnicodeString = new UnicodeString32(_dllPath, dllPathAddress);

                dllPathUnicodeStringAddress = _process.MemoryManager.AllocateVirtualMemory(Marshal.SizeOf <UnicodeString32>(), MemoryProtectionType.ReadWrite);

                _process.MemoryManager.WriteVirtualMemory(dllPathUnicodeStringAddress, dllPathUnicodeString);
            }

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

                dllPathUnicodeStringAddress = _process.MemoryManager.AllocateVirtualMemory(Marshal.SizeOf <UnicodeString64>(), MemoryProtectionType.ReadWrite);

                _process.MemoryManager.WriteVirtualMemory(dllPathUnicodeStringAddress, dllPathUnicodeString);
            }

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

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

            var moduleHandleAddress = _process.MemoryManager.AllocateVirtualMemory(IntPtr.Size, MemoryProtectionType.ReadWrite);

            var ntStatus = _process.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 (_process.Modules.TrueForAll(module => module.FilePath != _dllPath))
            {
                _process.Refresh();
            }

            _process.MemoryManager.FreeVirtualMemory(dllPathAddress);

            _process.MemoryManager.FreeVirtualMemory(dllPathUnicodeStringAddress);

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

            var remoteDllAddress = _process.MemoryManager.ReadVirtualMemory <IntPtr>(moduleHandleAddress);

            _process.MemoryManager.FreeVirtualMemory(moduleHandleAddress);

            if (!_injectionFlags.HasFlag(InjectionFlags.RandomiseDllHeaders))
            {
                return(remoteDllAddress);
            }

            // Write over the header region of the DLL with random bytes

            var randomBuffer = new byte[_peImage.PeHeaders.PEHeader.SizeOfHeaders];

            new Random().NextBytes(randomBuffer);

            _process.MemoryManager.WriteVirtualMemory(remoteDllAddress, randomBuffer);

            return(remoteDllAddress);
        }