API functie opzoeken in DLL
Hoi
Onderstaande code probeer ik werkend te krijgen.
Mijn orignele functie "GetProcAddressFromDLL1" werkt naar behoren.
Als voorbeeld probeer ik dan MessageBoxW aan te roepen en dat wordt netjes getoond op het scherm.
Nu dacht ik, wat als ik nu eerst kijk of een functie (MessageBoxW in dit geval) wel bestaat. (functie "GetProcAddressFromDLL2")
Nou dat is iets moeilijker dan gedacht.
Hierbij gebruik ik de uitleg op "exploring-the-export-table"
Op zich gaat het best aardig, als laatste probeer ik dan de name op te vragen, die wil ik dan vergelijken met de zoekopdracht.
Indien gelijk dan de ordinal opvragen, procaddress terug geven en klaar.
Ik loop dan ook vast om een lijst met namen terug te krijgen, wat ik ook probeer, ik krijg alleen troep terug.
Iemand ervaring hiermee, mijn C kennis is niet al te geweldig?
Code:
program ApiTest;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
WinAPI.Windows;
{----------------------------------------------------------------------------------------------------------------------}
{ in Windows.pas }
{function MessageBoxW(hWnd: HWND; lpText, lpCaption: LPCWSTR; uType: UINT): Integer; stdcall; external user32 name 'MessageBoxW';}
var
MessageBoxW : FUNCTION (hWnd:HWND; lpText, lpCaption: LPCWSTR; uType: UINT) : Integer; STDCALL;
{----------------------------------------------------------------------------------------------------------------------}
// Direct test, vanuitgaande dat de functie bestaat;
function GetProcAddressFromDLL1 (aHandle: THandle; aFunctionName: PChar) : Pointer;
begin
result := nil;
if aHandle = 0 then exit;
if Trim(aFunctionName) = '' then exit;
result := GetProcAddress(aHandle, aFunctionName);
end;
{----------------------------------------------------------------------------------------------------------------------}
// Indirect test, checking if the requested FunctionName exists in the DLL.
// https://dev.to/wireless90/getting-the-windows-pe-internals-kka
// Information 32bit structure: https://upload.wikimedia.org/wikipedia/commons/1/1b/Portable_Executable_32_bit_Structure_in_SVG_fixed.svg
//
// RVA (relative virtual address)
// In an image file, the address of an item after it is loaded into memory, with the base address of the image file
// subtracted from it. The RVA of an item almost always differs from its position within the file on disk (file pointer).
// VA (virtual address)
// Same as RVA, except that the base address of the image file is not subtracted. The address is called a “VA” because
// Windows creates a distinct VA space for each process, independent of physical memory. For almost all purposes,
// a VA should be considered just an address
// Info opgezocht met PPEE (PPEE (puppy) is a Professional PE file Explorer) https://www.mzrst.com/
// File: user32.dll | 07-03-2022 19:14 | 1701896 bytes Windows 10 Pro/x64
// Base = 000005DE = 1502
// NumberOfFunctions = 000004BF = 1215
// NumberOfNames = 000003E6 = 998
// AddressOfFunctions = 0009D238 = 643640
// AddressOfNames = 0009E534 = 648500
// AddressNamesOfNamesOrdinals = 0009F4CC = 652492
// MessageBoxW | Ordinal $086C = 2156 | RVA = $00080EC0 = 528064 | NameRVA = $000A2B0D = 666381
function GetProcAddressFromDLL2 (aPEbase: HMODULE; aFunctionName: PChar) : Pointer;
Type
BytePtr = ^Byte;
TDWordArray = array[0..0] of DWord;
PDWordArray = ^TDWordArray;
var
ImageDosHeader : PImageDosHeader;
ImageNTHeaders : PImageNTHeaders;
ImageExportDirectory : PImageExportDirectory;
NameIndex : Cardinal;
Name : PChar;
begin
result := nil;
if aPEbase = 0 then exit;
// PEbase points to IMAGE_DOS_HEADER structure
ImageDosHeader := pointer(aPEbase);
if NOT assigned (ImageDosHeader) then
begin
WriteLn(format('ERR %-35s : $%p (%d)',['ImageDosHeader', ImageDosHeader, cardinal(ImageDosHeader)]));
end
else
begin
WriteLn(format('OK %-35s : $%p (%d)',['ImageDosHeader', ImageDosHeader, cardinal(ImageDosHeader)]));
//Checking for a valid 'MZ' signature
if NOT ImageDosHeader.e_magic = IMAGE_DOS_SIGNATURE then
begin
WriteLn(format('ERR %-35s : $%x (%d)',['ImageDosHeader MZ Signature', ImageDosHeader.e_magic, ImageDosHeader.e_magic]));
end
else
begin
WriteLn(format('OK %-35s : $%x (%d)',['ImageDosHeader MZ Signature', ImageDosHeader.e_magic, ImageDosHeader.e_magic]));
// Checking for a valid PE signature in the ImageDosHeader
// _lfanew contains a RVA whose offset leads to the PImageNTHeaders structure
// lfanew = long file address of the new executable header
// To compute the destination (RVA), take Base Address (PEbase) and use the lfnew as offset
ImageNTHeaders := Pointer(dword(aPEbase) + dword(ImageDosHeader._lfanew));
if NOT assigned(ImageNTHeaders) then
begin
WriteLn(format('ERR %-35s : $%p (%d)',['ImageNTHeaders', ImageNTHeaders, cardinal(ImageNTHeaders)]));
end
else
begin
WriteLn(format('OK %-35s : $%p (%d)',['ImageNTHeaders', ImageNTHeaders, cardinal(ImageNTHeaders)]));
//Checking for a valid 'PE' signature
if NOT ImageNTHeaders.Signature = IMAGE_NT_SIGNATURE then
begin
WriteLn(format('ERR %-35s : $%x (%d)',['ImageNTHeaders PE Signature', ImageNTHeaders.Signature, ImageNTHeaders.Signature]));
end
else
begin
WriteLn(format('OK %-35s : $%x (%d)',['ImageNTHeaders PE Signature', ImageNTHeaders.Signature, ImageNTHeaders.Signature]));
// Get RVA for the 'ExportTable Data Directory' from the OptionalHeader DataDirectory Virtual Adress. RVA = PEbase + Virtual Address
ImageExportDirectory := Pointer(ImageNTHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + cardinal(aPEbase));
if NOT assigned(ImageExportDirectory) then
begin
WriteLn(format('ERR %-35s : $%p (%d)',['ImageExportDirectory', ImageExportDirectory, cardinal(ImageExportDirectory)]));
end
else
begin
WriteLn(format('OK %-35s : $%p (%d)',['ImageExportDirectory', ImageExportDirectory, cardinal(ImageExportDirectory)]));
// Get ExportAddressTable, NameOrdinalsArray and NameAddressArray
// https://dev.to/wireless90/exploring-the-export-table-windows-pe-internals-4l47 (voorbeeld)
//
// int nameIndex = 0;
// for (nameIndex = 0; nameIndex < numberOfNames; nameIndex++)
// {
// char* name = (char*)((unsigned char*)peBase + exportNamePointerTable[nameIndex]);
// if (strcmp("MessageBoxA", name) == 0)
// {
// WORD ordinal = nameOrdinalsPointer[nameIndex];
// PDWORD targetFunctionAddress = (PDWORD)((unsigned char*)peBase + exportAddressTable[ordinal]);
// }
// }
NameIndex := 0;
repeat //
Name := PChar ( aPEbase + cardinal(ImageExportDirectory.AddressOfNames) + NameIndex); //<-------- ISSUE
//--> TODO if Name = aFunctionName then result := GetProcAddress(aPEbase, aFunctionName);
inc(NameIndex);
until NameIndex ImageExportDirectory.NumberOfNames;
end;
end;
end;
end;
end;
end;
{----------------------------------------------------------------------------------------------------------------------}
var
DLLHandle : THandle = 0;
begin
try
DLLHandle := LoadLibrary ('user32.dll');
try
{
// Werkt
MessageBoxW := nil;
MessageBoxW := GetProcAddressFromDLL1(DLLHandle,'MessageBoxW');
if assigned(MessageboxW) then MessageBoxW(0,'Test 1 - Direct','Direct API Call',0);
}
// Werkt NIET
MessageBoxW := nil;
MessageBoxW := GetProcAddressFromDLL2(DLLHandle,'MessageBoxW');
if assigned(MessageboxW) then MessageBoxW(0,'Test 2 - Indirect','Indirect API Call',0);
finally
FreeLibrary(DLLHandle);
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
readln;
end.