AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Sonstige Fragen zu Delphi Delphi DLL-EntryPoint mit Funktion tauschen?

DLL-EntryPoint mit Funktion tauschen?

Ein Thema von himitsu · begonnen am 4. Jul 2009 · letzter Beitrag vom 5. Jul 2009
Antwort Antwort
Seite 2 von 3     12 3   
Benutzerbild von Aphton
Aphton

Registriert seit: 31. Mai 2009
1.198 Beiträge
 
Turbo Delphi für Win32
 
#11

Re: DLL-EntryPoint mit Funktion tauschen?

  Alt 4. Jul 2009, 13:37
Ich würd dir die "CFF Explorer" Software empfehlen; sie gibt dir einen guten Einblick in das Innenleben einer PE Datei

MfG
das Erkennen beginnt, wenn der Erkennende vom zu Erkennenden Abstand nimmt
MfG
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.124 Beiträge
 
Delphi 12 Athens
 
#12

Re: DLL-EntryPoint mit Funktion tauschen?

  Alt 4. Jul 2009, 13:49
@Apollonius: uffff, na dann mal sehn ob ich das mit dem IMAGE_DATA_DIRECTORY auch noch hinbekomm
(aber aktuell geht es ja erstmal)

Was ich mich dann aber noch frage ist, gibt es dann 2 Exporttabellen, welche ich ändern muß, oder sind Beides die "Selben" (also die in .edata und IMAGE_DATA_DIRECTORY)



Ohhh, na dann hi MrEmbreD

Nja, cryptisch war's ja nicht ... nur etwas "eigenartig" berechnet.
Aber hatte ja dennoch durch deinen Code den Weg gefunden und dank dem Hinweis von Apollonius wird nun auch die Prozedurliste ausgelesen.

jetzt muß ich nur noch rausbekommen, ob IMAGE_NT_HEADERS.OptionalHeader.AddressOfEntryPoin t auch als RVA definiert ist,
oder ob ich mir das auch noch umrechnen muß.

Delphi-Quellcode:
Program himXML_DLL_Modifizierer;

{$APPTYPE CONSOLE}

Uses Windows, SysUtils;

Type TSectionName = packed Array[0..IMAGE_SIZEOF_SHORT_NAME-1] of AnsiChar;

Var N: String;
  H, M: THandle;
  DOSHeader: ^IMAGE_DOS_HEADER;
  NTHeader: ^IMAGE_NT_HEADERS;
  SectionHeader: ^IMAGE_SECTION_HEADER;
  ExportDirectory: ^IMAGE_EXPORT_DIRECTORY;
  Names: PCardinal;
  InitProcedure, i: Integer;

Procedure WriteLn(Const S: String);
  Var OEMBuffer: Array[0..2047] of AnsiChar;

  Begin
    CharToOem(PChar(S), @OEMBuffer);
    System.WriteLn(OEMBuffer);
  End;

Procedure WriteError(Const S: String);
  Var S2: String;

  Begin
    S2 := SysErrorMessage(GetLastError);
    WriteLn(S + ' >> ' + S2);
  End;

Function RVA2RealPointer(RVA: LongWord): Pointer;
  Var
    SectionHeader2: ^IMAGE_SECTION_HEADER;
    i2: Integer;

  Begin
    Result := nil;
    SectionHeader := Pointer(Integer(NTHeader) + SizeOf(IMAGE_NT_HEADERS));
    i2 := 0;
    While i2 < NTHeader.FileHeader.NumberOfSections do Begin
      If (RVA < SectionHeader.VirtualAddress + SectionHeader.SizeOfRawData)
          and (RVA >= SectionHeader.VirtualAddress) Then
        If Result <> nil Then Begin
          Result := Pointer(1);
          WriteLn(' found more than one sections that includet this RVA');
        End Else Result := Pointer(Integer(DOSHeader) + SectionHeader.PointerToRawData
          - SectionHeader.VirtualAddress + RVA);
      Inc(SectionHeader);
      Inc(i2);
    End;
    If Cardinal(Result) = 1 Then Result := nil;
  End;

