CVE-2011-3441
CVE-2011-3246
A series of regex-writing challenges.
A series of XSS challenges: here's some unsafe code; exploit it! Shortest code wins.

My CSS-fu is weak; please use a recent browser.

Some rights reserved.

Random, semi-related image by Lounger.

Spotify vs OllyDbg

Spotify for Windows contains code so awesome that OllyDbg can't look at it without crashing.

The protection exploits, among other things, a Borland library bug that apparently has gone undetected since 1991. Let's start at the beginning.

If you haven't seen it, Spotify is a music player similar to iTunes, except that it uses a massive distributed music library. It's ad-supported (banners + occasional radio ads), but comes with a nice party mode: If you're using it as a jukebox for your party, you can pay a token $1 to disable the ads for the day.

OllyDbg is a lovely Windows debugger written by Oleh Yuschuk.

For some reason, they trust Mac users

The Macintosh version of Spotify has no anti-debugger protection at all, which is extremely odd for a product like this. It even logs readable debug output directly to the console, so you can pinpoint e.g. the ad loading routines using nothing but dtrace:

sudo dtrace -n 'syscall::write*:entry /execname == "Spotify" && arg0 == 2/ 
   { trace(copyinstr(arg1)); ustack(); }'

This prints a stack trace every time something is written on stderr. Just by looking at the stack traces, you can get a reasonable overview of what is going on:

"Found audio ad"

libSystem`write+0xa
libSystem`__sfvwrite+0xac
libSystem`fwrite+0x74
Spotify`0x71db6
Spotify`0x720fe
Spotify`0x71e5a
Spotify`0x71a9b
Spotify`0x71b48
Spotify`0xb461b
Spotify`0xab0d2
Spotify`0xab1fc
Spotify`0xebf68
Spotify`0x64ee4
Spotify`0x65bf7
Spotify`0x669a3
Spotify`0x66e05
Spotify`0x13051
Spotify`0x44ba1
Spotify`0x4b48b
Spotify`0x7ea8e

"Found banner ad"

libSystem`write+0xa
libSystem`__sfvwrite+0xac
libSystem`fwrite+0x74
Spotify`0x71db6
Spotify`0x720fe
Spotify`0x71e5a
Spotify`0x71a9b
Spotify`0x71b48
Spotify`0xb461b
Spotify`0xab0d2
Spotify`0xab1fc
Spotify`0xedc6a
Spotify`0x125a0
Spotify`0x130fe
Spotify`0x44ba1
Spotify`0x4b48b
Spotify`0x7ea8e
Spotify`0x7e9ec
Spotify`0x6ea6

Some other message

libSystem`write+0xa
libSystem`__sfvwrite+0xac
libSystem`fwrite+0x74
Spotify`0x71db6
Spotify`0x720fe
Spotify`0x71e5a
Spotify`0x71a9b
Spotify`0x71b48
Spotify`0xb461b
Spotify`0x107fd5
Spotify`0xb4a79
Spotify`0xce3db
Spotify`0xce587

The blue part is common to every log entry. Presumably the entries in the 0x71000 range correspond to the printf family of functions, the function at 0xb461b is a custom log() function, and the red part is ad-related :)

On Windows

On Windows, it's an entirely different matter. The application is suitably paranoid, and merely starting a debugger on the same machine is enough to make it run for cover.

The first stage of the loader is a simple xor/add decryption loop.

First decryption loop

Being lazy, you could try stepping through it using OllyDbg. If you do, an interesting thing happens. As soon as you try to step through the jump to the newly-decrypted code, OllyDbg locks up. If you go back and try again, it turns out you don't actually have to run the decrypted code for it to crash; merely looking at it is enough. The application hasn't accessed anything outside of its own memory space yet, so it shouldn't be able to influence the debugger. Maybe some obscure opcode sequence is able to throw Olly's disassembler into an infinite loop?

If you suspect a bug in your debugger, the obvious thing to do is to debug it. Now, if you try loading a copy of Olly into Olly, then loading Spotify into the innermost debugger, something rather baffling happens: Both debuggers crash. In fact, you can crash a whole stack of debuggers at once.

The Medusa float

By having a disassembly window open while stepping through the decryption routine, you can narrow it down to a single float-point constant which apparently is impossible to display (this screenshot is from the patched version of OllyDbg):

"Dangerous" floating point constant (in Spotify)

The crash happens in this routine, which is supposed to convert an 80-bit floating point number (long double) into an unsigned 64-bit integer (long long):

Float-to-int conversion routine (in OllyDbg)

In pseudo-C, the routine does something like this:

