Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi .text section dumpen (https://www.delphipraxis.net/187031-text-section-dumpen.html)

Lyan 21. Okt 2015 19:11

.text section dumpen
 
Hallo,

Ich würde gerne (so schön wie möglich) die .text oder CODE section aus meinem eigenen Prozess dumpen.

Mein momentaner Plan ist mittels ReadProcessMemory() ab der Imagebase den gesamten (eigenen) Prozess zu kopieren (aus dem Speicher) und dann mittels PE-Offsets die Stelle der .text-Section zu ermitteln.

Da ich wirklich faul bin und überhaupt keine Lust mehr habe ein PE-Tutorial auszupacken und mich durch die ganzen Offsets, Alignments und was weiß ich durchzuwühlen, hoffe ich hier um ehrlich zusein auf eine Codelösung.
a
Vieleicht hat ja jemand ein früheres Projekt in dem er eine Section des eigenen (oder fremden) Prozesses kopiert/gedumpt hat und wäre so freundlich das Snippet hier zu posten.

Ansonsten hoffe ich auf alternative Lösungen.

Alternative Lösungen sollten aber nur das von mir genannte Problem lösen, also keine Workarounds. Ich möchte aus dem Speicher heraus, eine Section kopieren - nicht anders.

Danke :)

Zacherl 21. Okt 2015 22:07

AW: .text section dumpen
 
Mit der PE Dokumentation hast du das in einer Stunde locker geschafft. Dauert deutlich weniger lange, als hier auf eine fertige Lösung zu warten (die aller Wahrscheinlichkeit nach bei dieser spezifischen Fragestellung nicht kommen wird).

ReadProcessMemory im eigenen Prozess zu verwenden ist btw. relativ unsinnig. Du kannst den Speicher auch einfach direkt ansprechen.

Lyan 22. Okt 2015 02:35

AW: .text section dumpen
 
Zitat:

Zitat von Zacherl (Beitrag 1319391)
Mit der PE Dokumentation hast du das in einer Stunde locker geschafft. Dauert deutlich weniger lange, als hier auf eine fertige Lösung zu warten (die aller Wahrscheinlichkeit nach bei dieser spezifischen Fragestellung nicht kommen wird).

ReadProcessMemory im eigenen Prozess zu verwenden ist btw. relativ unsinnig. Du kannst den Speicher auch einfach direkt ansprechen.

Ja - mein "Plan" war nicht ganz durchdacht..

Vermutlich hast du recht.

Ich muss auch gestehen, dass ich die letzte Zeile in diesem Thread gelöscht habe. In der stand: "Ich warte dann mal auf die Antwort von Zacherl, mit viel Glück hat er noch was übrig".

Wenn - dann hätte ich ein Snippet von dir erwartet hier als native Windows Experte :P


Naja dann pack ich mal die alten ARTeam Tut's aus ^^

Danke trotzdem ;)

Zacherl 22. Okt 2015 11:59

AW: .text section dumpen
 
Zitat:

Zitat von Lyan (Beitrag 1319394)
Ich muss auch gestehen, dass ich die letzte Zeile in diesem Thread gelöscht habe. In der stand: "Ich warte dann mal auf die Antwort von Zacherl, mit viel Glück hat er noch was übrig".

:-D

Habe leider nichts fertiges hier, aber zum iterieren der Sections schnell aus dem Kopf:
Delphi-Quellcode:
var
  ImageBase: Pointer;
  ImageDosHeader: PImageDosHeader;
  ImageNtHeaders: PImageNtHeaders;
  ImageSectionHeader: PImageSectionHeader;
  I: Integer;
begin
  ImageBase := Pointer(hInstance);
  ImageDosHeader := PImageDosHeader(ImageBase);
  if (ImageDosHeader^.e_magic <> IMAGE_DOS_SIGNATURE) then
  begin
    Exit;
  end;
  ImageNtHeaders := PImageNtHeaders(PByte(ImageDosHeader) + ImageDosHeader^._lfanew);
  if (ImageNtHeaders^.Signature <> IMAGE_NT_SIGNATURE) then
  begin
    Exit;
  end;
  ImageSectionHeader := PImageSectionHeader(PByte(ImageNtHeaders) + SizeOf(TImageNtHeaders) -
    SizeOf(TImageOptionalHeader) + ImageNtHeaders^.FileHeader.SizeOfOptionalHeader);
  I := 1;
  while (I < ImageNtHeaders^.FileHeader.NumberOfSections) do
  begin
    WriteLn('Section Name:');
    WriteLn(PAnsiChar(@ImageSectionHeader^.Name[0]));
    WriteLn('Virtual Address:');
    WriteLn(IntToHex(NativeUInt(ImageBase) + ImageSectionHeader^.VirtualAddress,
      SizeOf(Pointer) * 2));
    WriteLn('Size:');
    WriteLn(IntToHex(ImageSectionHeader^.SizeOfRawData, 1));
    Inc(ImageSectionHeader);
    Inc(I);
  end;
end;
Statt hInstance kannst du auch die ImageBase einer beliebigen Dll nehmen, falls du das brauchst. Die Section dumpst du dir dann einfach mit CreateFile/WriteFile über die Virtual Address.

Würde mich allerdings nicht drauf verlassen, dass sich alle Binaries an die .text bzw. .code Konvention bezüglich des Section Names halten.

Lyan 22. Okt 2015 15:05

AW: .text section dumpen
 
Zitat:

Zitat von Zacherl (Beitrag 1319431)
Zitat:

Zitat von Lyan (Beitrag 1319394)
Ich muss auch gestehen, dass ich die letzte Zeile in diesem Thread gelöscht habe. In der stand: "Ich warte dann mal auf die Antwort von Zacherl, mit viel Glück hat er noch was übrig".

:-D

Habe leider nichts fertiges hier, aber zum iterieren der Sections schnell aus dem Kopf:
Delphi-Quellcode:
var
  ImageBase: Pointer;
  ImageDosHeader: PImageDosHeader;
  ImageNtHeaders: PImageNtHeaders;
  ImageSectionHeader: PImageSectionHeader;
  I: Integer;
begin
  ImageBase := Pointer(hInstance);
  ImageDosHeader := PImageDosHeader(ImageBase);
  if (ImageDosHeader^.e_magic <> IMAGE_DOS_SIGNATURE) then
  begin
    Exit;
  end;
  ImageNtHeaders := PImageNtHeaders(PByte(ImageDosHeader) + ImageDosHeader^._lfanew);
  if (ImageNtHeaders^.Signature <> IMAGE_NT_SIGNATURE) then
  begin
    Exit;
  end;
  ImageSectionHeader := PImageSectionHeader(PByte(ImageNtHeaders) + SizeOf(TImageNtHeaders) -
    SizeOf(TImageOptionalHeader) + ImageNtHeaders^.FileHeader.SizeOfOptionalHeader);
  I := 1;
  while (I < ImageNtHeaders^.FileHeader.NumberOfSections) do
  begin
    WriteLn('Section Name:');
    WriteLn(PAnsiChar(@ImageSectionHeader^.Name[0]));
    WriteLn('Virtual Address:');
    WriteLn(IntToHex(NativeUInt(ImageBase) + ImageSectionHeader^.VirtualAddress,
      SizeOf(Pointer) * 2));
    WriteLn('Size:');
    WriteLn(IntToHex(ImageSectionHeader^.SizeOfRawData, 1));
    Inc(ImageSectionHeader);
    Inc(I);
  end;
end;
Statt hInstance kannst du auch die ImageBase einer beliebigen Dll nehmen, falls du das brauchst. Die Section dumpst du dir dann einfach mit CreateFile/WriteFile über die Virtual Address.

Würde mich allerdings nicht drauf verlassen, dass sich alle Binaries an die .text bzw. .code Konvention bezüglich des Section Names halten.

Wow vielen Dank ;)

Ja für .UPX etc. brauche ich ja keinen Support, schließlich dumpe ich ja die eigene Section und den Namen kann ich ja (wenn er wirklich != .text/.code sein sollte anpassen :)

Anonsten hast du mir das Leben erleichtert, ist schon eine ganze Weile her seitdem ich was mit w32 PE zeug gemacht habe, und ich vergesse leider schnell.

Ich schreibs später fertig, dann poste ich es mal :)


Bis dann & nochmals danke

SMO 22. Okt 2015 16:39

AW: .text section dumpen
 
Zitat:

Zitat von Zacherl (Beitrag 1319431)
Habe leider nichts fertiges hier, aber zum iterieren der Sections schnell aus dem Kopf:
Delphi-Quellcode:
    WriteLn('Section Name:');
    WriteLn(PAnsiChar(@ImageSectionHeader^.Name[0]));

Das ist strenggenommen falsch, denn TImageSectionHeader.Name ist nicht notwendigerweise nullterminiert!
Wenn der Name genau 8 Zeichen lang ist, wird ein einfacher PAnsiChar-Cast wie oben möglicherweise zusätzlichen Müll ausgeben.

TImageSectionHeader.Name ist dummerweise als Array of Byte deklariert, nicht als Array of Char.
Für letzteres hat Delphi nämlich ein paar Compiler-Magic-Funktionen, die aus einem Array of (Ansi)Char einen (Ansi)String machen und dabei nicht stur nach der Nullterminierung suchen, sondern auch die Maximallänge des Arrays berücksichtigen (_LStrFromArray, _LStrFromWArray, _UStrFromArray, _UStrFromWArray).

Um es besser zu machen, muss man entweder eigenen Code schreiben, der das Name-Bytearray in einen String kovertiert, oder man benutzt einfach einen Cast auf ein passendes Char-Array, damit die Compiler-Magic benutzt wird:
Delphi-Quellcode:
type
  TImageSectionHeaderName = array [0..IMAGE_SIZEOF_SHORT_NAME-1] of AnsiChar; // genaugenommen UTF-8 Bytes, argh
// ..
    WriteLn('Section Name:');
    WriteLn(TImageSectionHeaderName(ImageSectionHeader^.Name));
Um es ganz korrekt zu machen, sollte man den String als UTF-8 kodiert ansehen und dekodieren lassen...


Hier mal Code von mir:
Delphi-Quellcode:
// GetModuleSectionHeaders: get an array of all TImageSectionHeader structures of a given Module
function GetModuleSectionHeaders(const Module: HMODULE): TArray<TImageSectionHeader>;
var
  DosHeader: PImageDosHeader;
  NtHeaders: PImageNtHeaders;
  SectionHeader: PImageSectionHeader;
  i: Integer;
begin
begin
  Result := nil;
  DosHeader := PImageDosHeader(Module); // a HMODULE is a memory address
  // navigate the various headers and check their signatures
  if DosHeader.e_magic <> IMAGE_DOS_SIGNATURE then Exit;
  NtHeaders := Pointer(PByte(Module) + DosHeader._lfanew);
  if (NtHeaders.Signature <> IMAGE_NT_SIGNATURE) or
    (NtHeaders.OptionalHeader.Magic <> IMAGE_NT_OPTIONAL_HDR32_MAGIC) then Exit;
  // corrected, thanks to Zacherl
  SectionHeader := PImageSectionHeader(PByte(NtHeaders) + SizeOf(TImageNtHeaders) -
    SizeOf(TImageOptionalHeader) + NtHeaders^.FileHeader.SizeOfOptionalHeader);
  SetLength(Result, NtHeaders.FileHeader.NumberOfSections);
  for i := Low(Result) to High(Result) do
  begin
    Result[i] := SectionHeader^;
    // add Module's current base address to VirtualAddress
    Inc(Result[i].VirtualAddress, UIntPtr(Module));
    Inc(SectionHeader);
  end;
end;

// GetSectionHeaderName: convert SH.Name from UTF-8 byte array to string
function GetSectionHeaderName(const SH: TImageSectionHeader): string;
type
  TSectionHeaderName = array [0..IMAGE_SIZEOF_SHORT_NAME-1] of AnsiChar;
var
  Raw: RawByteString;
begin
  Raw := TSectionHeaderName(SH.Name); // _LStrFromArray
  Result := UTF8ToString(Raw);
end;

var
  SH: TImageSectionHeader;
begin
  for SH in GetModuleSectionHeaders(HInstance) do
    Writeln(Format('%-8s : VirtualAddress=%.8x, VirtualSize=%.8x, Characteristics=%.8x',
      [GetSectionHeaderName(SH), SH.VirtualAddress, SH.Misc.VirtualSize, SH.Characteristics]));
end;

Zacherl 22. Okt 2015 17:35

AW: .text section dumpen
 
Zitat:

Zitat von SMO (Beitrag 1319472)
Das ist strenggenommen falsch, denn TImageSectionHeader.Name ist nicht notwendigerweise nullterminiert!
Wenn der Name genau 8 Zeichen lang ist, wird ein einfacher PAnsiChar-Cast wie oben möglicherweise zusätzlichen Müll ausgeben.

Da hast du recht!

Deine Funktion berechnet allerdings den Zeiger auf die erste ImageSection nicht korrekt.
Delphi-Quellcode:
SectionHeader := PImageSectionHeader(NativeInt(NtHeaders) + SizeOf(NtHeaders^))
funktioniert nicht immer. Ist zwar ein ziemlich synthetischer Fall, aber das PE Format sieht vor, dass der OptionalHeader eine variable Länge haben kann. Deshalb muss die korrekte Berechnung über
Delphi-Quellcode:
ImageSectionHeader := PImageSectionHeader(PByte(ImageNtHeaders) + SizeOf(TImageNtHeaders) -
    SizeOf(TImageOptionalHeader) + ImageNtHeaders^.FileHeader.SizeOfOptionalHeader)
erfolgen.

SMO 22. Okt 2015 17:53

AW: .text section dumpen
 
Danke! Wieder was gelernt. :)
Der Code von mir war auch schon etwas älter, sehe ich gerade an der Benutzung von NativeInt. Heute caste ich Pointer nur noch auf vorzeichenlose Typen (NativeUInt oder UIntPtr), oder gleich auf PByte wie in deinem Beispiel.


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:05 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