Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Neuen Beitrag zur Code-Library hinzufügen (https://www.delphipraxis.net/33-neuen-beitrag-zur-code-library-hinzufuegen/)
-   -   Delphi Adresse von GetProcAddress OHNE GetProcAddress ermitteln ;) (https://www.delphipraxis.net/138858-adresse-von-getprocaddress-ohne-getprocaddress-ermitteln-%3B.html)

Aphton 18. Aug 2009 23:53


Adresse von GetProcAddress OHNE GetProcAddress ermitteln ;)
 
Hiermit möchte ich euch eine Routine beschreiben, mit der man ohne GetProcAddress die Adresse von GetProcAddress (und somit auch andere exportierte Funktionen) ermitteln kann.

Die Function _GetProcAddress() macht folgendes:
  • (1) Zuerst wird die Adresse von PEB (Process Enviroment Block) ermittelt
  • (2) Anschließend wird die doppelt verkettete Liste (LDR) abgearbeitet und nach dem Module "kernel32.dll" gesucht: wird sie gefunden, darfs weiter gehen
  • (3) die Funktion hangelt sich durch das Image-Format bis zur Export Table der DLL;
  • (4) hier werden alle Namen ausgelesen, verglichen und bei Übereinstimmung wird die Adresse der Funktion als Result zurück gegeben

Referenzen:
Undocumented.ntinternals - struct _PEB
msdn - PEB

MfG und viel Spaß damit ;)

Delphi-Quellcode:
{  --|  Code Snippet |--  }
uses
  Windows;

type
  _UNICODE_STRING = record
    Length: Word;
    MaximumLength: Word;
    Buffer: PWideChar;
  end;
  PUnicodeString = ^TUnicodeString;
  TUnicodeString = _UNICODE_STRING;

  PPEB_LDR_DATA = ^TPEB_LDR_DATA;
  TPEB_LDR_DATA = packed record
    Reserved1: Array[0..7] of Byte;
    Reserved2: Array[0..2] of Pointer;
    InMemoryOrderModuleList: LIST_ENTRY;
  end;

  PLDR_MODULE = ^LDR_MODULE;
  LDR_MODULE = packed record
    InLoadOrderModuleList: LIST_ENTRY;
    InMemoryOrderModuleList: LIST_ENTRY;
    InInitializationOrderModuleList: LIST_ENTRY;
    BaseAddress: Pointer;
    EntryPoint: Pointer;
    SizeOfImage: DWord;
    FullDllName: TUnicodeString;
    BaseDllName: TUnicodeString;
    Flags: DWord;
    LoadCount: Short;
    TlsIndex: SHort;
    HashTableEntry: LIST_ENTRY;
    TimeDateStamp: DWord;
  end;

  PPEB = ^PEB;
  PEB = record
    Reserved1: Array[0..1] of Byte;
    BeingDebugged: Byte;
    Spare: Byte;
    Mutant: DWord;
    ImageBase: Pointer;
    Ldr: PPEB_LDR_DATA;
    {REST NICHT IMPLEMENTIERT: WIRD FÜR >MEINE< ZWECKE NICHT BENÖTIGT}
  end;

function GetPEB(): PPEB;
asm
  mov eax, FS:[$30]
end;

function _GetProcAddress(): Pointer;
var
  _PEB: PPEB;
  _FirstItem, _CurrentItem: PListEntry;
  _Module: PLDR_MODULE;
  ModuleName: String;
  ModuleFound: Boolean;
  ImageBase: DWord;
  pDosHeader:  ^_IMAGE_DOS_HEADER;
  pNTHeaders:  ^_IMAGE_NT_HEADERS;
  pExportTable: ^_IMAGE_EXPORT_DIRECTORY;
  NameStartAddr: DWord;
  FuncStartAddr: DWord;
  ExportName: PChar;
  i: Integer;
const
  k32: PChar = 'kernel32.dll';
  GPA: PChar = 'GetProcAddress';
begin
// (1)
  Result       := NIL;
  _PEB         := GetPEB();
  _FirstItem   := @_PEB^.Ldr^.InMemoryOrderModuleList;
  if _FirstItem = NIL then
    Exit;
