Author Topic: Few things about Mini Games Patcher / debug info  (Read 2807 times)

dziugo

  • *
  • Posts: 1470
    • View Profile
    • A new copy of FF7 thanks to Salk. Pack (zip/rar/etc) your saved game before sending it to me.
Few things about Mini Games Patcher / debug info
« on: 2005-09-11 00:41:05 »
If you're unfamiliar with MGP, check this

Ok... first, the debug info from patching the ff7.exe ver 1.00.
Code: [Select]
1) Initial file analysis.
Free space in text segment (info by image section header): 0xcb
Needed free space: 0xff
Not enough free space. Let's see if we can get some more...
Available free space: 0xacb
Enlarging the segment by: 0x200
Updated segment raw pointer at: 0x1d8 New value: 0x3aac00
Updated segment raw pointer at: 0x200 New value: 0x3ae200
Updated segment raw pointer at: 0x228 New value: 0x58c800

Updated segment raw size at: 0x1b0 New value: 0x3aa800
Analysing text segment...
Checking free space...
Offset: 0x3aa935 Free space: 0x2cb
Done

2)Searching for references.
highway_init
Raw: 0x24f63d Offset: 0x65023d
highway_main
Raw: 0x24f2e2 Offset: 0x64fee2
snowboard_main
Raw: 0x31828f Offset: 0x718e8f
get_actual_cc
Raw: 0x25f240 Offset: 0x65fe40
calculate_cc
Raw: 0x25f270 Offset: 0x65fe70
convert_cc_to_float
Raw: 0x25f2fd Offset: 0x65fefd
frame_cap
Raw: 0x900 Offset: 0x401500
Raw: 0x1acd5 Offset: 0x41b8d5
Raw: 0x1f4016 Offset: 0x5f4c16
Raw: 0x237856 Offset: 0x638456
Raw: 0x2379c5 Offset: 0x6385c5
Raw: 0x2c2eda Offset: 0x6c3ada
Raw: 0x341da4 Offset: 0x7429a4
Raw: 0x36f276 Offset: 0x76fe76
Raw: 0x381f91 Offset: 0x782b91
Raw: 0x39d57b Offset: 0x79e17b
extra_call
Virtual address: 0x675c8b Raw offset: 0x27508b
imm_benchmark
Immediate: 0xda4228
imm_highway
Immediate: 0xd76fe4
imm_snowboard
Immediate: 0xdc9218
frame_cap
0x381f91
imm_old_cc
Immediate: 0xe65930
imm_actual_cc
Immediate: 0xe65920
imm_cc_per_frame
Immediate: 0xe65938
Done

3)Preparing the output file.
Allocating space at: 0x3aa935 amount of space allocated: 0x5c
Allocating space at: 0x3aa991 amount of space allocated: 0x22
Allocating space at: 0x3aa9b3 amount of space allocated: 0x41
Allocating space at: 0x3aa9f4 amount of space allocated: 0x40
Inserted a new call/jmp, destination: ffeb48f9
Inserted a new call/jmp, destination: ffeb4913
Inserted a new call/jmp, destination: ffeb4994
Inserted a new immediate, destination: e65920
Inserted a new immediate, destination: e65930
Inserted a new immediate, destination: e65920
Inserted a new immediate, destination: e65938
Inserted a new immediate, destination: e65920
Inserted a new immediate, destination: e65930
Inserted a new immediate, destination: e65924
Inserted a new immediate, destination: e65934
Inserted a new immediate, destination: da4228
Inserted a new immediate, destination: e65938
Inserted a new call/jmp, destination: ffeb486c
Inserted a new call/jmp, destination: ffffffb5
Inserted a new call/jmp, destination: ffffff51
Inserted a new call/jmp, destination: ffea48fa
Inserted a new immediate, destination: d76fe4
Inserted a new immediate, destination: d76fe4
Inserted a new immediate, destination: e65930
Inserted a new immediate, destination: d76fe4
Inserted a new call/jmp, destination: ffeb482d
Inserted a new call/jmp, destination: ffffff76
Inserted a new call/jmp, destination: ffffff12
Inserted a new call/jmp, destination: fff6d865
Inserted a new immediate, destination: dc9218
Inserted a new immediate, destination: dc9218
Inserted a new immediate, destination: e65930
Inserted a new immediate, destination: dc9218
Wrote: 0x5c bytes at offset: 0x3aa935
Wrote: 0x22 bytes at offset: 0x3aa991
Wrote: 0x41 bytes at offset: 0x3aa9b3
Wrote: 0x40 bytes at offset: 0x3aa9f4
Inserted a new jmp at: 24f2e7 jmp destination: 15b6c9
Inserted a new jmp at: 318292 jmp destination: 9275f
Last non-nop byte is at: 0x3aaa33 Size of image: 0x3aa634
Updated segment virtual size at: 0x1b0 New value: 0x3aa634
Raw: 0x547be0
Applying snowboard patch.
Done

