User:Hmoeller/Sandbox1
Contents
Cheat Engine AGTH Tutorial
This tutorial explains how to find an AGTH hook for a Japanese visual novel using Cheat Engine. The game 診てくださいます? by Complet's will be used as an example. You will need to know the basics of assembler programming. Reading the book “PC Assembly Language” by Paul Carter is recommended. It is short at only 200 pages and was used to teach assembler programming at a university. It can be downloaded for free here. Windows system locale has to be set to “Japanese” or this tutorial won't work. Is is also recommended to do the tutorial that comes with Cheat Engine.
Contents
[show]==Instructions that access the memory Edit== Start Cheat Engine and the game. Attach Cheat Engine to the game using the Process List dialog (File – Open Process – Open). Skip the prolog and start the game from the beginning then save the game immediately. Now click once to go to the next text. The screen will look like this:
[1]The text will be “ドアの脇に鞄を置いて、そのままキッチンへ向かう。”.
Choose “String” as value type and press “First scan”. Cheat Engine will find two addresses.
[2]Double click both addresses to add them to address list. Now click in the game window. The text will change and with it the text at the address 4422F8 will change too. This is the address where the game is writing the new text. You can delete the other address, we don't need it.
Right click the address 4422F8 in the address list and choose “Find out what accesses this address”. Cheat Engine will now set a breakpoint at this address and find all instructions (called opcodes) that access this address. A new window will open. Click once in the game window and a list of commands will appear in the new window.
[3]The window shows all assembler instructions, that access the address 4422F8. Click “Stop” to stop looking for instructions that access the address. Now we have to check the instructions one by one to find the right one.
[4]We will start with the instruction “0040FAAD - C6 00 00 - mov byte ptr [eax],00”. Select it and click on “Show in disassembler”. We have to set a breakpoint at the instruction at the address 40FAAD. Press F5 to set the breakpoint. Now click in the game window and Cheat Engine's debugger will stop at 40FAAD.
The instruction “mov byte ptr [eax],00” copies the value 00 to the address stored in the register EAX. When the debugger stops at 40FAAD the register EAX contains the address 4422FA. Right click EAX and choose "Show in hexview". As you can see in the address list the string starts at address 4422F8 but EAX points at the address 4422FA which is 2 bytes past the beginning of the string. Now press F9 and the debugger will stop again. You can see that the address in EAX has increased by 2 bytes to 4422FC and the two bytes at 4422FA and 4422FB have changed their values. Press F9 repeatedly to observe the changes in EAX and in the hexview. Remove the breakpoint by pressing F5 again.
Each time the game reaches this instruction 2 new bytes have been written to [EAX-2] (take the address at EAX and subtract 2 from it). These two bytes constitute one character in the Shift-JIS (SJIS) character page (encoding). The first byte of a double byte SJIS character is always greater than 0x80. SJIS also contains single byte characters. The value of a single byte character is always less than 0x80.
Now we can set a hook for AGTH at this address.
- We start with “/H” and add “BN”[1] because the game always writes one character in the SJIS encoding and we get “/HBN”.
- Now we add “-4” because the character address is in EAX and we get “/HBN-4”.
- EAX doesn't directly contain the character, instead it contains the address of the character so we need to add “*” getting “/HBN-4*”.
- The character actually isn't at the address held in EAX, but at [EAX-2]. We get “/HBN-4*-2”.
- Finally we add the address at which the command can be found and get “/HBN-4*-2@40FAAD”.
We have just found the hook “/HBN-4*-2@40FAAD”.
Now try setting the breakpoint at 40FAA0. You will see that the instruction “mov [eax],cl” writes the second byte of an SJIS character to the address at EAX (CL stands for the lowest byte of ECX). Some SJIS characters consist of two bytes. When the game reaches 40FAA0 only the first byte of a character is at [EAX-1]. Press F8 to step over the current instruction. The second byte is written to [EAX]. We can set the hook here at 40FAA2. We want to read the character which starts at [EAX-1]. Therefore the final hook will be “/HBN-4*-1@40FAA2”.
Finally let's set a breakpoint at 40FA8D. You will see that [EAX] is 00 when the game reaches this address. The instruction “mov [eax],dl” writes the first byte of an SJIS character to [EAX] (DL stands for the lowest byte of EDX). We can't do anything with just the first byte, so we can't create a hook at this address.
If you try the other instructions in the instruction list, you will see that they all have the same problem. When the game reaches an instruction the text at 4422F8 is still the old text and not the text that will be displayed. This means that those instructions can't be used to create a hook.
In this tutorial we used instructions that access the text that is constantly changing with every click. It is also possible to use instructions that access the text from the game database.
Instructions that access the text database Edit
[5]Load the saved game. Search the string “ドアの脇に鞄を置いて、そのままキッチンへ向かう。” CE will find one address. Add it to the address list and name it “database”.
[6]Right click the address “database” and choose “Find out what accesses this address”. Now click in the game window and the following window will appear.
[7]Let's look at “0040FA58 - 8A 10 - mov dl,[eax]” in the debugger (disassembler). Set a breakpoint at 40FA58 with F5 and click in the game window. Don't forget to press “Stop” in the opcode window. The screen shows the window after I pressed “Stop”. Right click EAX and choose “Show in hexview”.
[8]Now press F9 repeatedly and observe the changes of EAX. The hexview will not change because it shows the text database. You can see that EAX is increased by 2 every time and it always points to the start of an SJIS character. The first byte is often 81, 82, 83 or 91.
Let's place our hook here. We want to read one SJIS byte “B”, the address is 40FA58. The character is at [EAX] (address contained in EAX) therefore we need “*0”. The hook will be “/HBN-4*0@40FA58”. Let's ignore “N” for now which simply turns off the context.
Context and subcontext Edit
[9]The context is the value at the top of the stack. In Figure 8 the value at the top of the stack is (dword)00000001(1). That is it's the number 1. AGTH uses the context to create multiple threads for one hook.
In the screen shot above 0x00000001 is the context of the thread. AGTH shows the context as 0x00000001 when it's turned off. AGTH creates one thread for each context unless you turn off the context by adding “N” to the hook. That's what we did because we simply didn't need to create multiple threads. We didn't have to split our thread in multiple threads.
The second number 00000000 after “:” in the thread title is the subcontext. We didn't specify any subcontexts in our hook, therefore AGTH shows it as 00000000. The subcontext is a register value or a stack value that is used to split a thread into multiple threads. While the context is always the value at top of the stack, the subcontext can be freely defined and allows a lot of flexibility.
[10]It is even possible to use the context and a subcontext together. AGTH will create a thread for each pair of context and subcontext. If there are e.g. 3 different contexts and 5 different subcontexts then AGTH will create 15 different threads.
Let's look at a thread that is automatically created by AGTH. It shows the correct text “ドアの脇に鞄を置いて、そのままキッチンへ向かう。” but also the previous text. Couldn't we use a subcontext to split both texts in different threads? Let's try it.
0040DF02 is the context of the thread and the address of an automatic AGTH hook. In the debugger press Ctrl+G and go to 0040DF02. At 40DEFC we see a call to the function TextOutA. Let's set a breakpoint at this address. Press F5 to set a breakpoint.
[11]We see that EDI contains our text. Right click EDI and choose “Show in hexview”. Press F9 repeatedly and you will see that TextOutA is called once for each character. Also EDI is increased by 2 each time and EAX changes too. You will also see that first EDI accesses the old text and then it starts accessing the new text. When that happens all registers change their values. Our goal is to find a register that will be our subcontext and that will create two threads, one for the old text and one for the new text.
Press F9 until new text starts appearing. Write down all the register values except EAX and EDI because they change with every call to TextOutA. EIP should also be ignored.
Register | Value |
---|---|
EBX | 1CC |
ECX | 1310 |
EDX | 1CD |
ESI | A3012498 |
EBP | 7677522D |
ESP | 18F5D0 |
Now remove the breakpoint with F5 and press F9. Set the breakpoint again and press F9 repeatedly until the game starts displaying new text.
Create a table of register values again.
Register | Value |
---|---|
EBX | 1CC |
ECX | 1310 |
EDX | 1CD |
ESI | 31012433 |
EBP | 7677522D |
ESP | 18F5D0 |
Compare the tables. ESI is different so we have to remove ESI from the candidate list. Now create a third table for the register values when old text is displayed.
Register | Value |
---|---|
EBX | 1CC |
ECX | 1310 |
EDX | 1CD |
EBP | 7677522D |
ESP | 18EEB0 |
Register | New Text | New Text Again | Old Text |
---|---|---|---|
EBX | 1CC | 1CC | 1CC |
ECX | 1310 | 1310 | 1310 |
EDX | 1CD | 1CD | 1CD |
ESI | A3012498 | 31012433 | |
EBP | 7677522D | 7677522D | 7677522D |
ESP | 18F5D0 | 18F5D0 | 18EEB0 |
EBX, ECX, EDX and EBP are the same in the table for old and new text. Remove them from the candidate list. This only leaves us ESP. Let's make ESP our subcontext. EDI which points to an SJIS character is -20, ESP is -14.
The H-Code “/HBN-20*0:-14@40DEFC” is our new hook.
“:-14” in the hook means that ESP is the subcontext. Now AGTH shows two threads. One is 0x00000001:0018F5D0 and the other is 0x00000001:0018EEB0. Notice that the subcontext is the value of the ESP register. The context is 0x00000001 because we have turned them off with “N” in the hook.
It is also possible to use a value from the stack as the subcontext. I recommend using OllyDbg for that. OllyDbg allows copying the stack to the clipboard and pasting it in a spreadsheet. A spreadsheet makes it much easier to see which values stayed the same and which changed.
- ↑ “N” turns off the context. Contexts will be explained later.