mirror of
https://github.com/mrkite/regs.git
synced 2024-06-09 17:29:28 +00:00
175 lines
8.5 KiB
Markdown
Executable File
175 lines
8.5 KiB
Markdown
Executable File
# What is this?
|
|
|
|
This is a set of command-line tools designed specifically to reverse engineer Apple IIgs software. It is comprised of 3 separate tools; `2mg`, `omf`, and `regs`.
|
|
|
|
|
|
|
|
## 2mg
|
|
|
|
`2mg` extracts .2mg and .po prodos disk images. You can also just list the contents of the disk image with the `-l` or `--list` command line argument. Otherwise, it will create a folder with the name of the disk and extract all the files into that folder.
|
|
|
|
|
|
|
|
## omf
|
|
|
|
`omf` is a rather complicated tool which is designed to extract relocatable segments from OMF files. Apple IIgs executables (.sys16 files) and system tools (ex. SYSTEM/TOOLS/TOOL025) are in OMF format.
|
|
|
|
You first run this tool and pass it an OMF file and it will generate a .map file. This map file is a simple text file that you may edit. Each line is in the format:
|
|
|
|
`segment:memory location`
|
|
|
|
The `segment`is the segment number from the OMF file, and `memory location` is where in memory to relocate that segment.
|
|
|
|
`omf` does its best to automatically pack all the relocatable segments into the smallest memory possible, starting at `$2/0000`. You can change the starting memory address with the `-o` or `--org` argument. If you wish to manually specify where each segment should go in memory, feel free to edit the .map file however you wish.
|
|
|
|
The next step is to run `omf` again, this time specifying the map file with `-m` or `--map`. This will apply the .map to the OMF and output each segment along with a corresponding .map file. `omf` will throw an error if the segments cannot be mapped as the .map file dictates (for example, you modified the map file so that the segments accidentally overlap).
|
|
|
|
`omf` will modify each segment, applying the proper relocations before outputting the segment. If you wish to change where a segment is in memory, you should modify the original .map file and re-run `omf`. The resulting output files will be hardcoded for those specific memory locations.
|
|
|
|
The segment outputs will be named `segX` and `segX.map`, where `X` is the segment number, in hex. If you wish to change the prefix from `seg` use the `-p` or `--prefix` argument.
|
|
|
|
At this point, you can use the resulting segment files and map files as input to the `regs` tool.
|
|
|
|
|
|
|
|
## regs
|
|
|
|
`regs`is my 65816 tracing disassembler. It can be used in conjunction with the .map files created by `omf` or on its own. Since it is a tracing disassembler, it will start disassembly at a given location, and keep disassembling, following all possible paths. Everything not disassembled will be assumed to be data and shown in a hex view.
|
|
|
|
|
|
|
|
#### regs by itself
|
|
|
|
You can call `regs` and simply pass it a binary file and it will attempt to disassemble it. You can specify where in memory it should load the file before disassembly with the `-o` or `--org` argument. You can also control whether or not the disassembler is in emulation mode or 16-bit mode with various command-line arguments. Emulation mode is also useful for disassembling 8-bit Apple II software. Use `-e` to start in emulation mode (default native mode), `-m` to start with an 8-bit accumulator (default 16-bit), and `-x` to start with 8-bit index registers (default 16-bit).
|
|
|
|
|
|
|
|
#### regs with .map files
|
|
|
|
`regs` with .map files is where the disassembler really shines. You can call `regs` and pass it a .map file generated by `omf` and have real control over the disassembly. The .map file is designed to be edited by hand. The format is as follows:
|
|
|
|
```
|
|
gMAP "seg1"
|
|
sORG $30000
|
|
$30000:
|
|
$30053:mx
|
|
$31066:e
|
|
```
|
|
|
|
The first line specifies the segment file that this map applies to. The filename in the quotes should be relative to the current directory.
|
|
|
|
The next line specifies where the segment belongs in memory. **Do not edit this** if the segment was created by `omf`, since it has also been hardcoded in the binary.
|
|
|
|
The next lines are a list of entry points to begin disassembly at. If, when analyzing the disassembly you find a switch case encoded as an indirect jump, you can take that list of jumps and add them to the map file and re-run `regs` to disassemble the previously un-disassembled data. As you work through a disassembly, you may end up with a map file with hundreds of entry points, that's normal.
|
|
|
|
The flags after the colon are optional, and specify whether emulation mode should be enabled, or 16-bit or 8-bit accumulator and index registers should be used. It defaults to native mode with 16-bit registers.
|
|
|
|
You can also use bank-separators if you wish. `$3/1066` is the same as `$31066`.
|
|
|
|
|
|
|
|
## Pascal folder
|
|
|
|
You'll notice a pascal folder in this repository. These are the original GS/OS pascal header files. This is to make it easier for you to look up the arguments and structures of various tool calls you'll come across when disassembling.
|
|
|
|
|
|
|
|
# Examples
|
|
|
|
The flexibility of these tools makes their use a little complicated. So here are some examples of how to go about disassembling various things.
|
|
|
|
### Disassembling an S16
|
|
|
|
I'll be using the S16 from Dream Zone as an example.
|
|
|
|
Generate a basic map of your S16:
|
|
|
|
`$ omf dream.s16`
|
|
|
|
This will create a file called `dream.s16.map`, which we could edit if we choose. We'll leave it as it is. Extract the segments of the OMF with:
|
|
|
|
`$ omf --map=dream.s16.map dream.s16 --prefix=dream`
|
|
|
|
This will create files `dream1`to `dream5` as well as `dream1.map` to `dream5.map`.
|
|
|
|
The program's entry point is always the beginning of the first segment, so we'll start there.
|
|
|
|
`$ regs dream1.map > dream1.s`
|
|
|
|
This will disassemble the entry point. We can then modify the map to further refine the disassembly if we wish.
|
|
|
|
|
|
|
|
### Disassembling a Tool
|
|
|
|
This works the same as disassembling an S16, but with an important difference.
|
|
|
|
We'll start the same, generating a map and extracting it.
|
|
|
|
```
|
|
$ omf TOOL025
|
|
$ omf --map=TOOL025.map TOOL025
|
|
```
|
|
|
|
Now, we'll remove all disassembly instructions from the map. You'll see why in a second. So we edit the map file to look like the following:
|
|
|
|
```
|
|
gMAP "seg1"
|
|
sORG $20000
|
|
```
|
|
|
|
That's it.. no disassembly instructions. Now we run the disassembler:
|
|
|
|
`$ regs seg1.map > seg1.s`
|
|
|
|
This will just give us a hex dump of the segment. That's actually what we want. All tools start with a tool table. The first dword specifies the number of tools in this toolset. The next dwords all contain addresses (minus 1) of the various tool entry points.
|
|
|
|
Let's say I want to disassemble NoteOn. We check the pascal folder and discover that it's tool $0b inside the $19 toolset. Which is the TOOL025 file we're working on (the tool numbers in the filenames are in decimal). So we calculate the offset to that entry point.
|
|
|
|
`$0b * 4 + $20000 = $2:002c`
|
|
|
|
If we look at the hex dump at that location we'll discover the entry point of NoteOn: `$2:02dd`. Well that's minus one, so we add the real entry point to the .map file:
|
|
|
|
```
|
|
gMAP "seg1"
|
|
sORG $20000
|
|
$2/02de:
|
|
```
|
|
|
|
And rerun the disassembler.
|
|
|
|
`$ regs seg1.map > seg1.s`
|
|
|
|
We have just disassembled the NoteOn function.
|
|
|
|
|
|
|
|
### Disassembling a Specific Tool Call in ROM
|
|
|
|
Let's say I want to disassemble WriteRamBlock. We discover it's in the sound toolset $08. If you search, you'll discover that there isn't a TOOL008 anywhere, so we'll have to pull it from ROM. I'll be using an older 128k ROM just because it's convenient.
|
|
|
|
First thing I do, is actually hand make a `rom.map` file for the ROM.
|
|
|
|
```
|
|
gMAP "APPLE2GS.ROM"
|
|
sORG $fe0000
|
|
$fe/0000:
|
|
```
|
|
|
|
and disassemble it.
|
|
|
|
`$ regs rom.map > rom.s`
|
|
|
|
This is actually the bootstrap that initializes the `$e1/0000` tool call entrypoint. I notice it copies over a block of memory from `$fe/0051` into `$e1/0000`. So we add `$fe/0051` to the disassembly list of the map file, and disassemble it again.
|
|
|
|
Following along with the disassembly, we discover that there's a toolset list starting at `$fe/012f`. It starts with a dword with the number of toolsets in the ROM, followed by a list of offsets to the various toolsets. We want toolset 8 for the sound toolset.
|
|
|
|
`$8 * 4 + $fe012f = $fe014f`
|
|
|
|
Look up the dword in that location and I find that the toolset is located at `$ff/3e00`. If you then jump to that location, you'll find this is in the exact same format as a tool on disk. It starts with a tool table. WriteRamBlock is tool 9.
|
|
|
|
`$9 * 4 + $ff3e00 = $ff3e24`
|
|
|
|
At that location, we discover the offset to the tool entry point is `$ff/41a4` so we'll add `$ff/41a5`to the map file and rerun the disassembly.
|
|
|
|
Boom, we have just disassembled a specific tool call from ram. |