Camp Luna

I remember when the Mono people first announced the Moonlight project for Linux that would interoperate with Microsoft’s Silverlight. They claimed that Microsoft would release a special binary codec pack that would allow Linux users to play back their proprietary media codecs. However, this codec pack would not be allowed for use in any other application, like FFmpeg or GStreamer. How are they going to enforce that? Or so I wondered. Tonight I learned how.

I started investigating the API of the binary codec pack blobs a few weeks ago. I got as far as figuring out how Moonlight registers the codecs. Then I lost motivation, in no small part because there isn’t that much in the blob that I would deem interesting (perhaps one method for keeping people from sorting out the API). In the comments of the last post on the matter, people wondered if the codec pack included support for WMA Voice, which is still unknown. I can’t find any ‘voice’ strings in the blob. However, I do find references to lossless coding. This might pertain to Windows Lossless Audio, or it could just be a special coding mode for WMA3 Pro. Either way, I’m suddenly interested.

So I looked for interface points in the Moonlight source. Moonlight simply loads and invokes registration functions for WMA, WMV, and MP3. The registration functions don’t return any data that Moonlight stores. Moonlight doesn’t appear to load (via dlsym()) or invoke any other codec pack functions directly. So how can it possibly be interfacing? The only other way the interaction could flow is if the codec pack shared library was invoking functions in Moonlight…

Oh, no… they wouldn’t do that, would they?

…oh yes… they would…

$ ld silverlight-media-pack-linux-x86-5-1.so 
ld: warning: libmoon.so.0, needed by silverlight-media-pack-linux-x86-5-1.so, not found (try using -rpath or -rpath-link)
ld: warning: cannot find entry symbol _start; not setting start address
[...so]: undefined reference to `g_free'
[...so]: undefined reference to `g_memdup'
[...so]: undefined reference to `g_slist_free'
[...so]: undefined reference to `Media::Warning(int, char const*, ...)'
[...so]: undefined reference to `EventObject::SetSurface(Surface*)'
[...so]: undefined reference to `g_malloc'
[...so]: undefined reference to `EventObject::~EventObject()'
[...so]: undefined reference to `WMARawDecCBGetData'
[...so]: undefined reference to `g_slist_append'
[...so]: undefined reference to `g_strdup_printf'
[...so]: undefined reference to `OutputDebugString'
[...so]: undefined reference to `IMediaObject::Dispose()'
[...so]: undefined reference to `typeinfo for IMediaObject'
[...so]: undefined reference to `min'
[...so]: undefined reference to `g_realloc'
[...so]: undefined reference to `max'
[...so]: undefined reference to `Media::RegisterDecoder(DecoderInfo*)'
[...so]: undefined reference to `IMediaDecoder::IMediaDecoder(Media*, IMediaStream*)'
[...so]: undefined reference to `vtable for IMediaObject'

So the binary blob calls back into the calling library, thus forming a symbiotic interface which is at least partially in C++ to boot. This will make it significantly more challenging to subvert the codec.

I started on a program called camp-luna.c (inspired by this game), then camp-luna.cpp, to try to sort out the interface. Then I realized that this would most likely be a supremely silly endeavor to continue. As previously stated, the only halfway interesting, undiscovered target would be certain parts of WMA3, and we already have Linspire’s module (libwma3.so) for that. In fact, a lot of the strings from the Silverlight codec pack look strangely reminiscent. So much so that I dumped lists of strings from both files…

$ strings -a silverlight-media-pack-linux-x86-5-1.so > silverlight-strings.txt
$ strings -a libwma3.so > linspire-strings.txt

…then I wanted to look for all strings in common between the 2 files. I did a cursory Google search for any pre-made utilities but then just hammered out a naive Python script to do the same; common-strings.py:

Running ‘./common-strings.py silverlight-strings.txt linspire-strings.txt’ reveals 513 strings in common between the 2 modules, indicating that the 2 were clearly compiled from the same source code. Further, they both contain the same 4 symbols for dealing with some kind of lossless mode:

prvDecodeSubFrameChannelRawPCMPureLosslessMode
prvDecodeSubFrameChannelResiduePureLosslessModeVerB
prvDecodeSubFrameHeaderPureLosslessMode
prvDecodeSubFramePureLosslessMode

Always attack the weakest link. So, in the end, the best enforcement mechanism that the Silverlight codec pack has guarding against RE attempts is irrelevance.

7 thoughts on “Camp Luna

  1. Reimar

    I’m not sure it’s justified to assume these are anti-RE methods, it’s quite possible it is just honest bad design.

  2. Benjamin Larsson

    This pack might contain WMP2 support. WMARawDecCBGetData from libmoon would be of interest though. I need it to use wmavoice.

  3. Multimedia Mike Post author

    @Reimar: I know these aren’t specifically anti-RE methods; it’s mostly just coincidence. :-)

    @Mans: Simple shell tools come through again!

    @Benjamin: Is there evidence that the codec pack decodes WMA voice?

  4. Jonathan Wilson

    It may well be that the wierd design is intended to stop the codecs in the codec pack from being used for anything other than Moonlight playback of Windows Media files. AFAIK Microsoft (or the Moonlight people) specifically said when the codec pack was announced that the codec pack would only be licensed for use by Moonlight to play Windows Media files and not for other uses.

    Assuming that enough of Moonlight is open source, maybe someone needs to work on a project to wire up FFMPEG and its implementation of WM codecs to Moonlight so Moonlight will work without any MS binary blobs at all.

Comments are closed.