// convert a float to an unsigned integer, given 0 <= float < 2^64

void float80_to_uint64(float80* in_ptr, uint64* out_ptr) {
   if (float < 2^63) {
     // the number won't overflow, so it's safe
     // to use a signed conversion
     float80_to_int64(in_ptr, (int64*) out_ptr);
   } else {
     // 80-bit floats have an explicit 1 in the mantissa, so we can just
     // copy the raw bits if the exponent is exactly 63
     *out_ptr = *(uint64*)in_ptr;
   } 
}

... where the float80_to_int64 subroutine is implemented using the FIST instruction, which raises a floating point exception if the number does not fit into a signed 64-bit integer.

The red comment, of course, is wrong. An 80-bit float has 64 bits of precision, so with an exponent of 63 it is possible to pass in a value of

2^63 - 0.5 = 111111111111111111111111111111111111111111111111111111111111111.1

... which, while intially less than 2^63, will round up to 2^63 when converted to an integer. That number is not representable as a signed 64-bit int, and the FPU throws an exception. The debugger dies, and since the bad number is still on the FPU stack, it is able to kill the next debugger as well.

To see it in action, try setting one of the FPU registers to 403D FFFFFFFF FFFFFFFF hex. As soon as the last character is typed, the debugger dies:

Try this at home

The faulty routine is actually part of the run-time libraries shipped with the Borland C++ compiler. To verify, you can compile the following program with bcc32 and watch it crash in printf().

The middle window shows the result as compiled with GCC; the right shows the buggy version: One bit of accuracy is lost in the conversion, and the last printf() crashed.

A workaround

Load OllyDbg in itself, and search (Ctrl-S) for the instruction sequence

fld [ra]
fistp [rb]

When you find this routine,

Original float-to-int routine

... replace it with something like

Patched float-to-int routine

The and will clear the least significant bit of the float before doing the conversion, narrowly avoiding the bad case.

To make room for the added code, the patch exploits the fact that the function is called with input and output to the same buffer, so the last 5 lines of the original are unnecessary.

Comments

Wow, nice catch mr! And thanks for a very interesting read. (there are btw a few open source Spotify libraries and applications out there, though inofficial, just checkout http://despotify.se) I could hook you up with some Hex-Rays images of how that routine used to look like some months ago if there was just an email I could reach you on.
— bugtraq.org 2009-05-26
The loader is Themida but judging from your debugger sk1llz you already know this..
— ;ppPPppPpp 2009-05-26
That's some fascinating stuff. Great writeup. I always love seeing the nuts and bolts of stuff explained, especially in a writing style that makes it read like an interesting short story.
— Unindignant 2009-05-26
I would guess that the reason for this is that it was written on windows or by someone who write noid code for windows. When it was ported to mac, the care wasn't necessary. Or the mac dev is a lazy hippy. :)
— JT in MI 2009-05-26
Reading this reminded me of the copylock protection scheme from way back. Good times.
— I fought the lock and I won 2009-05-26
[Nice. Apparently you can still buy it!]
You sir are insane, and insane people can't write flawlessly. Did the ads really bother you that much?
— Josh 2009-05-26
[Not really. It's just for fun.]
This is ridiculous! How do you know how to do this? Good sleuthing.
— Alfonscius 2009-05-26
[If I had known, it wouldn't be any fun.]
you are awesome :)
— Somebody who's impressed. Good article! Thanks 2009-05-27
Grats on rediscovering a known/public anti-debugging trick. It's used by Themida <which BTW is what Spotify is now protected with>. You can google some things like "spotify themida" or take a look at: [link] Also, your text editor won't let me use a closing parenthesis.
— Huhu 2009-05-27
[Text editor?! It's your browser!]
Doesn't surprise me. I have never seen an ad on spotify. I don't know why, because I've never paid anything. I even looked for an ad, but still nothing.
— Scogle 2009-05-27
[They seem to come in waves. I didn't see anything for the first few weeks.]
<BODY ONLOAD=alert('lmao')<
— Aussie 2009-05-27
[Really? Well, at least you didn't try to end it with an </alert> tag like the last guy.]
Reminds me of some magic numbers and 'unlikely' instruction combos that would make pentiums lockup.. guess how they found those out?
— 2009-05-27
You might want to check out the related reddit discussion at: [link]
— Anonymous 2009-05-27
[Thanks, I noticed :-) I was more surprised to find that someone had posted this to the scifi reddit.]
I would have just paid the $1 token to remove the adds...
— One with common sense 2009-05-27
[Now where's the fun in that?]