Begin
  Try
    N := ExtractFilePath(ParamStr(0)) + 'himXML_DLL.dll';
    WriteLn('open "' + N + '"');
    H := CreateFile(PChar(N), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
    If H <> INVALID_HANDLE_VALUE Then Begin
      WriteLn('load file data');
      M := CreateFileMapping(H, nil, PAGE_READWRITE, 0, 0, nil);
      DOSHeader := MapViewOfFile(M, FILE_MAP_READ or FILE_MAP_WRITE, 0, 0, 0);
      If (M <> 0) and Assigned(DOSHeader) Then Begin
        WriteLn('check IMAGE_DOS_HEADER');
        If DOSHeader.e_magic = IMAGE_DOS_SIGNATURE Then Begin
          WriteLn('search and check IMAGE_NT_HEADERS');
          NTHeader := Pointer(Integer(DOSHeader) + DOSHeader._lfanew);
          If NTHeader.Signature = IMAGE_NT_SIGNATURE Then Begin
            WriteLn('search export section');
            SectionHeader := Pointer(Integer(NTHeader) + SizeOf(IMAGE_NT_HEADERS));
            ExportDirectory := nil;
            i := 0;
            While i < NTHeader.FileHeader.NumberOfSections do Begin
              WriteLn(' section "' + TSectionName(SectionHeader.Name) + '" found');
              If TSectionName(SectionHeader.Name) = '.edataThen
                If ExportDirectory <> nil Then Begin
                  ExportDirectory := Pointer(1);
                  WriteLn(' found more than one .edata sections');
                End Else ExportDirectory := Pointer(Integer(DOSHeader) + SectionHeader.PointerToRawData);
              Inc(SectionHeader);
              Inc(i);
            End;
            If Cardinal(ExportDirectory) > 1 Then Begin
              WriteLn('search the init procedure');
              Names := RVA2RealPointer(LongWord(ExportDirectory.AddressOfNames));
              InitProcedure := 0;
              i := -1;
              While i < ExportDirectory.NumberOfNames do Begin
                WriteLn(' procedure "' + PAnsiChar(RVA2RealPointer(Names^)) + '" found');
                If PAnsiChar(RVA2RealPointer(Names^)) = 'initDLLThen
                  If InitProcedure <> -1 Then Begin
                    InitProcedure := -2;
                    WriteLn(' found more than one init procedures');
                  End Else InitProcedure := i;
                Inc(Names);
                Inc(i);
              End;
              If InitProcedure >= 0 Then Begin


                If NTHeader.OptionalHeader.AddressOfEntryPoint <> 0 Then ;


                WriteLn('OK');
              End Else WriteError('not found');
            End Else WriteLn('not found');
          End Else WriteError('not found');
        End Else WriteError('not found');
        UnmapViewOfFile(DOSHeader);
      End Else WriteError('can''t load');
      CloseHandle(M);
    End Else WriteError('no access to file or not exists');
    CloseHandle(H);
  Except
    On E:Exception do WriteLn(E.Classname + ': ' + E.Message);
  End;
  ReadLn;
End.
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PosEx im Delphi viel seltener praktiziert.
  Mit Zitat antworten Zitat
Apollonius

Registriert seit: 16. Apr 2007
2.325 Beiträge
 
Turbo Delphi für Win32
 
#13

Re: DLL-EntryPoint mit Funktion tauschen?

  Alt 4. Jul 2009, 13:55
Das Export-Directory liegt normalerweise am Anfang einer Section namens .edata. Der Loader sucht aber nicht nach der Section, sondern nach dem Directory. Der "richtige" Weg verwendet also das Directory; das ist schneller als das Iterieren durch die Sections und funktioniert auch, wenn ein Linker das Export-Directory nicht an den Anfang einer Section namens .edata legt.
Wer erweist der Welt einen Dienst und findet ein gutes Synonym für "Pointer"?
"An interface pointer is a pointer to a pointer. This pointer points to an array of pointers, each of which points to an interface function."
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.124 Beiträge
 
Delphi 12 Athens
 
#14

Re: DLL-EntryPoint mit Funktion tauschen?

  Alt 4. Jul 2009, 14:05
Nein, das ist nicht schneller.

Denn wie ich grad mitbekommen habe, stehen die Adressen in diesem Directory als RVA drin
und demnach muß ich dennoch die Sektionen durchgehn und schauen wo es denn nun wirklich drin ist.

Aber da ich nun eine RVA2Pointer-Funktion hab und über das Directory vom Namen unabhängig bin, hab ich das Directory jetzt verwendet.

Delphi-Quellcode:
Program himXML_DLL_Modifizierer;

{$APPTYPE CONSOLE}

Uses Windows, SysUtils;

Type TSectionName = packed Array[0..IMAGE_SIZEOF_SHORT_NAME-1] of AnsiChar;

Var N: String;
  H, M: THandle;
  DOSHeader: ^IMAGE_DOS_HEADER;
  NTHeader: ^IMAGE_NT_HEADERS;
  SectionHeader: ^IMAGE_SECTION_HEADER;
  ExportDirectory: ^IMAGE_EXPORT_DIRECTORY;
  Names: PCardinal;
  InitProcedure, i: Integer;

Procedure WriteLn(Const S: String);
  Var OEMBuffer: Array[0..2047] of AnsiChar;

  Begin
    CharToOem(PChar(S), @OEMBuffer);
    System.WriteLn(OEMBuffer);
  End;

Procedure WriteError(Const S: String);
  Var S2: String;

  Begin
    S2 := SysErrorMessage(GetLastError);
    WriteLn(S + ' >> ' + S2);
  End;

Function RVA2RealPointer(RVA: LongWord): Pointer;
  Var
    SectionHeader2: ^IMAGE_SECTION_HEADER;
    i2: Integer;

  Begin
    Result := nil;
    SectionHeader := Pointer(Integer(NTHeader) + SizeOf(IMAGE_NT_HEADERS));
    i2 := 0;
    While i2 < NTHeader.FileHeader.NumberOfSections do Begin
      If (RVA < SectionHeader.VirtualAddress + SectionHeader.SizeOfRawData)
          and (RVA >= SectionHeader.VirtualAddress) Then
        If Result <> nil Then Begin
          Result := Pointer(1);
          WriteLn(' found more than one sections that includet this RVA');
        End Else Result := Pointer(Integer(DOSHeader) + SectionHeader.PointerToRawData
          - SectionHeader.VirtualAddress + RVA);
      Inc(SectionHeader);
      Inc(i2);
    End;
    If Cardinal(Result) = 1 Then Result := nil;
  End;

Begin
  Try
    N := ExtractFilePath(ParamStr(0)) + 'himXML_DLL.dll';
    WriteLn('open "' + N + '"');
    H := CreateFile(PChar(N), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
    If H <> INVALID_HANDLE_VALUE Then Begin
      WriteLn('load file data');
      M := CreateFileMapping(H, nil, PAGE_READWRITE, 0, 0, nil);
      DOSHeader := MapViewOfFile(M, FILE_MAP_READ or FILE_MAP_WRITE, 0, 0, 0);
      If (M <> 0) and Assigned(DOSHeader) Then Begin
        WriteLn('check IMAGE_DOS_HEADER');
        If DOSHeader.e_magic = IMAGE_DOS_SIGNATURE Then Begin
          WriteLn('search and check IMAGE_NT_HEADERS');
          NTHeader := Pointer(Integer(DOSHeader) + DOSHeader._lfanew);
          If NTHeader.Signature = IMAGE_NT_SIGNATURE Then Begin
            WriteLn('search export section');
            //SectionHeader := Pointer(Integer(NTHeader) + SizeOf(IMAGE_NT_HEADERS));
            //ExportDirectory := nil;
            //i := 0;
            //While i < NTHeader.FileHeader.NumberOfSections do Begin
            // WriteLn(' section "' + TSectionName(SectionHeader.Name) + '" found');
            // If TSectionName(SectionHeader.Name) = '.edata' Then
            // If ExportDirectory <> nil Then Begin
            // ExportDirectory := Pointer(1);
            // WriteLn(' found more than one .edata sections');
            // End Else ExportDirectory := Pointer(Integer(DOSHeader) + SectionHeader.PointerToRawData);
            // Inc(SectionHeader);
            // Inc(i);
            //End;
            {}ExportDirectory := RVA2RealPointer(NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
            If Cardinal(ExportDirectory) > 1 Then Begin
              WriteLn('search the init procedure');
              Names := RVA2RealPointer(LongWord(ExportDirectory.AddressOfNames));
              InitProcedure := -1;
              i := 0;
              While i < ExportDirectory.NumberOfNames do Begin
                WriteLn(' procedure "' + PAnsiChar(RVA2RealPointer(Names^)) + '" found');
                If PAnsiChar(RVA2RealPointer(Names^)) = 'initDLLThen
                  If InitProcedure <> -1 Then Begin
                    InitProcedure := -2;
                    WriteLn(' found more than one init procedures');
                  End Else InitProcedure := i;
                Inc(Names);
                Inc(i);
              End;
              If InitProcedure >= 0 Then Begin


                If NTHeader.OptionalHeader.AddressOfEntryPoint <> 0 Then ;


                WriteLn('OK');
              End Else WriteError('not found');
            End Else WriteLn('not found');
          End Else WriteError('not found');
        End Else WriteError('not found');
        UnmapViewOfFile(DOSHeader);
      End Else WriteError('can''t load');
      CloseHandle(M);
    End Else WriteError('no access to file or not exists');
    CloseHandle(H);
  Except
    On E:Exception do WriteLn(E.Classname + ': ' + E.Message);
  End;
  ReadLn;
End.
Aber jetzt muß ich dennoch testen, ob der EntryPoint ebenfalls als RVA definiert ist,
aber bei einem Wert von 213956 ( $000343C4 ) geh ich mal stark davon auß und müßte jetzt also nur noch die beiden Werte austauschen
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PosEx im Delphi viel seltener praktiziert.
  Mit Zitat antworten Zitat
brechi

Registriert seit: 30. Jan 2004
823 Beiträge
 
#15

Re: DLL-EntryPoint mit Funktion tauschen?

  Alt 4. Jul 2009, 14:13
Wenn du das manuell machen willst sollte das Programm lordpe reichen.
Ansonsten solltest du halt mal in meine Collection schauen da ist viel code mit der man auf die ExportSection und den EntryPoint zugreiften kann.

Eine alterantive Möglichkeit wäre die exportierte Funktion in die TLS Tabelle einzutragen. Dann wird diese Funktion vor DLL-Main aufgrufen. D.h. du musst nichts patchen (Entrypoint ändern). Da Delphi automatisch die TLS Tabelle erzeugt muss du die absolute Adresse nur hinzufügen.

Einfach in die .rData Section + 0x10 die absolute Exportaddresse eintragen.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.124 Beiträge
 
Delphi 12 Athens
 
#16

Re: DLL-EntryPoint mit Funktion tauschen?

  Alt 4. Jul 2009, 14:49
Nja, ich wollte mir ein Programm schreiben, welches nach dem Kompilieren die DLL automatisch patcht.

Und vor DLL-Main bringt mir nicht viel, da ich ja nach EXE-Main benötige (praktisch so als würde die DLL dynamisch und nicht statisch geladen )


Sooo, hab grad mal einige TestProjekte erstellt.

EXE und DLL funktionieren erstmal normal:
beim Start der EXE kommt "EntryPoint is called"
und beim Aufruf der Prozedur "InitDLL is called",
also soweit alles OK.

Das Patchen geht (anscheinend) auch.

Nur dann der Test mit der geänderten DLL:
beim Start der Exe kommt (wie erhofft) "InitDLL is called",
wonach der Tausch also funktioniert hat

blos zufrüh gefreut, denn beim Aufruf der Prozedur (welche den alten EntryPoint darstellt), knallt es

Delphi-Quellcode:
---------------------------
Benachrichtigung über Debugger-Problem
---------------------------
Im Projekt I:\Software+Hilfe\_Komponnten\himXML\DLLs\Test.exe sind zu viele auseinanderfolgende Exceptions aufgetreten: ''Zugriffsverletzung bei 0x00343700: Lesen von Adresse 0x01371e34''. Prozess wurde angehalten. Mit Einzelne Anweisung oder Start fortsetzen.
---------------------------
OK Hilfe
---------------------------
Konnte jetzt keine Infos finden, ob die Aufrufkonvention stimmt (aber das war doch ohne Parameter egal), also wird der EntryPoint wohl irgendwelche Parameter haben wollen?




[add]
ich glaub ich hab da was

http://msdn.microsoft.com/en-us/library/ms682583.aspx

mal sehn was passiert, wenn ich diese Werte zwischenspeicher und dem alten EntryPoint übergebe ...

[edit]
Anhang gelöscht (geht eh nicht)
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PosEx im Delphi viel seltener praktiziert.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.124 Beiträge
 
Delphi 12 Athens
 
#17

Re: DLL-EntryPoint mit Funktion tauschen?

  Alt 4. Jul 2009, 18:28
Arg, ich hatte eben meinen Testcode an einer DLL mit 2 Export-Funktionen getestet und da mußte ich feststellen, daß die Adressen in IMAGE_EXPORT_DIRECTORY.AddressOfFunctions nicht der Reinfolge in IMAGE_EXPORT_DIRECTORY.AddressOfNames entsprechen.

Hatte mich die ganze Zeit gewundert, warum die falsche Prozedur aufgerufen wird.

Nja, hab den "Index" in .AddressOfFunctions erstmal manuell angepaßt, um den Rest auszuprobieren, aber der läuft auch nicht so, wie er soll.

Die uallC hab ich grad durchgesehn und bin mein Problem bezüglich nicht wirklich schlauer geworden.


Bin jetzt erstmal am debuggen und versuch rauszufinden, warum es nicht läuft
und dann muß ich noch rausfinden, warum die Reihenfolge nicht stimmt.



Am Ende bleiben mir noch 2 Möglichkeiten:
* eine Dummy-DLL, welche als erstes statisch geladen wird
und wo ich dann im Nachhinein die eigentliche DLL dynamisch lade und die Imports der EXE mit den Verweisen zur neuen DLL hooke.

* alles aufgeben (dabei find ich die Objekte mit externen Funktionen echt geil) und es doch ganz anders machen


[add]
den ersten Fehler hab ich gefunden ... wie kann ich auch in eine ReadOnly MMF reinschreiben wollen


[edit]
Anhang gelöscht
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PosEx im Delphi viel seltener praktiziert.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.124 Beiträge
 
Delphi 12 Athens
 
#18

Re: DLL-EntryPoint mit Funktion tauschen?

  Alt 4. Jul 2009, 20:12
hier mal mein aktueller Versuch:

Leider hänge ich hierbei wegen was anderem (mach ich gleich 'nen anderen Thread dazu auf)
und zwar wird die MMF einfach nicht wiedergefunden. (existiert angeblich nicht)

Und das problem mit der Reihenfolge der beiden Namen- und Funktions-Tabellen hab ich auch noch nicht gelöst.

[edit]
anhang gelöscht ... nicht daß sich wer wundert
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PosEx im Delphi viel seltener praktiziert.
  Mit Zitat antworten Zitat
Apollonius

Registriert seit: 16. Apr 2007
2.325 Beiträge
 
Turbo Delphi für Win32
 
#19

Re: DLL-EntryPoint mit Funktion tauschen?

  Alt 4. Jul 2009, 20:53
Die Positionen in den AddressOfFunctions- und AddressOfNames-Tabellen werden durch die AddressOfNameOrdinals-Tabelle vermittelt: Der i-te Name in der AddressOfNames-Tabelle gehört zum NameOrdinals[i]-ten Eintrag in der AddressOfFunctions-Tabelle.
Wer erweist der Welt einen Dienst und findet ein gutes Synonym für "Pointer"?
"An interface pointer is a pointer to a pointer. This pointer points to an array of pointers, each of which points to an interface function."
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.124 Beiträge
 
Delphi 12 Athens
 
#20

Re: DLL-EntryPoint mit Funktion tauschen?

  Alt 4. Jul 2009, 21:00
Zitat von Apollonius:
Die Positionen in den AddressOfFunctions- und AddressOfNames-Tabellen werden durch die AddressOfNameOrdinals-Tabelle vermittelt: Der i-te Name in der AddressOfNames-Tabelle gehört zum NameOrdinals[i]-ten Eintrag in der AddressOfFunctions-Tabelle.
OK, das schau ich mir mal an ... dachte einfach in AddressOfNameOrdinals stehen die IndexWerte der Funktionen, welche man früher mal statt der Namen verwendete
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PosEx im Delphi viel seltener praktiziert.
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:46 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