DOS-Stub aus EXE/DLL löschen

Hier können Artikel, Tutorials, Bücherrezensionen, Dokumente aller Art, Texturen, Sprites, Sounds, Musik und Modelle zur Verfügung gestellt bzw. verlinkt werden.
Forumsregeln
Möglichst sinnvolle Präfixe oder die Themensymbole nutzen.

DOS-Stub aus EXE/DLL löschen

Beitragvon Krishty » 09.01.2018, 12:37

Ich habe endlich das Skript wiedergefunden, und damit ich’s selber nicht vergesse, schreibe ich’s auf. Und dann kann ich’s ja direkt mit euch teilen. Also:

  • Windows’ EXE- und DLL-Dateien haben das selbe Format: Portable Executable (PE).

  • PE ist abwärtskompatibel zu MS-DOS. (Bei Microsoft ist immer alles abwärtskompatibel.) Das bedeutet nicht, dass die tatsächlichen Programme auf MS-DOS laufen. Das bedeutet nur, dass MS-DOS moderne EXEs/DLLs lesen und starten kann.

  • Um das zu gewährleisten, wird PE tatsächlich in DOS-Executables (MZ) eingebettet. Das kleine MS-DOS-MZ, in das der moderne Code eingebettet wird, nennt sich MS-DOS Stub. Man *kann* es selber definieren, aber üblicherweise wird es von Compiler erzeugt.

  • Visual C++ erzeugt einen Stub, der – wird die EXE auf MS-DOS gestartet – den folgenden Text ausgibt und dann das Programm beendet: This program cannot be run in DOS mode.

  • Visual C++ kodiert außerdem die verwendete Toolset-Version in das ungenutzte Padding hinter dem MS-DOS-Stub in der PE. Entschlüsselt man das, kann man rekonstruieren, mit welcher Version von Visual C++ die EXE kompiliert wurde.
    MZ header.png
    MZ header.png (4.8 KiB) 476-mal betrachtet

Ich möchte nun sowohl das MS-DOS-Stub entfernen als auch die Linker-Informationen. Und das am besten automatisch im Build-Skript.

  • Offensichtlich kann man das Stub nicht einfach rausschmeißen, weil die PE in die MZ eingebettet ist, und ohne MZ kann Windows die PE nicht mehr laden. Mann kann es aber minimieren, zu einem leeren Stub.

  • Die Linker-Informationen stehen im Padding, und auch das ist nötigerweise da. Man kann es aber nullen.

Die naheliegende Lösung ist der CFF Explorer:
  • herunterladen
  • installieren
  • CFF Explorer starten
  • EXE öffnen
  • ganz links „Rebuilder“ auswählen
  • cff explorer.png

Das funktioniert: Stub und Linker-Informationen sind tatsächlich gelöscht. Allerdings wurde auch die Ausrichtung der einzelnen Abschnitte innerhalb der PE überschrieben. 512 B sind normalerweise auch Visual C++’ Standard-Ausrichtung, aber der CFF Explorer scheint irgendwie die nicht-ausgerichtete Größe ebenfalls auf den nächsthöheren ausgerichteten Wert zu padden. Das ist kein Problem, die EXE startet weiterhin 100 % normal. Es stört mich aber, weil ich die nicht-ausgerichtete Größe nachschlage, wenn ich den Platzverbrauch meines Codes kontrolliere.

Nun hat der Entwickler von CFF Explorer in seinem Artikel über den MS-DOS-Stub auch ein Skript für den CFF Explorer bereitgestellt, das das gleiche tut, ohne die Ausrichtung zu überschreiben. Dummerweise löscht es das Debug-Verzeichnis und Strong Name Signature mit. Wenn man das alles rausschmeißt, erhält man:
Code: Ansicht erweitern :: Alles auswählen
-- updated by Krishty 2018
-- do not remove debug directory (I want that for debugging)
-- do not remove strong name signature
-- fixed file name

-- © 2008 Daniel Pistelli. All rights reserved.
-- Header Pack Script Version: 1.0.0.1

