Concerned Project Repository

You can find a complete version of the project that is described in this paper on my Github account.

https://github.com/DarkCoderSc/Snippets

GetProcAddress Alternative

Recently, I released a unit to demonstrate how to enumerate DLL Export Table through PE Header parsing.

Using the same unit, we can bypass the need of using the famous GetProcAddress API to locate the memory address of any loaded library API.

This technique is very effective to bypass certain detection mechanisms and often used by Malware authors to escape detection.


GetProcAddress ALT Code

// Jean-Pierre LESUEUR (@DarkCoderSc)
// ...
uses tlhelp32, Windows, SysUtils, UntEnumDLLExport;
// ...

{
  Retrieve module full path from it handle (Returned by LoadLibrary()), we need
  that information to parse it PE Header and retrieve function address.
}
function GetModuleImagePath(hModule : HMODULE) : String;
var ASnap        : THandle;
    AModuleEntry : TModuleEntry32;

const TH32CS_SNAPMODULE32 = $00000010;

begin
  result := '';
  ///

  ASnap := CreateToolHelp32Snapshot(TH32CS_SNAPMODULE or TH32CS_SNAPMODULE32, GetCurrentProcessId());
  if ASnap = INVALID_HANDLE_VALUE then
    Exit();
  try
    ZeroMemory(@AModuleEntry, SizeOf(TModuleEntry32));

    AModuleEntry.dwSize := SizeOf(TModuleEntry32);
    ///

    if NOT Module32First(ASnap, AModuleEntry) then
      Exit();

    if (AModuleEntry.hModule = hModule) then begin
      result := AModuleEntry.szExePath;

      Exit();
    end;

    while True do begin
      ZeroMemory(@AModuleEntry, SizeOf(TModuleEntry32));

      AModuleEntry.dwSize := SizeOf(TModuleEntry32);
      ///

      if NOT Module32Next(ASnap, AModuleEntry) then
        Break;

      if (AModuleEntry.hModule = hModule) then begin
        result := AModuleEntry.szExePath;

        break;
      end;
    end;
  finally
    CloseHandle(ASnap);
  end;
end;

{
  Retrieve function address from DLL PE Header Export Function Table.
}
function GetProcAddress_ALT(hModule : HMODULE; lpProcName : LPCSTR) : Pointer;
var ADLLExport : TEnumDLLExport;
    I          : Integer;
begin
  result := nil;
  ///

  ADLLExport := TEnumDLLExport.Create(GetModuleImagePath(hModule));

  if (ADLLExport.Enum > 0) then begin
    for I := 0 to ADLLExport.Items.Count -1 do begin
      if (ADLLExport.Items[i].Name.ToLower = String(lpProcName).ToLower) then begin
        result := Pointer(hModule + ADLLExport.Items[i].RelativeAddr);

        break;
      end;
    end;
  end;
end;

Show MessageBox Example

//...
procedure LoadAndTriggerMessageBox();
var _MessageBoxW : function(hWnd: HWND; lpText, lpCaption: LPCWSTR; uType: UINT): Integer; stdcall;
    hModule      : HMODULE;
begin
  _MessageBoxW := nil;

  hModule := LoadLibrary('user32.dll');

  @_MessageBoxW := GetProcAddress_ALT(hModule, 'MessageBoxW');

  if Assigned(_MessageBoxW) then
    _MessageBoxW(0, 'Hello World', 'Hey', 0);
end;

begin
  LoadAndTriggerMessageBox();
end.
//...

Nov. 23, 2020, 5:31 p.m.