mirror of https://github.com/x64dbg/TitanEngine
739 lines
25 KiB
C++
739 lines
25 KiB
C++
#include "stdafx.h"
|
|
#include "IATReferenceScan.h"
|
|
#include "Architecture.h"
|
|
#include <set>
|
|
|
|
//#define DEBUG_COMMENTS
|
|
|
|
|
|
//FileLog IATReferenceScan::directImportLog(L"Scylla_direct_imports.log");
|
|
|
|
int IATReferenceScan::numberOfFoundDirectImports()
|
|
{
|
|
return (int)iatDirectImportList.size();
|
|
}
|
|
|
|
int IATReferenceScan::numberOfFoundUniqueDirectImports()
|
|
{
|
|
std::set<DWORD_PTR> apiPointers;
|
|
for(std::vector<IATReference>::iterator iter = iatDirectImportList.begin(); iter != iatDirectImportList.end(); iter++)
|
|
{
|
|
IATReference* ref = &(*iter);
|
|
apiPointers.insert(ref->targetAddressInIat);
|
|
}
|
|
|
|
return (int)apiPointers.size();
|
|
}
|
|
|
|
int IATReferenceScan::numberOfDirectImportApisNotInIat()
|
|
{
|
|
std::set<DWORD_PTR> apiPointers;
|
|
for(std::vector<IATReference>::iterator iter = iatDirectImportList.begin(); iter != iatDirectImportList.end(); iter++)
|
|
{
|
|
IATReference* ref = &(*iter);
|
|
|
|
if(ref->targetPointer == 0)
|
|
{
|
|
apiPointers.insert(ref->targetAddressInIat);
|
|
}
|
|
}
|
|
|
|
return (int)apiPointers.size();
|
|
}
|
|
|
|
int IATReferenceScan::getSizeInBytesOfJumpTableInSection()
|
|
{
|
|
return (numberOfFoundUniqueDirectImports() * 6); //for x86 and x64 the same size, FF25 00000000
|
|
}
|
|
|
|
void IATReferenceScan::startScan(DWORD_PTR imageBase, DWORD imageSize, DWORD_PTR iatAddress, DWORD iatSize)
|
|
{
|
|
MEMORY_BASIC_INFORMATION memBasic = {0};
|
|
|
|
IatAddressVA = iatAddress;
|
|
IatSize = iatSize;
|
|
ImageBase = imageBase;
|
|
ImageSize = imageSize;
|
|
|
|
if(ScanForNormalImports)
|
|
{
|
|
iatReferenceList.clear();
|
|
iatReferenceList.reserve(200);
|
|
}
|
|
if(ScanForDirectImports)
|
|
{
|
|
iatDirectImportList.clear();
|
|
iatDirectImportList.reserve(50);
|
|
}
|
|
|
|
|
|
|
|
DWORD_PTR section = imageBase;
|
|
|
|
do
|
|
{
|
|
if(!VirtualQueryEx(ProcessAccessHelp::hProcess, (LPCVOID)section, &memBasic, sizeof(MEMORY_BASIC_INFORMATION)))
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"VirtualQueryEx failed %d", GetLastError());
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if(ProcessAccessHelp::isPageExecutable(memBasic.Protect))
|
|
{
|
|
//do read and scan
|
|
scanMemoryPage(memBasic.BaseAddress, memBasic.RegionSize);
|
|
}
|
|
}
|
|
|
|
section = (DWORD_PTR)((SIZE_T)section + memBasic.RegionSize);
|
|
|
|
}
|
|
while(section < (imageBase + imageSize));
|
|
|
|
|
|
}
|
|
|
|
//void IATReferenceScan::patchNewIatBaseMemory(DWORD_PTR newIatBaseAddress)
|
|
//{
|
|
// NewIatAddressVA = newIatBaseAddress;
|
|
//
|
|
// for (std::vector<IATReference>::iterator iter = iatReferenceList.begin(); iter != iatReferenceList.end(); iter++)
|
|
// {
|
|
// patchReferenceInMemory(&(*iter));
|
|
// }
|
|
//}
|
|
//
|
|
//void IATReferenceScan::patchNewIatBaseFile(DWORD_PTR newIatBaseAddress)
|
|
//{
|
|
// NewIatAddressVA = newIatBaseAddress;
|
|
//
|
|
// for (std::vector<IATReference>::iterator iter = iatReferenceList.begin(); iter != iatReferenceList.end(); iter++)
|
|
// {
|
|
// patchReferenceInFile(&(*iter));
|
|
// }
|
|
//}
|
|
|
|
void IATReferenceScan::patchDirectImportsMemory(bool junkByteAfterInstruction)
|
|
{
|
|
JunkByteAfterInstruction = junkByteAfterInstruction;
|
|
for(std::vector<IATReference>::iterator iter = iatDirectImportList.begin(); iter != iatDirectImportList.end(); iter++)
|
|
{
|
|
patchDirectImportInMemory(&(*iter));
|
|
}
|
|
}
|
|
|
|
|
|
void IATReferenceScan::scanMemoryPage(PVOID BaseAddress, SIZE_T RegionSize)
|
|
{
|
|
BYTE* dataBuffer = (BYTE*)calloc(RegionSize, 1);
|
|
BYTE* currentPos = dataBuffer;
|
|
int currentSize = (int)RegionSize;
|
|
DWORD_PTR currentOffset = (DWORD_PTR)BaseAddress;
|
|
_DecodeResult res;
|
|
unsigned int instructionsCount = 0, next = 0;
|
|
|
|
if(!dataBuffer)
|
|
return;
|
|
|
|
if(ProcessAccessHelp::readMemoryFromProcess((DWORD_PTR)BaseAddress, RegionSize, (LPVOID)dataBuffer))
|
|
{
|
|
while(1)
|
|
{
|
|
ZeroMemory(&ProcessAccessHelp::decomposerCi, sizeof(_CodeInfo));
|
|
ProcessAccessHelp::decomposerCi.code = currentPos;
|
|
ProcessAccessHelp::decomposerCi.codeLen = currentSize;
|
|
ProcessAccessHelp::decomposerCi.dt = ProcessAccessHelp::dt;
|
|
ProcessAccessHelp::decomposerCi.codeOffset = currentOffset;
|
|
|
|
instructionsCount = 0;
|
|
|
|
res = distorm_decompose(&ProcessAccessHelp::decomposerCi, ProcessAccessHelp::decomposerResult, sizeof(ProcessAccessHelp::decomposerResult) / sizeof(ProcessAccessHelp::decomposerResult[0]), &instructionsCount);
|
|
|
|
if(res == DECRES_INPUTERR)
|
|
{
|
|
break;
|
|
}
|
|
|
|
for(unsigned int i = 0; i < instructionsCount; i++)
|
|
{
|
|
if(ProcessAccessHelp::decomposerResult[i].flags != FLAG_NOT_DECODABLE)
|
|
{
|
|
analyzeInstruction(&ProcessAccessHelp::decomposerResult[i]);
|
|
}
|
|
}
|
|
|
|
if(res == DECRES_SUCCESS) break; // All instructions were decoded.
|
|
else if(instructionsCount == 0) break;
|
|
|
|
next = (unsigned long)(ProcessAccessHelp::decomposerResult[instructionsCount - 1].addr - ProcessAccessHelp::decomposerResult[0].addr);
|
|
|
|
if(ProcessAccessHelp::decomposerResult[instructionsCount - 1].flags != FLAG_NOT_DECODABLE)
|
|
{
|
|
next += ProcessAccessHelp::decomposerResult[instructionsCount - 1].size;
|
|
}
|
|
|
|
currentPos += next;
|
|
currentOffset += next;
|
|
currentSize -= next;
|
|
}
|
|
}
|
|
|
|
free(dataBuffer);
|
|
}
|
|
|
|
void IATReferenceScan::analyzeInstruction(_DInst* instruction)
|
|
{
|
|
if(ScanForNormalImports)
|
|
{
|
|
findNormalIatReference(instruction);
|
|
}
|
|
|
|
if(ScanForDirectImports)
|
|
{
|
|
findDirectIatReferenceMov(instruction);
|
|
|
|
#ifndef _WIN64
|
|
findDirectIatReferenceCallJmp(instruction);
|
|
findDirectIatReferenceLea(instruction);
|
|
findDirectIatReferencePush(instruction);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void IATReferenceScan::findNormalIatReference(_DInst* instruction)
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
_DecodedInst inst;
|
|
#endif
|
|
|
|
IATReference ref;
|
|
|
|
|
|
if(META_GET_FC(instruction->meta) == FC_CALL || META_GET_FC(instruction->meta) == FC_UNC_BRANCH)
|
|
{
|
|
if(instruction->size >= 5)
|
|
{
|
|
if(META_GET_FC(instruction->meta) == FC_CALL)
|
|
{
|
|
ref.type = IAT_REFERENCE_PTR_CALL;
|
|
}
|
|
else
|
|
{
|
|
ref.type = IAT_REFERENCE_PTR_JMP;
|
|
}
|
|
ref.addressVA = (DWORD_PTR)instruction->addr;
|
|
ref.instructionSize = instruction->size;
|
|
|
|
#ifdef _WIN64
|
|
if(instruction->flags & FLAG_RIP_RELATIVE)
|
|
{
|
|
|
|
#ifdef DEBUG_COMMENTS
|
|
distorm_format(&ProcessAccessHelp::decomposerCi, instruction, &inst);
|
|
Scylla::debugLog.log(PRINTF_DWORD_PTR_FULL L" " PRINTF_DWORD_PTR_FULL L" %S %S %d %d - target address: " PRINTF_DWORD_PTR_FULL, (DWORD_PTR)instruction->addr, ImageBase, inst.mnemonic.p, inst.operands.p, instruction->ops[0].type, instruction->size, INSTRUCTION_GET_RIP_TARGET(instruction));
|
|
#endif
|
|
|
|
if(INSTRUCTION_GET_RIP_TARGET(instruction) >= IatAddressVA && INSTRUCTION_GET_RIP_TARGET(instruction) < (IatAddressVA + IatSize))
|
|
{
|
|
ref.targetPointer = INSTRUCTION_GET_RIP_TARGET(instruction);
|
|
|
|
getIatEntryAddress(&ref);
|
|
|
|
//Scylla::debugLog.log(L"iat entry "PRINTF_DWORD_PTR_FULL,ref.targetAddressInIat);
|
|
|
|
iatReferenceList.push_back(ref);
|
|
}
|
|
}
|
|
#else
|
|
|
|
if(instruction->ops[0].type == O_DISP)
|
|
{
|
|
//jmp dword ptr || call dword ptr
|
|
#ifdef DEBUG_COMMENTS
|
|
distorm_format(&ProcessAccessHelp::decomposerCi, instruction, &inst);
|
|
Scylla::debugLog.log(PRINTF_DWORD_PTR_FULL L" " PRINTF_DWORD_PTR_FULL L" %S %S %d %d - target address: " PRINTF_DWORD_PTR_FULL, (DWORD_PTR)instruction->addr, ImageBase, inst.mnemonic.p, inst.operands.p, instruction->ops[0].type, instruction->size, instruction->disp);
|
|
#endif
|
|
|
|
if(instruction->disp >= IatAddressVA && instruction->disp < (IatAddressVA + IatSize))
|
|
{
|
|
ref.targetPointer = (DWORD_PTR)instruction->disp;
|
|
|
|
getIatEntryAddress(&ref);
|
|
|
|
//Scylla::debugLog.log(L"iat entry "PRINTF_DWORD_PTR_FULL,ref.targetAddressInIat);
|
|
|
|
iatReferenceList.push_back(ref);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
void IATReferenceScan::getIatEntryAddress(IATReference* ref)
|
|
{
|
|
if(!ProcessAccessHelp::readMemoryFromProcess(ref->targetPointer, sizeof(DWORD_PTR), &ref->targetAddressInIat))
|
|
{
|
|
ref->targetAddressInIat = 0;
|
|
}
|
|
}
|
|
|
|
bool IATReferenceScan::isAddressValidImageMemory(DWORD_PTR address)
|
|
{
|
|
MEMORY_BASIC_INFORMATION memBasic = {0};
|
|
|
|
if(!VirtualQueryEx(ProcessAccessHelp::hProcess, (LPCVOID)address, &memBasic, sizeof(MEMORY_BASIC_INFORMATION)))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return (memBasic.Type == MEM_IMAGE && ProcessAccessHelp::isPageExecutable(memBasic.Protect));
|
|
}
|
|
|
|
void IATReferenceScan::patchReferenceInMemory(IATReference* ref)
|
|
{
|
|
DWORD_PTR newIatAddressPointer = ref->targetPointer - IatAddressVA + NewIatAddressRVA;
|
|
|
|
DWORD patchBytes = 0;
|
|
|
|
#ifdef _WIN64
|
|
patchBytes = (DWORD)(newIatAddressPointer - ref->addressVA - 6);
|
|
#else
|
|
patchBytes = newIatAddressPointer;
|
|
#endif
|
|
ProcessAccessHelp::writeMemoryToProcess(ref->addressVA + 2, sizeof(DWORD), &patchBytes);
|
|
}
|
|
|
|
void IATReferenceScan::patchDirectImportInMemory(IATReference* ref)
|
|
{
|
|
DWORD patchBytes = 0;
|
|
BYTE patchPreBytes[2];
|
|
|
|
if(ref->targetPointer)
|
|
{
|
|
patchPreBytes[0] = 0xFF;
|
|
|
|
if(ref->type == IAT_REFERENCE_DIRECT_CALL) //FF15
|
|
{
|
|
patchPreBytes[1] = 0x15;
|
|
}
|
|
else if(ref->type == IAT_REFERENCE_DIRECT_JMP) //FF25
|
|
{
|
|
patchPreBytes[1] = 0x25;
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(!JunkByteAfterInstruction)
|
|
{
|
|
ref->addressVA -= 1;
|
|
}
|
|
|
|
ProcessAccessHelp::writeMemoryToProcess(ref->addressVA, 2, patchPreBytes);
|
|
|
|
#ifdef _WIN64
|
|
patchBytes = (DWORD)(ref->targetPointer - ref->addressVA - 6);
|
|
#else
|
|
patchBytes = ref->targetPointer;
|
|
#endif
|
|
ProcessAccessHelp::writeMemoryToProcess(ref->addressVA + 2, sizeof(DWORD), &patchBytes);
|
|
}
|
|
}
|
|
|
|
DWORD_PTR IATReferenceScan::lookUpIatForPointer(DWORD_PTR addr)
|
|
{
|
|
if(!iatBackup)
|
|
{
|
|
iatBackup = (DWORD_PTR*)calloc(IatSize + sizeof(DWORD_PTR), 1);
|
|
if(!iatBackup)
|
|
{
|
|
return 0;
|
|
}
|
|
if(!ProcessAccessHelp::readMemoryFromProcess(IatAddressVA, IatSize, iatBackup))
|
|
{
|
|
free(iatBackup);
|
|
iatBackup = 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
for(int i = 0; i < ((int)IatSize / (int)sizeof(DWORD_PTR)); i++)
|
|
{
|
|
if(iatBackup[i] == addr)
|
|
{
|
|
return (DWORD_PTR)&iatBackup[i] - (DWORD_PTR)iatBackup + IatAddressVA;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void IATReferenceScan::patchNewIat(DWORD_PTR stdImagebase, DWORD_PTR newIatBaseAddress, PeParser* peParser)
|
|
{
|
|
NewIatAddressRVA = newIatBaseAddress;
|
|
DWORD patchBytes = 0;
|
|
|
|
for(std::vector<IATReference>::iterator iter = iatReferenceList.begin(); iter != iatReferenceList.end(); iter++)
|
|
{
|
|
IATReference* ref = &(*iter);
|
|
|
|
DWORD_PTR newIatAddressPointer = (ref->targetPointer - IatAddressVA) + NewIatAddressRVA + stdImagebase;
|
|
|
|
#ifdef _WIN64
|
|
patchBytes = (DWORD)(newIatAddressPointer - (ref->addressVA - ImageBase + stdImagebase) - 6);
|
|
#else
|
|
patchBytes = newIatAddressPointer;
|
|
#endif
|
|
DWORD_PTR patchOffset = peParser->convertRVAToOffsetRelative(ref->addressVA - ImageBase);
|
|
int index = peParser->convertRVAToOffsetVectorIndex(ref->addressVA - ImageBase);
|
|
BYTE* memory = peParser->getSectionMemoryByIndex(index);
|
|
DWORD memorySize = peParser->getSectionMemorySizeByIndex(index);
|
|
|
|
|
|
if(memorySize < (DWORD)(patchOffset + 6))
|
|
{
|
|
// Scylla::debugLog.log(L"Error - Cannot fix IAT reference RVA: " PRINTF_DWORD_PTR_FULL, ref->addressVA - ImageBase);
|
|
}
|
|
else
|
|
{
|
|
memory += patchOffset + 2;
|
|
|
|
*((DWORD*)memory) = patchBytes;
|
|
}
|
|
//Scylla::debugLog.log(L"address %X old %X new %X",ref->addressVA, ref->targetPointer, newIatAddressPointer);
|
|
|
|
}
|
|
}
|
|
|
|
void IATReferenceScan::printDirectImportLog()
|
|
{
|
|
// IATReferenceScan::directImportLog.log(L"------------------------------------------------------------");
|
|
// IATReferenceScan::directImportLog.log(L"ImageBase " PRINTF_DWORD_PTR_FULL L" ImageSize %08X IATAddress " PRINTF_DWORD_PTR_FULL L" IATSize 0x%X", ImageBase, ImageSize, IatAddressVA, IatSize);
|
|
int count = 0;
|
|
bool isSuspect = false;
|
|
|
|
for(std::vector<IATReference>::iterator iter = iatDirectImportList.begin(); iter != iatDirectImportList.end(); iter++)
|
|
{
|
|
IATReference* ref = &(*iter);
|
|
|
|
ApiInfo* apiInfo = apiReader->getApiByVirtualAddress(ref->targetAddressInIat, &isSuspect);
|
|
|
|
count++;
|
|
const WCHAR* type = L"U";
|
|
|
|
if(ref->type == IAT_REFERENCE_DIRECT_CALL)
|
|
{
|
|
type = L"CALL";
|
|
}
|
|
else if(ref->type == IAT_REFERENCE_DIRECT_JMP)
|
|
{
|
|
type = L"JMP";
|
|
}
|
|
else if(ref->type == IAT_REFERENCE_DIRECT_MOV)
|
|
{
|
|
type = L"MOV";
|
|
}
|
|
else if(ref->type == IAT_REFERENCE_DIRECT_PUSH)
|
|
{
|
|
type = L"PUSH";
|
|
}
|
|
else if(ref->type == IAT_REFERENCE_DIRECT_LEA)
|
|
{
|
|
type = L"LEA";
|
|
}
|
|
|
|
//IATReferenceScan::directImportLog.log(L"%04d AddrVA " PRINTF_DWORD_PTR_FULL L" Type %s Value " PRINTF_DWORD_PTR_FULL L" IatRefPointer " PRINTF_DWORD_PTR_FULL L" Api %s %S", count, ref->addressVA, type, ref->targetAddressInIat, ref->targetPointer,apiInfo->module->getFilename(), apiInfo->name);
|
|
|
|
}
|
|
|
|
//IATReferenceScan::directImportLog.log(L"------------------------------------------------------------");
|
|
}
|
|
|
|
void IATReferenceScan::findDirectIatReferenceCallJmp(_DInst* instruction)
|
|
{
|
|
IATReference ref;
|
|
|
|
if(META_GET_FC(instruction->meta) == FC_CALL || META_GET_FC(instruction->meta) == FC_UNC_BRANCH)
|
|
{
|
|
if((instruction->size >= 5) && (instruction->ops[0].type == O_PC)) //CALL/JMP 0x00000000
|
|
{
|
|
if(META_GET_FC(instruction->meta) == FC_CALL)
|
|
{
|
|
ref.type = IAT_REFERENCE_DIRECT_CALL;
|
|
}
|
|
else
|
|
{
|
|
ref.type = IAT_REFERENCE_DIRECT_JMP;
|
|
}
|
|
|
|
ref.targetAddressInIat = (DWORD_PTR)INSTRUCTION_GET_TARGET(instruction);
|
|
|
|
checkMemoryRangeAndAddToList(&ref, instruction);
|
|
}
|
|
}
|
|
}
|
|
|
|
void IATReferenceScan::findDirectIatReferenceMov(_DInst* instruction)
|
|
{
|
|
IATReference ref;
|
|
ref.type = IAT_REFERENCE_DIRECT_MOV;
|
|
|
|
if(instruction->opcode == I_MOV)
|
|
{
|
|
#ifdef _WIN64
|
|
if(instruction->size >= 7) //MOV REGISTER, 0xFFFFFFFFFFFFFFFF
|
|
#else
|
|
if(instruction->size >= 5) //MOV REGISTER, 0xFFFFFFFF
|
|
#endif
|
|
{
|
|
if(instruction->ops[0].type == O_REG && instruction->ops[1].type == O_IMM)
|
|
{
|
|
ref.targetAddressInIat = (DWORD_PTR)instruction->imm.qword;
|
|
|
|
checkMemoryRangeAndAddToList(&ref, instruction);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void IATReferenceScan::findDirectIatReferencePush(_DInst* instruction)
|
|
{
|
|
IATReference ref;
|
|
ref.type = IAT_REFERENCE_DIRECT_PUSH;
|
|
|
|
if(instruction->size >= 5 && instruction->opcode == I_PUSH)
|
|
{
|
|
ref.targetAddressInIat = (DWORD_PTR)instruction->imm.qword;
|
|
|
|
checkMemoryRangeAndAddToList(&ref, instruction);
|
|
}
|
|
}
|
|
|
|
void IATReferenceScan::findDirectIatReferenceLea(_DInst* instruction)
|
|
{
|
|
IATReference ref;
|
|
ref.type = IAT_REFERENCE_DIRECT_LEA;
|
|
|
|
if(instruction->size >= 5 && instruction->opcode == I_LEA)
|
|
{
|
|
if(instruction->ops[0].type == O_REG && instruction->ops[1].type == O_DISP) //LEA EDX, [0xb58bb8]
|
|
{
|
|
ref.targetAddressInIat = (DWORD_PTR)instruction->disp;
|
|
|
|
checkMemoryRangeAndAddToList(&ref, instruction);
|
|
}
|
|
}
|
|
}
|
|
|
|
void IATReferenceScan::checkMemoryRangeAndAddToList(IATReference* ref, _DInst* instruction)
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
_DecodedInst inst;
|
|
#endif
|
|
|
|
if(ref->targetAddressInIat > 0x000FFFFF && ref->targetAddressInIat != (DWORD_PTR) - 1)
|
|
{
|
|
if((ref->targetAddressInIat < ImageBase) || (ref->targetAddressInIat > (ImageBase + ImageSize))) //outside pe image
|
|
{
|
|
//if (isAddressValidImageMemory(ref->targetAddressInIat))
|
|
{
|
|
bool isSuspect = false;
|
|
if(apiReader->getApiByVirtualAddress(ref->targetAddressInIat, &isSuspect) != 0)
|
|
{
|
|
ref->addressVA = (DWORD_PTR)instruction->addr;
|
|
ref->instructionSize = instruction->size;
|
|
ref->targetPointer = lookUpIatForPointer(ref->targetAddressInIat);
|
|
|
|
#ifdef DEBUG_COMMENTS
|
|
distorm_format(&ProcessAccessHelp::decomposerCi, instruction, &inst);
|
|
Scylla::debugLog.log(PRINTF_DWORD_PTR_FULL L" " PRINTF_DWORD_PTR_FULL L" %S %S %d %d - target address: " PRINTF_DWORD_PTR_FULL, (DWORD_PTR)instruction->addr, ImageBase, inst.mnemonic.p, inst.operands.p, instruction->ops[0].type, instruction->size, ref->targetAddressInIat);
|
|
#endif
|
|
iatDirectImportList.push_back(*ref);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void IATReferenceScan::patchDirectJumpTableEntry(DWORD_PTR targetIatPointer, DWORD_PTR stdImagebase, DWORD directImportsJumpTableRVA, PeParser* peParser, BYTE* jmpTableMemory, DWORD newIatBase)
|
|
{
|
|
DWORD patchBytes = 0;
|
|
for(std::vector<IATReference>::iterator iter = iatDirectImportList.begin(); iter != iatDirectImportList.end(); iter++)
|
|
{
|
|
IATReference* ref = &(*iter);
|
|
|
|
//only one jmp in table for different direct imports with same iat address
|
|
if(ref->targetPointer == targetIatPointer)
|
|
{
|
|
//patch dump
|
|
DWORD patchOffset = (DWORD)peParser->convertRVAToOffsetRelative(ref->addressVA - ImageBase);
|
|
int index = peParser->convertRVAToOffsetVectorIndex(ref->addressVA - ImageBase);
|
|
BYTE* memory = peParser->getSectionMemoryByIndex(index);
|
|
DWORD memorySize = peParser->getSectionMemorySizeByIndex(index);
|
|
DWORD sectionRVA = peParser->getSectionAddressRVAByIndex(index);
|
|
|
|
if(ref->type == IAT_REFERENCE_DIRECT_CALL || ref->type == IAT_REFERENCE_DIRECT_JMP)
|
|
{
|
|
#ifndef _WIN64
|
|
if(ref->instructionSize == 5)
|
|
{
|
|
patchBytes = directImportsJumpTableRVA - (ref->addressVA - ImageBase) - 5;
|
|
patchDirectImportInDump32(1, 5, patchBytes, memory, memorySize, false, patchOffset, sectionRVA);
|
|
}
|
|
#endif
|
|
}
|
|
else if(ref->type == IAT_REFERENCE_DIRECT_PUSH || ref->type == IAT_REFERENCE_DIRECT_MOV)
|
|
{
|
|
#ifndef _WIN64
|
|
if(ref->instructionSize == 5) //for x86
|
|
{
|
|
patchBytes = directImportsJumpTableRVA + stdImagebase;
|
|
patchDirectImportInDump32(1, 5, patchBytes, memory, memorySize, true, patchOffset, sectionRVA);
|
|
}
|
|
#else
|
|
if(ref->instructionSize == 10) //for x64
|
|
{
|
|
DWORD_PTR patchBytes64 = directImportsJumpTableRVA + stdImagebase;
|
|
patchDirectImportInDump64(2, 10, patchBytes64, memory, memorySize, true, patchOffset, sectionRVA);
|
|
}
|
|
#endif
|
|
}
|
|
else if(ref->type == IAT_REFERENCE_DIRECT_LEA)
|
|
{
|
|
#ifndef _WIN64
|
|
if(ref->instructionSize == 6)
|
|
{
|
|
patchBytes = directImportsJumpTableRVA + stdImagebase;
|
|
patchDirectImportInDump32(2, 6, patchBytes, memory, memorySize, true, patchOffset, sectionRVA);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void IATReferenceScan::patchDirectJumpTable(DWORD_PTR stdImagebase, DWORD directImportsJumpTableRVA, PeParser* peParser, BYTE* jmpTableMemory, DWORD newIatBase)
|
|
{
|
|
|
|
std::set<DWORD_PTR> apiPointers;
|
|
for(std::vector<IATReference>::iterator iter = iatDirectImportList.begin(); iter != iatDirectImportList.end(); iter++)
|
|
{
|
|
IATReference* ref = &(*iter);
|
|
apiPointers.insert(ref->targetPointer);
|
|
}
|
|
|
|
DWORD patchBytes;
|
|
|
|
for(std::set<DWORD_PTR>::iterator apiIter = apiPointers.begin(); apiIter != apiPointers.end(); apiIter++)
|
|
{
|
|
DWORD_PTR refTargetPointer = *apiIter;
|
|
if(newIatBase) //create new iat in section
|
|
{
|
|
refTargetPointer = (*apiIter - IatAddressVA) + newIatBase + ImageBase;
|
|
}
|
|
//create jump table in section
|
|
DWORD_PTR newIatAddressPointer = refTargetPointer - ImageBase + stdImagebase;
|
|
|
|
#ifdef _WIN64
|
|
patchBytes = (DWORD)(newIatAddressPointer - (directImportsJumpTableRVA + stdImagebase) - 6);
|
|
#else
|
|
patchBytes = newIatAddressPointer;
|
|
DWORD relocOffset = (directImportsJumpTableRVA + 2);
|
|
//directImportLog.log(L"Relocation direct imports fix: Base RVA %08X Type HIGHLOW Offset %04X RelocTableEntry %04X", relocOffset & 0xFFFFF000, relocOffset & 0x00000FFF, (IMAGE_REL_BASED_HIGHLOW << 12) + (relocOffset & 0x00000FFF));
|
|
#endif
|
|
jmpTableMemory[0] = 0xFF;
|
|
jmpTableMemory[1] = 0x25;
|
|
*((DWORD*)&jmpTableMemory[2]) = patchBytes;
|
|
|
|
patchDirectJumpTableEntry(*apiIter, stdImagebase, directImportsJumpTableRVA, peParser, jmpTableMemory, newIatBase);
|
|
|
|
jmpTableMemory += 6;
|
|
directImportsJumpTableRVA += 6;
|
|
}
|
|
}
|
|
|
|
void IATReferenceScan::patchDirectImportInDump32(int patchPreFixBytes, int instructionSize, DWORD patchBytes, BYTE* memory, DWORD memorySize, bool generateReloc, DWORD patchOffset, DWORD sectionRVA)
|
|
{
|
|
if(memorySize < (DWORD)(patchOffset + instructionSize))
|
|
{
|
|
//Scylla::debugLog.log(L"Error - Cannot fix direct import reference RVA: %X", sectionRVA + patchOffset);
|
|
}
|
|
else
|
|
{
|
|
memory += patchOffset + patchPreFixBytes;
|
|
if(generateReloc)
|
|
{
|
|
DWORD relocOffset = sectionRVA + patchOffset + patchPreFixBytes;
|
|
// directImportLog.log(L"Relocation direct imports fix: Base RVA %08X Type HIGHLOW Offset %04X RelocTableEntry %04X", relocOffset & 0xFFFFF000, relocOffset & 0x00000FFF, (IMAGE_REL_BASED_HIGHLOW << 12) + (relocOffset & 0x00000FFF));
|
|
}
|
|
|
|
*((DWORD*)memory) = patchBytes;
|
|
}
|
|
}
|
|
|
|
void IATReferenceScan::patchDirectImportInDump64(int patchPreFixBytes, int instructionSize, DWORD_PTR patchBytes, BYTE* memory, DWORD memorySize, bool generateReloc, DWORD patchOffset, DWORD sectionRVA)
|
|
{
|
|
if(memorySize < (DWORD)(patchOffset + instructionSize))
|
|
{
|
|
// Scylla::debugLog.log(L"Error - Cannot fix direct import reference RVA: %X", sectionRVA + patchOffset);
|
|
}
|
|
else
|
|
{
|
|
memory += patchOffset + patchPreFixBytes;
|
|
if(generateReloc)
|
|
{
|
|
DWORD relocOffset = sectionRVA + patchOffset + patchPreFixBytes;
|
|
// directImportLog.log(L"Relocation direct imports fix: Base RVA %08X Type DIR64 Offset %04X RelocTableEntry %04X", relocOffset & 0xFFFFF000, relocOffset & 0x00000FFF, (IMAGE_REL_BASED_DIR64 << 12) + (relocOffset & 0x00000FFF));
|
|
}
|
|
|
|
*((DWORD_PTR*)memory) = patchBytes;
|
|
}
|
|
}
|
|
|
|
DWORD IATReferenceScan::addAdditionalApisToList()
|
|
{
|
|
std::set<DWORD_PTR> apiPointers;
|
|
|
|
for(std::vector<IATReference>::iterator iter = iatDirectImportList.begin(); iter != iatDirectImportList.end(); iter++)
|
|
{
|
|
IATReference* ref = &(*iter);
|
|
|
|
if(ref->targetPointer == 0)
|
|
{
|
|
apiPointers.insert(ref->targetAddressInIat);
|
|
}
|
|
}
|
|
|
|
DWORD_PTR iatAddy = IatAddressVA + IatSize;
|
|
DWORD newIatSize = IatSize;
|
|
|
|
bool isSuspect = false;
|
|
for(std::set<DWORD_PTR>::iterator apiIter = apiPointers.begin(); apiIter != apiPointers.end(); apiIter++)
|
|
{
|
|
for(std::vector<IATReference>::iterator iter = iatDirectImportList.begin(); iter != iatDirectImportList.end(); iter++)
|
|
{
|
|
IATReference* ref = &(*iter);
|
|
|
|
if(ref->targetPointer == 0 && ref->targetAddressInIat == *apiIter)
|
|
{
|
|
ref->targetPointer = iatAddy;
|
|
ApiInfo* apiInfo = apiReader->getApiByVirtualAddress(ref->targetAddressInIat, &isSuspect);
|
|
apiReader->addFoundApiToModuleList(iatAddy, apiInfo, true, isSuspect);
|
|
}
|
|
}
|
|
|
|
iatAddy += sizeof(DWORD_PTR);
|
|
newIatSize += sizeof(DWORD_PTR);
|
|
}
|
|
|
|
return newIatSize;
|
|
}
|
|
|
|
|