4)Saving file.
Done


The debug info contains four headers:
Code: [Select]
1) Initial file analysis.
2) Searching for references.
3) Preparing the output file.
4) Saving file.


Let's take a look at the first one... What the patcher does in it's first stage? Basically, it checks, if the amount of free space in the *.exe file is high enough (first release of my patch needs at least 0xFF bytes). If it's not it'll try to enlarge that area a bit... It requires writing new values into the file header. If the file can be enlarged, the patcher does it (the file will be a little bit bigger after patching). When the first step is successfull...

Patcher moves to the second stage... It will search for all needed functions in the text-segment of the exe file... Here is the full list of the functions:
Code: [Select]
highway_init - function which is called to prepare the HighwayMiniGame (needed only to get the extra_call function)
highway_main - function which is responsible for creating each frame of the HighwayMiniGame (we'll do some modifications here)
snowboard_main - we'll do some modifications here too :P
get_actual_cc - function gets a memory address, and writes there the rdtsc results...
calculate_cc - function gets three memory addresses, subtracts the value in the second one from the value in the first one and writes the result to the third one :P
convert_cc_to_float - gets memory address and converts a hex-value stored there into the float-variable, stores it on the FPU's stack
frame_cap - ok... here ARE the functions responsible for frame-limiting of some modules of ff7 (field, menu, battle, submarine...) - explained below
extra_call - function returns the imm_benchmark value using EAX registry - we aren't exactly searching for this... we get the address from the highway_init function


Here is the first question: Can't we just use some of the existing frame-limiters? We can, but since they aren't optimized at all, and required some pre-call modifications... I decided to write my own (basing on the existing one of course :P). Then why do we search for those? We don't need the code, but we need some safe variables. By safe, I mean the variables which could be used freely. If we're playing HighwayMiniGame then we CAN use SubMarine variables, and we will :). We'll unpack the required variables from some function and hardcode it into our functions. Which function will we hijack? The 9th is the SubMarine frame-limiter and I think it's the best choice (you can always pick some other function, use the -hijack switch when using my patcher).

Immediates used when preparing the code:
Code: [Select]
imm_benchmark - value which stores the address of some MAIN variables... if we add 0x30 to this pointer we'd get a pointer to a value which contains the speed of our CPU in clock cycles (very importand value - VIV :P)
imm_highway - value which contains 1 if the HighwayMiniGame is running - we'll hijack that value too :P see below
imm_snowboard - same as imm_highway, just refers to SnowboardMiniGame
frame_cap - raw_pointer to our hijacked frame-limiting function
imm_old_cc - stores the old clock cycles count
imm_actual_cc - stores the actual clock cycles count
imm_cc_per_frame - imm_benchmark divided by the frame-rate - clock cycles per frame


After that, you can tell if the chosen frame-limiting function was a good one :P. Simply look at the imm_cc variables. If they are something like 0x<six digits here> and are similar, it was a good choice.

If the second part was successfull, patcher moves to the third section...

It'll "allocate" the free space for functions we need to inject into the *.exe file. If it happens, that there is enough free-space (to put our code) in the middle of the text segment it will do that (jumps at the beginning of each function will do the job if it was just a NOP-ed field inside of some bigger functions).

Functions to be injected:
Code: [Select]
frame_cap_main - function which will pause our game if the frame was processed to fast
frame_cap_init - function which will fill the imm_cc values with the initial data
highway_hijack - code which will handle calling the frame_cap_main and frame_cap_init functions
snowboard_hijack - same as above
We will use the imm_highway and imm_snowboard variables to check, if the frame_cap_init was called already. Since these values are BOOLEANS, we will change some code to use (for example) TEST EAX, 0x01 instead of TEST EAX, EAX. Doing that will allow us to use other bits (we'll take the second one :P). If our bit isn't set we call the frame_cap_init and set that bit. Simple isn't it?

We'll do the necessary CMPs in our hijack_functions and use the CMP field in the highway_main and snowboard_main to to our hijack_ones...

When the patch is completed, it's written into the file. At the end the patcher checks if SnowboardMiniGame needs patching (don't know if it's the only problem with that minigame...) and do that if necessary...

When the third step is completed successfully, the patcher creates a new patched file... And that's it... If you read that, you'll know that this patch is somehow flexible. It'll accept ANY version of ff7 as long as the needed functions aren't heavy-modified. If there are any questions/comments (there won't be any :P that's for sure) post them below.

dziugo