Final Countdown - Amiga - Opening the binaries

 In the last post, we looked at the contents of the disk images for Final Countdown. The next part should be taking a look at the executables and try to extract the code to analyze. 

Quick recap: the first disk contains 3 executables: intro, zob and space. The first one is the cracker intro (this is the cracked version, after all). The startup sequence is running intro, then showing a text file, then running zob and space in sequence. We assume the intro binary only shows the intro and does nothing else to the system (this may be a wrong assumption, but it's simpler for now). So we have to analyze zob and space. 

The format for AmigaOS binaries is called Hunk. I searched the internet looking for a tool that dumped this format, without success. It's likely that such a tool does exist, but I couldn't find one. So I decided to write a tool to dump Amiga Hunk binaries. 

The format is specified in "The AmigaDOS Manual", Part 3 (AmigaDOS Technical Reference Manual), Chapter 2 (Amiga Binary File Structure). I'm interested in the executable code inside the binary, so my tool does not dump every type of data, only the code. 

Using this tool, let's take a look at zob:

$ ./amginspect zob
Amiga Inspect
Opening file zob ...
* Header check OK
* No calls to resident libraries found
* Hunk table size: 2
* First hunk: 0
* Last hunk: 1
* Total number of hunks in file: 2
* Memory size for hunk 0: 75
* Memory size for hunk 1: 1
========================================
* Dumping Hunk #0
----------
* Hunk block type: Code block
* Code block size: 75 long words = 300 bytes
** Code:
48 e7 ff fe 4d f9 00 df f1 80 41 fa 00 ba 43 f9
00 00 01 20 20 18 22 18 2a 18 24 49 d1 c0 d5 c1
20 20 b1 85 e2 88 66 02 61 76 65 32 72 08 76 01
e2 88 66 02 61 6a 65 4c 72 03 42 44 61 6e 36 02
d6 44 72 07 e2 88 66 02 61 56 e3 92 51 c9 ff f6
15 02 51 cb ff ee 60 38 72 08 78 08 60 de 72 02
61 4a b4 3c 00 02 6d 12 b4 3c 00 03 67 ea 72 08
61 3a 36 02 32 3c 00 0c 60 0a 32 3c 00 09 d2 42
54 42 36 02 61 26 53 4a 14 b2 20 00 51 cb ff f8
3c 88 b3 ca 6d 8e 4c df 7f ff 4e f9 00 00 01 20
20 20 b1 85 44 fc 00 10 e2 90 4e 75 53 41 42 42
e2 88 66 0a 20 20 b1 85 44 fc 00 10 e2 90 e3 92
51 c9 ff ee 4e 75 00 00 00 58 00 00 00 60 fa b3
67 55 18 81 01 a9 00 81 80 08 19 b6 24 03 26 08
08 10 f0 03 14 92 e3 95 70 97 3f fb f8 21 f0 07
34 28 61 e0 78 01 80 d2 90 13 33 81 80 57 30 03
30 80 61 f8 30 01 00 10 04 06 60 18 07 dc 78 0c
50 9f f9 39 97 df f7 fb 94 fa 41 63 50 f2 d8 8d
27 80 0d 07 2d 2d 00 00 00 10 00 00
----------
* Hunk block type: 32-bit relocation information
----------
* Hunk block type: End block of a hunk
========================================
* Dumping Hunk #1
----------
* Hunk block type: Uninitialized data block
** BSS block size: 1 long words = 4 bytes
----------
* Hunk block type: End block of a hunk
========================================

zob is composed of two hunks, the first one being a code hunk. The second hunk is a data block with only 4 bytes, probably used for a couple of variables. The code itself is only 300 bytes long, and this dump can be easily disassembled (which we'll do, but not now). It could be a loader or something else that sets the stage for the real executable, space. But in space no one can hear you scream, I mean, we hit trouble. Let's look at the dump:

$ ./amginspect space
Amiga Inspect
Opening file space ...
* Header check OK
* No calls to resident libraries found
* Hunk table size: 2
* First hunk: 0
* Last hunk: 1
* Total number of hunks in file: 2
* Memory size for hunk 0: 153
* Memory size for hunk 1: 25290
========================================
* Dumping Hunk #0
----------
* Hunk block type: Code block
* Code block size: 153 long words = 612 bytes
** Code:
4e f9 00 00 00 36 00 01 8b 20 00 00 a1 24 e3 0e
66 00 00 0a 1c 1c 00 3c 00 10 e3 16 4e 75 70 00
e3 0e 66 00 00 0a 1c 1c 00 3c 00 10 e3 16 e3 90
51 cd ff ee 4e 75 48 e7 ff fe 2e 3a ff ce 28 7c
00 00 00 00 4e b8 01 22 23 c0 00 00 00 02 2a 4c
20 4c d9 fa ff b2 58 8c 2f 0c d1 c7 19 20 53 87
66 fa 2e 3a ff a2 7c 00 61 a4 65 00 00 08 78 00
60 00 00 56 61 98 65 00 00 08 70 01 60 00 00 10
7a 01 61 9a b0 3c 00 03 67 00 00 12 54 00 28 00
53 80 1a dc 51 c8 ff fc 60 00 00 2e 7a 01 61 00
ff 7e b0 3c 00 03 67 00 00 06 5a 80 60 e0 7a 02
61 00 ff 6c b0 3c 00 07 67 00 00 06 50 80 60 ce
7a 0b 61 00 ff 5a 60 c6 9e 84 67 00 00 da 61 00
ff 3e 65 00 00 28 61 00 ff 36 65 00 00 10 7a 05
61 00 ff 3c 54 00 78 02 60 00 00 aa 7a 08 61 00
ff 2e d0 7c 00 42 78 02 60 00 00 9a 61 00 ff 10
65 00 00 08 78 03 60 00 00 58 7a 02 61 00 ff 10
b0 3c 00 01 6b 00 00 1a 67 00 00 08 54 00 60 00
00 3e 7a 06 61 00 fe f8 d0 7c 00 0a 60 00 00 30
61 00 fe dc 65 00 00 1a 7a 02 61 00 fe e2 56 40
9e 80 53 40 12 1c 1a c1 51 c8 ff fc 60 00 ff 1a
7a 02 61 00 fe ca 74 08 e1 6a 30 02 60 e2 28 00
61 00 fe ac 65 00 00 10 7a 07 61 00 fe b2 d0 7c
00 22 60 00 00 20 61 00 fe 96 65 00 00 0e 7a 04
61 00 fe 9c 54 00 60 00 00 0c 7a 08 61 00 fe 90
d0 7c 01 22 26 4d 97 c0 9e 84 53 44 1a db 51 cc
ff fc 60 00 fe c4 24 5f 2c 78 00 04 20 3c 00 00
04 b0 72 01 4e ae ff 3a 26 40 2c 00 28 7c 00 00
00 00 7e fc 3f 3c ff ff 22 4a 58 47 20 1c 67 00
00 56 b0 bc 00 00 03 e9 66 00 00 1a 42 ac ff fc
20 0c e4 88 22 80 22 4c 20 1c 26 cc e5 88 d9 c0
60 00 00 1a b0 bc 00 00 03 ea 67 e0 20 1c 26 ca
72 00 60 00 00 04 24 c1 51 c8 ff fc 20 1c b0 bc
00 00 03 f2 67 b4 2f 0c 3f 07 20 1c 67 ee 52 80
e5 88 d9 c0 60 f4 42 91 24 46 30 1f 6b 00 00 20
2a 72 00 00 28 5f 2e 1c 67 f0 20 1c e5 88 2c 32
00 00 20 1c dd b5 08 00 53 87 66 f6 60 e8 22 4a
20 3c 00 00 04 b0 4e ae ff 2e 4c df 7f ff 60 00
fd a0 00 00
----------
* Hunk block type: 32-bit relocation information
** N1: 2
** Hunk number 1: 1
** Offset 0: 00 00 00 40
** Offset 1: 00 00 01 be
** N2: 2
** Hunk number 2: 0
** Offset 0: 00 00 00 02
** Offset 1: 00 00 00 4a
----------
* Hunk block type: End block of a hunk
========================================
* Dumping Hunk #1
----------
* Hunk block type: Initialized data block
** Data block size: 10313 long words = 41252 bytes
----------
* Hunk block type: End block of a hunk
========================================

Just like zob, space has only two hunks, the first one being a code hunk and the second one a data hunk. The trouble is that the code block is only 612 bytes long. It's much too small to be the whole code for the game. Where's the code then?

The data hunk is 40kb of initialized data, that is, it's not space reserved for variables but static data already included in the binary. We know the disk images have separate files for sounds, graphics, and even the game text, so I don't think this data hunk includes any of it. My guess is that the data hunk is compressed code. In order to save space on the disk, the executable was compressed. At runtime, either zob or the small 612-byte code at the start of the file decompresses the code and runs it. 

So we really have to disassemble and analyze zob and the small amount of code at the start of space to know. This is the next step.  

Comments

Popular posts from this blog

How many instructions per frame?

Reference on D88 disk image format