added a PE_find_static_relative_reference function (not used yet)

Function that can be used to find cross-references of a global variable
or a function
This commit is contained in:
Maxime Meignan
2022-08-22 17:22:46 +02:00
parent 1e8713cfb5
commit 4d2789b21b
3 changed files with 372 additions and 354 deletions
+1 -1
View File
@@ -58,5 +58,5 @@ PVOID PE_functionAddr(PE* pe, LPCSTR functionName);
VOID PE_parseRelocations(PE* pe); VOID PE_parseRelocations(PE* pe);
VOID PE_rebasePE(PE* pe, LPVOID newBaseAddress); VOID PE_rebasePE(PE* pe, LPVOID newBaseAddress);
PVOID PE_search_pattern(PE* pe, PBYTE pattern, size_t patternSize); PVOID PE_search_pattern(PE* pe, PBYTE pattern, size_t patternSize);
PVOID PE_search_relative_reference(PE* pe, PVOID target, DWORD relativeReferenceSize); DWORD PE_find_static_relative_reference(PE* pe, DWORD targetRVA, DWORD relativeReferenceSize, DWORD fromRVA);
VOID PE_destroy(PE* pe); VOID PE_destroy(PE* pe);
+370 -352
View File
@@ -11,15 +11,15 @@
IMAGE_SECTION_HEADER* PE_sectionHeader_fromRVA(PE* pe, DWORD rva) { IMAGE_SECTION_HEADER* PE_sectionHeader_fromRVA(PE* pe, DWORD rva) {
IMAGE_SECTION_HEADER* sectionHeaders = pe->sectionHeaders; IMAGE_SECTION_HEADER* sectionHeaders = pe->sectionHeaders;
for (DWORD sectionIndex = 0; sectionIndex < pe->ntHeader->FileHeader.NumberOfSections; sectionIndex++) { for (DWORD sectionIndex = 0; sectionIndex < pe->ntHeader->FileHeader.NumberOfSections; sectionIndex++) {
DWORD currSectionVA = sectionHeaders[sectionIndex].VirtualAddress; DWORD currSectionVA = sectionHeaders[sectionIndex].VirtualAddress;
DWORD currSectionVSize = sectionHeaders[sectionIndex].Misc.VirtualSize; DWORD currSectionVSize = sectionHeaders[sectionIndex].Misc.VirtualSize;
if (currSectionVA <= rva && rva < currSectionVA + currSectionVSize) { if (currSectionVA <= rva && rva < currSectionVA + currSectionVSize) {
return &sectionHeaders[sectionIndex]; return &sectionHeaders[sectionIndex];
} }
} }
return NULL; return NULL;
} }
/* /*
@@ -28,395 +28,413 @@ Exemple : PE_nextSectionHeader_fromPermissions(pe, textSection, 1, -1, 0) return
Returns NULL if no section header is found. Returns NULL if no section header is found.
*/ */
IMAGE_SECTION_HEADER* PE_nextSectionHeader_fromPermissions(PE* pe, IMAGE_SECTION_HEADER* prev, INT8 readable, INT8 writable, INT8 executable) { IMAGE_SECTION_HEADER* PE_nextSectionHeader_fromPermissions(PE* pe, IMAGE_SECTION_HEADER* prev, INT8 readable, INT8 writable, INT8 executable) {
IMAGE_SECTION_HEADER* sectionHeaders = pe->sectionHeaders; IMAGE_SECTION_HEADER* sectionHeaders = pe->sectionHeaders;
DWORD firstSectionIndex = prev == NULL ? 0 : (DWORD)((prev + 1) - sectionHeaders); DWORD firstSectionIndex = prev == NULL ? 0 : (DWORD)((prev + 1) - sectionHeaders);
for (DWORD sectionIndex = firstSectionIndex; sectionIndex < pe->ntHeader->FileHeader.NumberOfSections; sectionIndex++) { for (DWORD sectionIndex = firstSectionIndex; sectionIndex < pe->ntHeader->FileHeader.NumberOfSections; sectionIndex++) {
DWORD sectionCharacteristics = sectionHeaders[sectionIndex].Characteristics; DWORD sectionCharacteristics = sectionHeaders[sectionIndex].Characteristics;
if (readable != 0) { if (readable != 0) {
if (sectionCharacteristics & IMAGE_SCN_MEM_READ) { if (sectionCharacteristics & IMAGE_SCN_MEM_READ) {
if (readable == -1) { if (readable == -1) {
continue; continue;
} }
} }
else { else {
if (readable == 1) { if (readable == 1) {
continue; continue;
} }
} }
} }
if (writable != 0) { if (writable != 0) {
if (sectionCharacteristics & IMAGE_SCN_MEM_WRITE) { if (sectionCharacteristics & IMAGE_SCN_MEM_WRITE) {
if (writable == -1) { if (writable == -1) {
continue; continue;
} }
} }
else { else {
if (writable == 1) { if (writable == 1) {
continue; continue;
} }
} }
} }
if (executable != 0) { if (executable != 0) {
if (sectionCharacteristics & IMAGE_SCN_MEM_EXECUTE) { if (sectionCharacteristics & IMAGE_SCN_MEM_EXECUTE) {
if (executable == -1) { if (executable == -1) {
continue; continue;
} }
} }
else { else {
if (executable == 1) { if (executable == 1) {
continue; continue;
} }
} }
} }
return &sectionHeaders[sectionIndex]; return &sectionHeaders[sectionIndex];
} }
return NULL; return NULL;
} }
PVOID PE_RVA_to_Addr(PE* pe, DWORD rva) { PVOID PE_RVA_to_Addr(PE* pe, DWORD rva) {
PVOID peBase = pe->dosHeader; PVOID peBase = pe->dosHeader;
if (pe->isMemoryMapped) { if (pe->isMemoryMapped) {
return (PBYTE)peBase + rva; return (PBYTE)peBase + rva;
} }
IMAGE_SECTION_HEADER* rvaSectionHeader = PE_sectionHeader_fromRVA(pe, rva); IMAGE_SECTION_HEADER* rvaSectionHeader = PE_sectionHeader_fromRVA(pe, rva);
if (NULL == rvaSectionHeader) { if (NULL == rvaSectionHeader) {
return NULL; return NULL;
} }
else { else {
return (PBYTE)peBase + rvaSectionHeader->PointerToRawData + (rva - rvaSectionHeader->VirtualAddress); return (PBYTE)peBase + rvaSectionHeader->PointerToRawData + (rva - rvaSectionHeader->VirtualAddress);
} }
} }
DWORD PE_Addr_to_RVA(PE* pe, PVOID addr) { DWORD PE_Addr_to_RVA(PE* pe, PVOID addr) {
for (int i = 0; i < pe->ntHeader->FileHeader.NumberOfSections; i++) { for (int i = 0; i < pe->ntHeader->FileHeader.NumberOfSections; i++) {
DWORD sectionVA = pe->sectionHeaders[i].VirtualAddress; DWORD sectionVA = pe->sectionHeaders[i].VirtualAddress;
DWORD sectionSize = pe->sectionHeaders[i].Misc.VirtualSize; DWORD sectionSize = pe->sectionHeaders[i].Misc.VirtualSize;
PVOID sectionAddr = PE_RVA_to_Addr(pe, sectionVA); PVOID sectionAddr = PE_RVA_to_Addr(pe, sectionVA);
if (sectionAddr <= addr && addr < (PVOID)((intptr_t)sectionAddr + (intptr_t)sectionSize)) { if (sectionAddr <= addr && addr < (PVOID)((intptr_t)sectionAddr + (intptr_t)sectionSize)) {
intptr_t relativeOffset = ((intptr_t)addr - (intptr_t)sectionAddr); intptr_t relativeOffset = ((intptr_t)addr - (intptr_t)sectionAddr);
assert(relativeOffset <= MAXDWORD); assert(relativeOffset <= MAXDWORD);
return sectionVA + (DWORD)relativeOffset; return sectionVA + (DWORD)relativeOffset;
} }
} }
return 0; return 0;
} }
VOID PE_parseRelocations(PE* pe) { VOID PE_parseRelocations(PE* pe) {
IMAGE_BASE_RELOCATION* relocationBlocks = PE_RVA_to_Addr(pe, pe->dataDir[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); IMAGE_BASE_RELOCATION* relocationBlocks = PE_RVA_to_Addr(pe, pe->dataDir[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
IMAGE_BASE_RELOCATION* relocationBlockPtr = relocationBlocks; IMAGE_BASE_RELOCATION* relocationBlockPtr = relocationBlocks;
IMAGE_BASE_RELOCATION* nextRelocationBlockPtr; IMAGE_BASE_RELOCATION* nextRelocationBlockPtr;
pe->nbRelocations = 0; pe->nbRelocations = 0;
DWORD relocationsLength = 16; DWORD relocationsLength = 16;
pe->relocations = calloc(relocationsLength, sizeof(PE_relocation)); pe->relocations = calloc(relocationsLength, sizeof(PE_relocation));
if (NULL == pe->relocations) if (NULL == pe->relocations)
exit(1); exit(1);
while (((size_t)relocationBlockPtr - (size_t)relocationBlocks) < pe->dataDir[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size) { while (((size_t)relocationBlockPtr - (size_t)relocationBlocks) < pe->dataDir[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size) {
IMAGE_RELOCATION_ENTRY* relocationEntry = (IMAGE_RELOCATION_ENTRY*)&relocationBlockPtr[1]; IMAGE_RELOCATION_ENTRY* relocationEntry = (IMAGE_RELOCATION_ENTRY*)&relocationBlockPtr[1];
nextRelocationBlockPtr = (IMAGE_BASE_RELOCATION*)(((PBYTE)relocationBlockPtr) + relocationBlockPtr->SizeOfBlock); nextRelocationBlockPtr = (IMAGE_BASE_RELOCATION*)(((PBYTE)relocationBlockPtr) + relocationBlockPtr->SizeOfBlock);
while ((PBYTE)relocationEntry < (PBYTE)nextRelocationBlockPtr) { while ((PBYTE)relocationEntry < (PBYTE)nextRelocationBlockPtr) {
DWORD relocationRVA = relocationBlockPtr->VirtualAddress + relocationEntry->Offset; DWORD relocationRVA = relocationBlockPtr->VirtualAddress + relocationEntry->Offset;
if (pe->nbRelocations >= relocationsLength) { if (pe->nbRelocations >= relocationsLength) {
relocationsLength *= 2; relocationsLength *= 2;
void* pe_relocations = pe->relocations; void* pe_relocations = pe->relocations;
assert(NULL != pe_relocations); assert(NULL != pe_relocations);
pe->relocations = realloc(pe_relocations, relocationsLength * sizeof(PE_relocation)); pe->relocations = realloc(pe_relocations, relocationsLength * sizeof(PE_relocation));
assert(NULL != pe->relocations); assert(NULL != pe->relocations);
} }
pe->relocations[pe->nbRelocations].RVA = relocationRVA; pe->relocations[pe->nbRelocations].RVA = relocationRVA;
pe->relocations[pe->nbRelocations].Type = relocationEntry->Type; pe->relocations[pe->nbRelocations].Type = relocationEntry->Type;
pe->nbRelocations++; pe->nbRelocations++;
relocationEntry++; relocationEntry++;
} }
relocationBlockPtr = nextRelocationBlockPtr; relocationBlockPtr = nextRelocationBlockPtr;
} }
void* pe_relocations = pe->relocations; void* pe_relocations = pe->relocations;
assert(pe_relocations != NULL); assert(pe_relocations != NULL);
pe->relocations = realloc(pe_relocations, pe->nbRelocations * sizeof(PE_relocation)); pe->relocations = realloc(pe_relocations, pe->nbRelocations * sizeof(PE_relocation));
if (NULL == pe->relocations) if (NULL == pe->relocations)
exit(1); exit(1);
} }
VOID PE_rebasePE(PE* pe, LPVOID newBaseAddress) VOID PE_rebasePE(PE* pe, LPVOID newBaseAddress)
{ {
DWORD* relocDwAddress; DWORD* relocDwAddress;
QWORD* relocQwAddress; QWORD* relocQwAddress;
if (pe->isMemoryMapped) { if (pe->isMemoryMapped) {
printf_or_not("ERROR : Cannot rebase PE that is memory mapped (LoadLibrary'd)\n"); printf_or_not("ERROR : Cannot rebase PE that is memory mapped (LoadLibrary'd)\n");
return; return;
} }
if (NULL == pe->relocations) { if (NULL == pe->relocations) {
PE_parseRelocations(pe); PE_parseRelocations(pe);
} }
assert(pe->relocations != NULL); assert(pe->relocations != NULL);
PVOID oldBaseAddress = pe->baseAddress; PVOID oldBaseAddress = pe->baseAddress;
pe->baseAddress = newBaseAddress; pe->baseAddress = newBaseAddress;
for (DWORD i = 0; i < pe->nbRelocations; i++) { for (DWORD i = 0; i < pe->nbRelocations; i++) {
switch (pe->relocations[i].Type) { switch (pe->relocations[i].Type) {
case IMAGE_REL_BASED_ABSOLUTE: case IMAGE_REL_BASED_ABSOLUTE:
break; break;
case IMAGE_REL_BASED_HIGHLOW: case IMAGE_REL_BASED_HIGHLOW:
relocDwAddress = (DWORD*)PE_RVA_to_Addr(pe, pe->relocations[i].RVA); relocDwAddress = (DWORD*)PE_RVA_to_Addr(pe, pe->relocations[i].RVA);
intptr_t relativeOffset = ((intptr_t)newBaseAddress) - ((intptr_t)oldBaseAddress); intptr_t relativeOffset = ((intptr_t)newBaseAddress) - ((intptr_t)oldBaseAddress);
assert(relativeOffset <= MAXDWORD); assert(relativeOffset <= MAXDWORD);
*relocDwAddress += (DWORD)relativeOffset; *relocDwAddress += (DWORD)relativeOffset;
break; break;
case IMAGE_REL_BASED_DIR64: case IMAGE_REL_BASED_DIR64:
relocQwAddress = (QWORD*)PE_RVA_to_Addr(pe, pe->relocations[i].RVA); relocQwAddress = (QWORD*)PE_RVA_to_Addr(pe, pe->relocations[i].RVA);
*relocQwAddress += ((intptr_t)newBaseAddress) - ((intptr_t)oldBaseAddress); *relocQwAddress += ((intptr_t)newBaseAddress) - ((intptr_t)oldBaseAddress);
break; break;
default: default:
printf_or_not("Unsupported relocation : 0x%x\nExiting...\n", pe->relocations[i].Type); printf_or_not("Unsupported relocation : 0x%x\nExiting...\n", pe->relocations[i].Type);
exit(1); exit(1);
} }
} }
return; return;
} }
PE* PE_create(PVOID imageBase, BOOL isMemoryMapped) { PE* PE_create(PVOID imageBase, BOOL isMemoryMapped) {
PE* pe = calloc(1, sizeof(PE)); PE* pe = calloc(1, sizeof(PE));
if (NULL == pe) { if (NULL == pe) {
exit(1); exit(1);
} }
pe->isMemoryMapped = isMemoryMapped; pe->isMemoryMapped = isMemoryMapped;
pe->isInAnotherAddressSpace = FALSE; pe->isInAnotherAddressSpace = FALSE;
pe->hProcess = INVALID_HANDLE_VALUE; pe->hProcess = INVALID_HANDLE_VALUE;
pe->dosHeader = imageBase; pe->dosHeader = imageBase;
pe->ntHeader = (IMAGE_NT_HEADERS*)(((PBYTE)imageBase) + pe->dosHeader->e_lfanew); pe->ntHeader = (IMAGE_NT_HEADERS*)(((PBYTE)imageBase) + pe->dosHeader->e_lfanew);
pe->optHeader = &pe->ntHeader->OptionalHeader; pe->optHeader = &pe->ntHeader->OptionalHeader;
if (isMemoryMapped) { if (isMemoryMapped) {
pe->baseAddress = imageBase; pe->baseAddress = imageBase;
} }
else { else {
pe->baseAddress = (PVOID)pe->optHeader->ImageBase; pe->baseAddress = (PVOID)pe->optHeader->ImageBase;
} }
pe->dataDir = pe->optHeader->DataDirectory; pe->dataDir = pe->optHeader->DataDirectory;
pe->sectionHeaders = (IMAGE_SECTION_HEADER*)(((PBYTE)pe->optHeader) + pe->ntHeader->FileHeader.SizeOfOptionalHeader); pe->sectionHeaders = (IMAGE_SECTION_HEADER*)(((PBYTE)pe->optHeader) + pe->ntHeader->FileHeader.SizeOfOptionalHeader);
DWORD exportRVA = pe->dataDir[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; DWORD exportRVA = pe->dataDir[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
if (exportRVA == 0) { if (exportRVA == 0) {
pe->exportDirectory = NULL; pe->exportDirectory = NULL;
pe->exportedNames = NULL; pe->exportedNames = NULL;
pe->exportedFunctions = NULL; pe->exportedFunctions = NULL;
pe->exportedOrdinals = NULL; pe->exportedOrdinals = NULL;
} }
else { else {
pe->exportDirectory = PE_RVA_to_Addr(pe, exportRVA); pe->exportDirectory = PE_RVA_to_Addr(pe, exportRVA);
pe->exportedNames = PE_RVA_to_Addr(pe, pe->exportDirectory->AddressOfNames); pe->exportedNames = PE_RVA_to_Addr(pe, pe->exportDirectory->AddressOfNames);
pe->exportedFunctions = PE_RVA_to_Addr(pe, pe->exportDirectory->AddressOfFunctions); pe->exportedFunctions = PE_RVA_to_Addr(pe, pe->exportDirectory->AddressOfFunctions);
pe->exportedOrdinals = PE_RVA_to_Addr(pe, pe->exportDirectory->AddressOfNameOrdinals); pe->exportedOrdinals = PE_RVA_to_Addr(pe, pe->exportDirectory->AddressOfNameOrdinals);
pe->exportedNamesLength = pe->exportDirectory->NumberOfNames; pe->exportedNamesLength = pe->exportDirectory->NumberOfNames;
} }
pe->relocations = NULL; pe->relocations = NULL;
DWORD debugRVA = pe->dataDir[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; DWORD debugRVA = pe->dataDir[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
if (debugRVA == 0) { if (debugRVA == 0) {
pe->debugDirectory = NULL; pe->debugDirectory = NULL;
} }
else { else {
pe->debugDirectory = PE_RVA_to_Addr(pe, debugRVA); pe->debugDirectory = PE_RVA_to_Addr(pe, debugRVA);
if (pe->debugDirectory->Type != IMAGE_DEBUG_TYPE_CODEVIEW) { if (pe->debugDirectory->Type != IMAGE_DEBUG_TYPE_CODEVIEW) {
pe->debugDirectory = NULL; pe->debugDirectory = NULL;
} }
else { else {
pe->codeviewDebugInfo = PE_RVA_to_Addr(pe, pe->debugDirectory->AddressOfRawData); pe->codeviewDebugInfo = PE_RVA_to_Addr(pe, pe->debugDirectory->AddressOfRawData);
if (pe->codeviewDebugInfo->signature != *((DWORD*)"RSDS")) { if (pe->codeviewDebugInfo->signature != *((DWORD*)"RSDS")) {
pe->debugDirectory = NULL; pe->debugDirectory = NULL;
pe->codeviewDebugInfo = NULL; pe->codeviewDebugInfo = NULL;
} }
} }
} }
return pe; return pe;
} }
PE* PE_create_from_another_address_space(HANDLE hProcess, PVOID imageBase) { PE* PE_create_from_another_address_space(HANDLE hProcess, PVOID imageBase) {
PE* pe = calloc(1, sizeof(PE)); PE* pe = calloc(1, sizeof(PE));
if (NULL == pe) { if (NULL == pe) {
exit(1); exit(1);
} }
pe->isMemoryMapped = TRUE; pe->isMemoryMapped = TRUE;
pe->hProcess = hProcess; pe->hProcess = hProcess;
pe->isInAnotherAddressSpace = TRUE; pe->isInAnotherAddressSpace = TRUE;
pe->baseAddress = imageBase; pe->baseAddress = imageBase;
pe->dosHeader = imageBase; pe->dosHeader = imageBase;
DWORD ntHeaderPtrAddress = 0; DWORD ntHeaderPtrAddress = 0;
ReadProcessMemory(hProcess, (LPCVOID)((intptr_t)imageBase + offsetof(IMAGE_DOS_HEADER, e_lfanew)), &ntHeaderPtrAddress, sizeof(ntHeaderPtrAddress), NULL); ReadProcessMemory(hProcess, (LPCVOID)((intptr_t)imageBase + offsetof(IMAGE_DOS_HEADER, e_lfanew)), &ntHeaderPtrAddress, sizeof(ntHeaderPtrAddress), NULL);
pe->ntHeader = (IMAGE_NT_HEADERS*)((intptr_t)pe->baseAddress + ntHeaderPtrAddress); pe->ntHeader = (IMAGE_NT_HEADERS*)((intptr_t)pe->baseAddress + ntHeaderPtrAddress);
pe->optHeader = (IMAGE_OPTIONAL_HEADER*)(&pe->ntHeader->OptionalHeader); pe->optHeader = (IMAGE_OPTIONAL_HEADER*)(&pe->ntHeader->OptionalHeader);
pe->dataDir = pe->optHeader->DataDirectory; pe->dataDir = pe->optHeader->DataDirectory;
WORD sizeOfOptionnalHeader = 0; WORD sizeOfOptionnalHeader = 0;
ReadProcessMemory(hProcess, &pe->ntHeader->FileHeader.SizeOfOptionalHeader, &sizeOfOptionnalHeader, sizeof(sizeOfOptionnalHeader), NULL); ReadProcessMemory(hProcess, &pe->ntHeader->FileHeader.SizeOfOptionalHeader, &sizeOfOptionnalHeader, sizeof(sizeOfOptionnalHeader), NULL);
pe->sectionHeaders = (IMAGE_SECTION_HEADER*)((intptr_t)pe->optHeader + sizeOfOptionnalHeader); pe->sectionHeaders = (IMAGE_SECTION_HEADER*)((intptr_t)pe->optHeader + sizeOfOptionnalHeader);
DWORD exportRVA = 0; DWORD exportRVA = 0;
ReadProcessMemory(hProcess, &pe->dataDir[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress, &exportRVA, sizeof(exportRVA), NULL); ReadProcessMemory(hProcess, &pe->dataDir[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress, &exportRVA, sizeof(exportRVA), NULL);
if (exportRVA == 0) { if (exportRVA == 0) {
pe->exportDirectory = NULL; pe->exportDirectory = NULL;
pe->exportedNames = NULL; pe->exportedNames = NULL;
pe->exportedFunctions = NULL; pe->exportedFunctions = NULL;
pe->exportedOrdinals = NULL; pe->exportedOrdinals = NULL;
} }
else { else {
pe->exportDirectory = PE_RVA_to_Addr(pe, exportRVA); pe->exportDirectory = PE_RVA_to_Addr(pe, exportRVA);
DWORD AddressOfNames = 0; DWORD AddressOfNames = 0;
ReadProcessMemory(pe->hProcess, &pe->exportDirectory->AddressOfNames, &AddressOfNames, sizeof(AddressOfNames), NULL); ReadProcessMemory(pe->hProcess, &pe->exportDirectory->AddressOfNames, &AddressOfNames, sizeof(AddressOfNames), NULL);
pe->exportedNames = PE_RVA_to_Addr(pe, AddressOfNames); pe->exportedNames = PE_RVA_to_Addr(pe, AddressOfNames);
DWORD AddressOfFunctions = 0; DWORD AddressOfFunctions = 0;
ReadProcessMemory(pe->hProcess, &pe->exportDirectory->AddressOfFunctions, &AddressOfFunctions, sizeof(AddressOfFunctions), NULL); ReadProcessMemory(pe->hProcess, &pe->exportDirectory->AddressOfFunctions, &AddressOfFunctions, sizeof(AddressOfFunctions), NULL);
pe->exportedFunctions = PE_RVA_to_Addr(pe, AddressOfFunctions); pe->exportedFunctions = PE_RVA_to_Addr(pe, AddressOfFunctions);
DWORD AddressOfNameOrdinals = 0; DWORD AddressOfNameOrdinals = 0;
ReadProcessMemory(pe->hProcess, &pe->exportDirectory->AddressOfNameOrdinals, &AddressOfNameOrdinals, sizeof(AddressOfNameOrdinals), NULL); ReadProcessMemory(pe->hProcess, &pe->exportDirectory->AddressOfNameOrdinals, &AddressOfNameOrdinals, sizeof(AddressOfNameOrdinals), NULL);
pe->exportedOrdinals = PE_RVA_to_Addr(pe, AddressOfNameOrdinals); pe->exportedOrdinals = PE_RVA_to_Addr(pe, AddressOfNameOrdinals);
ReadProcessMemory(pe->hProcess, &pe->exportDirectory->NumberOfNames, &pe->exportedNamesLength, sizeof(pe->exportedNamesLength), NULL); ReadProcessMemory(pe->hProcess, &pe->exportDirectory->NumberOfNames, &pe->exportedNamesLength, sizeof(pe->exportedNamesLength), NULL);
} }
pe->relocations = NULL; pe->relocations = NULL;
DWORD debugRVA = 0; DWORD debugRVA = 0;
ReadProcessMemory(hProcess, &pe->dataDir[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress, &debugRVA, sizeof(debugRVA), NULL); ReadProcessMemory(hProcess, &pe->dataDir[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress, &debugRVA, sizeof(debugRVA), NULL);
if (debugRVA == 0) { if (debugRVA == 0) {
pe->debugDirectory = NULL; pe->debugDirectory = NULL;
} }
else { else {
pe->debugDirectory = PE_RVA_to_Addr(pe, debugRVA); pe->debugDirectory = PE_RVA_to_Addr(pe, debugRVA);
DWORD debugDirectoryType; DWORD debugDirectoryType;
ReadProcessMemory(hProcess, &pe->debugDirectory->Type, &debugDirectoryType, sizeof(debugDirectoryType), NULL); ReadProcessMemory(hProcess, &pe->debugDirectory->Type, &debugDirectoryType, sizeof(debugDirectoryType), NULL);
if (debugDirectoryType != IMAGE_DEBUG_TYPE_CODEVIEW) { if (debugDirectoryType != IMAGE_DEBUG_TYPE_CODEVIEW) {
pe->debugDirectory = NULL; pe->debugDirectory = NULL;
} }
else { else {
pe->codeviewDebugInfo = PE_RVA_to_Addr(pe, pe->debugDirectory->AddressOfRawData); pe->codeviewDebugInfo = PE_RVA_to_Addr(pe, pe->debugDirectory->AddressOfRawData);
DWORD codeviewDebugInfoSignature; DWORD codeviewDebugInfoSignature;
ReadProcessMemory(hProcess, &pe->codeviewDebugInfo->signature, &codeviewDebugInfoSignature, sizeof(pe->codeviewDebugInfo->signature), NULL); ReadProcessMemory(hProcess, &pe->codeviewDebugInfo->signature, &codeviewDebugInfoSignature, sizeof(pe->codeviewDebugInfo->signature), NULL);
if (codeviewDebugInfoSignature != *((DWORD*)"RSDS")) { if (codeviewDebugInfoSignature != *((DWORD*)"RSDS")) {
pe->debugDirectory = NULL; pe->debugDirectory = NULL;
pe->codeviewDebugInfo = NULL; pe->codeviewDebugInfo = NULL;
} }
} }
} }
return pe; return pe;
} }
DWORD PE_functionRVA(PE* pe, LPCSTR functionName) { DWORD PE_functionRVA(PE* pe, LPCSTR functionName) {
IMAGE_EXPORT_DIRECTORY* exportDirectory = pe->exportDirectory; IMAGE_EXPORT_DIRECTORY* exportDirectory = pe->exportDirectory;
LPDWORD exportedNames = pe->exportedNames; LPDWORD exportedNames = pe->exportedNames;
LPDWORD exportedFunctions = pe->exportedFunctions; LPDWORD exportedFunctions = pe->exportedFunctions;
LPWORD exportedNameOrdinals = pe->exportedOrdinals; LPWORD exportedNameOrdinals = pe->exportedOrdinals;
DWORD nameOrdinal_low = 0; DWORD nameOrdinal_low = 0;
LPCSTR exportName_low = PE_RVA_to_Addr(pe, exportedNames[nameOrdinal_low]); LPCSTR exportName_low = PE_RVA_to_Addr(pe, exportedNames[nameOrdinal_low]);
DWORD nameOrdinal_high = exportDirectory->NumberOfNames; DWORD nameOrdinal_high = exportDirectory->NumberOfNames;
DWORD nameOrdinal_mid; DWORD nameOrdinal_mid;
LPCSTR exportName_mid; LPCSTR exportName_mid;
while (nameOrdinal_high - nameOrdinal_low > 1) { while (nameOrdinal_high - nameOrdinal_low > 1) {
nameOrdinal_mid = (nameOrdinal_high + nameOrdinal_low) / 2; nameOrdinal_mid = (nameOrdinal_high + nameOrdinal_low) / 2;
exportName_mid = PE_RVA_to_Addr(pe, exportedNames[nameOrdinal_mid]); exportName_mid = PE_RVA_to_Addr(pe, exportedNames[nameOrdinal_mid]);
if (strcmp(exportName_mid, functionName) > 0) { if (strcmp(exportName_mid, functionName) > 0) {
nameOrdinal_high = nameOrdinal_mid; nameOrdinal_high = nameOrdinal_mid;
} }
else { else {
nameOrdinal_low = nameOrdinal_mid; nameOrdinal_low = nameOrdinal_mid;
exportName_low = exportName_mid; exportName_low = exportName_mid;
} }
} }
if (!strcmp(exportName_low, functionName)) if (!strcmp(exportName_low, functionName))
return exportedFunctions[exportedNameOrdinals[nameOrdinal_low]]; return exportedFunctions[exportedNameOrdinals[nameOrdinal_low]];
return 0; return 0;
} }
PVOID PE_functionAddr(PE* pe, LPCSTR functionName) { PVOID PE_functionAddr(PE* pe, LPCSTR functionName) {
DWORD functionRVA = PE_functionRVA(pe, functionName); DWORD functionRVA = PE_functionRVA(pe, functionName);
if (functionRVA == 0) { if (functionRVA == 0) {
return NULL; return NULL;
} }
return PE_RVA_to_Addr(pe, functionRVA); return PE_RVA_to_Addr(pe, functionRVA);
} }
PVOID PE_search_pattern(PE* pe, PBYTE pattern, size_t patternSize) { PVOID PE_search_pattern(PE* pe, PBYTE pattern, size_t patternSize) {
for (int i = 0; i < pe->ntHeader->FileHeader.NumberOfSections; i++) { for (int i = 0; i < pe->ntHeader->FileHeader.NumberOfSections; i++) {
DWORD sectionVA = pe->sectionHeaders[i].VirtualAddress; DWORD sectionVA = pe->sectionHeaders[i].VirtualAddress;
DWORD sectionSize = pe->sectionHeaders[i].Misc.VirtualSize; DWORD sectionSize = pe->sectionHeaders[i].Misc.VirtualSize;
if ((size_t)sectionSize < patternSize) { if ((size_t)sectionSize < patternSize) {
continue; continue;
} }
assert(patternSize <= MAXDWORD); assert(patternSize <= MAXDWORD);
DWORD endSize = sectionSize - (DWORD)patternSize; DWORD endSize = sectionSize - (DWORD)patternSize;
for (DWORD offset = 0; offset < endSize; offset++) { for (DWORD offset = 0; offset < endSize; offset++) {
PBYTE ptr = PE_RVA_to_Addr(pe, sectionVA + offset); PBYTE ptr = PE_RVA_to_Addr(pe, sectionVA + offset);
if (!memcmp(ptr, pattern, patternSize)) { if (!memcmp(ptr, pattern, patternSize)) {
return ptr; return ptr;
} }
} }
} }
return NULL; return NULL;
} }
PVOID PE_search_relative_reference(PE* pe, PVOID target, DWORD relativeReferenceSize) { /*
signed long long int maximum; * Look for an instruction that references address targetRVA relatively from its own address, starting the search at fromRVA.
signed long long int minimum; * Searches a 8, 16 or 32 bits relative displacement that points to targetRVA (on x86_84, 64-bits relative displacements do not exist)
* Returns the RVA of the reference (in the middle of the instruction)
*
* Example:
*
* PAGE:14084EA2B 45 33 FF xor r15d, r15d
* PAGE:14084EA2E 4C 8D 2D [6B DA 49 00] lea r13, PspCreateProcessNotifyRoutine ; array at address 140CEC4A0
* PAGE:14084EA35 4E 8D 24 FD 00 00 00 00 lea r12, ds:0[r15*8]
*
* At address 14084EA31 (14084EA2E+3), we find the DWORD 0x0049DA6B (see brackets), which is a displacement relative to the
* address of the next instruction (14084EA35). 0x0049DA6B + 0x14084EA35 being equal to 0x140CEC4A0, this is how the array
* PspCreateProcessNotifyRoutine is referenced by the lea instruction.
*/
DWORD PE_find_static_relative_reference(PE* pe, DWORD targetRVA, DWORD relativeReferenceSize, DWORD fromRVA) {
QWORD startRVA;
QWORD endRVA;
switch (relativeReferenceSize) switch (relativeReferenceSize)
{ {
case 1: case 1:
minimum = MININT8; startRVA = (QWORD)targetRVA - MAXINT8 - relativeReferenceSize;
maximum = MAXINT8; endRVA = (QWORD)targetRVA - MININT8 - relativeReferenceSize;
break; break;
case 2: case 2:
minimum = MININT16; startRVA = (QWORD)targetRVA - MAXINT16 - relativeReferenceSize;
maximum = MAXINT16; endRVA = (QWORD)targetRVA - MININT16 - relativeReferenceSize;
break; break;
case 4: case 4:
minimum = MININT32; startRVA = (QWORD)targetRVA - MAXINT32 - relativeReferenceSize;
maximum = MAXINT32; endRVA = (QWORD)targetRVA - MININT32 - relativeReferenceSize;
break; break;
default: default:
minimum = 0; return 0;
maximum = 0; }
break; if (startRVA > targetRVA) {
} startRVA = 0;
for (int i = 0; i < pe->ntHeader->FileHeader.NumberOfSections; i++) { }
DWORD sectionVA = pe->sectionHeaders[i].VirtualAddress; if (startRVA < fromRVA) {
DWORD sectionSize = pe->sectionHeaders[i].Misc.VirtualSize; startRVA = fromRVA;
DWORD targetRVA = PE_Addr_to_RVA(pe, target); }
//TODO : implement optimization rva in range(targetRVA - maximum - relativeReferenceSize,targetRVA + minimum - relativeReferenceSize) inter range(sectionVA, sectionVA+sectionSize) if (endRVA > MAXDWORD) {
for (DWORD rva = sectionVA; rva <= sectionVA + sectionSize - relativeReferenceSize; rva++) { endRVA = MAXDWORD;
switch (relativeReferenceSize) { }
case 1: for (int i = 0; i < pe->ntHeader->FileHeader.NumberOfSections; i++) {
if (rva + relativeReferenceSize + *(INT8*)PE_RVA_to_Addr(pe, rva) == targetRVA) { DWORD startRVA_inSection = pe->sectionHeaders[i].VirtualAddress;
return PE_RVA_to_Addr(pe, rva); startRVA_inSection = max(startRVA_inSection, (DWORD)startRVA);
} DWORD endRVA_inSection = startRVA_inSection + pe->sectionHeaders[i].Misc.VirtualSize - relativeReferenceSize;
break; endRVA_inSection = min(endRVA_inSection, (DWORD)endRVA);
case 2: for (DWORD rva = startRVA_inSection; rva <= endRVA_inSection; rva++) {
if (rva + relativeReferenceSize + *(INT16*)PE_RVA_to_Addr(pe, rva) == targetRVA) { switch (relativeReferenceSize) {
return PE_RVA_to_Addr(pe, rva); case 1:
} if (rva + relativeReferenceSize + *(INT8*)PE_RVA_to_Addr(pe, rva) == targetRVA) {
break; return rva;
case 4: }
if (rva + relativeReferenceSize + *(INT32*)PE_RVA_to_Addr(pe, rva) == targetRVA) { break;
return PE_RVA_to_Addr(pe, rva); case 2:
} if (rva + relativeReferenceSize + *(INT16*)PE_RVA_to_Addr(pe, rva) == targetRVA) {
break; return rva;
default: }
minimum = 0; break;
maximum = 0; case 4:
break; if (rva + relativeReferenceSize + *(INT32*)PE_RVA_to_Addr(pe, rva) == targetRVA) {
} return rva;
} }
break;
}
}
} }
return NULL; return 0;
} }
VOID PE_destroy(PE* pe) VOID PE_destroy(PE* pe)
{ {
if (pe->relocations) { if (pe->relocations) {
free(pe->relocations); free(pe->relocations);
pe->relocations = NULL; pe->relocations = NULL;
} }
free(pe); free(pe);
} }