Anti-Jammer-Thread

Hier kann über allgemeine Themen diskutiert werden, die sonst in kein Forum passen.
Insbesondere über Szene, Games, Kultur, Weltgeschehen, Persönliches, Recht, Hard- und Software.
Benutzeravatar
Krishty
Establishment
Beiträge: 8420
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Anti-Jammer-Thread

Beitrag von Krishty »

State of the Art ist seit einigen Jahren das Ghidra der NSA. Das kostet im Gegensatz zu IDA nichts.

Ghidra hat eine offene Architektur, man lädt sich also bspw. das Plugin zum Disassemblieren und Dekompilieren von PlayStation-Executables herunter.

Das kommt mit einer Erkennung aller Standardfunktioneren der Sony-C-Laufzeitbibliothek, die damals ausgeliefert wurden und in jedem PSX-Executable ähnlich gelinkt sind. Damit sind schonmal alle Aufrufe an sprintf() und scrnBlit() und malloc() und Hunderte mehr im Dekompilat als solche gekennzeichnet.

Weiterhin sind auch ihre Rückgabetypen gekennzeichnet, Ghidra weist dann also jeder Variable, die aus malloc() befüllt wird, rekursiv void * zu. Und jeder, die in strcpy() gereicht wird, char *. Damit sind schonmal 80–90 % aller Zeiger, Integer, und Gleitkommazahlen (hatte die PSX nur extrem begrenzt) im Dekompilat unterscheidbar. Man weiß zwar noch nicht, ob es ein signed oder unsigned int ist, oder welcher konkrete Datentyp hinter einem Zeiger steckt, aber das macht alles gehörig einfacher.

Und das hatten wir alles 2019, als wir Driver reverse engineered hatten, ohne KI.

Mit Debug-Symbolen bekommt man dann nochmal die Namen aller Funktionen dazu. 2019 war das ein scheiß Akt, die Debug-Informationen ins passende Format für Ghidra zu konvertieren, aber mittlerweile gibt es für so ziemlich alle Formate Ghidra-Plugins.

Jetzt kommen die neuen KI-Assistenten und Agenten, die in den letzten Jahren entstanden sind.

Was Jonathan erwähnt – der KI sagen, dass links unten ein HUD sein sollte, und das im Code finden – wird bei PS2-Spielen bspw. von https://github.com/hkmodd/PCSX2-MCP versprochen. Häng deinen Agenten an PCSX2-MCP und Ghidra, und lass ihn werkeln. Ich hab’s noch nicht selber ausprobiert, nur grob verfolgt wie andere das machen.

