PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Vorgänge in einem Programm automatisieren



makenshi
17.03.2007, 12:01
Aloa liebes PGM Forum,

Die Vorerklärung:

für die folgende Problembeschreibung muss ich etwas ausholen. Im Moment arbeiten ein guter Freund und ich mithilfe eines Spieleeditors an einem Freewarespielchen. Dieses besitzt bereits viele fertige Funktionen wie auch z.B. ein Lade/Speichersystem. Diese System kann am Anfang über ein Menü erreicht werden.
Das ganze sieht in etwa so aus:
http://home.arcor.de/makenshi2k/system.png


Dieses Menü lässt sich über die Pfeiltasten bedienen. Sobald man per "New Game" ins Spiel gelangt, kann man mit der Funktionstaste "F12" wieder zurück in das abgebildete Menü wechseln. Sobald man "Load Game" anwählt, taucht ein Ladescreen auf. In diesem können mehrere Spielstände ausgewählt werden.


Was ich nun möchte:

Ich möchte gerne den Vorgang :

"F12 drücken -> "Load Game" auswählen -> Enter drücken" automatisieren. Ich müsste also dem Programm auf irgendeine Art und Weise mitteilen das es ins Hauptmenü zurückspringen soll(eventuell ja über F12) und dann entsprechend auf den "Load Game" Eintrag zu navigieren. Dort brauche ich dann noch einen Enter Tastendruck.
Die Sache ist nun nur: wie soll ich das bewerkstelligen?

Ich habe ein Programm gesehen welches genau dies tut. Jedoch funktioniert es für die Version des Editors die ich benutze leider nicht. Der Autor des Programms lässt zur Benutzung über ein weiteres Miniprogramm ersteinmal einen Offsetwert ermitteln. Dieser scheint mit der EXE des Spieles zusammenzuhängen. Jedoch beginnt ab hier absolutes Neuland für mich. Wenn er das ganze über den Arbeitsspeicher realisiert, dann weiß ich leider nicht wie er in diesen Vorgang genau ins Rollen bringt.

Ich erhoffe mir nun also von den Antworten hier das mir jemand einen Weg zeigen kann wie ich die eben beschriebene Automatisierung verwirklichen kann. Ob dies nun über den Arbeitsspeicher passiert oder auf anderem Wege ist mir dabei egal.

Als kleine Zusatzfrage:

Das eben erwähnte Editorsystem hat zur Realisierung des eigenen Spiels natürlich auch eine Funktion mit der man Variablen anlegen kann. Diese Variablen sind dabei entweder vom Typ Boolean oder eine Art Integer.
Kann man diese Variablen die sich wahrscheinlich während der Laufzeit des Programms im Speicher befinden dürften irgendwie auslesen? Kann man eventuell auch die Variablen des Programms im Speicher selbst modifizieren? Während das Programm läuft?


Das war es dann nun auch endlich mit einer Anfrage. Ich hoffe trotz der Menge an Text auf Antworten. An sich ist mir jeder Weg lieb der hier jemandem einfällt. Falls ich etwas vergessen haben sollte zu erwähnen, dann werde ich es natürlich nennen.


PS: Bei dem Editor handelt es sich um den RPG Maker 2003. Jedoch geht hierbei ja nicht um den Editor an sich. Hoffe das die Frage damit trotzdem legitim ist. Ich wüsste nicht nämlich außer der Programmierung keine Zuflucht für dieses Problem. Ich habe es selbst schon mit Java versucht. Jedoch bietet dieses leider keine Methoden um den Speicher in irgendeiner Weise auszulesen. :/


MFG Makenshi