-- This neat little script does the following:
--
-- packs the dos header + PE header + section headers
-- removes useless things like the Rich Signature
-- removes linker references inside the PE header
-- strips the debug information (if any) from the PE
-- if it's a .NET, removes Strong Name Signature
-- updates checksum

-- shows an invalid PE Msgbox
function InvPEMsg()
        MsgBox("The current file seems to be an invalid PE. Cannot proceed!",
                strScriptName, MB_ICONEXCLAMATION)
end

-- --------------------------------------------------
-- the main code starts here
-- --------------------------------------------------

strScriptName = "Header Pack Script 1.0.0.1 - by Daniel Pistelli"

filename = @"test.exe"

local hPE = OpenFile(filename)

if hPE == null then
        MsgBox("Couldn't open file.", "Error", MB_ICONEXCLAMATION)
        return
end

local OptHdrOffset = GetOffset(hPE, PE_OptionalHeader)

if OptHdrOffset == null then
        InvPEMsg()
        return
end

-- --------------------------------------------------
-- START PROCESSING
-- --------------------------------------------------

-- PACK HEADERS

do
        local SecrHdrsOffset = GetOffset(hOriginalPE, PE_SectionHeaders)
       
        local SizeOfSections = GetNumberOfSections(hPE)
                * IMAGE_SIZEOF_SECTION_HEADER
               
        local FileHdrOffset = GetOffset(hPE, PE_FileHeader)
       
        local SizeOfOptionalHdr = ReadWord(hPE, FileHdrOffset + 16)
       
        local SizeOfPEHeader = 4 + 20 + SizeOfOptionalHdr;
       
        local PEHdrOffset = GetOffset(hPE, PE_NtHeaders)
       
        -- we assume that the PE header comes right after
        -- the Dos header, this is a normal PE
       
        FillBytes(hPE, 0x40, PEHdrOffset - 0x40, 0)
       
        -- move headers
       
        local HeadersSize = SizeOfPEHeader + SizeOfSections
       
        local PEHdrAndSects = ReadBytes(hPE, PEHdrOffset, HeadersSize)
       
        FillBytes(hPE, PEHdrOffset, HeadersSize, 0)
       
        WriteBytes(hPE, 0x40, PEHdrAndSects, HeadersSize)
       
        -- e_lfanew
        WriteDword(hPE, 0x3C, 0x40)
       
        OptHdrOffset = GetOffset(hPE, PE_OptionalHeader)
       
end

-- REMOVE LINKER REF

do

        WriteWord(hPE, OptHdrOffset + 2, 0x0000)

end

-- UPDATE CHECKSUM

UpdateChecksum(hPE)

-- SAVE FILE

SaveFile(hPE)


Um dieses Skript zu benutzen, müsst ihr
  1. in Zeile 30 test.exe durch euren tatsächlichen Dateinamen ersetzen
  2. den CFF Explorer mit dem Skript als Parameter aufrufen

… und das geht wunderbar als Post-Build-Event oder im Deploy-Batch-Skript oder so. Danach ist die EXE „sauber“:
minimal MZ header.png
minimal MZ header.png (1018 Bytes) 476-mal betrachtet
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
 
Beiträge: 6588
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Re: DOS-Stub aus EXE/DLL löschen

Beitragvon Krishty » 15.01.2018, 03:54

Ich habe auch noch einen Weg gefunden, den PDB-Pfad zu kürzen.

Standardmäßig schreibt Visual C++ den vollen Pfad der Debug-Infos in EXEs/DLLs, auch im Release-Build. Ich möchte das nicht abschalten (oder nachträglich löschen, wie der CFF Explorer erlaubt), weil ich dann keine Crash Dumps von fremden Usern mehr debuggen kann – die Möglichkeit, dann eine gespeicherte PDB zu laden und direkt den Quelltext vor sich zu haben, ist einfach zu wertvoll.

Stattdessen kann Visual C++’ Linker /pdbaltpath:%_PDB% als zusätzlicher Befehl übergeben werden. Dann steht in der EXE/DLL nur noch foo.pdb statt X:\projects\foobar\x64\release\foo.pdb.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
 
Beiträge: 6588
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy


Zurück zu Artikel, Tutorials und Materialien

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 3 Gäste

cron