// (2)
  _CurrentItem := _FirstItem^.Flink;
  ModuleFound  := False;
  while ( _CurrentItem <> _FirstItem ) and ( not ModuleFound ) do
  begin
    _Module    := PLDR_MODULE( _CurrentItem );
    ModuleName := WideCharToString( _Module^.FullDllName.Buffer );
    ModuleFound := ModuleName = k32;
    _CurrentItem := _CurrentItem^.Flink;
  end;
// (3)
  if ModuleFound then
  begin
    ImageBase  := DWord( _Module^.InInitializationOrderModuleList.Flink );
    pDosHeader := Pointer( ImageBase );
    if pDosHeader^.e_magic = IMAGE_DOS_SIGNATURE then
    begin
      pNTHeaders := Pointer( ImageBase );
      inc( Cardinal( pNTHeaders ), pDosHeader^._lfanew );
      if pNTHeaders^.Signature = IMAGE_NT_SIGNATURE then
      begin
        pExportTable := Pointer( ImageBase +
          pNTHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress );
        NameStartAddr := ImageBase + DWord( pExportTable^.AddressOfNames );
        FuncStartAddr := ImageBase + DWord( pExportTable^.AddressOfFunctions );
// (4)
        for i := 0 to pExportTable^.NumberOfNames-1 do
        begin
          ExportName := pChar( ImageBase + PDWord( NameStartAddr + 4*i )^ );
          if String( ExportName ) = String( GPA ) then
          begin
            Result := Pointer( ImageBase + PDWord( FuncStartAddr + 4*(i+1) )^ );
            Exit;
          end;
        end;
      end;
    end;
  end;
end;
Delphi-Quellcode:
function _GetModuleAddress( ModuleName: PChar ): Pointer;
var
  _PEB: PPEB;
  _FirstItem, _CurrentItem: PListEntry;
  _Module: PLDR_MODULE;
  CurrentModule: String;
  ModuleFound: Boolean;
begin
  Result       := NIL;
  _PEB         := GetPEB();
  _FirstItem   := @_PEB^.Ldr^.InMemoryOrderModuleList;
  if _FirstItem = NIL then
    Exit;
  _CurrentItem := _FirstItem^.Flink;
  ModuleFound  := False;
  while ( _CurrentItem <> _FirstItem ) and ( not ModuleFound ) do
  begin
    _Module      := PLDR_MODULE( _CurrentItem );
    CurrentModule := WideCharToString( _Module^.FullDllName.Buffer );
    ModuleFound  := CurrentModule = ModuleName;
    _CurrentItem := _CurrentItem^.Flink;
  end;
  if ModuleFound then
    Result := _Module^.InInitializationOrderModuleList.Flink;
end;

function _GetProcAddress( ModuleAddress: Pointer; ProcName: PChar ): Pointer;
var
  pDosHeader:  ^_IMAGE_DOS_HEADER;
  pNTHeaders:  ^_IMAGE_NT_HEADERS;
  pExportTable: ^_IMAGE_EXPORT_DIRECTORY;
  NameStartAddr: DWord;
  FuncStartAddr: DWord;
  ExportName: PChar;
  i: Integer;
begin
  pDosHeader := ModuleAddress;
  if pDosHeader^.e_magic = IMAGE_DOS_SIGNATURE then
  begin
    pNTHeaders := ModuleAddress;
    inc( Cardinal( pNTHeaders ), pDosHeader^._lfanew );
    if pNTHeaders^.Signature = IMAGE_NT_SIGNATURE then
    begin
      pExportTable := Pointer( DWord( ModuleAddress ) +
        pNTHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress );
      NameStartAddr := DWord( ModuleAddress ) + DWord( pExportTable^.AddressOfNames );
      FuncStartAddr := DWord( ModuleAddress ) + DWord( pExportTable^.AddressOfFunctions );
      for i := 0 to pExportTable^.NumberOfNames-1 do
      begin
        ExportName := pChar( DWord( ModuleAddress ) + PDWord( NameStartAddr + 4*i )^ );
        if String( ExportName ) = String( ProcName ) then
        begin
          Result := Pointer( DWord( ModuleAddress ) + PDWord( FuncStartAddr + 4*(i+1) )^ );
          Exit;
        end;
      end;
    end;
  end;
end;

Dax 19. Aug 2009 00:19

Re: Adresse von GetProcAddress OHNE GetProcAddress ermitteln
 
Ohne in Abrede zu stellen, dass das ein sehr interessante Stück Code ist - wozu soll das gut sein? :)

