bool MapRemoteModule(unsigned long pId, char *module) { IMAGE_DOS_HEADER *dosHd; IMAGE_NT_HEADERS *ntHd; HANDLE hFile = CreateFile(module, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile == INVALID_HANDLE_VALUE) return false; unsigned int fSize; if(GetFileAttributes(module) & FILE_ATTRIBUTE_COMPRESSED) fSize = GetCompressedFileSize(module, NULL); else fSize = GetFileSize(hFile, NULL); unsigned char *dllBin = new unsigned char[fSize]; unsigned int nBytes; ReadFile(hFile, dllBin, fSize, (LPDWORD)&nBytes, FALSE); CloseHandle(hFile); // Every PE file contains a little DOS stub for backwards compatibility // it's only real relevance is that it contains a pointer to the actual // PE header. dosHd = MakePtr(IMAGE_DOS_HEADER *, dllBin, 0); // Make sure we got a valid DOS header if(dosHd->e_magic != IMAGE_DOS_SIGNATURE) { delete dllBin; printf("invalid dos header\n"); return false; } // Get the real PE header from the DOS stub header ntHd = MakePtr(IMAGE_NT_HEADERS *, dllBin, dosHd->e_lfanew); // Verify the PE header if(ntHd->Signature != IMAGE_NT_SIGNATURE) { delete dllBin; printf("invalid nt header\n"); return false; } HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pId); if(!hProcess) { printf("open process failed\n"); return false; } // Allocate space for the module in the remote process void *moduleBase = VirtualAllocEx(hProcess, NULL, ntHd->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); // Make sure we got the memory space we wanted if(!moduleBase) { printf("virtual alloc failed (moduleBase)\n"); return false; } // Allocate space for our stub void *stubBase = VirtualAllocEx(hProcess, NULL, MakeDelta(SIZE_T, DC_stubend, DllCall_stub), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); // Make sure we got the memory space we wanted if(!stubBase) { printf("virtual alloc failed(stubBase)\n"); return false; } // Fix up the import table of the new module IMAGE_IMPORT_DESCRIPTOR *impDesc = (IMAGE_IMPORT_DESCRIPTOR *)GetPtrFromRVA( (DWORD)(ntHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress), ntHd, (PBYTE)dllBin); if(ntHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size) FixImports(pId, (unsigned char *)dllBin, ntHd, impDesc); // Fix "base relocations" of the new module. Base relocations are places // in the module that use absolute addresses to reference data. Since // the base address of the module can be different at different times, // the base relocation data is necessary to make the module loadable // at any address. IMAGE_BASE_RELOCATION *reloc = (IMAGE_BASE_RELOCATION *)GetPtrFromRVA( (DWORD)(ntHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress), ntHd, (PBYTE)dllBin); if(ntHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size) FixRelocs(dllBin, moduleBase, ntHd, reloc, ntHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size); // Write the PE header into the remote process's memory space WriteProcessMemory(hProcess, moduleBase, dllBin, ntHd->FileHeader.SizeOfOptionalHeader + sizeof(ntHd->FileHeader) + sizeof(ntHd->Signature), (SIZE_T *)&nBytes); // Map the sections into the remote process(they need to be aligned // along their virtual addresses) MapSections(hProcess, moduleBase, dllBin, ntHd); // Change the page protection on the DllCall_stub function from PAGE_EXECUTE_READ // to PAGE_EXECUTE_READWRITE, so we can patch it. VirtualProtect((LPVOID)DllCall_stub, MakeDelta(SIZE_T, DC_stubend, DllCall_stub), PAGE_EXECUTE_READWRITE, (DWORD *)&nBytes); // Patch the stub so it calls the correct address *MakePtr(unsigned long *, DllCall_stub, 9) = MakePtr(unsigned long, moduleBase, ntHd->OptionalHeader.AddressOfEntryPoint); // Write the stub into the remote process WriteProcessMemory(hProcess, stubBase, (LPVOID)DllCall_stub, MakeDelta(SIZE_T, DC_stubend, DllCall_stub), (SIZE_T *)&nBytes); // Execute our stub in the remote process CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)stubBase, moduleBase, // Pass the base address of the module as the argument to the stub. // All a module handle is, is the base address of the module(except // in windows CE), so we're really passing a handle to the module // so that it can refer to itself, create dialogs, etc.. 0, NULL); delete dllBin; return true; }
//////////////////////////////////////////////////////////////////////////////////////////// // MapRemoteModuleW //////////////////////////////////////////////////////////////////////////////////////////// BOOL MapRemoteModuleW( DWORD dwProcessId, LPCWSTR lpModulePath ) { BOOL bRet = FALSE; HANDLE hFile = 0; DWORD fileSize = 0; BYTE *dllBin = 0; PIMAGE_NT_HEADERS nt_header = 0; PIMAGE_DOS_HEADER dos_header = 0; HANDLE hProcess = 0; LPVOID lpModuleBase = 0; PIMAGE_IMPORT_DESCRIPTOR pImgImpDesc = 0; PIMAGE_BASE_RELOCATION pImgBaseReloc = 0; PIMAGE_TLS_DIRECTORY pImgTlsDir = 0; __try { // Get a handle for the target process. hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | // Required by Alpha PROCESS_CREATE_THREAD | // For CreateRemoteThread PROCESS_VM_OPERATION | // For VirtualAllocEx/VirtualFreeEx PROCESS_VM_WRITE | // For WriteProcessMemory PROCESS_VM_READ, FALSE, dwProcessId); if(!hProcess) { PRINT_ERROR_MSGA("Could not get handle to process (PID: 0x%X).", dwProcessId); __leave; } hFile = CreateFileW( lpModulePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile == INVALID_HANDLE_VALUE) { PRINT_ERROR_MSGA("CreateFileW failed."); __leave; } if(GetFileAttributesW(lpModulePath) & FILE_ATTRIBUTE_COMPRESSED) { fileSize = GetCompressedFileSizeW(lpModulePath, NULL); } else { fileSize = GetFileSize(hFile, NULL); } if(fileSize == INVALID_FILE_SIZE) { PRINT_ERROR_MSGA("Could not get size of file."); __leave; } dllBin = (BYTE*)malloc(fileSize); { DWORD NumBytesRead = 0; if(!ReadFile(hFile, dllBin, fileSize, &NumBytesRead, FALSE)) { PRINT_ERROR_MSGA("ReadFile failed."); } } dos_header = (PIMAGE_DOS_HEADER)dllBin; // Make sure we got a valid DOS header if(dos_header->e_magic != IMAGE_DOS_SIGNATURE) { PRINT_ERROR_MSGA("Invalid DOS header."); __leave; } // Get the real PE header from the DOS stub header nt_header = (PIMAGE_NT_HEADERS)( (DWORD_PTR)dllBin + dos_header->e_lfanew); // Verify the PE header if(nt_header->Signature != IMAGE_NT_SIGNATURE) { PRINT_ERROR_MSGA("Invalid PE header."); __leave; } // Allocate space for the module in the remote process lpModuleBase = VirtualAllocEx( hProcess, NULL, nt_header->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if(!lpModuleBase) { PRINT_ERROR_MSGA("Could not allocate memory in remote process."); __leave; } // fix imports pImgImpDesc = (PIMAGE_IMPORT_DESCRIPTOR)GetPtrFromRVA( nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, nt_header, (PBYTE)dllBin); if(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size) { if(!FixIAT(dwProcessId, hProcess, (PBYTE)dllBin, nt_header, pImgImpDesc)) { PRINT_ERROR_MSGA("@Fixing imports."); __leave; } } // fix relocs pImgBaseReloc = (PIMAGE_BASE_RELOCATION)GetPtrFromRVA( (DWORD)(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress), nt_header, (PBYTE)dllBin); if(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size) { if(!FixRelocations(dllBin, lpModuleBase, nt_header, pImgBaseReloc)) { PRINT_ERROR_MSGA("@Fixing relocations."); __leave; } } // Write the PE header into the remote process's memory space { SIZE_T NumBytesWritten = 0; SIZE_T nSize = nt_header->FileHeader.SizeOfOptionalHeader + sizeof(nt_header->FileHeader) + sizeof(nt_header->Signature); if(!WriteProcessMemory(hProcess, lpModuleBase, dllBin, nSize, &NumBytesWritten) || NumBytesWritten != nSize) { PRINT_ERROR_MSGA("Could not write to memory in remote process."); __leave; } } // Map the sections into the remote process(they need to be aligned // along their virtual addresses) if(!MapSections(hProcess, lpModuleBase, dllBin, nt_header)) { PRINT_ERROR_MSGA("@Map sections."); __leave; } // call all tls callbacks // pImgTlsDir = (PIMAGE_TLS_DIRECTORY)GetPtrFromRVA( nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress, nt_header, (PBYTE)dllBin); if(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size) { if(!CallTlsInitializers(dllBin, nt_header, hProcess, (HMODULE)lpModuleBase, DLL_PROCESS_ATTACH, pImgTlsDir)) { PRINT_ERROR_MSGA("@Call TLS initializers."); __leave; } } // call entry point if(!RemoteDllMainCall( hProcess, (LPVOID)( (DWORD_PTR)lpModuleBase + nt_header->OptionalHeader.AddressOfEntryPoint), (HMODULE)lpModuleBase, 1, 0)) { PRINT_ERROR_MSGA("@Call DllMain."); __leave; } bRet = TRUE; wprintf(L"Successfully injected (%s | PID: %x):\n\n" L" AllocationBase:\t0x%p\n" L" EntryPoint:\t\t0x%p\n" L" SizeOfImage:\t\t0x%p\n" L" CheckSum:\t\t0x%p\n", lpModulePath, dwProcessId, lpModuleBase, (DWORD_PTR)lpModuleBase + nt_header->OptionalHeader.AddressOfEntryPoint, nt_header->OptionalHeader.SizeOfImage, nt_header->OptionalHeader.CheckSum); } __finally { if(hFile) { CloseHandle(hFile); } if(dllBin) { free(dllBin); } if(hProcess) { CloseHandle(hProcess); } } return bRet; }
bool MapRemoteModule(unsigned long pId, const char *module) { IMAGE_DOS_HEADER *dosHd; IMAGE_NT_HEADERS *ntHd; IMAGE_NT_HEADERS64 *ntHd64 = NULL; HANDLE hFile = CreateFileA(module, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile == INVALID_HANDLE_VALUE) return false; unsigned int fSize; if(GetFileAttributesA(module) & FILE_ATTRIBUTE_COMPRESSED) fSize = GetCompressedFileSizeA(module, NULL); else fSize = GetFileSize(hFile, NULL); unsigned char *dllBin = new unsigned char[fSize]; unsigned int nBytes; // copy into our dllBin buffer the entire DLL ReadFile(hFile, dllBin, fSize, (LPDWORD)&nBytes, FALSE); CloseHandle(hFile); // Every PE file contains a little DOS stub for backwards compatibility // its only real relevance is that it contains a pointer to the actual // PE header. dosHd = MakePtr(IMAGE_DOS_HEADER *, dllBin, 0); // Make sure we got a valid DOS header if(dosHd->e_magic != IMAGE_DOS_SIGNATURE) { wxMessageBox( _("The DOS header was invalid"), _("Error: Invalid DOS header"), wxICON_ERROR ); delete [] dllBin; return false; } // Get the real PE header from the DOS stub header // This header contains pointers to the Optional Header and the // COFF File Header. ntHd = MakePtr(IMAGE_NT_HEADERS *, dllBin, dosHd->e_lfanew); // Verify that the PE header is PE00 if(ntHd->Signature != IMAGE_NT_SIGNATURE) { wxMessageBox( _("The PE Header was not found."), _("Error: PE Header not found"), wxICON_ERROR ); delete [] dllBin; return false; } // Verify that the image file is a DLL if( (ntHd->FileHeader.Characteristics & IMAGE_FILE_DLL) == false ) { wxMessageBox( _("You may only inject DLL image files."), _("Error: Injected image file was not a DLL"), wxICON_ERROR ); delete [] dllBin; return false; } // Open the target process HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pId); // We failed to open the process, so return false if(!hProcess) { wxMessageBox( _("Failed to open target process."), _("Error: Failed to open process"), wxICON_ERROR ); delete [] dllBin; return false; } // Determine whether the image is a PE32 or PE32+ executable if( ntHd->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC ) { if( ntHd->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC ) { ntHd64 = (IMAGE_NT_HEADERS64 *)ntHd; wxMessageBox( _("Image is a PE32+ executable.\nInjector Gadget doesn't support PE32+ executables yet."), _("Error: Image is not a PE32 executable"), wxICON_ERROR ); } else if( ntHd->OptionalHeader.Magic == IMAGE_ROM_OPTIONAL_HDR_MAGIC ) { wxMessageBox( _("Image is a ROM image.\nInjector Gadget doesn't support ROM images."), _("Error: Image is not a PE32 executable"), wxICON_ERROR ); } delete [] dllBin; return false; } // Allocate space for the module in the remote process void *imageBase = VirtualAllocEx(hProcess, NULL, ntHd->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); // Make sure we got the memory space we wanted if(!imageBase) { delete [] dllBin; return false; } // Allocate space for our stub void *stubBase = VirtualAllocEx(hProcess, NULL, MakeDelta(SIZE_T, DC_stubend, DllCall_stub), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); // Make sure we got the memory space we wanted if(!stubBase) { delete [] dllBin; return false; } // We now need to fix up the tables. // The tables are as follows (in order): // Export Table, Import Table, Resource Table, Exception Table, // Certificate Table, Base Relocation Table, Debug, Architecture, // Global Ptr, TLS Table, Load Config Table, Bound Import, IAT, // Delay Import Descriptor, CLR Runtime Header, Reserved // First important section is the Export Table. We're going to skip this // since the whole point of cloaking a DLL is to hide its presence. // Second important section is the Import Table. We really need this. if( ntHd->OptionalHeader.NumberOfRvaAndSizes > 1 ) { IMAGE_IMPORT_DESCRIPTOR *impDesc = (IMAGE_IMPORT_DESCRIPTOR *)GetPtrFromRVA( (DWORD)(ntHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress), ntHd, (PBYTE)dllBin); if(ntHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size) FixImports(pId, (unsigned char *)dllBin, ntHd, impDesc); else // size was 0 for the import directory entry { wxMessageBox( _("Size of import directory entry was 0"), _("Error: Import Directory size is 0"), wxICON_ERROR); delete [] dllBin; return false; } } else // IMAGE_DIRECTORY_ENTRY_IMPORT didn't exist in the data directories { wxMessageBox( _("The import table referenced an invalid index in the data directory."), _("Error: Import table could not be located"), wxICON_ERROR ); delete [] dllBin; return false; } // Fix "base relocations" of the new module. Base relocations are places // in the module that use absolute addresses to reference data. Since // the base address of the module can be different at different times, // the base relocation data is necessary to make the module loadable // at any address. IMAGE_BASE_RELOCATION *reloc = (IMAGE_BASE_RELOCATION *)GetPtrFromRVA( (DWORD)(ntHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress), ntHd, (PBYTE)dllBin); if(ntHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size) FixRelocs(dllBin, imageBase, ntHd, reloc, ntHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size); // Write the PE header into the remote process's memory space WriteProcessMemory(hProcess, imageBase, dllBin, ntHd->FileHeader.SizeOfOptionalHeader + sizeof(ntHd->FileHeader) + sizeof(ntHd->Signature), (SIZE_T *)&nBytes); // Map the sections into the remote process(they need to be aligned // along their virtual addresses) MapSections(hProcess, imageBase, dllBin, ntHd); // Change the page protection on the DllCall_stub function from PAGE_EXECUTE_READ // to PAGE_EXECUTE_READWRITE, so we can patch it. VirtualProtect((LPVOID)DllCall_stub, MakeDelta(SIZE_T, DC_stubend, DllCall_stub), PAGE_EXECUTE_READWRITE, (DWORD *)&nBytes); // Patch the stub so it calls the correct address *MakePtr(unsigned long *, DllCall_stub, 9) = MakePtr(unsigned long, imageBase, ntHd->OptionalHeader.AddressOfEntryPoint); // Write the stub into the remote process WriteProcessMemory(hProcess, stubBase, (LPVOID)DllCall_stub, MakeDelta(SIZE_T, DC_stubend, DllCall_stub), (SIZE_T *)&nBytes); #ifdef __USING_DEBUGGER wxMessageBox(_("Calling CreateRemoteThread")); wxMessageBox( _("hProcess: ") + wxString::Format("%08X",hProcess) ); wxMessageBox( _("stubBase: ") + wxString::Format("%08X",stubBase) ); wxMessageBox( _("moduleBas: ") + wxString::Format("%08X",imageBase) ); #endif // Execute our stub in the remote process CreateRemoteThread(hProcess, NULL, ntHd->OptionalHeader.SizeOfStackCommit, (LPTHREAD_START_ROUTINE)stubBase, imageBase, // Pass the base address of the module as the argument to the stub. // All a module handle is, is the base address of the module(except // in windows CE), so we're really passing a handle to the module // so that it can refer to itself, create dialogs, etc.. 0, NULL); delete dllBin; return true; }