Nützliches Zeug für das Einlesen der exportierten Funktionen aus der
DLL (MMF) und der geladenen Version im Speicher (ohne GetProcAddress):
MMF: (todo: Anpassungen und spezielle Validierungen für dieses Projekt)
TDLLInfo.ReadExportDirectory
Mem: (todo: spezielle Validierungen für dieses Projekt)
Delphi-Quellcode:
function GetProcAddressPE32(Module: HMODULE; ProcName: LPCSTR): TFarProc;
type
PWordArray = ^TWordArray;
TWordArray = array [Word] of WORD;
PDWordArray = ^TDWordArray;
TDWordArray = array [Word] of DWORD;
var
NtHeaders: PImageNtHeaders;
ExpDatDir: PImageDataDirectory;
ExportDir: PImageExportDirectory;
Functions: PDWordArray;
FuncIndex: DWORD;
Ordinals: PWordArray;
OrdIndex: DWORD;
Names: PDWordArray;
ModName: array [0..MAX_PATH] of AnsiChar;
OrdStrLo: DWORD;
OrdStrHi: DWORD;
SCompare: Integer;
function RvaToVa(Rva: DWORD): Pointer;
begin
Result := Pointer(Cardinal(Module) + Rva);
end;
function IsForwarderRva(Rva: DWORD): Boolean;
begin
Result := (Rva >= ExpDatDir.VirtualAddress) and
(Rva < ExpDatDir.VirtualAddress + ExpDatDir.Size);
end;
begin
Result := nil;
if HMODULE(nil) = Module then
begin
SetLastError(ERROR_INVALID_PARAMETER);
Exit;
end;
with PImageDosHeader(Module)^ do
if (IMAGE_DOS_SIGNATURE = e_magic) and (e_lfanew > 0) then
NtHeaders := PImageNtHeaders(Cardinal(Module) + DWORD(e_lfanew))
else
NtHeaders := PImageNtHeaders(Module);
with NtHeaders^, FileHeader, OptionalHeader do
if (IMAGE_NT_SIGNATURE = Signature) and
(SizeOfOptionalHeader >= SizeOf(TImageOptionalHeader) -
SizeOf(DataDirectory) + SizeOf(TImageDataDirectory)) and
(IMAGE_NT_OPTIONAL_HDR_MAGIC = Magic) then
begin
ExpDatDir := Addr(DataDirectory[0]);
ExportDir := RvaToVa(ExpDatDir.VirtualAddress);
end
else
begin
SetLastError(ERROR_INVALID_DATA);
Exit;
end;
if (0 = ExpDatDir.Size) or (nil = ExportDir) then
begin
SetLastError(ERROR_PROC_NOT_FOUND);
Exit;
end;
Functions := RvaToVa(Cardinal(ExportDir.AddressOfFunctions));
Ordinals := RvaToVa(Cardinal(ExportDir.AddressOfNameOrdinals));
Names := RvaToVa(Cardinal(ExportDir.AddressOfNames));
if nil = Functions then
begin
SetLastError(ERROR_PROC_NOT_FOUND);
Exit;
end;
// Checks done ;)
if Cardinal(ProcName) <= MAXWORD then
begin
// Import by Oridinal
FuncIndex := Cardinal(ProcName) - Cardinal(ExportDir.Base);
if (FuncIndex >= ExportDir.NumberOfFunctions) or
(0 = Functions[FuncIndex]) then
SetLastError(ERROR_PROC_NOT_FOUND)
else
begin
if IsForwarderRva(Functions[FuncIndex]) then
begin
// Forwarder
ProcName := lstrcpynA(PAnsiChar(Addr(ModName[0])),
PAnsiChar(RvaToVa(Functions[FuncIndex])), MAX_PATH);
while ProcName[0] <> #0 do
if ProcName[0] <> '.' then
Inc(ProcName)
else
begin
ProcName[0] := #0;
Break;
end;
ProcName := PAnsiChar(Cardinal(RvaToVa(Functions[FuncIndex])) +
Cardinal(lstrlenA(PAnsiChar(Addr(ModName[0])))));
if ProcName[0] <> '.' then
SetLastError(ERROR_INVALID_DATA)
else
begin
Inc(ProcName);
Module := HMODULE(GetModuleHandleA(PAnsiChar(Addr(ModName[0]))));
if HMODULE(nil) = Module then
SetLastError(ERROR_MOD_NOT_FOUND)
else
Result := GetProcAddressPE32(Module, ProcName);
end;
end
else
// Function RVA
Result := TFarProc(RvaToVa(Functions[FuncIndex]));
end;
end
else
begin
// Import by Name
OrdStrLo := 0;
OrdStrHi := DWORD(Integer(ExportDir.NumberOfNames) - 1);
while OrdStrLo <= OrdStrHi do
begin
OrdIndex := (OrdStrHi - OrdStrLo) div 2 + OrdStrLo;
SCompare := lstrcmpA(ProcName, PAnsiChar(RvaToVa(Names[OrdIndex])));
if 0 = SCompare then
begin
// Resolve by Ordinal
Result := GetProcAddressPE32(Module,
PAnsiChar(Ordinals[OrdIndex] + ExportDir.Base));
Exit;
end;
if SCompare < 0 then
OrdStrHi := OrdIndex - 1
else
OrdStrLo := OrdIndex + 1;
end;
SetLastError(ERROR_PROC_NOT_FOUND);
end;
end;
Die beiden dürften als Vorlage relativ nützlich sein (der Code unterstützt auch Forwarder). Das ganze Projekt kann ich nicht veröffentlichen, da ich nicht das alleinige Copyright darauf habe... könnte also sein, dass ein paar Typen und Konstanten fehlen (sollten alle im
MSDN/
PSDK zu finden sein).
Gruß Nico