Into War

October 9, 2019

Categories: Software , Tags: DOS, Small

A friend recently let me know of a tiny program (opens new window) that runs a 3D scene with both audio and video. How tiny? The executable, a .com file, is 64 bytes in size (yeah, that's pretty damn small!), and the camera view is a flyover of a grassy field with a blue sky above. The audio is a single note played once, overlaid with the sound of a helicopter's whirring blades and a periodic swooshing noise that sounds like the wind. It seems too amazing to be real, especially when you've seen the video:

# DOSBox

Being inquisitive and skeptical, I decided to grab the code and try to run it in DOSBox (opens new window). Luckily, the developer had included a config file for DOSBox in his code archive. All I needed to do was install DOSBox and launch the binary.

First, installing software on Windows is a lot easier if we use Chocolatey (opens new window):

choco install -y dosbox

# Launching

Once DOSBox is installed, we just need to find out which folder it was installed to (C:\Program Files (x86)\DOSBox-0.74-3\) and figure our our command to run in powershell:

& "C:\Program Files (x86)\DOSBox-0.74-3\DOSBox.exe" -fullscreen -conf .\dosbox-0.74.conf -c "mount C ." -c "C:\"

The command line options above run DOXBox fullscreen (-fullscreen), load our custom config (-conf .\dosbox-0.74.conf), mount the current folder as the C drive (-c "mount C ."), and launch the binary from the C drive ("C:\").

This command can be dropped into a powershell script file in the same folder as the code, so that we can run it easily. Just create a file with a .ps1 extension (I used dosbox.ps1) and double click on the file to launch.

# What? How?

The important thing to realise here is that these 64 bytes of code are not creating a 3D environment with textured grass, sky and a soundtrack. The code uses a few clever tricks to fake these things. Each trick does something to either the screen or audio output, and when put together they end up giving the impression of a 3D flyover of a field.

Someone far cleverer than me has delved into what's going on (opens new window) over on Reddit. I recommend having a read of that comment to get a better idea of how it all works. However, ignore the thread's title - "3D animation with sound in 64 bytes of assembler" - as this is clearly not a proper 3D animation, but rather some graphical smarts that end up looking like a rendered 3D scene. It seems like a little bit of maths is used to create a single line of varying green colour pixels, wider than the screen, starting at the bottom of the screen. The lines are moved up the screen towards the "horizon", and scaled (shrunk) as they are moved up - giving the illusion of perspective. The lines of pixels only appear to change every few lines, which creates a checkerboard effect. Above this horizon the screen is simply painted blue. A new line of pixels is injected at the bottom of the screen each time a line is moved up, and the overall effect looks like a flat plane of grass heading off into the distance, with the movement of these lines of pixels giving the impression that the camera is flying over them.

The Reddit breakdown suggests that the audio is created from simply sending the code's own binary to the MIDI port. My suspicion there is that the coder just blindly tried this approach, and then when he found that the set of noises it made were reminiscent of a helicopter flying into battle, chose to name the program accordingly. This is a much more believable scenario than the idea that the code was somehow deliberately written in a way that was designed to make these particular sounds when fed to the MIDI port.

As far as my analysis is concerned, here's the code in hex (4 rows of 16 bytes), just to show that it's only 64 bytes:

14 13 BA 30 03 F3 6E CD 10 B8 4F 0C E6 40 E2 F7
1F 68 00 A5 07 B8 CD CC F7 E7 89 E8 80 EE F6 F6
F6 92 2C 7F F6 EA 02 16 6C 04 92 30 C6 F6 EE D4
09 9C 9D 2C 74 AA AF EB DC C9 38 99 46 67 51 7F

And here's the program loaded into the free version of IDA (opens new window) (16 bit import):

seg000:0000 ; Format      : Binary file
seg000:0000 ; Base Address: 0000h Range: 0000h - 0040h Loaded length: 0040h
seg000:0000                 .686p
seg000:0000                 .mmx
seg000:0000                 .model flat
seg000:0000 ; ===========================================================================
seg000:0000 ; Segment type: Pure code
seg000:0000 seg000          segment byte public 'CODE' use16
seg000:0000                 assume cs:seg000
seg000:0000                 assume es:nothing, ss:nothing, ds:nothing, fs:nothing, gs:nothing
seg000:0000                 adc     al, 13h
seg000:0002                 mov     dx, 330h
seg000:0005                 rep outsb
seg000:0007 loc_7:                                  ; CODE XREF: seg000:000E↓j
seg000:0007                 int     10h             ; - VIDEO -
seg000:0009                 mov     ax, 0C4Fh
seg000:000C                 out     40h, al         ; Timer 8253-5 (AT: 8254.2).
seg000:000E                 loop    loc_7
seg000:0010                 pop     ds
seg000:0011                 push    0A500h
seg000:0014                 pop     es
seg000:0015                 assume es:nothing
seg000:0015 loc_15:                                 ; CODE XREF: seg000:0037↓j
seg000:0015                 mov     ax, 0CCCDh
seg000:0018                 mul     di
seg000:001A                 mov     ax, bp
seg000:001C                 sub     dh, 0F6h
seg000:001F                 div     dh
seg000:0021                 xchg    ax, dx
seg000:0022                 sub     al, 7Fh
seg000:0024                 imul    dl
seg000:0026                 add     dl, ds:46Ch
seg000:002A                 xchg    ax, dx
seg000:002B                 xor     dh, al
seg000:002D                 imul    dh
seg000:002F                 aam     9
seg000:0031                 pushf
seg000:0032                 popf
seg000:0033                 sub     al, 74h
seg000:0035                 stosb
seg000:0036                 scasw
seg000:0037                 jmp     short loc_15
seg000:0037 ; ---------------------------------------------------------------------------
seg000:0039                 db 0C9h
seg000:003A                 db 38h, 99h, 46h, 67h, 51h, 7Fh
seg000:003A seg000          ends
seg000:003A                 end