Delphi Inline ASM GetProcAddress Api Replacement

Post date: Sep 2, 2010 8:47:30 PM

This code can be used as a replacement for the GetProcAddress Api call

Tested and working Windows XP, Vista, 7; x86, x64

Author: NicoDE

Compiled: Delphi 2007

program GetProcAddress;
uses
  Windows;
const
  MAX_API_STRING_LENGTH = 150;
type
  PSEHStruct = ^TSEHStruct;
  TSEHStruct = record
    saveEsp: Cardinal;
    saveEbp: Cardinal;
    gotoEip: Cardinal;
  end;
var
  SEH: TSEHStruct;
function SEHHandler(p1, p2, p3, p4: Pointer): Cardinal; cdecl;
begin
  with PContext(p3)^ do
  begin
    Esp := SEH.saveEsp;
    Ebp := SEH.saveEbp;
    Eip := SEH.gotoEip;
  end;
  Result := 0;  // ExceptionContinueExecution
end;
function ASMGetProcAddress(DllBase: LongWord; ApiName: PChar): Pointer; pascal;
{ directive "pascal" to force stack frame }
asm
        { save used registers }
        PUSH    ESI
        PUSH    EDI
        PUSH    ECX
        PUSH    EBX
        PUSH    EDX
        { using [EDX] saves some space over [0] }
        XOR     EDX, EDX
        { set up SEH frame }
        PUSH    OFFSET SEHHandler
        PUSH    DWORD PTR FS:[EDX]
        MOV     SEH.saveEsp, ESP
        MOV     SEH.saveEbp, EBP
        MOV     SEH.gotoEip, OFFSET @@NotFound
        MOV     FS:[EDX], ESP
        { string length the target api }
        MOV     EDI, ApiName
        MOV     ECX, MAX_API_STRING_LENGTH
        XOR     AL, AL
        REPNZ   SCASB
        MOV     ECX, EDI
        SUB     ECX, ApiName
        { get and check PE file header }
        MOV     EDX, DllBase
        CMP     [EDX].TImageDosHeader.e_magic, IMAGE_DOS_SIGNATURE
        JNZ     @@NotFound
        ADD     EDX, [EDX].TImageDosHeader._lfanew
        CMP     [EDX].TImageNtHeaders.Signature, IMAGE_NT_SIGNATURE
        JNZ     @@NotFound
        { get and check export directory }
        MOV     EDX, [EDX].TImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].TImageDataDirectory.VirtualAddress
        OR      EDX, EDX
        JZ      @@NotFound
        ADD     EDX, DllBase
        { scan names }
        MOV     EBX, [EDX].TImageExportDirectory.AddressOfNames
        ADD     EBX, DllBase
        XOR     EAX, EAX
@@Loop:
        MOV     EDI, [EBX]
        ADD     EDI, DllBase
        MOV     ESI, ApiName
        PUSH    ECX
        REPZ    CMPSB
        POP     ECX
        JE      @@Found
        ADD     EBX, 4
        INC     EAX
        CMP     EAX, [EDX].TImageExportDirectory.NumberOfNames
        JB      @@Loop
        JMP     @@NotFound
@@Found:
        { name -> ordinal }
        SHL     EAX, 1
        ADD     EAX, [EDX].TImageExportDirectory.AddressOfNameOrdinals
        ADD     EAX, DllBase
        MOV     AX, [EAX]
        AND     EAX, $0000FFFF
        { ordinal -> function }
        SHL     EAX, 2
        ADD     EAX, [EDX].TImageExportDirectory.AddressOfFunctions
        ADD     EAX, DllBase
        MOV     EAX, [EAX]
        ADD     EAX, DllBase
        JMP     @@Exit
@@NotFound:
        { return 0 on error }
        XOR     EAX, EAX
@@Exit:
        { clean up SEH frame }
        XOR     EDX, EDX
        POP     DWORD PTR FS:[EDX]
        ADD     ESP, 4
        { restore used registers }
        POP     EDX
        POP     EBX
        POP     ECX
        POP     EDI
        POP     ESI
end;
var
  xMessageBoxA : function(hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall;
begin
  xMessageBoxA := ASMGetProcAddress(LoadLibrary('user32.dll'),'MessageBoxA');
  if Assigned(xMessageBoxA) then
    xMessageBoxA(0,'Assigned!','',0);
end.