Aphton 19. Aug 2009 00:44

Re: Adresse von GetProcAddress OHNE GetProcAddress ermitteln
 
Im Grunde wird sie genau dann benötigt, wenn einem GetProcAddress nicht zur Verfügung
steht - dh. Code-Injection, Shellcode Entwicklung ( Computer Sicherheit ) usw.

Natürlich kann man es auch für andere Zwecke missbrauchen :P

MfG

sx2008 19. Aug 2009 02:53

Re: Adresse von GetProcAddress OHNE GetProcAddress ermitteln
 
Könntest du das nicht in zwei Funktionen zerlegen?
  • (1) Zuerst wird die Adresse von PEB (Process Enviroment Block) ermittelt
  • (2) Anschließend wird die doppelt verkettete Liste (LDR) abgearbeitet und nach dem Module "kernel32.dll" gesucht: wird sie gefunden, darfs weiter gehen
Diese beiden Punkte zusammen entsprechen ja der Funktion GetModuleAddress('kernel.dll').
Mit dieser Adresse und dem Namen der Funktion (hier: 'GetProcAddress') ruft man dann die zweite Funktion auf,
und erhält dann die Einsprungadresse.
Dies entspricht dann Punkt (3) und (4).

Nach dieser Zerlegung in zwei Funktionen versteht man den Code besser und kann auch mehr damit anfangen.

Aphton 19. Aug 2009 03:17

Re: Adresse von GetProcAddress OHNE GetProcAddress ermitteln
 
Vorschlag angenommen; Siehe Beitrag #1

sx2008 19. Aug 2009 04:11

Re: Adresse von GetProcAddress OHNE GetProcAddress ermitteln
 
Zitat:

Zitat von Aphton
Vorschlag angenommen; Siehe Beitrag #1

:thumb: Ok, und dann noch schnell die Früchte der Arbeit ernten:
Delphi-Quellcode:
function _GetProcAddress(): Pointer; overload;
begin
  Result := _GetModuleAddress('kernel.dll');
  if Assigned(result) then
    Result := _GetProcAddress(Result, 'GetProcAddress');
end;

Aphton 19. Aug 2009 04:54

Re: Adresse von GetProcAddress OHNE GetProcAddress ermitteln
 
:warn:

:roll:

wicht 19. Aug 2009 07:58

Re: Adresse von GetProcAddress OHNE GetProcAddress ermitteln
 
+1 Internets.
Auch wenn ich noch nicht weiß, ob ich es jemals gebrauchen kann...

OldGrumpy 19. Aug 2009 08:55

Re: Adresse von GetProcAddress OHNE GetProcAddress ermitteln
 
Man kann damit auch die Leute etwas ärgern, die immer alles umsonst haben müssen :mrgreen: ;)

hitzi 19. Aug 2009 09:18

Re: Adresse von GetProcAddress OHNE GetProcAddress ermitteln
 
Zitat:

Zitat von OldGrumpy
Man kann damit auch die Leute etwas ärgern, die immer alles umsonst haben müssen :mrgreen: ;)

Kannst du dazu bitte ein bissl mehr sagen? Würde mich interessieren.

himitsu 19. Aug 2009 09:21

Re: Adresse von GetProcAddress OHNE GetProcAddress ermitteln
 
ich vermute mal, daß er es so meint, daß es über diese Funktionen schwerer sein wird, einfach irgendwelche Funktionen zu hocken und auf diese Weise z.B. etwas freizuschalten.

allerdings vermute ich mal, daß die entsprechenden APIs es auch nicht sehr viel anders machen.

PS: ist wem schon aufgefallen, daß _GetModuleAddress im Grunde dem GetModuleHandle gleicht?
(unter WinNT entspricht ja zufällig das Handle der Adresse)

sirius 19. Aug 2009 09:48

Re: Adresse von GetProcAddress OHNE GetProcAddress ermitteln
 
