I have a project where I am trying to 'stream' a DOS game, working in DOSBox on Ubuntu. The idea is to take screenshots of the screen, then upload these to a server. To take screenshots from DOSBox, I use xdotool to trigger the key combination "Ctrl+F5", which triggers a screen capture. The screenshot is then saved into the /capture folder, from which I can read the file.
The problem is that the screenshots are named progName_000.png, progName_001.png, ... I would prefer that a single file is overriden. Is it possible to achieve?
Currently I am using the horrendous bash code below:
WID=`xdotool search --limit 1 --name "DOSBox" 2>/dev/null`
while [ 1 ]; do
fN=`ls ./DOSBox/capture/ | head -1`
cp ./DOSBox/capture/$fN ./img.png
rm ./DOSBox/capture/*
xdotool key --window $WID Ctrl+F5
sleep 0.10;
done
Every 100 ms, I read the capture file, take the first file that I encounter, copy it to ./img.png, and clear the capture folder, and take another screenshot. What is a better alternative?
(P.S: The above code is simplified; normally I copy the captured images to more than one image; img0.png and img1.png, so that while one is being written on, the other can be read, like page flipping. Anyway.)
I found a solution by tampering with the compiled DOSBox binary directly. I could have edited the source and simply built the project, but where is the fun in that?
The binary file is in /usr/bin/dosbox. I opened gdb
in a terminal as root and wrote
gdb -write -silent /usr/bin/dosbox
This is the solution for my DOSBox 0.74 binary, compiled for Ubuntu 14.04.
First, the screenshot filenames include a 3-digit number, such as 'whatevs_000.png'. It was likely that the filename was constructed as a string using the sprintf
function call, using a format string that included either %3d
or %03d
. A lucky search with objdump -s /usr/bin/dosbox | grep "\%03"
revealed that the string "%s%c%s%03d%s"
was indeed stored at 0x5fa9c7
.
After setting a hardware access watchpoint with awatch *0x5fa9c7
, I run
ned the program in gdb
(several continue
s might be required). Once the DOSBox boots, I used Ctrl+F5 to take a screenshot and trap the program at the instruction in the sprintf function. After several up
s, I was in the main program flow (address 0x4a9949
). disass
ing upwards, I discovered a for
loop that had standard library calls to achieve directory listing. I detected the entry point of the loop (using two continue
statements in the loop, which I verified later by checking the source code), and replaced the for-loop termination statement (0x4a9854) with an unconditional jump to the end of the loop (0x4a9908) as below:
set write on
set *(unsigned char*)0x4a9854 = 0xeb Short jump to 0x4a98d4
set *(unsigned char*)0x4a9855 = 0x7e
set *(unsigned char*)0x4a9856 = 0x90 Fill the remaining
set *(unsigned char*)0x4a9857 = 0x90 bytes of the previous
set *(unsigned char*)0x4a9858 = 0x90 instruction with NOPs
set *(unsigned char*)0x4a9859 = 0x90 because why not
set *(unsigned char*)0x4a98d4 = 0xeb Short jump to 0x4a9908
set *(unsigned char*)0x4a98d5 = 0x32
(I make two short jumps to jump over a longer range because this is the only opcode I could remember by heart and I am too sleepy to Google the rest)
After this point, DOSBox always overrides filename_000.png
, filename
being the name of the binary being emulated.