10#define MIN_THUNKS_COUNT 2
13 BYTE*
get_buffer_space_at(IN BYTE* buffer, IN
const size_t buffer_size, IN
const DWORD buffer_rva, IN
const DWORD required_rva, IN
const size_t required_size)
15 if (!buffer || buffer_rva > required_rva)
return nullptr;
16 size_t offset = required_rva - buffer_rva;
18 BYTE* req_ptr = offset + buffer;
19 if (peconv::validate_ptr(buffer, buffer_size, req_ptr, required_size)) {
30 return get_buffer_space_at(this->namesBuf, this->namesBufSize, this->namesRVA, rva, required_size);
35 return get_buffer_space_at(this->dllsBuf, this->dllsBufSize, this->dllsRVA, rva, required_size);
40bool pesieve::ImpReconstructor::hasDynamicIAT()
const
42 size_t maxSize = getMaxDynamicIATSize(
true);
46size_t pesieve::ImpReconstructor::getMainIATSize()
const
48 std::map<DWORD, IATBlock*>::const_iterator iats_itr;
51 size_t totalIatSize = 0;
52 for (iats_itr = foundIATs.cbegin(); iats_itr != foundIATs.cend(); ++iats_itr) {
53 const IATBlock* iblock = iats_itr->second;
57 totalIatSize += currCount;
63size_t pesieve::ImpReconstructor::getMaxDynamicIATSize(IN
bool isIatTerminated)
const
65 std::map<DWORD, IATBlock*>::const_iterator iats_itr;
67 size_t maxIATSize = 0;
68 for (iats_itr = foundIATs.cbegin(); iats_itr != foundIATs.cend(); ++iats_itr) {
69 const IATBlock* iblock = iats_itr->second;
75 if (currCount > maxIATSize) {
76 maxIATSize = currCount;
87 int filter = IMP_REC0;
88 switch (imprec_mode) {
90 filter = IMP_REC0;
break;
92 filter = IMP_REC1;
break;
94 filter = IMP_REC2;
break;
101 const size_t untermIATSize = getMaxDynamicIATSize(
false);
103 const size_t mainIATSize = getMainIATSize();
104 const size_t termIATSize = getMaxDynamicIATSize(
true);
106 if ((untermIATSize > mainIATSize) && (untermIATSize > termIATSize)) {
114 while (!findIATsCoverage(exportsMap, (t_imprec_filter)filter)) {
117 return IMP_RECOVERY_ERROR;
122 if (filter == IMP_REC_COUNT) {
123 return IMP_RECOVERY_ERROR;
131 if (appendImportTable(*impBuf)) {
138 return IMP_RECOVERY_ERROR;
143 return IMP_RECREATED_FILTER0;
145 return IMP_RECREATED_FILTER1;
147 return IMP_RECREATED_FILTER2;
149 return IMP_RECREATED_FILTER0;
154 if (!exportsMap || imprec_mode == pesieve::PE_IMPREC_NONE) {
155 return IMP_RECOVERY_SKIPPED;
158 if (!collectIATs(exportsMap)) {
159 return IMP_NOT_FOUND;
162 if (!peBuffer.isValidPe()) {
164 return IMP_RECOVERY_NOT_APPLICABLE;
166 if (!peconv::is_pe_raw_eq_virtual(peBuffer.vBuf, peBuffer.vBufSize)
167 && peconv::is_pe_raw(peBuffer.vBuf, peBuffer.vBufSize))
170 return IMP_RECOVERY_NOT_APPLICABLE;
176 const bool is_default_valid = this->isDefaultImportValid(exportsMap);
177 if (is_default_valid) {
181 if (findImportTable(exportsMap)) {
186 const bool isDotnet = peconv::is_dot_net(peBuffer.vBuf, peBuffer.vBufSize);
196 return _recreateImportTableFiltered(exportsMap, imprec_mode);
198 return IMP_RECOVERY_ERROR;
203 if (!foundIATs.size()) {
208 if (
report.is_open() ==
false) {
212 std::map<DWORD, IATBlock*>::iterator itr;
213 for (itr = foundIATs.begin(); itr != foundIATs.end(); ++itr) {
214 report << itr->second->toString();
220bool pesieve::ImpReconstructor::isDefaultImportValid(IN
const peconv::ExportsMapper* exportsMap)
222 BYTE *vBuf = this->peBuffer.vBuf;
223 const size_t vBufSize = this->peBuffer.vBufSize;
224 if (!vBuf || !vBufSize)
return false;
226 IMAGE_DATA_DIRECTORY *iat_dir = peconv::get_directory_entry(vBuf, IMAGE_DIRECTORY_ENTRY_IAT,
true);
227 if (!iat_dir)
return false;
229 IMAGE_DATA_DIRECTORY *imp_dir = peconv::get_directory_entry(vBuf, IMAGE_DIRECTORY_ENTRY_IMPORT,
true);
230 if (!imp_dir)
return false;
232 if (imp_dir->VirtualAddress == 0 && imp_dir->Size == 0
233 && iat_dir->VirtualAddress == 0 && iat_dir->Size == 0)
239 if (iat_dir->VirtualAddress != 0 && imp_dir->VirtualAddress == 0) {
246 DWORD iat_offset = iat_dir->VirtualAddress;
247 IATBlock* iat_block = this->findIATBlock(exportsMap, iat_offset);
252 const size_t start_offset = peconv::get_hdrs_size(vBuf);
253 const bool is64bit = peconv::is64bit(vBuf);
254 size_t table_size = 0;
269 DWORD imp_table_offset =
DWORD((ULONG_PTR)import_table - (ULONG_PTR)vBuf);
270 if (imp_dir->VirtualAddress == imp_table_offset) {
276IATBlock* pesieve::ImpReconstructor::findIATBlock(IN
const peconv::ExportsMapper* exportsMap,
size_t start_offset)
278 if (!exportsMap)
return nullptr;
284 ThunkFilterSelfCallback(
const ULONGLONG mod_start,
size_t mod_size)
285 : startAddr(mod_start), endAddr(mod_start + mod_size)
289 virtual bool shouldProcessVA(ULONGLONG va)
291 if (va >= startAddr && va < endAddr) {
298 virtual bool shouldAcceptExport(ULONGLONG va,
const peconv::ExportedFunc &exp)
305 const ULONGLONG startAddr;
306 const ULONGLONG endAddr;
309 ThunkFilterSelfCallback filter = ThunkFilterSelfCallback(peBuffer.moduleBase, peBuffer.getBufferSize());
313 iat_block =
find_iat<ULONGLONG>(this->peBuffer.vBuf, this->peBuffer.vBufSize, exportsMap, start_offset, &filter);
316 iat_block =
find_iat<DWORD>(this->peBuffer.vBuf, this->peBuffer.vBufSize, exportsMap, start_offset, &filter);
322void pesieve::ImpReconstructor::collectMainIatData()
324 BYTE* vBuf = this->peBuffer.vBuf;
325 const size_t vBufSize = this->peBuffer.vBufSize;
328 if (!peconv::has_valid_import_table(vBuf, vBufSize)) {
332 peconv::collect_thunks(vBuf, vBufSize, mainIatThunks);
335IATBlock* pesieve::ImpReconstructor::findIAT(IN
const peconv::ExportsMapper* exportsMap,
size_t start_offset)
337 BYTE *vBuf = this->peBuffer.vBuf;
338 const size_t vBufSize = this->peBuffer.vBufSize;
339 if (!vBuf)
return nullptr;
341 IATBlock* iat_block = findIATBlock(exportsMap, start_offset);
345 DWORD mainIatRVA = 0;
346 DWORD mainIatSize = 0;
347 IMAGE_DATA_DIRECTORY* dir = peconv::get_directory_entry(vBuf, IMAGE_DIRECTORY_ENTRY_IAT,
true);
349 mainIatRVA = dir->VirtualAddress;
350 mainIatSize = dir->Size;
352 if ( (mainIatRVA != 0 && iat_block->
iatOffset >= mainIatRVA && iat_block->
iatOffset < (mainIatRVA + mainIatSize) )
353 || mainIatThunks.find(iat_block->
iatOffset) != mainIatThunks.end() )
360size_t pesieve::ImpReconstructor::collectIATs(IN
const peconv::ExportsMapper* exportsMap)
362 BYTE *vBuf = this->peBuffer.vBuf;
363 const size_t vBufSize = this->peBuffer.vBufSize;
367 const size_t pe_hdr_size = peconv::get_hdrs_size(vBuf);
369 for (
size_t search_offset = pe_hdr_size; search_offset < vBufSize;) {
371 IATBlock *currIAT = findIAT(exportsMap, search_offset);
378 const size_t iat_end = iat_offset + currIAT->
iatSize;
379 if (!appendFoundIAT(iat_offset, currIAT)) {
383 if (iat_end <= search_offset) {
386 search_offset = iat_end;
391bool pesieve::ImpReconstructor::findImportTable(IN
const peconv::ExportsMapper* exportsMap)
393 BYTE *vBuf = this->peBuffer.vBuf;
394 const size_t vBufSize = this->peBuffer.vBufSize;
395 if (!vBuf)
return false;
397 IMAGE_DATA_DIRECTORY* imp_dir = peconv::get_directory_entry(vBuf, IMAGE_DIRECTORY_ENTRY_IMPORT,
true);
401 IMAGE_DATA_DIRECTORY *iat_dir = peconv::get_directory_entry(vBuf, IMAGE_DIRECTORY_ENTRY_IAT,
true);
405 IMAGE_IMPORT_DESCRIPTOR* import_table =
nullptr;
406 size_t table_size = 0;
408 const size_t start_offset = peconv::get_hdrs_size(vBuf);
410 std::map<DWORD, IATBlock*>::iterator itr;
411 for (itr = foundIATs.begin(); itr != foundIATs.end(); ++itr) {
416 std::cout <<
"[*] Searching import table for IAT: " << std::hex << iat_offset <<
", size: " << currIAT->
iatSize << std::endl;
418 bool is64bit = peconv::is64bit(vBuf);
432 iat_dir->VirtualAddress = iat_offset;
438 if (!import_table)
return false;
441 if (imp_dir->VirtualAddress == imp_offset && imp_dir->Size == table_size) {
446 if (imp_dir->Size == table_size) {
447 std::cout <<
"[*] Validated Imports size!\n";
451 imp_dir->VirtualAddress = imp_offset;
456bool pesieve::ImpReconstructor::findIATsCoverage(IN
const peconv::ExportsMapper* exportsMap, t_imprec_filter filter)
458 size_t neededIATs = 0;
460 std::map<DWORD, IATBlock*>::iterator itr;
461 for (itr = foundIATs.begin(); itr != foundIATs.end(); ++itr) {
466 if (!
iat->isInMain && !
iat->isTerminated) {
476 if (
iat->makeCoverage(exportsMap)) {
480 std::cout <<
"[-] Failed covering block: " << std::hex << itr->first <<
" series: " <<
iat->thunkSeries.size() <<
"\n";
483 if (neededIATs == 0) {
486 return (covered == neededIATs);
491 BYTE *vBuf = this->peBuffer.vBuf;
492 const size_t vBufSize = this->peBuffer.vBufSize;
493 if (!vBuf || !vBufSize)
return nullptr;
495 size_t ready_blocks = 0;
496 std::map<DWORD, IATBlock*>::iterator itr;
497 for (itr = foundIATs.begin(); itr != foundIATs.end(); ++itr) {
499 if (
iat->isValid()) {
500 ready_blocks +=
iat->thunkSeries.size();
503 if (ready_blocks == 0) {
508 if (!importTableBuffer) {
514 DWORD orig_thunk_rva = names_start_rva;
515 size_t names_space = 0;
517 for (itr = foundIATs.begin(); itr != foundIATs.end(); ++itr) {
519 if (!
iat->isValid()) {
522 IATThunksSeriesSet::iterator sItr;
523 for (sItr =
iat->thunkSeries.begin(); sItr !=
iat->thunkSeries.end(); ++sItr, ++i) {
526 importTableBuffer->
descriptors[i].OriginalFirstThunk = orig_thunk_rva;
529 names_space += names_space_size;
530 orig_thunk_rva += names_space_size;
536 size_t dlls_area_size = 0;
538 for (itr = foundIATs.begin(); itr != foundIATs.end(); ++itr) {
540 if (!
iat->isValid()) {
543 IATThunksSeriesSet::iterator sItr;
544 for (sItr =
iat->thunkSeries.begin(); sItr !=
iat->thunkSeries.end(); ++sItr++, ++i) {
548 BYTE *buf = importTableBuffer->
getNamesSpaceAt(name_rva, names_space_size);
552 series->
fillNamesSpace(buf, names_space_size, name_rva, this->is64bit);
554 dlls_area_size +=
iat->sizeOfDllsSpace();
558 DWORD dll_name_rva = dlls_rva;
561 for (itr = foundIATs.begin(); itr != foundIATs.end(); ++itr) {
563 if (!
iat->isValid()) {
567 IATThunksSeriesSet::iterator sItr;
568 for (sItr =
iat->thunkSeries.begin(); sItr !=
iat->thunkSeries.end(); ++sItr, ++i) {
570 importTableBuffer->
descriptors[i].Name = dll_name_rva;
571 BYTE *buf = importTableBuffer->
getDllSpaceAt(dll_name_rva, max_dll_name);
576 dll_name_rva += max_dll_name;
579 return importTableBuffer;
585 const size_t new_size = peBuffer.vBufSize + import_table_size;
587 if (!peBuffer.resizeBuffer(new_size)) {
591 const DWORD imports_start_rva = importTable.
getRVA();
592 peBuffer.resizeLastSection(imports_start_rva + import_table_size);
593 return importTable.
setTableInPe(peBuffer.vBuf, peBuffer.vBufSize);
size_t countThunks() const
size_t sizeOfNamesSpace(bool is64b)
bool fillNamesSpace(const BYTE *buf_start, size_t buf_size, DWORD bufRVA, bool is64b)
t_imprec_res rebuildImportTable(const IN peconv::ExportsMapper *exportsMap, IN const pesieve::t_imprec_mode &imprec_mode)
bool printFoundIATs(const std::string &reportPath)
enum pesieve::ImpReconstructor::imprec_res t_imprec_res
bool allocDllsSpace(DWORD dlls_rva, size_t dlls_area_size)
bool allocNamesSpace(DWORD names_rva, size_t names_size)
BYTE * getDllSpaceAt(const DWORD rva, size_t required_size)
BYTE * getNamesSpaceAt(const DWORD rva, size_t required_size)
bool setTableInPe(BYTE *vBuf, size_t vBufSize)
size_t getDescriptorsSize()
bool allocDesciptors(size_t descriptors_count)
IMAGE_IMPORT_DESCRIPTOR * descriptors
A class containing callbacks for functions: find_iat, fill_iat.
#define MASK_TO_DWORD(val)
DWORD(__stdcall *_PssCaptureSnapshot)(HANDLE ProcessHandle
BYTE * get_buffer_space_at(IN BYTE *buffer, IN const size_t buffer_size, IN const DWORD buffer_rva, IN const DWORD required_rva, IN const size_t required_size)
IMAGE_IMPORT_DESCRIPTOR * find_import_table(IN bool is64bit, IN BYTE *vBuf, IN size_t vBufSize, IN const peconv::ExportsMapper *exportsMap, IN DWORD iat_offset, OUT size_t &table_size, IN OPTIONAL size_t search_offset)
IATBlock * find_iat(BYTE *vBuf, size_t vBufSize, IN const peconv::ExportsMapper *exportsMap, IN size_t search_offset, IN ThunkFoundCallback *callback)
@ PE_IMPREC_AUTO
try to autodetect the most suitable mode
@ PE_IMPREC_REBUILD0
build the import table from the scratch, basing on the found IAT(s): use only terminated blocks (rest...
@ PE_IMPREC_UNERASE
recover erased parts of the partialy damaged import table
@ PE_IMPREC_REBUILD2
build the import table from the scratch, basing on the found IAT(s): use all found blocks (aggressive...
@ PE_IMPREC_REBUILD1
build the import table from the scratch, basing on the found IAT(s): use terminated blocks,...
Final summary about the scanned process.