![]() |
Re: DLL-EntryPoint mit Funktion tauschen?
Ich würd dir die "CFF Explorer" Software empfehlen; sie gibt dir einen guten Einblick in das Innenleben einer PE Datei
MfG |
Re: DLL-EntryPoint mit Funktion tauschen?
@Apollonius: uffff, na dann mal sehn ob ich das mit dem IMAGE_DATA_DIRECTORY auch noch hinbekomm :freak:
(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 :hi: Nja, cryptisch war's ja nicht ... nur etwas "eigenartig" berechnet. :mrgreen: 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) = '.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; 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^)) = 'initDLL' Then 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. |
Re: DLL-EntryPoint mit Funktion tauschen?
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.
|
Re: DLL-EntryPoint mit Funktion tauschen?
Nein, das ist nicht schneller. :tongue:
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:
Aber jetzt muß ich dennoch testen, ob der EntryPoint ebenfalls als RVA definiert ist,
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^)) = 'initDLL' Then 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 bei einem Wert von 213956 ( $000343C4 ) geh ich mal stark davon auß und müßte jetzt also nur noch die beiden Werte austauschen :) |
Re: DLL-EntryPoint mit Funktion tauschen?
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. |
Re: DLL-EntryPoint mit Funktion tauschen?
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 :nerd: ) 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 :firejump: blos zufrüh gefreut, denn beim Aufruf der Prozedur (welche den alten EntryPoint darstellt), knallt es :cry:
Delphi-Quellcode:
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? :gruebel:
---------------------------
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 --------------------------- [add] ich glaub ich hab da was ![]() mal sehn was passiert, wenn ich diese Werte zwischenspeicher und dem alten EntryPoint übergebe ... [edit] Anhang gelöscht (geht eh nicht) |
Re: DLL-EntryPoint mit Funktion tauschen?
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. :shock:
Hatte mich die ganze Zeit gewundert, warum die falsche Prozedur aufgerufen wird. :wall: 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. :cry: 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 :wall: [edit] Anhang gelöscht |
Re: DLL-EntryPoint mit Funktion tauschen?
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 |
Re: DLL-EntryPoint mit Funktion tauschen?
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.
|
Re: DLL-EntryPoint mit Funktion tauschen?
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:31 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz