Log in

View Full Version : How I cracked the iTunes 7 DRM, Pt V


Ring3 Circus
December 9th, 2007, 17:21
The story so far: Part 1 ("http://www.ring3circus.com/rce/how-i-cracked-the-itunes-7-drm-pt-i/"), Part 2 ("http://www.ring3circus.com/rce/how-i-cracked-the-itunes-7-drm-pt-ii/"), Part 3 ("http://www.ring3circus.com/rce/how-i-cracked-the-itunes-7-drm-pt-iii/"), Part 4 ("http://www.ring3circus.com/rce/how-i-cracked-the-itunes-7-drm-pt-iv/").
The remainder of this project consisted of developing the interface and injection DLL in parallel. This all went fairly smoothly, so I’ll present a summary of the workings.


Two programs are involved:

DLLBugger.dll - a C++ toolkit DLL designed for injection into iTunes. It sniffs out DRM keys as they are passed to the MP4-playing subroutine, exposes a variety of methods for inter-process communication, and invokes iTunes’s decrypter function when ordered to do so.
The peculiar name is something of a relic from the DLL’s twin program, who unfortunately didn’t make it this far.
DisaRM.exe - a C# GUI responsible for locating the iTunes process (launching it, if necessary), injecting DLLBugger, parsing the database, asking the user which tracks to unlock, and overseeing the decryption process as performed by DLLBugger within the iTunes address-space.

When launched, DisaRM immediately loads DLLBugger into its own address-space. Next, it launches iTunes.exe and acquires a handle to the process. From here DLLBugger is injected into iTunes. Having the DLL present in both processes makes for an ‘easy’ way to communicate data back-and-forth (using a shared PE segment). As it turned out, there was no need to use the Win32 debugging API and so DRMBugger.exe outlived its usefulness.
Because I had never written anything involving inter-process communication before, I was quite unprepared for the volume of work required to make this shared-segment approach successful. So it wasn’t before familiarising myself with semaphores and planning out how everything could be made to work with exchange limited to POD, that a rudimentary communication state-machine was implemented.
DLLBugger exports twelve functions:
Code:
bool CreateHooks(void* decrypt_call, void* decrypt_func,
void* cfw_call);

DWORD InjectMain(void *lpParam);

void* GetRemoteProcAddress(LPCSTR lpModuleName,
LPCSTR lpProcName);

bool KillRemoteThread(HANDLE hRemoteThread);

bool RemoteDecrypt(wchar_t* in_name, wchar_t* out_name,
RijndaelKey key);

RijndaelKey GetLastKey();

void SetStoredKey(RijndaelKey key);

void RemoveHooks();

long GetLastTrackFirstLength();

char* GetLastTrackFirstData(long* buffer_size);

WCHAR* GetLastAudioFileName();

bool PollNewFile();

Passing hard-coded addresses (I know, yuck), DisaRM invokes CreateHooks in the iTunes process. This installs hooks in Kernel32!CreateFileW, iTunes!Decrypt and iTunes!_PlayMP4+_CallToDecrypter (the point at which the previous function is called). Now any attempts to load a track or decrypt a chunk of AAC will be intercepted.
After DisaRM has loaded and displayed the protected subset of the iTunes library, the user chooses which tracks to unlock and hits the ‘Get Keys’ button. This triggers DisaRM to launch the first track into iTunes, causing a call to CreateFileW to be intercepted by the DLL. The arguments are stored and execution is allowed to continue. With this, DLLBugger has a good idea which track will be playing at any given time. Once iTunes has loaded the protected MP4 file, determined its decryption key and done whatever else it does, it necessarily makes a call to the Decrypt function. Naturally, this too is intercepted by our DLL and we begin to generate a mapping of file-names to DRM keys. Sanity checks exist in the form of GetLastTrackFirstLength, GetLastTrackFirstData, GetLastKey, and GetLastAudioFileName. Once the confidence level is high enough (as all this business is done asynchronously by iTunes and it isn’t safe to assume too much about the order of events) DLLBugger reports back to DisaRM, and the next track is launched. In this way, DisaRM learns the keys for each file it needs to decrypt.
Provided everything went smoothly, the DisaRM displays the keys alongside the track name, artist, album and such (this was initially useful for debugging purposes, but I left it in because it looks kinda cool). The user gets a chance to reconsider before hitting the ‘Remove DRM’ button. Because what DRM-removal tool would be complete without one?
The decryption process itself is relatively straightforward. A single call to RemoteDecrypt from DisaRM creates a new thread in iTunes, which opens up the MP4 file and parses the data to find the stbl atom. This part of the file lists the offsets and sizes of each chunk of AAC data (’cause they come in chunks, you know) among other things. For each chunk, the thread calls the Decrypt function, passing the appropriate offset, size and key. With the stream decrypted, some offensive atoms are removed and the file is made to look like it never had any DRM in the first place. DLLBugger saves the result to disk and that’s that.
I’ll take this opportunity to apologise to any Mac users who were hoping to learn something about the iTunes DRM from this series. Clearly, I didn’t reverse-engineer the protocol to any substantial degree and so none of the methods described port very far away from Windows XP. Maybe another time.

A few things were learned over the four weeks I spent. Here are just a few:


Writing an inter-process communication framework is not a task to be taken lightly, no matter how little of it you think you need.
C# is excellent for GUI development and awful at low-level hackery. But when you have a shiny new hammer, everything starts to look like a nail.
Over-engineering a solution is as bad as under-engineering it. I’m sure I could have saved myself a fortnight if I hadn’t bothered writing that debugger I didn’t need.
A profiler can be an excellent RCE tool. If I’d only thought to profile a few seconds of each of m4p and m4a playback, I could have isolated the decrypter function in minutes, rather than days.
QuickTime is horrible.
So that marks the end of this series of posts. I can assure you, though, that I haven’t nearly reached the end of the story.



http://www.ring3circus.com/rce/how-i-cracked-the-itunes-7-drm-pt-v/

JMI
December 9th, 2007, 18:33
Again, thanks for keeping this series coming.

Regards,

reverser
December 9th, 2007, 19:22
This was already done last year without any extra dlls.
http://hymn-project.org/forums/viewtopic.php?t=1553

xenakis
December 9th, 2007, 20:06
Thanks for this series, it has been delightful to follow along

@ reverser
If you would read Part I of the series, you would "discover" the following:

"As it happened, QTFairUse6 was released mere days after I produced a working prototype..."

So I don't think this is a pissing contest

JMI
December 9th, 2007, 20:13
And we appreciate the effort to do the work and to share it with our readers, whether or not someone else may have solved the problem and/or solved it using a different technique. The more solutions to a given problem, the more we learn.

Regards,

rendari
December 9th, 2007, 22:01
Quote:

A profiler can be an excellent RCE tool. If I’d only thought to profile a few seconds of each of m4p and m4a playback, I could have isolated the decrypter function in minutes, rather than days.


What exactly is a profiler? Am I missing something crucial here? :P

dELTA
December 10th, 2007, 04:07
It's a program that analyzes where in the code of another program the most execution time is spent etc.

http://en.wikipedia.org/wiki/Profiler_%28computer_science%29

rendari
December 10th, 2007, 22:23
Ahh, I see. Thanks