Crash-Override
17.03.2007, 16:51
Wie wäre es mit http://multimediaxis.net/search.php.
z.B. hier (http://multimediaxis.net/showpost.php?p=1582765&postcount=5) aus diesem Thread (http://multimediaxis.net/showthread.php?t=86152&highlight=RPG-Maker)
edit: Ach ja der letze Satz bezog sich darauf das er absolut keine Ahnung hatte und am Ende, wie du selbst lesen kannst, etwas unhöglich wurde.

Java ist für sowas sowieso fehl am Platz (meiner persönlichen Meinung nach ist Java immer fehl am Platz). Speicherzugriffe kann man recht leicht in C machen, wenn du es einfacher haben willst würde ich Delphi nehmen, wenn du es schwer willst Assembler. Alle drei Sprachen wirst du kostenlos beziehen können (Nur nimm bei C(++) bitte nicht ein Microsoft Produkt, sonst wirst du enttäuscht werden - garantiert).
Also an sich ist es möglich, aber wenn du schon nicht weißt wie du es machen musst, informiere dich ab Besten vorher über alles mögliche und überlege dir gut ob du wirklich denkst du kannst es, sonst verschwendest du nur deine Zeit.

Ineluki
17.03.2007, 18:09
genau mit dem selben Krempel habe ich mich auch schon fuer den rm2k rumgeschlagen fuer meine Patches .. und bei allen habe ich dann aus Zeitmangel aufgegeben.

Ich hatte sigar mal eine Loesung fuer F12+runter+enter, aber dort war das Problem dann, dass das timing exakt stimmen musste. Also hab ich die funktion irgendwann ausgebaut, weil es einfach zu kompliziert war, die tastendruecke in exakt dem richtigen moment zu senden.

Fuer das Load Problem waere es wohl eine loesung, wenn man im Spiel die Addresse der Load Subroutine mit einem Debugger oder einem Disassembler rausbekommen wuerde, und dann in einer dll (z.B. dem Tastenpatch), die vom rm2k geladen wird (-> gleicher addressraum) als funktionspointer aufruft. Allerdings hab ich das noch nicht probiert, da ich mich mit debuggern nicht so sonderlich auskenne und keine Zeit hab zum einarbeiten ...

Beim rm2k3 sieht es noch schlechter aus, da dort die moeglichkeit wegfaellt, ueber eine DLL freien Zugriff auf die Programmbibliotheken zu bekommen ...

Das Problem mit dem Aendern der Variablen ist aehnlich vertrackt. Zwar kannst du mit Read/WriteProcessMemory daten lesen und schreiben, das Problem ist allerdings, zu wissen, wo die Daten stehen. Da der maker seinen Speicher dynamisch alloziiert, stehen die bei jedem Start idR wo anders im speicher. Zwar sollte es eine konstante Addresse geben (die pointervariable zum Speicherbereich) die die addresse enthaellt, und ich konnte auch schon die Routine ermitteln (rm2k), in der die Variablen geaendert werden, doch fehlte mir dann zeit und ausdauer, den schritt zu komplementieren.

Alles in allem ein kompliziertes Problem, selbst fuer mich.

Ich kann ja mal posten, was ich damals so rausbekommen habe ...
Vielleicht nuetzt es ja einem. Alle Angaben natuerlich ohne Gewähr.



Speicherauszug aus RPG_RT.EXE

0046a047 8BD6 mov edx,esi
0046a049 C1E202 shl edx,0x2
0046a04c 8D4328 lea eax,[ebx+0x28]
0046a04f E8DC86F9FF call 0x00402730
0046a054 8B5324 mov edx,[ebx+0x24]
0046a057 8BC6 mov eax,esi
0046a059 48 dec eax
0046a05a 2BC2 sub eax,edx
0046a05c 7C0D jl short 0x0046A06B
0046a05e 40 inc eax
0046a05f 8B4B28 mov ecx,[ebx+0x28]
0046a062 33FF xor edi,edi
0046a064 893C91 mov [ecx+edx*4],edi
0046a067 42 inc edx
0046a068 48 dec eax
0046a069 75F4 jnz short 0x0046A05F
0046a06b 897324 mov [ebx+0x24],esi
0046a06e 5F pop edi
0046a06f 5E pop esi
0046a070 5B pop ebx
0046a071 C3 retn
0046a072 8BC0 mov eax,eax
0046a074 83FA01 cmp edx,0x1
0046a077 7C05 jl short 0x0046A07E
0046a079 3B5024 cmp edx,[eax+0x24]
0046a07c 7E03 jle short 0x0046A081
0046a07e 33C0 xor eax,eax
0046a080 C3 retn
0046a081 8B4028 mov eax,[eax+0x28]
0046a084 8B4490FC mov eax,[eax+edx*4-0x4]
0046a088 C3 retn
0046a089 8D4000 lea eax,[eax] eax=eax^ <---- Begin Subrotine ?
0046a08c 53 push ebx speichern ebx
0046a08d 56 push esi speichern esi
0046a08e 57 push edi speichern edi
0046a08f 8BF9 mov edi,ecx edi=ecx
0046a091 8BF2 mov esi,edx esi=edx
0046a093 8BD8 mov ebx,eax ebx=eax
0046a095 83FE01 cmp esi,0x1 esi-1
0046a098 7C15 jl short 0x0046A0AF ? < 0 goto pops
0046a09a 3B7324 cmp esi,[ebx+0x24] esi - (ebx+0x24)^ <---- Begin Patch
0046a09d 7E09 jle short 0x0046A0A8 ? <=0 ueberspringe call
0046a09f 8BD6 mov edx,esi edx=esi
0046a0a1 8BC3 mov eax,ebx eax=ebx
0046a0a3 E898FFFFFF call 0x0046A040 Unterprogramm 0046A040
0046a0a8 8B4328 mov eax,[ebx+0x28] eax=(ebx+0x28)^ <---- Ende Patch
0046a0ab 897CB0FC mov [eax+esi*4-0x4],edi (eax+esi*4-0x4)^=edi --> v[esi]=wert
0046a0af 5F pop edi reload edi
0046a0b0 5E pop esi reload esi
0046a0b1 5B pop ebx reload ebx
0046a0b2 C3 retn fertsch <---- Ende Subrotine ??
0046a0b3 90 nop
0046a0b4 53 push ebx
0046a0b5 56 push esi
0046a0b6 8BF1 mov esi,ecx
0046a0b8 8BDA mov ebx,edx
0046a0ba 6A01 push 0x1
0046a0bc 56 push esi
0046a0bd 8B0DE4AE4900 mov ecx,[0x49AEE4]
0046a0c3 BADCA04600 mov edx,0x46A0DC
0046a0c8 8BC3 mov eax,ebx
0046a0ca E899F8FEFF call 0x00459968
0046a0cf 5E pop esi
0046a0d0 5B pop ebx
0046a0d1 C3 retn
0046a0d2 0000 add [eax],al
0046a0d4 FFFF ???
0046a0d6 FFFF ???
0046a0d8 050000004D add eax,0x4D000000
0046a0dd 7573 jnz short 0x0046A152
0046a0df 6963000000558B imul esp,[ebx],0x8B550000
0046a0e6 EC in al,dx
0046a0e7 83C4F8 add esp,-0x8
0046a0ea 53 push ebx
0046a0eb 56 push esi
0046a0ec 33DB xor ebx,ebx
0046a0ee 895DF8 mov [ebp-0x8],ebx
0046a0f1 884DFF mov [ebp-0x1],cl

Patch Ansatz ....

Original:
0x46A09A:
3B 73 24 7E 09 8B D6 8B C3 E8 98 FF FF FF 8B 43 28

Modifiziert:
0x46A09A:
90 90 90 90 90 8B D6 8B C3 8B 43 28 A3 9A A0 46 00

danach steht pointer auf v[1] in 0x46A09A

0x46A09A
asm original asm modifiziert

3B 90 nop <--- Hier kommt die Addr rein
73 90 nop
24 cmp esi,[ebx+0x24] 90 nop
7E 90 nop <--- 32 Bit = Ende Addresse
09 jle short 0x0046A0A8 90 nop
8B 8B
D6 mov edx,esi D6 mov edx,esi
8B 8B
C3 mov eax,ebx C3 mov eax,ebx
E8 8B
98 43
FF +--> 28 mov eax,[ebx+0x28] <--- Addresse steht nun in eax
FF | A3
FF call 0x0046A040 | 9A
8B | A0
43 | 46
28 mov eax,[ebx+0x28] +--+ 00 mov [0x46A09A],eax <--- Addresse speichern in 0x46A09A
*************************************************************************
89
7C
B0
FC mov [eax+esi*4-0x4],edi
5F pop edi
5E pop esi
5B pop ebx
C3 retn


Bitte nicht schlagen .. ich hab den Code vor Jahren geschrieben, und war damals noch dumm und unwissend ^^

Ziel war es also, beim ersten Aufruf von ChangeVariable im Spiel nach injektion des neuen codes den wert des Pointers zu bekommen. Den habe ich kurzerhand im Programmsegment nops ueberschreiben lassen, weil ich dann genau wusste, wo er steht. nach dem change Variable, wenn ich den pointer hatte, ersetzte ich den veraenderten code wieder durch das original. Das Problem watr aber immer, man brauchte Change Variable dazu, wobei die ausfuehrung exakt einmal kommen musste. wuerde in der zeit vor der wiederherstellung nochmal change variable durchgefuehrt, haette man das Programm ins Nirvana geschickt.

Das Verfahren hat wirklich funktioniert, allerdings war es mir fuer den allgemeinen Markt zu unsicher.

makenshi
18.03.2007, 09:11
Ersteinmal: vielen Dank an dich Ineluki und auch an Crash-Override.
Besonderes letzterer hat mir netterweise per Messenger ausgeholfen.

Im Endeffekt hat sich nun eine entsprechend modifizierte EXE gefunden die die Grundlage bot um die gewünschten Effekte umzusetzen. Mit ein paar Zusatzexen konnten auch die fehlenden Bestandteile eingefügt werden. Im großen und ganzen kann ich mich also nur nochmals bedanken.

In diesem Sinne -> der Thread kann gern geschlossen werde.