#include #include "ldr.h" // Parse reloc table void ldr_reloc(LPVOID pModule, PIMAGE_NT_HEADERS pImageNtHeader) { DWORD dwRelocSize = pImageNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; DWORD dwRelocAddr = pImageNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress; if (dwRelocAddr == 0 || dwRelocSize == 0) return; // no reloc table here! LPBYTE lpPtr = CALC_OFFSET(LPBYTE, pModule, dwRelocAddr); //std::cout << "sizeof(base_relocation_block): " << sizeof(base_relocation_block) << std::endl; //std::cout << "sizeof(base_relocation_entry): " << sizeof(base_relocation_entry) << std::endl; while(dwRelocSize > 0) { base_relocation_block_t block; memcpy(&block, lpPtr, sizeof(base_relocation_block_t)); dwRelocSize -= block.BlockSize; lpPtr += sizeof(base_relocation_block_t); //std::cout << "Block: " << std::hex << block.PageRVA << std::endl; //std::cout << " Size: " << std::hex << block.BlockSize << std::endl; block.BlockSize -= 8; while(block.BlockSize) { base_relocation_entry_t entry; memcpy(&entry, lpPtr, sizeof(WORD)); //__asm mov ecx, entry.offset; LPDWORD ptrOffset = CALC_OFFSET(LPDWORD, pModule, block.PageRVA + entry.offset); DWORD dwOldValue = *ptrOffset; DWORD dwNewValue = dwOldValue - pImageNtHeader->OptionalHeader.ImageBase + (DWORD) pModule; LPWORD ptrHighOffset = CALC_OFFSET_DISP(LPWORD, pModule, block.PageRVA + entry.offset, 2); LPWORD ptrLowOffset = CALC_OFFSET_DISP(LPWORD, pModule, block.PageRVA + entry.offset, 0); WORD wLowNewOffset = (WORD) ((DWORD) pModule & 0xffff); WORD wHighNewOffset = (WORD) (((DWORD) pModule & 0xffff0000) >> 16); switch(entry.type) { // The base relocation is skipped. This type can be used to pad a block. case IMAGE_REL_BASED_ABSOLUTE: //std::cout << "Unsupported" << std::endl; break; // The base relocation adds the high 16 bits of the difference to the 16-bit field at offset. The 16-bit field represents the high value of a 32-bit word. case IMAGE_REL_BASED_HIGH: //*ptrHighOffset = *ptrHighOffset - wHighNewOffset; break; // The base relocation adds the low 16 bits of the difference to the 16-bit field at offset. The 16-bit field represents the low half of a 32-bit word. case IMAGE_REL_BASED_LOW: break; // The base relocation applies all 32 bits of the difference to the 32-bit field at offset case IMAGE_REL_BASED_HIGHLOW: *ptrOffset = dwNewValue; break; // The base relocation adds the high 16 bits of the difference to the 16bit field at offset. The 16-bit field represents the high value of a 32-bit word. // The low 16 bits of the 32-bit value are stored in the 16-bit word that follows this base relocation. This means that this base relocation occupies two slots. case IMAGE_REL_BASED_HIGHADJ: break; // The base relocation applies the difference to the 64-bit field at offset. case IMAGE_REL_BASED_DIR64: break; } // FIX ENTRY++ lpPtr += sizeof(base_relocation_entry); block.BlockSize -= 2; } } } typedef HMODULE (WINAPI *LoadLibraryA_p)(LPCSTR strDllName); void ldr_importdir(LPVOID pModule, PIMAGE_NT_HEADERS pImageNtHeader) { CHAR strKernel32A[] = {'k', 'e', 'r', 'n', 'e', 'l', '3', '2', 0x0}; WCHAR strKernel32[] = {L'k', L'e', L'r', L'n', L'e', L'l', L'3', L'2', L'\0'}; CHAR strLoadLibrary[] = { 'L', 'o', 'a', 'd', 'L', 'i', 'b', 'r', 'a', 'r', 'y', 'A', 0x0 }; DWORD dwIatSize = pImageNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size; DWORD dwIatAddr = pImageNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; // no import directory here! if (dwIatAddr == 0) return; PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor = CALC_OFFSET(PIMAGE_IMPORT_DESCRIPTOR, pModule, dwIatAddr); while(pImportDescriptor) { if (pImportDescriptor->FirstThunk == 0) { pImportDescriptor = NULL; continue; } LPDWORD pImportLookupTable = CALC_OFFSET(LPDWORD, pModule, pImportDescriptor->FirstThunk); LPCSTR lpModName = CALC_OFFSET(LPCSTR, pModule, pImportDescriptor->Name); LoadLibraryA_p fpLoadLibraryA = (LoadLibraryA_p) GetProcAddress(LoadLibrary(strKernel32), strLoadLibrary); HMODULE hMod = fpLoadLibraryA(lpModName); //HMODULE hMod = LoadLibraryA(lpModName); if (hMod != NULL) while(*pImportLookupTable != 0x00) { if ((*pImportLookupTable & IMAGE_ORDINAL_FLAG) != 0x00) { // IMPORT BY ORDINAL DWORD pOrdinalValue = *(CALC_OFFSET(LPDWORD, pImportLookupTable, 0)) & 0x0000ffff; *pImportLookupTable = (DWORD) GetProcAddress(hMod, (LPCSTR) pOrdinalValue); // SOSTITUISCE EXITPROCESS CON EXITTHREAD if (*pImportLookupTable == (DWORD)GetProcAddress(fpLoadLibraryA(strKernel32A), "ExitProcess")) *pImportLookupTable = (DWORD)ExitThread; } else { // IMPORT BY NAME LPCSTR lpProcName = CALC_OFFSET_DISP(LPCSTR, pModule, (*pImportLookupTable), 2); // adding two bytes *pImportLookupTable = (DWORD) GetProcAddress(hMod, lpProcName); // SOSTITUISCE EXITPROCESS CON EXITTHREAD if (*pImportLookupTable == (DWORD)GetProcAddress(fpLoadLibraryA(strKernel32A), "ExitProcess")) *pImportLookupTable = (DWORD)ExitThread; } pImportLookupTable++; } pImportDescriptor++; } } ULONG ldr_exportdir(HMODULE hModule) { ULONG pFunction = NULL; PIMAGE_DOS_HEADER pImageDosHeader = (PIMAGE_DOS_HEADER) hModule; PIMAGE_NT_HEADERS pImageNtHeaders = CALC_OFFSET(PIMAGE_NT_HEADERS, hModule, pImageDosHeader->e_lfanew); PIMAGE_DATA_DIRECTORY pExportDir = &pImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; if (pExportDir->Size == 0 || pExportDir->VirtualAddress == 0) { // this module have no export directory) return pFunction; } // Processing export directory table PIMAGE_EXPORT_DIRECTORY pExportDirectory = (PIMAGE_EXPORT_DIRECTORY) ((PBYTE)pExportDir->VirtualAddress + (ULONG)hModule); //DWORD dwOrdinalBase = pExportDirectory->Base; // Fixing pointer with BASE pExportDirectory->AddressOfNames += DWORD(hModule); pExportDirectory->AddressOfFunctions += DWORD(hModule); pExportDirectory->AddressOfNameOrdinals += DWORD(hModule); // Fixing pointers of names and functions LPDWORD ptrFunctions = (LPDWORD) pExportDirectory->AddressOfFunctions; LPDWORD ptrNames = (LPDWORD) pExportDirectory->AddressOfNames; for(DWORD i = 0; i < pExportDirectory->NumberOfNames; i++) { ptrFunctions[i] += (DWORD) hModule; ptrNames[i] += (DWORD) hModule; pFunction = ptrFunctions[i]; } return pFunction; } BOOL MemoryLoader(LPBYTE lpRawBuffer) { LPVOID lpAddress = NULL; DWORD header_size = 0; IMAGE_DOS_HEADER dos_header; IMAGE_NT_HEADERS32 pe_header; if (lpRawBuffer != NULL) { memcpy(&dos_header, lpRawBuffer, sizeof(dos_header)); // get DOS HEADER if (dos_header.e_magic != IMAGE_DOS_SIGNATURE || dos_header.e_lfanew == 0) { // invalid MZ signature return FALSE; } memcpy(&pe_header, CALC_OFFSET(LPVOID, lpRawBuffer, dos_header.e_lfanew), sizeof(pe_header)); if (pe_header.Signature != IMAGE_NT_SIGNATURE) { // invalid PE signature return FALSE; } lpAddress = VirtualAlloc(NULL, pe_header.OptionalHeader.SizeOfImage, MEM_COMMIT, PAGE_READWRITE); // allocate image if (lpAddress == NULL) { // wrong image size or insufficient memory! return FALSE; } header_size = dos_header.e_lfanew + pe_header.FileHeader.SizeOfOptionalHeader + sizeof(pe_header.FileHeader) + 4; IMAGE_SECTION_HEADER section; LPVOID lpBufferPtr = CALC_OFFSET(LPVOID, lpRawBuffer, header_size); memcpy(§ion, lpBufferPtr, sizeof(section)); // now first section is in memory?!?!? memcpy(lpAddress, lpRawBuffer, section.PointerToRawData); // loading PE header in memory! PIMAGE_SECTION_HEADER sections = CALC_OFFSET(PIMAGE_SECTION_HEADER, lpAddress, header_size); for(USHORT i = 0; i < pe_header.FileHeader.NumberOfSections; i++, sections++) { LPVOID lpSectionBuffer = CALC_OFFSET(LPVOID, lpAddress, sections->VirtualAddress); // raw copy .. // @TODO: PointerToRawData can be 0 for uninitialized sections like SizeOfRawData memcpy(lpSectionBuffer, CALC_OFFSET(LPVOID, lpRawBuffer, sections->PointerToRawData), sections->SizeOfRawData); } } DWORD ignore = 0; // section initialized! // @TODO: relocations ldr_reloc(lpAddress, &pe_header); // @TODO: IAT ldr_importdir((HMODULE) lpAddress, &pe_header); PIMAGE_SECTION_HEADER sections = CALC_OFFSET(PIMAGE_SECTION_HEADER, lpAddress, header_size); for(USHORT i = 0; i < pe_header.FileHeader.NumberOfSections; i++, sections++) { LPVOID lpSectionBuffer = CALC_OFFSET(LPVOID, lpAddress, sections->VirtualAddress); if ((sections->Characteristics & IMAGE_SCN_MEM_EXECUTE) == IMAGE_SCN_MEM_EXECUTE) { // set +X to page! VirtualProtect(lpSectionBuffer, sections->Misc.VirtualSize, PAGE_EXECUTE_READWRITE, &ignore); } } // at end set +R section VirtualProtect(lpAddress, header_size, PAGE_READONLY, &ignore); CALC_OFFSET(LPVOID, lpAddress, pe_header.OptionalHeader.AddressOfEntryPoint); MAIN ptrMain = (MAIN)CALC_OFFSET(LPVOID, lpAddress, pe_header.OptionalHeader.AddressOfEntryPoint); ptrMain((HINSTANCE)lpAddress, NULL, "", 0xa); return TRUE; } .