Tras publicar la herramienta Visor de datos exportados por un ejecutable a raiz de éste hilo, me pareció que sería bueno ampliar el estudio del PE y escribir otra herramienta mas potente que explorara tanto los datos y funciones exportados como las funciones importadas en la IAT del PE.
La gran diferencia con la anterior herramienta es que es que aquella estaba basada en funciones que exploraban el PE una vez cargado por el S.O. Esta técnica impide la exploración de algunos módulos que no se pueden cargar con un LoadLibrary. Ahora explora en bruto el archivo no cargado lo que la convierte en mas versatil y potente.
Esta nueva herramienta es capaz de explorar los archivos ejecutables del Kernel sin necesidad de ser administradores del Sistema y sin trucos hacking. Nos muestra de forma amigable los datos con su nombre y direcciones hexadecimales u offsets a la ImageBase de la carga del ejecutable, si así lo preferimos. Nos permite ordenar los datos para una mejor visualización.
Las funciones en las que se basa el corazón de la herramienta son las siguientes:
//--------------------------------------------------------------------------- void TForm1::GetExportData(PVOID lpFile) { PIMAGE_EXPORT_DIRECTORY IED; int DeltaVA; ClearData(); DWORD ImageBase; DWORD ModuleEntryPoint; IED = (PIMAGE_EXPORT_DIRECTORY) GetImageDirectory(lpFile, (DWORD)0, &DeltaVA); if(!IED){ ViewError(ListView1, "No exported data"); return; } Update(); char** Names = (char**)(IED->AddressOfNames + DeltaVA); DWORD* EntryPoints = (DWORD*)(IED->AddressOfFunctions + DeltaVA); WORD* Index = (WORD*)(IED->AddressOfNameOrdinals + DeltaVA); // Listar las funciones exportadas: ::ImageBase = GetKernelModuleBase(ComboBox1->Text.c_str()); if(::ImageBase == 0) ::ImageBase = GetOptionalHeader(lpFile)->ImageBase; if(CheckBox1->Checked) ImageBase = 0; else ImageBase = ::ImageBase; ModuleEntryPoint = (DWORD)GetModuleEntryPoint(lpFile) + ImageBase; StatusBar1->Panels->Items[0]->Text = "Base Address: " + IntToHex((int)ImageBase, 8)+"h"; StatusBar1->Panels->Items[1]->Text = "Entry Point: " + IntToHex((int)ModuleEntryPoint, 8)+"h"; StatusBar1->Panels->Items[2]->Text = IntToStr((int)IED->NumberOfNames) + " Functions and variables"; for(UINT n=0; n<IED->NumberOfNames; n++){ if(Index[n]>=IED->NumberOfFunctions) continue; char* Name = Names[n] + DeltaVA; TListItem *pItem = ListView1->Items->Add(); pItem->Caption = ""; pItem->SubItems->Add(IntToStr(Index[n] + IED->Base));// IED->Base es el Ordinal Base pItem->SubItems->Add(IntToHex(int(EntryPoints[Index[n]] + ImageBase), 8)+"h"); pItem->SubItems->Add(Name); Application->ProcessMessages(); } } //--------------------------------------------------------------------------- void TForm1::GetImportData(PVOID lpFile) { PIMAGE_IMPORT_DIRECTORY ID; PIMAGE_SECTION_HEADER SH; PIMAGE_THUNK_DATA thunk, thunkIAT; PIMAGE_IMPORT_BY_NAME pOrdinalName; int nModules = 0; int nFunc = 0; char *ModuleName, *FunctionName; int DeltaVA; DWORD Ordinal; DWORD ImageBase; ID = (PIMAGE_IMPORT_DIRECTORY)GetImageDirectory(lpFile, IMAGE_DIRECTORY_ENTRY_IMPORT, &DeltaVA); SH = GetSectionHeader(lpFile, PVOID((DWORD)ID-DeltaVA)); if(!SH || !ID){ ViewError(ListView2, "No imported data"); return; } ImageBase = GetKernelModuleBase(ComboBox1->Text.c_str()); if(ImageBase == 0) ImageBase = GetOptionalHeader(lpFile)->ImageBase; if(CheckBox1->Checked) ImageBase = 0; while (ID->dwRVAModuleName){ // Localizo el ModuleName ModuleName = (char*)(ID->dwRVAModuleName + DeltaVA); thunk = (PIMAGE_THUNK_DATA)ID->dwRVAFunctionNameList; thunkIAT = (PIMAGE_THUNK_DATA)ID->dwRVAFunctionAddressList; if(thunk==0) thunk = thunkIAT; if(thunk==0){ ViewError(ListView1, "No imported data"); return; } thunk = (PIMAGE_THUNK_DATA)((DWORD)thunk + DeltaVA); thunkIAT = (PIMAGE_THUNK_DATA)((DWORD)thunkIAT + DeltaVA); while (thunk->u1.AddressOfData){ // Localizo los Nombres de función, ordinales y IAT thunk pOrdinalName = (PIMAGE_IMPORT_BY_NAME)(thunk->u1.AddressOfData + DeltaVA); if(thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG){ Ordinal = IMAGE_ORDINAL(thunk->u1.Ordinal); FunctionName = ""; }else{ Ordinal = pOrdinalName->Hint; FunctionName = pOrdinalName->Name; } TListItem *pItem = ListView2->Items->Add(); pItem->Caption = ModuleName; pItem->SubItems->Add(Ordinal); pItem->SubItems->Add(IntToHex((int)thunkIAT - DeltaVA, 8)+"h"); pItem->SubItems->Add(FunctionName); // Incremento el contador de funciones y los thunk nFunc++; thunk++; thunkIAT++; } // Incremento el import_directory_entry y el contador de módulos. ID++; nModules++; } StatusBar2->Panels->Items[0]->Text = IntToStr(nModules)+" imported modules"; StatusBar2->Panels->Items[1]->Text = IntToStr(nFunc)+" imported functions"; } //---------------------------------------------------------------------------
Espero que sea de utilidad o que sirva, al menos, para esclarecer y servir de ejemplo con código, parte del formato de archivo de PE.
Saludos.