… dann hängt man einen SDL-basierten Wrapper für PlayStation-Standardfunktionen dran (gibt’s zu hauf im Internet; für ReDriver2 hatte Soapy damals Psy-Cross weiterentwickelt https://github.com/OpenDriver2/PsyCross) und schon ist der vibe-coded Port fertig.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Jonathan
Establishment
Beiträge: 2959
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Re: Anti-Jammer-Thread

Beitrag von Jonathan »

Spiele Programmierer hat geschrieben: 22.06.2026, 19:38 Okay, es ist ein Missverständnis mit dem Begirfflichkeiten: C-Code generieren ist "out of scope" für einen Disassembler, denn der erzeugt nur Assemblercode. Alle normalen Debugger kriegen das wunderbar hin und denke gibt auch dedizierte Projekte. Deswegen meinte ich, dass es simpel ist.
Ah, ja, natürlich. Zwei ganz unterschiedliche Dinge, Assemblercode anzeigen kann in der Tat nicht so schwierig sein.

Nochmal bezüglich templates: Natürlich war das ein bisschen weitgegriffenes Wunschdenken. ABER: Wenn man einmal C-Code mit sinnvollen Namen und so hat, ist der Rest ja quasi nur noch Umstrukturieren. Da würde ich KI schon recht viel zutrauen. "Kann man diesen Code kompakter uns lesbarer machen, indem man ähnliche Teile zusammen fasst?" - Fast gleiche Funktionen die nur unterschiedliche Typen haben werden sicherlich erkannt. Außerdem kann man ja die Anforderungen lockern. Sagen wir, man könnte aus einem Haufen Funktionen eine Klasse machen, aber dann würde nach dem erneuten kompilieren immer noch ein this-Zeiger kopiert werden müssen - macht mein Programm vielleicht 0.2% langsamer, und das ist heute egal. Dadurch kommt hinten dann sicherlich nicht der identische Code raus, der vor 20 Jahren tatsächlich geschrieben wurde, aber das Verhalten bleibt gleich, er ist gut strukturiert und lesbar und performancetechnisch immer noch total ok.

Vollautomatisch würde ich das wohl eh nicht machen wollen, am Ende muss ja der Mensch entscheiden, was tatsächlich lesbar ist. Aber solche Vorschläge finden und auf Entwicklerwunsch automatisch umsetzen und auf Korrektheit testen halte ich für recht realistisch.
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
Spiele Programmierer
Establishment
Beiträge: 436
Registriert: 23.01.2013, 15:55

Re: Anti-Jammer-Thread

Beitrag von Spiele Programmierer »

Krishty hat geschrieben: 22.06.2026, 20:17 Weiterhin sind auch ihre Rückgabetypen gekennzeichnet, Ghidra weist dann also jeder Variable, die aus malloc() befüllt wird, rekursiv void * zu. Und jeder, die in strcpy() gereicht wird, char *. Damit sind schonmal 80–90 % aller Zeiger, Integer, und Gleitkommazahlen (hatte die PSX nur extrem begrenzt) im Dekompilat unterscheidbar. Man weiß zwar noch nicht, ob es ein signed oder unsigned int ist, oder welcher konkrete Datentyp hinter einem Zeiger steckt, aber das macht alles gehörig einfacher.
Ja das ist lieb, aber in einem echten Programm sind doch die wenigsten Zeiger char-, Integer- oder Gleitkommazahlzeiger. Statt einem int-Zeiger, ist eStattdessen ist es ein Zeiger auf ein Spielobjekt, welches von einem dynamischen Typ in einem Spiel-Manager-Objekt liegt, welches in einem Levelobjekt liegt, welches...
Es reicht nicht rekursiv Funktionen und Register zu verfolgen. Du musst auch durch Speicheroperationen durchschauen. Da wird es erst lustig und das ist wo dann alles mögliche passieren kann.
Oder reden wir einfach von so alten Spielen, wo noch alles in globalen Arrays ohne OO-Hölle lag?
Krishty hat geschrieben: 22.06.2026, 20:17 Was Jonathan erwähnt – der KI sagen, dass links unten ein HUD sein sollte, und das im Code finden – wird bei PS2-Spielen bspw. von https://github.com/hkmodd/PCSX2-MCP versprochen. Häng deinen Agenten an PCSX2-MCP und Ghidra, und lass ihn werkeln. Ich hab’s noch nicht selber ausprobiert, nur grob verfolgt wie andere das machen.
Ich bin da sehr skeptisch. 0 issues, 11 Sternchen, Readme sieht nach KI-Slop aus. Das eigentliche soll wohl auch eine externe KI lösen, aber hat diese KI überhaupt schon so viel debugging und Reverse-Engeneering-Erfahrung? Ich finde das von Jonathan beschrieben Szenario recht komplex. Ich wäre da echt erstaunt, wenn das quasi automatisch geht.
Krishty hat geschrieben: 22.06.2026, 20:17 … dann hängt man einen SDL-basierten Wrapper für PlayStation-Standardfunktionen dran (gibt’s zu hauf im Internet; für ReDriver2 hatte Soapy damals Psy-Cross weiterentwickelt https://github.com/OpenDriver2/PsyCross) und schon ist der vibe-coded Port fertig.
Implizierst du, dass dein Dekompilator bereits Code erzeugen kann, der bis auf Funktionsaufrufe direkt wieder für x86 kompiliert?
Falls ja, dann bin ich auf jeden Fall beieindruckt. SO habe ich das nicht in Erinnerung bei uns.
ABER: Wenn man einmal C-Code mit sinnvollen Namen und so hat, ist der Rest ja quasi nur noch Umstrukturieren.
Ja, wenn nicht geinlined ist, die Namen ähnlich sind und es analog aussieht.
Inlining ist wohl der größte Spielverderber.
erneuten kompilieren immer noch ein this-Zeiger kopiert werden müssen - macht mein Programm vielleicht 0.2% langsamer, und das ist heute egal.
Wieso soll eine Klasse das Programm 0.2% langsamer machen?
Benutzeravatar
Krishty
Establishment
Beiträge: 8420
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Anti-Jammer-Thread

Beitrag von Krishty »

Spiele Programmierer hat geschrieben: 22.06.2026, 21:58Ja das ist lieb, aber in einem echten Programm sind doch die wenigsten Zeiger char-, Integer- oder Gleitkommazahlzeiger. Statt einem int-Zeiger, ist eStattdessen ist es ein Zeiger auf ein Spielobjekt, welches von einem dynamischen Typ in einem Spiel-Manager-Objekt liegt, welches in einem Levelobjekt liegt, welches...
Es reicht nicht rekursiv Funktionen und Register zu verfolgen. Du musst auch durch Speicheroperationen durchschauen. Da wird es erst lustig und das ist wo dann alles mögliche passieren kann.
Ist seit zehn Jahren drin. Sobald du eine Reihe von Zeiger-Dereferenzierungen mit Integer-Offsets im Dekompilat siehst, klickst du rechts drauf und wählst “Auto Create Structure”. Dann legt Ghidra dir eine struct-Definition an und leitet aus den Speicheroperationen und Offsets her, an welcher Stelle welches Member liegt und wie groß die Struktur wohl insgesamt ist. Und der neue Zeiger-Typ wird dann wieder aus der aktuellen Funktion hoch und quer propagiert.

Bild

(Sorry, das PSX-Dekompilat kriege ich gerade nicht auf weil ich das Plugin ewig nicht aktualisiert habe)

Hier links ist das Disassembly von einem Programm aus dem Job, für das große Teile des Quelltextes verloren gegangen sind. Voller movs. Du drückst auf eine Adresse, drückst L (label), und wenn sie im Daten-Segment liegt legt Ghidra eine globale Variable an der Stelle an (Größe und Typ entsprechend aller Zugriffe, die programmweit lesen/schreiben). Du siehst überall mov mit Offset, markierst die Variable im Dekompilat, Rechtsklick, Auto Create Structure, Ghidra legt dir ein struct an. Im Dekompilat rechts siehst du ja deutlich, wie der Code auf dreifach geschachtelte Klassen samt Array-Indizes zugreift. Habe dir die Definition der Struktur geöffnet, voller unbekannter Bytes, weil keine Funktion in der Nähe auf die zugreift.

In das Dekompilat kannst du nicht schreiben, das habe also nicht ich dahingemacht. Das wird von Ghidra immer on-the-fly generiert, während du navigierst, aus der Ground Truth im Disassembly links plus meine Variablennamen und Strukturdefinitionen.

this kommt auch von Ghidra, weil es den Compiler erkannt hat und weiß, in welchem Register der das this hält.

Ich will nicht sagen, dass es ein Kinderspiel wäre, aber schon wesentlich einfacher und scheller als was ich 2014 mit IDA machen musste.
Implizierst du, dass dein Dekompilator bereits Code erzeugen kann, der bis auf Funktionsaufrufe direkt wieder für x86 kompiliert?
Falls ja, dann bin ich auf jeden Fall beieindruckt. SO habe ich das nicht in Erinnerung bei uns.
Ghidra spuckt C aus mit Platzhalter-Datentypen und Platzhalter-Funktionen für Dinge, an denen sich das Dekompilieren verschluckt hat. Wie viel nachgebessert werden muss, hängt von Architektur und Compiler der Executable ab. Das if oben ist schräg optimiert worden; keine Ahnung, ob das so kompiliert. Geht vor allem am Anfang fast nie, aber wenn man die Worst Offender glattgebügelt hat, ist man recht nah dran. Ich weiß übrigens nicht, wie man das ganze Projekt nach C exportiert – ich picke mir immer nur die Funktionieren raus, die ich brauche. Aber ich mache das halt auch nicht professionell.

Ich weiß auch nicht, warum ich hier auf “Ja aber” antworte, guck doch einfach ein Video über Ghida 😁
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Jonathan
Establishment
Beiträge: 2959
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Re: Anti-Jammer-Thread

Beitrag von Jonathan »

Spiele Programmierer hat geschrieben: 22.06.2026, 21:58 Wieso soll eine Klasse das Programm 0.2% langsamer machen?
Ich auch nicht wirklich, war aber auch nur ein zufälliges Beispiel. Vielleicht realistischer: Man packt alle strings in std::string. Das macht den Code netter lesbar und man kann ein paar mehr High-Level Funktionen verwenden, aber ab und an verursacht es extra Kosten die vielleicht nicht rausoptimiert werden können. Um meinen Spielernamen in die Highscore zu schreiben ist mir sowas aber total egal, deshalb würde ich wollen, dass so etwas ersetzt wird. Aber das wäre wohl wirklich erst ein zweiter Schritt, nachdem man schon Code hat den man gut neukompilieren kann, denke ich.

Hmmm, Ghidra klingt echt interessant. Aber selbst wenn es so gut und einfach wäre, das Dekompilieren ähnlich zeitaufwändig ist, wie das ursprüngliche Schreiben, ist das ja für ein durchschnittliches Spiel trotzdem noch jahrelange Arbeit. Würde ich gerne mal ausprobieren, aber naja, es wird ja eh nicht fertig :'(
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
antisteo
Establishment
Beiträge: 1017
Registriert: 15.10.2010, 09:26
Wohnort: Dresdem

Re: Anti-Jammer-Thread

Beitrag von antisteo »

Spiele Programmierer hat geschrieben: 22.06.2026, 14:03 Was ist für euch ein KI-Disassembler?

Disassemblen ist doch voll simpel, da braucht man doch keine KI dafür.

Dekompilieren, Variablennamene wählen und die richtigen Abstraktionen in einer höheren Sprache wie C++ finden, dass ist schwer. Ich weiß nicht, wie weit die Werkzeuge da heute sind, aber da habe ich in der Vergangenheit nix Gutes gefunden und es war noch viel Handarbeit.
Aber darum geht es doch gerade!

Naja und ein maschineller Disassembler wird niemals korrekt Daten/Code auseinander halten können.
https://memcp.org/ <-- coole MySQL-kompatible In-Memory-Datenbank
https://launix.de <-- kompetente Firma
In allen Posts ist das imo und das afaik inbegriffen.
Benutzeravatar
Krishty
Establishment
Beiträge: 8420
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Anti-Jammer-Thread

Beitrag von Krishty »

antisteo hat geschrieben: 23.06.2026, 10:43Naja und ein maschineller Disassembler wird niemals korrekt Daten/Code auseinander halten können.
Was ist „maschinell“ (Laufen nicht alle Programme maschinell?!) und warum?
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
antisteo
Establishment
Beiträge: 1017
Registriert: 15.10.2010, 09:26
Wohnort: Dresdem

Re: Anti-Jammer-Thread

Beitrag von antisteo »

Krishty hat geschrieben: 23.06.2026, 12:57
antisteo hat geschrieben: 23.06.2026, 10:43Naja und ein maschineller Disassembler wird niemals korrekt Daten/Code auseinander halten können.
Was ist „maschinell“ (Laufen nicht alle Programme maschinell?!) und warum?
Unter maschinell meine ich einen verständlichen mittelkomplexen Algorithmus, also alles außer neuronalen Netzen und selbstlernenden KIs.
https://memcp.org/ <-- coole MySQL-kompatible In-Memory-Datenbank
https://launix.de <-- kompetente Firma
In allen Posts ist das imo und das afaik inbegriffen.
Benutzeravatar
Krishty
Establishment
Beiträge: 8420
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Anti-Jammer-Thread

Beitrag von Krishty »

Und der soll was genau nicht können?
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Chromanoid
Moderator
Beiträge: 4321
Registriert: 16.10.2002, 19:39
Echter Name: Christian Kulenkampff
Wohnort: Lüneburg

Re: Anti-Jammer-Thread

Beitrag von Chromanoid »

edit: ich hatte das mit maschinell erst falsch gelesen. Da stimme ich zu. Die Abbildung ist bei Maschinencode einfach zu vieldeutig. Da muß probabilistisch extrapoliert werden.

Wenn man die KI mit genug Daten füttert, kann die das extrapolieren. Das müsste genauso sein wie sowas https://lift4d.github.io/ nur in einem anderen Lösungsraum mit anderen Zusammenhängen.
Benutzeravatar
TomasRiker
Establishment
Beiträge: 132
Registriert: 18.07.2011, 11:45
Echter Name: David Scherfgen
Wohnort: Hildesheim

Re: Anti-Jammer-Thread

Beitrag von TomasRiker »

Ich könnte mir vorstellen, dass ein Decompiler erstmal nach festen Regeln arbeitet und dann auf den erzeugten Hochsprachen-Code eine KI loslässt, um z. B. Variablen und Funktionen sinnvoll zu benennen und ggf. die Struktur des Codes zu verschönern. Bei strukturellen Änderungen sollte man darauf achten, dass sich der zurückkompilierte Maschinencode nicht signifikant ändert, denn das wäre ein möglicher Hinweis darauf, dass die KI einen Fehler gemacht hat.
Benutzeravatar
Krishty
Establishment
Beiträge: 8420
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Anti-Jammer-Thread

Beitrag von Krishty »

Chromanoid hat geschrieben: 23.06.2026, 22:57Da stimme ich zu.
Bei was? Beziehst du dich jetzt auf antisteo (und auf welchen Teil?), auf Jonathan, Spiele Programmierer?

Ich klinke mich aus mit
  • Dekompilieren ist schwer, aber keine Magie
     
  • Mit modernen nicht-LLM-Tools kommt man richtig weit (been there, done that) – nicht an ein direkt wieder kompilierbares Projekt, aber nah genug
     
  • Noobs setzen LLMs erfolgreich ein, um aus Dekompilat Ports bekannter Spiele zu machen, die dann schrecklich laufen
     
  • Obwohl noch nicht selber benutzt, bezweifle ich den Nutzen von LLMs in der Interpretation von Dekompilat nicht weil
    1. 90 % einer Game-Executable sind Boilerplate-Code (C-Runtime, Dateiroutinen, Listen-Verwaltung, Aufrufe an 3D-APIs) – bei Spielen auf Basis bekannter Engines wie Quake noch viel mehr – das braucht Fleißarbeit, nicht Intelligenz
    2. LLMs sind großartig im Übersetzen und im Zusammenfassen von Texten – die Kerntätigkeiten beim Arbeiten mit Dekompilat
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Chromanoid
Moderator
Beiträge: 4321
Registriert: 16.10.2002, 19:39
Echter Name: Christian Kulenkampff
Wohnort: Lüneburg

Re: Anti-Jammer-Thread

Beitrag von Chromanoid »

Ich hatte antisteo erst so verstanden, dass er glaubt Disassemblierung wäre prinzipiell nicht durch eine Maschine machbar. Er meint aber lediglich, dass es nur mit generativen probabilistischen Algorithmen geht. Da stimme ich insofern zu, dass das Mapping von Hochsprache wie C++ zu Assembler eine asymmetrische Transformation ist bei der zu viele Informationen verloren gehen, um beim zurückübersetzen ohne generative Verfahren, was direkt nutzbares rauszubekommen.

Wenn ich deinen Post richtig lese, siehst du das im Grunde ähnlich.

Wenn man genug statische Libraries einpflegt, kommt man bestimmt sehr weit ohne LLM. Aber es bleibt etwas übrig, das man nur schwer interpretieren kann, wenn man nicht weiß was es so für Programmier-Patterns gibt und wie die dann in Assembly aussehen. Die verteilen sich dann ja auch über inlining usw. so dass das kein einfaches Pattern-Matching mehr ist. Sondern man braucht dann im Grunde das was LLMs gut können.
Benutzeravatar
Krishty
Establishment
Beiträge: 8420
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Anti-Jammer-Thread

Beitrag von Krishty »

Dann hast du den Post anders verstanden als ich – ich lese da nämlich nichts über nicht-bijektive Abbildungen beim Dekompilieren, sondern nur etwas über die Unterscheidung zwischen Daten und Code im Disassemblieren, das gütig gesagt höchstens in sehr abstrakter Theorie relevant sein könnte. Disassemblieren ist ein komplett verlustfreier Vorgang, wenn nicht jemand handgeschriebe Assembler-Tricks einsetzt, die auf modernen Systemen seit 20 Jahren nicht mehr benutzbar sind. Aber ja, beim Dekompilieren geht Information verloren – dei Frge is, wviel dvon niht-rdeudnat st nd d Wdrrherstlng vhindrt. LLMs müssten da wirklich glänzen, aber jedes Pattern Matching ist ziemlich gut – schließlich arbeitet ein Compiler nicht willkürlich, sondern nach festen (und recht einfachen) Regeln.

Praktisches Beispiel: Musste ein Watcom-Executable reversen; Funktionsaufrufe waren unlesbar für Ghidra weil die Calling Convention völlig anders war als bei den bekannteren Compilern. Habe ein Plugin mit 30 Zeilen runtergeladen, das die Register bei Aufrufen in der besonderen Reihenfolge interpretiert. Alle Parameterübergaben wieder lesbar. Braucht kein LLM. Für das if in meinen Screenshot ähnlich.

Die Frage ist auch – möchtest du ein exaktes Replika des Original-Codes (klassische Dekompilation) oder reicht es dir, wenn da statt eines handgeschriebenen Sortieralgorithmus im Original jetzt ein std::sort(players.begin(), players.end()) steht? Letzteres machen LLM wirklich, wirklich gut, aber es ist einigen nicht „pur“ genug.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Spiele Programmierer
Establishment
Beiträge: 436
Registriert: 23.01.2013, 15:55

Re: Anti-Jammer-Thread

Beitrag von Spiele Programmierer »

Danke Krishty für deinen Erfahrungsbericht. Hört sich nun nicht mehr so anders an als ich das in Erinnerung habe, nur vlt. etwas praktischer und auf jeden Fall VIEL GÜNSTIGER.

Da bekommt man direkt Bock mal was zu dekompilieren. :D

Hier wird oft Disassemblieren und Dekompilieren durcheinander geworfen. Ich denke disassemblieren kann theoretisch auch komplex sein, z.B. wenn selbstmodifierender Code im Spiel ist oder der selbe Code mit verschiedenen Offsets angesprungen wird (innerhalb eines Befehls als neuen Befehl interpretieren.). So einen Code generiert aber kein Compiler und ist extrem exotisch, evt. kann ich es mir in bestimmten Programmen als erschwerende Maßnahme gegen Reverse-Engennering vorstellen (wobei das schreiben des Codes mindestens genauso komplexer wird, also fraglich ob es sich lohnt).
Benutzeravatar
Chromanoid
Moderator
Beiträge: 4321
Registriert: 16.10.2002, 19:39
Echter Name: Christian Kulenkampff
Wohnort: Lüneburg

Re: Anti-Jammer-Thread

Beitrag von Chromanoid »

Ja, sorry, ich meinte natürlich dekompilieren und hatte das bei antisteo auch so verstanden.... aber wenn ich es genau lese bin ich mir nicht sicher, was da gemeint ist.

ps: vielleicht geht es um Späße wie zur Laufzeit berechnete Sprungziele und andere Obfuscation-Ansätze.
Antworten