Bzgl GetProcAddress hatte Hagen hier folgendes publiziert:
Delphi-Quellcode:
function GetProcAddr(Module: hModule; Name: PChar): Pointer;
asm
        XOR  ECX,ECX                // except frame
        PUSH OFFSET @@6 
        PUSH DWord Ptr FS:[ECX]
        MOV  FS:[ECX],ESP
        PUSH EBP
        PUSH EBX
        MOV  EBP,EDX
        AND  EAX,not 3 
        PUSH EDI
        MOV  EDX,[EAX + 03Ch]
        PUSH ESI
        TEST EBP,EBP
        JZ   @@5 
        CMP  Word Ptr [EAX + EDX],'EP'
        MOV  EDX,[EAX + EDX + 078h]
        JNZ  @@5 
        ADD  EDX,EAX
        TEST EBP,0FFFF0000h
        MOV  EBX,EAX
        JZ   @@3                         // import by ordinal ?? 
        MOV  EAX,[EDX + 018h]
        MOV  ECX,[EDX + 020h]
        NOT  EAX
@@1:   INC  EAX
        MOV  ESI,EBP
        JZ   @@4 
        MOV  EDI,[EBX + ECX]
        ADD  ECX,4 
        ADD  EDI,EBX
@@2:   CMPSB
        JNE  @@1 
        CMP  Byte Ptr [ESI - 1],0 
        JNE  @@2 
        ADD  EAX,[EDX + 018h]
        MOV  ECX,[EDX + 024h]
        ADD  ECX,EBX
        MOVZX EBP,Word Ptr [ECX + EAX * 2]
        INC  EBP
@@3:   MOV  ECX,[EDX + 01Ch]
        DEC  EBP
        ADD  ECX,EBX
        MOV  EAX,[ECX + EBP * 4]
        ADD  EAX,EBX
@@4:   POP  ESI
        POP  EDI
        POP  EBX
        POP  EBP
        POP  DWord Ptr FS:[0]
        POP  ECX
        RET
@@5:   XOR  EAX,EAX
        JMP  @@4 
@@6:   MOV  EAX,[ESP + 00Ch]                // except handler
        PUSH OFFSET @@5 
        POP  DWord Ptr [EAX + 0B8h]
        SUB  EAX,EAX
end;

OldGrumpy 19. Aug 2009 09:56

Re: Adresse von GetProcAddress OHNE GetProcAddress ermitteln
 
Wie himitsu schon ganz richtig vermutete ist das halt ein Weg an OS-Funktionen zu kommen ohne die ganz offensichtlich statisch oder "konventionell dynamisch" zu linken. Insbesondere bei Shareware die für einen bestimmten Zeitraum voll funktionsfähig ist und sich dann totschaltet, ist es ja essentiell, ein halbwegs verlässliches Datum zu bekommen. Das kann man sich mit obiger Funktion holen ohne dass es auf den ersten Blick zu sehen ist. Stichwort Obfuskierung. Dass das keine wirkliche Hürde ist, sollte aber auch jedem klar sein, deswegen schrieb ich "etwas" und den :mrgreen: ;)

//Edit: In Zeiten des überall verfügbaren Internets hat die Bedeutung natürlich allgemein abgenommen, und die Bedeutung serverbasierter Authentifizierung stark zugenommen. Brauchemergarneddrübberredde ;)

Aphton 19. Aug 2009 15:29

Re: Adresse von GetProcAddress OHNE GetProcAddress ermitteln
 
Zitat:

Zitat von himitsu
PS: ist wem schon aufgefallen, daß _GetModuleAddress im Grunde dem GetModuleHandle gleicht?
(unter WinNT entspricht ja zufällig das Handle der Adresse)

Ja klar :)

brechi 19. Aug 2009 17:33

Re: Adresse von GetProcAddress OHNE GetProcAddress ermitteln
 
Fehlen aber noch Forwarded Functions und Ordinals
--> http://uall.cheat-project.com/uallCollection/ -> uallKernel

Und wenn du (laut Titel) nur GetProcAddress haben willst reicht das Handle des Kernel32.dll:

Delphi-Quellcode:
function GetKernelHandle: DWord; stdcall;
asm
  MOV    EAX, DWORD PTR FS:[030H]
  TEST   EAX, EAX
  JS     @@W9X
@@WNT:
  MOV    EAX, DWORD PTR [EAX+00CH]
  MOV    ESI, DWORD PTR [EAX+01CH]
  LODSD
  MOV    EAX, DWORD PTR [EAX+008H]
  JMP    @@K32
@@W9X:
  MOV    EAX, DWORD PTR [EAX+034H]
  LEA    EAX, DWORD PTR [EAX+07CH]
  MOV    EAX, DWORD PTR [EAX+03CH]
@@K32:
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:14 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz