Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Topics - FF7ExpNeg1

Pages: [1]
1
FF7 Engineering Part I

On the first PSX FF7 disc there is a file in the root drive named SYSTEM.CNF (the .CNF might not be visible due to Windows).  This is just a plain text file that we can open in Notepad.  The first line contains the following:
Code: [Select]
BOOT = cdrom:\SCUS_941.63;1

This tells us that the PlayStation will launch the file SCUS_941.63 on boot.  If we look on the root of the disc we can see this file.

SCUS_941.63 happens to be a binary file that we can't really look at using Notepad.  We will write a simple Java program to display the binary data in a more readable form.  This code does just that:
Code: [Select]

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
public class HexDump {
public static void main(String[] args) {
if (args.length < 3) {
System.out.print("USAGE: java HexDump [filename] [start hex address] [num lines]");
System.exit(1);
}
File f = new File(args[0]);
if (!f.exists()) {
System.out.println("ERROR: File not found!");
System.exit(1);
}
RandomAccessFile in = null;
try {
in = new RandomAccessFile(f, "r");
} catch (FileNotFoundException e) {e.printStackTrace(); System.exit(1);}
long startAddress = 0;
int numLines = 0;
try {
startAddress = Long.parseLong(args[1], 16); //base 16, hexadecimal
numLines = Integer.parseInt(args[2]);
} catch (NumberFormatException e) {e.printStackTrace(); System.exit(1);}
try {
in.seek(startAddress);
} catch (IOException e) {e.printStackTrace(); System.exit(1);}
byte[] buf = new byte[16]; //one line of hexadecimal values
try {
for (int i = 0; i < numLines; i++) {
in.read(buf);
System.out.printf("0x%08X  ", startAddress);
StringBuilder ascii = new StringBuilder();
for (int j = 0; j < 16; j++) {
System.out.printf("%02X ", buf[j]);
if (buf[j] < 32 || buf[j] > 127)
ascii.append('.');
else
ascii.append((char)buf[j]);
}
System.out.print(" ");
System.out.println(ascii.toString());
startAddress += 16;
}
in.read(buf);
} catch (IOException e) {e.printStackTrace(); System.exit(1);}
try {
in.close();
} catch (IOException e) {e.printStackTrace(); System.exit(1);}
}
}


The program above can be compiled on the command line:
Code: [Select]
javac HexDump.java

Now make sure the command prompt's current working directory contains the SCUS_941.63 file.  We can now run the above program and look at the first few bytes of the boot file:

Code: [Select]
java HexDump SCUS_941.63 0 10

This produces the following:
Code: [Select]

0x00000000  50 53 2D 58 20 45 58 45 00 00 00 00 00 00 00 00  PS-X EXE........
0x00000010  C0 10 01 80 00 00 00 00 00 00 01 80 00 08 06 00  ................
0x00000020  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0x00000030  F0 FF 1F 80 00 00 00 00 00 00 00 00 00 00 00 00  ................
0x00000040  00 00 00 00 00 00 00 00 00 00 00 00 53 6F 6E 79  ............Sony
0x00000050  20 43 6F 6D 70 75 74 65 72 20 45 6E 74 65 72 74   Computer Entert
0x00000060  61 69 6E 6D 65 6E 74 20 49 6E 63 2E 20 66 6F 72  ainment Inc. for
0x00000070  20 4E 6F 72 74 68 20 41 6D 65 72 69 63 61 20 61   North America a
0x00000080  72 65 61 00 00 00 00 00 00 00 00 00 00 00 00 00  rea.............
0x00000090  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................


We can definitely see that this is a PlayStation executable by looking at the first line.  Lets now look at three important values on the second line (address 0x00000010).

The last four bytes are 00 08 06 00. All four byte integer values in this file are in little-endian format so to get a better look at a particular integer we need to byteswap it.  To do this we make the first byte the last, the second the third, the third the second, and the last the first.  Byteswapping the current four bytes we are looking at produces 00 06 08 00 or just 0x60800.  If we convert this to a decimal value we get the value 395,264.  

Hmmm, this is quite interesting.  Why?  Take a look at the size of SCUS_941.63: 397,312.  This is exactly 2048 byte (2k) difference.  We can make the safe assumption that a PlayStation executable header is 2k in length.  We can then reason that the PlayStation loads the data starting at offset 2k and with a length of 0x60800.  This would take us to the end of the file.  But where does it load the data to?

To answer this question let us look at the second to last four bytes on line two: 00 00 01 80.  If we byteswap these we get 0x80010000, which is a valid memory location on the PlayStation.

Once the the data is loaded in memory, execution must begin at some address.  For this we turn to the first four bytes of line two (byteswapped of course): 0x800110C0.  This is where execution of Final Fantasy 7 begins (well, not really, there is a ton of startup and initialization code).

This concludes part I.  In the next installment we will go through dis-assembling the first few MIPS opcodes. Feedback appreciated!

2
Scripting and Reverse Engineering / FF7 PSX Code Location
« on: 2005-09-25 05:05:45 »
Hello,

I have been digging into the PSX version of FF7 for about 10 days now.  I wrote a simple disassembler in Java to look at some of the code in SCUS_941.63 (the file on the root of disc 1).  Is there any MIPS code in other files on the disc, or does this file contain all of the executable code? (I know from reading gears.pdf that there is cross-platform script code in other files).

Thank you!
(This forum has a wealth of great information, keep up the good work!)

Pages: [1]