Hex Editor automatisieren
-
Hallo zusammen,
Ich habe mich hier angemeldet da ich zurzeit an einigen Projekten für das qhimm Forum arbeite und nicht weiterkomme. Allgemein muss ich einige simple Änderungen an Binary Files vornehmen, welche ich problemlos mit einem Hex Editor realisieren könnte.Das einzige Problem ist, dass ich 713 Dateien zu bearbeiten habe und daher natürlich lieber ein Programm schreiben würde, welches die Arbeitsschritte automatisch durchführt.
Genau genommen muss ich bei jedem File die Bytes 0x4-0x6 einlesen, da sie das Offset in little endian(das wird schon ein Spass das zu übersetzen) welches ich brauche enthalten. Da steht dann z.B. F0 90 01, das heisst ich muss später zum Offset 0x190F0 in dieser Datei springen. So an folgender Stelle muss ich dann den Wert eines Bytes um 1 erhöhen.
Was ich also per Programm können muss:
1. Binary öffnen und gezielt die Werte von bestimmten Bytes auslesen
2. An eine bestimmte Stelle im File springen und dort den Wert eines Bytes verändernDas alles natürlich mit Variablen damit ich beim Aufruf des Programms lediglich den Filename mit Speicherort als Parameter übergeben muss und dieser File dann verändert wird.
Ich habe mich heute natürlich erstmal selbst informiert wie ich das anstelle und die Funktionen, die ich verwenden muss sind wohl fopen, fseek, fscanf und fprintf. Dummerweise liefen alle meine Tests schief da ich zu dumm bin diese Befehle selbstständig zu meinen Gunsten zu verwenden.
Vielleicht hat irgendjemand eine Idee wie ich das ganze möglichst einfach realisieren kann oder ein Beispielprogramm für eine ähnliche Situation ? Ich bin bereits an der Stelle gescheitert wo ich bytes 0x4-0x6 in eine Variable einlesen muss. Ich bekomm dann entweder einen völlig irsinnigen Integer Wert oder halt Characters.....kein Plan wie ich die Werte in Hex bekomme, welche mir auch im Hex Editor so angezeigt werden.
Ich weiss das ist verdammt viel verlangt deshalb bin ich über jeden kleinen Vorschlag sehr sehr froh und sehr dankbar dafür!
-
Nun, du könntest fopen, fseek, fscanf und fprintf verwenden
.
Wenn es nicht funktioniert, dann wirst du sie wohl falsch benutzen. Was du falsch machst, darüber kann man nur spekulieren. Ein paar Spekulationen:
-Technische Fehler, zum Beispiel Datei nicht im binary-Modus geöffnet. Dann berechnen sich die Offsets anders und du bekommst unerwartete Ergebnisse.
-Falsche Erwartungen:Ich bekomm dann entweder einen völlig irsinnigen Integer Wert oder halt Characters.....kein Plan wie ich die Werte in Hex bekomme, welche mir auch im Hex Editor so angezeigt werden.
Hexadezimal, Dezimal oder "als Zeichen" sind doch bloß unterschiedliche Schreibweisen. Was in der Datei steht (und was du verändern möchtest) ist der Wert einer Zahl. In welcher Form du solch einen Wert auf den Bildschirm schreibst, ist dir überlassen.
Traditionell (also die Schreibweise, die du vom Hex-Editor kennst) stellt man die Werte Byte für Byte dar, jeweils Hexadezimal geschrieben. So kann man nämlich jedes Byte kompakt als zwei Ziffern darstellen. printf und scanf beherrschen jede Menge verschiedene Zahlenformate, guck dir mal die Referenzen an. Wichtig ist natürlich, dass du nicht diese Darstellung in die Datei schreibst oder annimmst, dass diese Darstellung in der Datei stünde. In der Datei stehen die Werte der Zahl, nicht die Darstellung, und entsprechend musst du auch die Werte in die Datei schreiben. Die scanf und printf Familien von Funktionen sind dazu nicht geeignet, die sind dazu da, mit einem Menschen zu kommunizieren, also um eine eingetippte Zahl zu lesen oder einen Wert in lesbarer Form auszugeben. Wenn du die rohen Werte lesen und schreiben möchtest, dann nimm die Funktionen, die hier unter Character und Direct input/output aufgeführt sind:
http://www.cplusplus.com/reference/cstdio/
-
Ich denke mir das etwa so:
#include <stdio.h> #include <inttypes.h> enum { ERR_PROCESSING_SUCCESSFUL, ERR_COULD_NOT_OPEN_FILE, ERR_COULD_NOT_SEEK, ERR_IO_ERROR }; void swap_bytes(uint8_t *p, uint8_t *q) { uint8_t x = *p; *p = *q; *q = x; } uint32_t host_from_little_endian_32(uint32_t le_number) { #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ union { uint32_t u32; uint8_t u8[4]; } punner; swap_bytes(punner.u8 + 0, punner.u8 + 3); swap_bytes(punner.u8 + 1, punner.u8 + 2); le_number = punner.u32; #elif __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ #error "Komischer Endian" #endif return le_number; } char const *process_error(int ecode) { switch(ecode) { case ERR_COULD_NOT_OPEN_FILE: return "Datei konnte nicht geöffnet werden"; case ERR_COULD_NOT_SEEK: return "Datei ist nicht random-accessible"; case ERR_IO_ERROR: return "Ein-/Ausgabefehler"; } return "Unbekannter Fehler"; } int process_fd(FILE *fd) { uint32_t offset = 0; uint8_t x; if(0 != fseek(fd, 0x04, SEEK_SET)) { return ERR_COULD_NOT_SEEK; } if(1 != fread(&offset, 3, 1, fd )) { return ERR_IO_ERROR ; } /* Da offset vorher 0 war und sein hinterstes Bit nicht angefasst wurde, ist * es hier ein 32-Bit-Int in Little-Endian. */ offset = host_from_little_endian_32(offset); if(0 != fseek(fd, offset, SEEK_SET)) { return ERR_COULD_NOT_SEEK; } if(1 != fread(&x, 1, 1, fd )) { return ERR_IO_ERROR ; } if(0 != fseek(fd, offset, SEEK_SET)) { return ERR_COULD_NOT_SEEK; } x += 1; if(1 != fwrite(&x, 1, 1, fd )) { return ERR_IO_ERROR ; } return ERR_PROCESSING_SUCCESSFUL; } int process_file(char const *fname) { int err; FILE *fd = fopen(fname, "r+"); if(fd != NULL) { err = process_fd(fd); fclose(fd); } else { err = ERR_COULD_NOT_OPEN_FILE; } return err; } int main(int argc, char *argv[]) { int i; for(i = 1; i < argc; ++i) { int err = process_file(argv[i]); if(err != ERR_PROCESSING_SUCCESSFUL) { printf("Fehler beim Bearbeiten der Datei %s: %s\n", argv[i], process_error(err)); } } return 0; }
-
Danke Leute ihr seid super!! Ich habs jetzt hinbekommen!
Nur eine Sache die noch fehlt....Ich möchte ja den Dateinamen beim Aufrufen von a.out als Parameter übergeben. Im Moment kann ich mit meinem Programm immer nur eine Datei auf einmal bearbeiten (was schon gut ist) aber noch besser is wenn ich nur noch ./a.out /myfolder/* machen mussDas Problem: Ich mache int main ( char name[30] )
und dann übergebe ich name an fopen als Dateinamen. Das Programm wird so ohne Fehlermeldung kompiliert beim Ausführen von a.out kommt dann aber SEGMENTATION FAULT 11und nix passiert.
Sorry wenn das ne noob Frage is die woanders hingehört...
-
Du kannst dir main nicht definieren wie du willst.
Schau dir das Beispiel von seldon an, da ist die richtige Definition.
Und deine gewünschte Funktion ist auch schon eingebaut.Wenn du nicht weißt was argc und argv sind, läßt sich das sicher rausfinden.
Die Stichworte hast du ja jetzt.Die Wildcardexpanison macht unter Linux die Shell,
Bei Windows muss es das Programm selber machen.
-
Habe jetzt dieses Programm geschrieben:
#include <stdio.h> #include <string.h> int main(int argc , char *argv[]) { int n[0]; int offset ; char filename[50]; FILE *fp; strcpy(filename, argv[1]); fp = fopen(filename, "rb+"); fseek(fp,4,SEEK_SET); fread(n, sizeof(int),1,fp); offset = n[0] + 12 ; fseek(fp,offset,SEEK_SET); fread(n,sizeof(int),1,fp); n[0] = n[0] + 65536 ; rewind(fp); fseek(fp,offset,SEEK_SET); fwrite(n,sizeof(int),1,fp); fclose(fp); }
Und habe meine Arbeit damit mit Erfolg beendet. Ich bedanke mich erneut bei allen die sich beteiligt haben !
-
Was soll denn dieser komische Umweg mit dem filename? Mach doch einfach
fopen(argv[1], "rb+");
Dann kann man dein Programm auch nicht mehr kapern, indem man mehr als 50 Zeichen eingibt.
Und ein Array mit 0 Elementen?
Das ist falsch. Du hast bloß Pech, dass das Programm zufällig trotzdem funktioniert, aber das wird dir noch bei nächster Gelegenheit um die Ohren fliegen. Dabei nutzt du sogar an keiner Stelle die Array-Eigenschaft. Lass mich raten: Du hast zuerst korrekterweise einen int gehabt, aber dann wollte
fwrite(n,sizeof(int),1,fp);
nicht compilieren. Dann hast du so lange wild zufällige Zeichen in dein Programm geschrieben, bis es doch zufällig compilierte, ohne zu verstehen, was vorher falsch war oder was die Neuerung überhaupt genau bedeutet. Geht diese Vermutung in die richtige Richtung?
Aus unserem Thread für Neulinge:
c.rackwitz schrieb:
Wenn du selber Code schreibst, musst du ihn auch verstehen. Code ist kein Haufen von wahllos zusammengeschmissenen Buchstaben und Zeichen, Code ist Logik pur. Du musst genau wissen, warum du wo und welches Zeichen setzt.
-
Ich hätte ein Array mit 1 Element logisch gefunden (genau ein int als Übergabe wollte fwrite nich) aber das ergab einen seltsamen Fehler. Das Programm erhöhte zwar mein byte um 1 aber ab diesem offset war die datei völlig verändert. Meine Idee: fwrite schreibt noch irgendeine undeklarierte zweite Variable ins File also hab ich den Index um 1 verringert und jez läufts
Bitte regen Sie sich nich auf ich bin froh dass es funktioniert hat. Und zumindest das hat es, ich habe das Mass update ausgiebig analysiert und getestet, am Ende diente es als ISO Edit auf FFVII und das ist geglückt also feier ich das jez
-
Klassischer Fall von so vielen Fehlern, das einige sich wieder gegenseitig aufheben. Es ist ein kleines Wunder, dass das tatsächlich funktioniert haben soll. Sicher, dass es funktioniert hat?
Die von dir vermutete Erklärung ist jedenfalls Unsinn.
-
Ich sehe ehrlich gesagt keine Fehler im netz steht das "0 length arrays" unter gnu erlaubt sind. Warum es mit Index 1 nich funktionierte...was weiss ich ^^
Ja es hat geklappt, ich habe die Files mit nem Hex Editor mit den Originalen verglichen und der einzige Unterschied ist jeweils das eine Byte welches ich um 1 erhöht habe. Auch beim Testen des ISOs erzielte ich keine Fehler und die gewünschte Veränderung.
-
Du siehst keinen Fehler darin, das erste Element eines Arrays der Länge Null zu benutzen? Selbst wenn es legal wäre, Arrays der Länge Null (außerhalb der letzten Datenmember von Structs) zu deklarieren, müsste ziemlich offensichtlich sein, dass das Unfug ist.
-
Karabellum schrieb:
Ich sehe ehrlich gesagt keine Fehler im netz steht das "0 length arrays" unter gnu erlaubt sind.
Erlaubt: Mag sein. Aber was ist das erste Element eines Arrays ohne Elemente, welches du fröhlich benutzt? Das ist irgendetwas hinter dem eigentlichen Array. Das heißt, du schreibst und liest hier fröhlich in andere lokale Variablen hinein. Je nach dem, wie die Variablen genau auf dem Stack angeordnet sind, könntest du dir damit zum Beispiel dein Offset zerschießen. Deshalb wundere ich mich auch gerade sehr, dass es funktioniert, denn ich hatte in Erinnerung, dass der GCC ohne Optimierung die Variablen einfach in der Reihenfolge anordnet, wie sie im Programm auftauchen, so dass du hier tatsächlich unabsichtlich im Offset rumpfuschen würdest. Vielleicht irre ich mich auch mit der Reihenfolge. Oder du hast Optimierungen aktiviert und hast Glück, dass "nur" im unbenutzten Dateinamen rumgeschrieben wird. Oder du merkst gar nicht, dass das Programm falsch gelaufen ist. Jedenfalls eine ganze Menge Glück, wenn das wirklich funktioniert haben sollte. Oder Pech, weil du nun nicht einmal einsiehst, dass das falsch ist und dir das falsch einprägst. Beim nächsten Mal geht's dann schief.
Warum es mit Index 1 nich funktionierte...was weiss ich ^^
Da sind garantiert noch mehr Fehler drin, denn allein die Verwendung eines Arrays ist schon falsch. Wozu soll man bitte ein Array mit einem Element brauchen? Da nimmt man einfach eine einzelne Variable. Ich habe vorhin nur oberflächlich über den Code geschaut und dies waren die Fehler, die mir sofort ins Auge sprangen. Wenn du noch einmal den fehlerhaften Code mit genauer Fehlerbeschreibung zeigst, kann man sich das mal genauer ansehen.
-
Ein unentdecktes Fehlverhalten des Programms ist ausgeschlossen. Es hat die Aufgabe genau 1 Byte zu verändern, wenn am File irgendwas sonst anders wäre, hätte der Hex Editor das beim Vergleich gefunden.
Dass Array[0] komisch is weiss ich auch aber er sagte ja "so viele Fehler" der Rest sollte aber ok sein.
Und ich merke mir das auch nich so, int und array[1] funktionierten nich deswegen hab ich was anderes probiert und warum das funzt - nix für Ungut Jungs - is mir in diesem Einzelfall dann ehrlich gesagt egal.
Das Programm hab ich doch auf der letzten Seite gepostet, wenn du es dir genauer ansehen willst nur zu. Fehlermeldungen gab es keine.
-
Ich hoffe, dass du in einem halben Jahr, wenn du dir ein bisschen Ahnung erarbeitet hast, auf diesen Thread zurückblickst und er dir richtig peinlich ist. Mehr kann ich dazu wirklich nicht mehr sagen.
-
Das hoffst du ? Finde ich aber nicht sehr nett
Deine Missgunst verstehe ich in keinem Fall.
-
Karabellum, SeppJ und seldon wollen dir nur helfen.
Mag sein, dass dein Programm - so wie es jetzt kompiliert wurde mit diesen Einstellungen und Compiler - funktioniert. Wie SeppJ schon sagte, Glück gehabt.
Aber wenn du in der Zukunft so weiter programmierst, wirst du vielleicht kein Glück mehr haben. Dann wird die von uns allen so geliebte Windowsfehlermeldung (sofern du Windows benutzt), die aussagt, dass dein Programm nicht mehr funktioniert. Und dann wirst du die nächsten Stunden/Tage/Wochen* damit verbringen, herauszufinden, wo du Speicher bearbeitest, der dir nicht gehört.
Und davor wollen wir dich schützen. Wir haben diese Fehler schon alle gemacht.
Wir wollen nicht, dass du sie auch machst.
Aber wenn du nicht willst, ok!
Sag später nur nicht, wir hätten dich nicht gewarnt...*Ernsthaft; ich übertreibe nicht. Mit etwas Glück gehts schneller, aber das Umschreiben wird lange dauern.
-
Is mir schon klar aber warum muss man sich da aufregen? Ich habe ja bereits gesagt dass ich das nicht so weiterverwenden werde oder mir merke dass das richtig ist oder so. Ich brauchte dieses Programm jetzt für eine bestimmte Sache und es ging mir nur darum die zuende zu bringen, danach brauche ich das nie wieder.
Ich bin mit der Sache jetzt fertig geworden und da gibt es dann eigentlich nichts mehr zu zusagen. Wär ich selbst Moderator TOPIC CLOSED
-
Auch wenn du es vermutlich eh nicht mehr liest:
Karabellum schrieb:
Is mir schon klar aber warum muss man sich da aufregen?
Sie regen sich nicht auf, sie sind ganz sachlich geblieben.
Ich habe ja bereits gesagt dass ich das nicht so weiterverwenden werde oder mir merke dass das richtig ist oder so. Ich brauchte dieses Programm jetzt für eine bestimmte Sache und es ging mir nur darum die zuende zu bringen, danach brauche ich das nie wieder.
Trotzdem wäre es besser, sich falsche Dinge nicht anzugewöhnen.
Das denkst du später dann vielleicht auch und dann gehts nicht mehr.
Sieh es einfach als Übung.
-
Klar les ich das. Und du hast Recht genau wie deine Vorredner. Und sie haben mir ja auch geholfen sehr sogar. Is doch alles gut ^^