Page MenuHomedesp's stash

No OneTemporary

diff --git a/README.md b/README.md
index c138839..a7f0c41 100644
--- a/README.md
+++ b/README.md
@@ -1,147 +1,152 @@
Scylla - x64/x86 Imports Reconstruction
=======================================
ImpREC, CHimpREC, Imports Fixer... this are all great tools to rebuild an import table,
but they all have some major disadvantages, so I decided to create my own tool for this job.
Scylla's key benefits are:
- x64 and x86 support
- full unicode support
- written in C/C++
- plugin support
- works great with Windows 7
This tool was designed to be used with Windows 7 x64, so it is recommend to use this operating system.
But it may work with XP and Vista, too.
Source code is licensed under GNU GENERAL PUBLIC LICENSE v3.0
Known Bugs
----------
+### Windows 7 x64
+
+Sometimes the API kernel32.dll GetProcAddress cannot be resolved, because the IAT has an entry from apphelp.dll
+Solution? I don't know
+
### Only Windows XP x64:
Windows XP x64 has some API bugs. 100% correct imports reconstruction is impossible.
If you still want to use XP x64, here are some hints:
* EncodePointer/DecodePointer exported by kernel32.dll have both the same VA.
Scylla, CHimpREC and other tools cannot know which API is correct. You need to fix this manually.
Your fixed dump will probably run fine on XP but crash on Vista/7.
### ImpREC plugin support:
Some ImpREC Plugins don't work with Windows Vista/7 because they don't "return 1" in the DllMain function.
Keyboard Shortcuts
------------------
- CTRL + D: [D]ump
- CTRL + F: [F]ix Dump
- CTRL + R: PE [R]ebuild
- CTRL + O: L[o]ad Tree
- CTRL + S: [S]ave Tree
- CTRL + T: Auto[t]race
- CTRL + G: [G]et Imports
- CTRL + I: [I]AT Autosearch
Changelog
---------
-Version 0.9.4
+Version 0.9.4 Final
-- direct import scan + fix: 5 byte CALL/JMP, junk byte must be after CALL/JMP
+- direct import scanner (LEA, MOV, PUSH, CALL, JMP) + fixer with 2 fix methods
- create new iat in section
- fixed various bugs
Version 0.9.3
- new dll function: iat search
- new dll function: iat fix auto
Version 0.9.2
- Pick DLL -> Set DLL Entrypoint
- Advanced IAT Search Algorithm (Enable/Disable it in Options), thanks to ahmadmansoor
- Fixed bug in Options
- Added donate information, please feel free to donate some BTC to support this project
Version 0.9.1
- Fixed virtual device bug
- Fixed 2 minor bugs
Version 0.9
- updated to distorm v3.3
- added application exception handler
- fixed bug in dump engine
- improved "suspend process" feature, messagebox on exit
Version 0.8
- added OriginalFirstThunk support. Thanks to p0c
- fixed malformed dos header bug
- NtCreateThreadEx added infos from waliedassar, thanks!
Version 0.7 Beta
- fixed bug Overlapped Headers
- fixed bug SizeOfOptionalHeader
- added feature: suspend process for dumping, more information
- improved disassembler
- fixed various bugs
Version 0.6b
- internal code changes
- added option: fix iat and oep
Version 0.6a
- fixed buffer to small bug in dump memory
Version 0.6
- added dump memory regions
- added dump pe sections -> you can edit some values in the dialog
- improved dump engine with intelligent dumping
- improved pe rebuild engine -> removed yoda's code
- fixed various bugs
Version 0.5a:
- fixed memory leak
- improved IAT search
Version 0.5:
- added save/load import tree feature
- multi-select in tree view
- fixed black icons problem in tree view
- added keyboard shortcuts
- dll dump + dll dump fix now working
- added support for scattered IATs
- pre select target path in open file dialogs
- improved import resolving engine with api scoring
- api selection dialog
- minor bug fixes and improvements
Version 0.4:
- GUI code improvements
- bug fixes
- imports by ordinal
Version 0.3a:
- Improved import resolving
- fixed buffer overflow errors
Version 0.3:
- ImpREC plugin support
- minor bug fix
diff --git a/Scylla/IATReferenceScan.cpp b/Scylla/IATReferenceScan.cpp
index f37b93a..d6b4268 100644
--- a/Scylla/IATReferenceScan.cpp
+++ b/Scylla/IATReferenceScan.cpp
@@ -1,714 +1,737 @@
#include "IATReferenceScan.h"
#include "Scylla.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 ((int)iatDirectImportList.size() * 6); //for x86 and x64 the same size
}
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 (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));
}
}
bool IATReferenceScan::isPageExecutable( DWORD Protect )
{
if (Protect & PAGE_NOCACHE) Protect ^= PAGE_NOCACHE;
if (Protect & PAGE_WRITECOMBINE) Protect ^= PAGE_WRITECOMBINE;
switch(Protect)
{
case PAGE_EXECUTE:
{
return true;
}
case PAGE_EXECUTE_READ:
{
return true;
}
case PAGE_EXECUTE_READWRITE:
{
return true;
}
case PAGE_EXECUTE_WRITECOPY:
{
return true;
}
default:
return false;
}
}
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 && 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++;
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::patchDirectJumpTable( DWORD_PTR stdImagebase, DWORD directImportsJumpTableRVA, PeParser * peParser, BYTE * jmpTableMemory, DWORD newIatBase )
+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);
- DWORD_PTR refTargetPointer = ref->targetPointer;
+ //only one jmp in table for different direct imports with same iat address
+ if (ref->targetPointer == targetIatPointer)
+ {
+ //patch dump
+ 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);
+ DWORD sectionRVA = peParser->getSectionAddressRVAByIndex(index);
+
+ if (ref->type == IAT_REFERENCE_DIRECT_CALL || ref->type == IAT_REFERENCE_DIRECT_JMP)
+ {
+ if (ref->instructionSize == 5)
+ {
+ patchBytes = directImportsJumpTableRVA - (ref->addressVA - ImageBase) - 5;
+ patchDirectImportInDump32(1, 5, patchBytes, memory, memorySize, false, patchOffset, sectionRVA);
+ }
+ }
+ else if (ref->type == IAT_REFERENCE_DIRECT_PUSH || ref->type == IAT_REFERENCE_DIRECT_MOV)
+ {
+ if (ref->instructionSize == 5)
+ {
+ patchBytes = directImportsJumpTableRVA + stdImagebase;
+ patchDirectImportInDump32(1, 5, patchBytes, memory, memorySize, true, patchOffset, sectionRVA);
+ }
+ }
+ else if (ref->type == IAT_REFERENCE_DIRECT_LEA)
+ {
+ if (ref->instructionSize == 6)
+ {
+ patchBytes = directImportsJumpTableRVA + stdImagebase;
+ patchDirectImportInDump32(2, 6, patchBytes, memory, memorySize, true, patchOffset, sectionRVA);
+ }
+ }
+ }
+ }
+}
+
+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 = (ref->targetPointer - IatAddressVA) + newIatBase + ImageBase;
+ refTargetPointer = (*apiIter - IatAddressVA) + newIatBase + ImageBase;
}
//create jump table in section
DWORD_PTR newIatAddressPointer = refTargetPointer - ImageBase + stdImagebase;
#ifdef _WIN64
- patchBytes = (DWORD)(newIatAddressPointer - (ref->addressVA - ImageBase + stdImagebase) - 6);
+ patchBytes = (DWORD)(newIatAddressPointer - (directImportsJumpTableRVA + stdImagebase) - 6);
#else
patchBytes = newIatAddressPointer; //dont forget relocation here
directImportLog.log(L"Relocation direct imports fix: Base RVA %08X Offset %04X Type IMAGE_REL_BASED_HIGHLOW", (directImportsJumpTableRVA + 2) & 0xFFFFF000, (directImportsJumpTableRVA + 2) & 0x00000FFF);
#endif
jmpTableMemory[0] = 0xFF;
jmpTableMemory[1] = 0x25;
*((DWORD *)&jmpTableMemory[2]) = patchBytes;
- //patch dump
- 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);
- DWORD sectionRVA = peParser->getSectionAddressRVAByIndex(index);
-
- if (ref->type == IAT_REFERENCE_DIRECT_CALL || ref->type == IAT_REFERENCE_DIRECT_JMP)
- {
- if (ref->instructionSize == 5)
- {
- patchBytes = directImportsJumpTableRVA - (ref->addressVA - ImageBase) - 5;
- patchDirectImportInDump32(1, 5, patchBytes, memory, memorySize, false, patchOffset, sectionRVA);
- }
- }
- else if (ref->type == IAT_REFERENCE_DIRECT_PUSH || ref->type == IAT_REFERENCE_DIRECT_MOV)
- {
- if (ref->instructionSize == 5)
- {
- patchBytes = directImportsJumpTableRVA + stdImagebase;
- patchDirectImportInDump32(1, 5, patchBytes, memory, memorySize, true, patchOffset, sectionRVA);
- }
- }
- else if (ref->type == IAT_REFERENCE_DIRECT_LEA)
- {
- if (ref->instructionSize == 6)
- {
- patchBytes = directImportsJumpTableRVA + stdImagebase;
- patchDirectImportInDump32(2, 6, patchBytes, memory, memorySize, true, patchOffset, sectionRVA);
- }
- }
-
+ 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)
{
directImportLog.log(L"Relocation direct imports fix: Base RVA %08X Offset %04X Type IMAGE_REL_BASED_HIGHLOW", (sectionRVA + patchOffset + patchPreFixBytes) & 0xFFFFF000, (sectionRVA + patchOffset+ patchPreFixBytes) & 0x00000FFF);
}
*((DWORD *)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;
}
diff --git a/Scylla/IATReferenceScan.h b/Scylla/IATReferenceScan.h
index d5fb371..37b2488 100644
--- a/Scylla/IATReferenceScan.h
+++ b/Scylla/IATReferenceScan.h
@@ -1,125 +1,126 @@
#pragma once
#include <vector>
#include "ProcessAccessHelp.h"
#include "PeParser.h"
#include "Logger.h"
#include "ApiReader.h"
enum IATReferenceType {
IAT_REFERENCE_PTR_JMP,
IAT_REFERENCE_PTR_CALL,
IAT_REFERENCE_DIRECT_JMP,
IAT_REFERENCE_DIRECT_CALL,
IAT_REFERENCE_DIRECT_MOV,
IAT_REFERENCE_DIRECT_PUSH,
IAT_REFERENCE_DIRECT_LEA
};
class IATReference
{
public:
DWORD_PTR addressVA; //Address of reference
DWORD_PTR targetPointer; //Place inside IAT
DWORD_PTR targetAddressInIat; //WIN API?
BYTE instructionSize;
IATReferenceType type;
};
class IATReferenceScan
{
public:
IATReferenceScan()
{
apiReader = 0;
IatAddressVA = 0;
IatSize = 0;
ImageBase = 0;
ImageSize = 0;
iatBackup = 0;
ScanForDirectImports = false;
ScanForNormalImports = true;
}
~IATReferenceScan()
{
iatReferenceList.clear();
iatDirectImportList.clear();
if (iatBackup)
{
free(iatBackup);
}
}
bool ScanForDirectImports;
bool ScanForNormalImports;
bool JunkByteAfterInstruction;
ApiReader * apiReader;
void startScan(DWORD_PTR imageBase, DWORD imageSize, DWORD_PTR iatAddress, DWORD iatSize);
//void patchNewIatBaseMemory(DWORD_PTR newIatBaseAddress);
//void patchNewIatBaseFile(DWORD_PTR newIatBaseAddress);
void patchNewIat(DWORD_PTR stdImagebase, DWORD_PTR newIatBaseAddress, PeParser * peParser);
void patchDirectJumpTable( DWORD_PTR imageBase, DWORD directImportsJumpTableRVA, PeParser * peParser, BYTE * jmpTableMemory, DWORD newIatBase);
void patchDirectImportsMemory(bool junkByteAfterInstruction);
int numberOfFoundDirectImports();
int numberOfFoundUniqueDirectImports();
int numberOfDirectImportApisNotInIat();
int getSizeInBytesOfJumpTableInSection();
static FileLog directImportLog;
void printDirectImportLog();
void changeIatBaseOfDirectImports( DWORD newIatBaseAddressRVA );
DWORD addAdditionalApisToList();
private:
DWORD_PTR NewIatAddressRVA;
DWORD_PTR IatAddressVA;
DWORD IatSize;
DWORD_PTR ImageBase;
DWORD ImageSize;
DWORD_PTR * iatBackup;
std::vector<IATReference> iatReferenceList;
std::vector<IATReference> iatDirectImportList;
bool isPageExecutable( DWORD Protect );
void scanMemoryPage( PVOID BaseAddress, SIZE_T RegionSize );
void analyzeInstruction( _DInst * instruction );
void findNormalIatReference( _DInst * instruction );
void getIatEntryAddress( IATReference* ref );
void findDirectIatReferenceCallJmp( _DInst * instruction );
bool isAddressValidImageMemory( DWORD_PTR address );
void patchReferenceInMemory( IATReference * ref );
void patchReferenceInFile( IATReference* ref );
void patchDirectImportInMemory( IATReference * iter );
DWORD_PTR lookUpIatForPointer( DWORD_PTR addr );
void findDirectIatReferenceMov( _DInst * instruction );
void findDirectIatReferencePush( _DInst * instruction );
void checkMemoryRangeAndAddToList( IATReference * ref, _DInst * instruction );
void findDirectIatReferenceLea( _DInst * instruction );
void patchDirectImportInDump32( int patchPreFixBytes, int instructionSize, DWORD patchBytes, BYTE * memory, DWORD memorySize, bool generateReloc, DWORD patchOffset, DWORD sectionRVA );
-
+ void patchDirectJumpTableEntry(DWORD_PTR targetIatPointer, DWORD_PTR stdImagebase, DWORD directImportsJumpTableRVA, PeParser * peParser, BYTE * jmpTableMemory, DWORD newIatBase );
+
};
/*
PE64
----------
000000013FF82D87 FF15 137C0A00 CALL QWORD [RIP+0xA7C13]
Result: 000000014002A9A0
000000013F65C952 FF25 F8EA0B00 JMP QWORD [RIP+0xBEAF8]
Result: 000000013F71B450
PE32
----------
0120FFA5 FF15 8C6D2601 CALL DWORD [0x01266D8C]
0120FF52 FF25 D4722601 JMP DWORD [0x012672D4]
*/

File Metadata

Mime Type
text/x-diff
Expires
Sat, Jul 5, 12:39 PM (15 h, 49 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
d0/7a/2854f3d1f8e8043c6984e33c316b

Event Timeline