Qhimm.com Forums
Miscellaneous Forums => Scripting and Reverse Engineering => Topic started by: Marco on 2005-11-17 14:51:16
-
I managed to dissasemble the FF7 executable ("only" 105 MB or so) and now I'd like to re-assemble it. Would anyone be able to walk me through it?
So far I've just tried masm32 version 8 but it don't want to do it.
ff7n.asm(60) : error A2085: instruction or register not accepted in current CPU mode
ff7n.asm(66) : error A2066: incompatible CPU mode and segment size
ff7n.asm(69) : error A2085: instruction or register not accepted in current CPU mode
....
ff7n.asm(217) : fatal error A1012: error count exceeds 100; stopping assembly
-
Probably the CPU mode hadn't been set, but...
Aren't those errors kind of... self-explanatory to you? If not: What are you going to do with the code you've "obtained"? Change it? Not knowing the assembly language?
dziugo
-
I'm guessing that he probably "reversed" the program by doing some kind of object dump. I'm pretty sure that he didn't follow any functions or bother to figure out what exactly is going on in the program.
Here a tip: Object dumps most often can't be reassembled again, don't bother trying.
The code has been very optimized, also one can easily add code to loop up an object dumper so it spits out bad machine code.
Here's a test, pick a function, any function in your "reversed code" and tell me how the inherited data from the parent class is handed off.
If you reversed the code, and the fact FF7 is written is C++, finding classes should be a piece of cake. Right?
We need more people to identify functions in the code so we can see how it works. Trying to recompile fowled object dumps does nothing.
-
I was pretty sure Final Fantasy® VII was written in C.
Also, I have identified all the functions related to loading battle animations, but lost most of that information because I stored it as comment information inside Memory Hacking Software (so it would be easily portable) but, being the author of the software and having to run debug sessions and find problems with it on my own, I eventually made some errors that forced me to delete those files.
I have a few left on paper but I will have to look for them tomorrow.
I am at work now.
L. Spiro
-
No clue if I've done it correctly. Probably not.
Anyway I've "traced" some damage calculating function down to 005C79C0. As usual there.
push ebp
mov ebp, esp
sub esp, 14h
mov eax, [ebp+arg_0]
xor ecx, ecx
mov cl, [eax+5]
push ecx
mov edx, [ebp+arg_0]
push edx
call Calc_Dam1
add esp, 8
mov [ebp+var_C], eax
mov eax, [ebp+arg_0]
xor ecx, ecx
mov cl, [eax+5]
add ecx, 1
push ecx
mov edx, [ebp+arg_0]
push edx
call Calc_Dam1
add esp, 8
mov [ebp+var_8], eax
mov eax, [ebp+var_C]
imul eax, 64h
mov ecx, [ebp+arg_0]
xor edx, edx
mov dx, [ecx+24h]
mov ecx, edx
cdq
idiv ecx
sub eax, 64h
mov [ebp+var_14], eax
mov edx, [ebp+var_14]
push edx
call Calc_Dam2
add esp, 4
mov [ebp+var_10], eax
mov eax, [ebp+arg_0]
xor ecx, ecx
mov cx, [eax+24h]
mov [ebp+var_4], ecx
mov eax, [ebp+var_8]
sub eax, [ebp+var_C]
mov edx, [ebp+var_10]
xor ecx, ecx
mov cl, byte_98E6C4[edx]
imul eax, ecx
cdq
mov ecx, 64h // Defense calculation?
idiv ecx
mov edx, [ebp+var_4]
add edx, eax
mov [ebp+var_4], edx
cmp [ebp+var_4], 270Fh // damage cap check
jle short loc_5C7A62 // if less then 9999 skip next step
mov [ebp+var_4], 270Fh // otherwise set damage to 9999
loc_5C7A62:
mov eax, [ebp+arg_0]
mov cx, word ptr [ebp+var_4]
mov [eax+24h], cx
mov esp, ebp
pop ebp
retn
I thought I'd get the thing to compile back before I started investigating what goes on to verify that I do have the correct set of data.
-
if you have disassemble it, most likely it will be decompiled into assembly.
Since a compiler converts all the high level code (c/c++ etc) into assembly/machine code (older systems).
So there is no notable way to go back to high level code with out first understanding assembly ?
-
No clue if I've done it correctly. Probably not.
Anyway I've "traced" some damage calculating function down to 005C79C0. As usual there.
push ebp
mov ebp, esp
sub esp, 14h
mov eax, [ebp+arg_0]
xor ecx, ecx
mov cl, [eax+5]
push ecx
mov edx, [ebp+arg_0]
push edx
call Calc_Dam1
add esp, 8
mov [ebp+var_C], eax
mov eax, [ebp+arg_0]
xor ecx, ecx
mov cl, [eax+5]
add ecx, 1
push ecx
mov edx, [ebp+arg_0]
push edx
call Calc_Dam1
add esp, 8
mov [ebp+var_8], eax
mov eax, [ebp+var_C]
imul eax, 64h
mov ecx, [ebp+arg_0]
xor edx, edx
mov dx, [ecx+24h]
mov ecx, edx
cdq
idiv ecx
sub eax, 64h
mov [ebp+var_14], eax
mov edx, [ebp+var_14]
push edx
call Calc_Dam2
add esp, 4
mov [ebp+var_10], eax
mov eax, [ebp+arg_0]
xor ecx, ecx
mov cx, [eax+24h]
mov [ebp+var_4], ecx
mov eax, [ebp+var_8]
sub eax, [ebp+var_C]
mov edx, [ebp+var_10]
xor ecx, ecx
mov cl, byte_98E6C4[edx]
imul eax, ecx
cdq
mov ecx, 64h // Defense calculation?
idiv ecx
mov edx, [ebp+var_4]
add edx, eax
mov [ebp+var_4], edx
cmp [ebp+var_4], 270Fh // damage cap check
jle short loc_5C7A62 // if less then 9999 skip next step
mov [ebp+var_4], 270Fh // otherwise set damage to 9999
loc_5C7A62:
mov eax, [ebp+arg_0]
mov cx, word ptr [ebp+var_4]
mov [eax+24h], cx
mov esp, ebp
pop ebp
retn
I thought I'd get the thing to compile back before I started investigating what goes on to verify that I do have the correct set of data.
Hmmmm let me take a stab at making some C based code from this...
typedef struct
{
UINT8 ZZ0[5];
UINT8 ZZ5;
UINT8 ZZ6[30];
UINT16 ZZ24;
} Record;
fnc_n(Record *arg_0,
{
int var_C;
var_C = Calc_dam1(arg_0, arg_0->ZZ5);
var_8 = Calc_dam1(arg_0, arg_0->ZZ5 + 1);
var_14 = ((var_C * 100) / arg_0->ZZ24) - 100;
var_10 = Calc_dam2(var_14);
var_4 = arg_0->ZZ24;
var_4 += AZZ0[var_8 - var_C]/100;
if(var_4 > 9999)
var_4 = 9999;
arg_0->ZZ24 = var_4;
}
That's my current guess :)
Cyb
-
Well, it was something like that I imagined it. So if this is correct we can be rather sure that var_4 is used to hold a temporary damage value, and the value gets copied into a struct that the calling function supplies, thus I believe this function does something else besides just calculating damage, as the straight way would be to just return it in EAL or AX.
-
I was pretty sure Final Fantasy® VII was written in C.
Also, I have identified all the functions related to loading battle animations, but lost most of that information because I stored it as comment information inside Memory Hacking Software (so it would be easily portable) but, being the author of the software and having to run debug sessions and find problems with it on my own, I eventually made some errors that forced me to delete those files.
I have a few left on paper but I will have to look for them tomorrow.
I am at work now.
L. Spiro
Nope it's C++. Look at Gears, I have a partial source listing in the back
-
Definitely C++, yes. The code itself is something like 95% C (the legacy of the PSX version) and 5% C++ (DirectX interface etc.). It's all compiled with a C++ compiler though (MS Visual C++ 6.0 I think).
-
Yeah, you can see traces of code generated from OO design models, so I believe it should have been written in C++
-
Wouldn't it be easier to disassemble the PSX version since there would be no DirectX C++ and could easily be run through an emulator?
-
That would entirely depend on how familiar you are with PSX disassembly (I forgot the name of the CPU), and the quality of the tools available.
-
That would entirely depend on how familiar you are with PSX disassembly (I forgot the name of the CPU), and the quality of the tools available.
The PS1 uses a MIPSR3000 CPU there are plenty of excelent disassemblers for this.
In fact there are a lot of good tools for the R3K in general.
I won't mention any specific tools because that is kind of gray.
Cyb
-
Has anyone succesfully recompiled the program?
-
Doesn't look like it it.
What about extracting/decompressing the executable? Is there any program that can handle that?
-
What about extracting/decompressing the executable? Is there any program that can handle that?
What about you tell us: Why (...) would you do that?
dziugo
-
I belive that if I do get it uncompressed and fully working, then I could see the disassembled source code.
While it may or may not be possible to reassemble, the data available should be accurate enought to start checking out how the game works.
-
You can already do exactly what you are trying to do with any debugger available.
And if you don’t know how to use one, there is no reason to think you would know what to do with recompiled assembly using the method you are trying already.
A debugger (with disassembler) already shows you the disassembled “source code†with the same detail you would get from recompiling assembly output.
Especially considering function and symbol names have been stripped and you don’t get them back using your method.
Run the game in a debugger if you want to see how it works.
The code for the game comes shipped with every copy of the game.
L. Spiro
-
You do have a point :/
Anyway I think I did manage to get a program to extract the file.
Just in case someone didn't know this, the executable seems to assume that it's named ff7.exe. It only works properly under that name.
I don't yet know if it's correct, but at least the decompiler picks it up as a Visual C project.
-
thats incorrect, I have 2 FF7.exe's
1 is named FF7widescreen.exe which has The Saint's Hires patch
2 is named FF732TNT.exe which has the 32bit patch applied.
The ONLY time I rename them back to FF7.exe is to use it with FF7music