mirror of
https://github.com/CloudDelphi/Virtual-File-System
synced 2025-12-19 09:53:54 +01:00
164 lines
5.2 KiB
ObjectPascal
164 lines
5.2 KiB
ObjectPascal
unit VfsApiDigger;
|
|
(*
|
|
Description: Provides means for detecting real WinAPI functions addresses, bypassing proxy dlls and
|
|
other low level code routines.
|
|
*)
|
|
|
|
|
|
(***) interface (***)
|
|
|
|
uses
|
|
SysUtils, Windows,
|
|
Utils, DataLib, PatchForge;
|
|
|
|
|
|
(* Determines real exported API addresses for all specified DLL handles. If DLL imports function
|
|
with the same name, as the exported one, then imported one is treated as real function.
|
|
Example: kernel32.ReadProcessMemory can be a bridge to imported kernelbase.ReadProcessMemory.
|
|
If DLL handle was processed earlier, it's skipped *)
|
|
procedure FindOutRealSystemApiAddrs (const DllHandles: array of integer);
|
|
|
|
(* Returns real code address, bypassing possibly nested simple redirection stubs like JMP [...] or JMP XXX. *)
|
|
function GetRealAddress (CodeOrRedirStub: pointer): {n} pointer;
|
|
|
|
(* Enhanced version of kernel32.GetProcAddress, traversing bridge chains and using info, gained by FindOutRealSystemApiAddrs earlier *)
|
|
function GetRealProcAddress (DllHandle: integer; const ProcName: string): {n} pointer;
|
|
|
|
|
|
(***) implementation (***)
|
|
|
|
|
|
var
|
|
(* Map of DLL handle => API name => Real api address *)
|
|
{O} DllRealApiAddrs: {O} TObjDict {OF TDict};
|
|
|
|
|
|
procedure FindOutRealSystemApiAddrs (const DllHandles: array of integer);
|
|
const
|
|
PE_SIGNATURE_LEN = 4;
|
|
|
|
type
|
|
PImageImportDirectory = ^TImageImportDirectory;
|
|
TImageImportDirectory = packed record
|
|
RvaImportLookupTable: integer;
|
|
TimeDateStamp: integer;
|
|
ForwarderChain: integer;
|
|
RvaModuleName: integer;
|
|
RvaImportAddressTable: integer;
|
|
end;
|
|
|
|
PHintName = ^THintName;
|
|
THintName = packed record
|
|
Hint: word;
|
|
Name: array [0..MAXLONGINT - 5] of char;
|
|
end;
|
|
|
|
var
|
|
ImportDirInfo: PImageDataDirectory;
|
|
ImportDir: PImageImportDirectory;
|
|
ImportLookupTable: Utils.PEndlessIntArr;
|
|
ImportAddrTable: Utils.PEndlessIntArr;
|
|
DllApiRedirs: {U} TDict {of pointer};
|
|
DllHandle: integer;
|
|
i, j: integer;
|
|
|
|
begin
|
|
ImportDirInfo := nil;
|
|
ImportDir := nil;
|
|
ImportLookupTable := nil;
|
|
ImportAddrTable := nil;
|
|
DllApiRedirs := nil;
|
|
// * * * * * //
|
|
for i := 0 to high(DllHandles) do begin
|
|
DllHandle := DllHandles[i];
|
|
ImportDirInfo := @PImageOptionalHeader(DllHandle + PImageDosHeader(DllHandle)._lfanew + PE_SIGNATURE_LEN + sizeof(TImageFileHeader)).DataDirectory[1];
|
|
DllApiRedirs := DllRealApiAddrs[Ptr(DllHandle)];
|
|
|
|
if DllApiRedirs = nil then begin
|
|
DllApiRedirs := DataLib.NewDict(NOT Utils.OWNS_ITEMS, DataLib.CASE_SENSITIVE);
|
|
DllRealApiAddrs[Ptr(DllHandle)] := DllApiRedirs;
|
|
|
|
// Found valid import directory in Win32 PE
|
|
if ((ImportDirInfo.Size > 0) and (ImportDirInfo.VirtualAddress <> 0)) then begin
|
|
ImportDir := pointer(DllHandle + integer(ImportDirInfo.VirtualAddress));
|
|
|
|
while ImportDir.RvaImportLookupTable <> 0 do begin
|
|
ImportLookupTable := pointer(DllHandle + ImportDir.RvaImportLookupTable);
|
|
ImportAddrTable := pointer(DllHandle + ImportDir.RvaImportAddressTable);
|
|
|
|
j := 0;
|
|
|
|
while (j >= 0) and (ImportLookupTable[j] <> 0) do begin
|
|
if ImportLookupTable[j] > 0 then begin
|
|
DllApiRedirs[pchar(@PHintName(DllHandle + ImportLookupTable[j]).Name)] := Ptr(ImportAddrTable[j]);
|
|
end;
|
|
|
|
Inc(j);
|
|
end;
|
|
|
|
Inc(ImportDir);
|
|
end; // .while
|
|
end; // .if
|
|
end; // .if
|
|
end; // .for
|
|
end; // .procedure FindOutRealSystemApiAddrs
|
|
|
|
function GetRealAddress (CodeOrRedirStub: pointer): {n} pointer;
|
|
const
|
|
MAX_DEPTH = 100;
|
|
|
|
var
|
|
Depth: integer;
|
|
|
|
begin
|
|
{!} Assert(CodeOrRedirStub <> nil);
|
|
result := CodeOrRedirStub;
|
|
Depth := 0;
|
|
|
|
while Depth < MAX_DEPTH do begin
|
|
// JMP DWORD [PTR]
|
|
if pword(result)^ = PatchForge.OPCODE_JMP_PTR_CONST32 then begin
|
|
result := ppointer(integer(result) + sizeof(word))^;
|
|
// JXX SHORT CONST8
|
|
end else if PatchForge.IsShortJumpConst8Opcode(pbyte(result)^) then begin
|
|
result := pointer(integer(result) + sizeof(byte) + pshortint(integer(result) + sizeof(byte))^);
|
|
// JMP NEAR CONST32
|
|
end else if pbyte(result)^ = PatchForge.OPCODE_JMP_CONST32 then begin
|
|
result := pointer(integer(result) + sizeof(PatchForge.TJumpCall32Rec) + pinteger(integer(result) + sizeof(byte))^);
|
|
// JXX (conditional) NEAR CONST32
|
|
end else if PatchForge.IsNearJumpConst32Opcode(pword(result)^) then begin
|
|
result := pointer(integer(result) + sizeof(word) + sizeof(integer) + pinteger(integer(result) + sizeof(word))^);
|
|
// Regular code
|
|
end else begin
|
|
break;
|
|
end; // .else
|
|
|
|
Inc(Depth);
|
|
end; // .while
|
|
end; // .function GetRealAddress
|
|
|
|
function GetRealProcAddress (DllHandle: integer; const ProcName: string): {n} pointer;
|
|
var
|
|
{Un} DllApiRedirs: {U} TDict {OF pointer};
|
|
|
|
begin
|
|
DllApiRedirs := DllRealApiAddrs[Ptr(DllHandle)];
|
|
result := nil;
|
|
// * * * * * //
|
|
|
|
if DllApiRedirs <> nil then begin
|
|
result := DllApiRedirs[ProcName];
|
|
end;
|
|
|
|
if result = nil then begin
|
|
result := Windows.GetProcAddress(DllHandle, pchar(ProcName));
|
|
end;
|
|
|
|
if result <> nil then begin
|
|
result := GetRealAddress(result);
|
|
end;
|
|
end; // .function GetRealProcAddress
|
|
|
|
begin
|
|
DllRealApiAddrs := DataLib.NewObjDict(Utils.OWNS_ITEMS);
|
|
end. |