I spent
the whole weekend looking for a DRM-encumbered Sony CD so that I could check
for myself whether my code was really being redistributed without permission.
I eventually found one: Suspicious Activity?, by The Bad Plus. A rather
enjoyable post-modern jazz album. I am rather lucky, it could have been
C line Dion.
As expected, installing the CD s custom player also installed a stealth
aries.sys driver along with a few other interesting files such
as $sys$DRMServer.exe, all hidden in a $sys$filesystem
directory. I rapidly got rid of this cruft and started studying the really
important file, ECDPlayerControl.ocx.
It is the file Sebastian Porst and Matti Nikki found to be containing parts of mpglib, LAME, faad2, VLC...
Evidence that the DRMS code comes from VLC
There are of course obvious similarities between some functions and
structures of ECDPlayerControl.ocx and the ones in VLC s source.
However, given how precise the implementation of a cryptographic protocol
needs to be, the possibility that two separate implementations show many
similarities must not be dismissed. The data structures and constant tables
especially are likely to be identical. I think however that I found strong
enough evidence that this is not the case here.
The original drms.c was written by Jon on 01/05/04. I then hacked on that file on 01/18/04 and reorganised it, also replacing the reverse-engineered MD5 and AES functions with clean implementations, then Jon added DRMSv2 support on 05/05/04 and I reorganised the code again on 05/08/04. Some of these changes were specific to VLC (not in that they made the code unusable outside of VLC, but rather that they made it possible to use an external MD5 hash provider, for instance), so they were the bits I was looking for in ECDPlayerControl.ocx.
For instance, Jon s original code had the following instruction:
Since all bytes of this long word are comprised between 0x20 and 0x7f, it was later rewritten like this:p_acei[ 4 ] = 0x5476212A;
This change makes the code more human-readable because many other secrets in the Apple DRMS protocol are ASCII strings. Also, I know how to look for binaries that use the string "Tv!*", but it takes me some more time to think of a way to find binaries that use 0x5476212A. And the Sony rootkit uses the following (only relevant lines shown):char p_secret1[] = "Tv!*";
The use of xxxxx+4 shows that ECDPlayerControl.ocx uses a string instead of a 32 bits integer to store the secret, disregarding the fact that the 5th character of the string (a null char) is never used. Another example: in this commit I reorganised the DoExtShuffle() function, merging FourthPass() and FifthPass() and discarding a structure allocated on the stack. What is important here is that DoExtShuffle() was built by a complex combination of choices, the main purpose of which being to reduce the size of the C functions:.text:100883B8 mov cl, byte ptr ds:xxxxx+4 ; 0 .text:100883C2 mov eax, dword ptr ds:xxxxx ; "Tv!*" .text:100883C8 mov [esp+70h+yyyyy], eax .text:100883DC mov [esp+7Ch+zzzzz], cl
Note how i_ret is not reused and could be merged into the p_bordel array, or maybe SecondPass() merged into FirstPass(). This choice is definitely a legacy of how the code evolved. And the Sony equivalent: a perfect match.static void DoExtShuffle( uint32_t * p_bordel ) uint32_t i_ret; i_ret = FirstPass( p_bordel ); SecondPass( p_bordel, i_ret ); ThirdPass( p_bordel ); FourthPass( p_bordel );
After having studied the Sony code for a while, I have of course gathered dozens of such examples. But I also discovered a few new things. Where does the DRMS code come from? The code undoubtedly comes originally from VLC, but it has traveled a lot. I would be surpried if it came directly from VLC, as no other part of VLC is included with the rootkit. And although there are parts of FAAC in the Sony code and FAAC includes VLC s drms.c, the version currently in the FAAC CVS is horribly outdated. Sebastian Porst also noticed a few obvious differences between the Sony code and the version of drms.c present in VLC. The most obvious being this one:.text:10089F3C xxxxx: .text:10089F3C mov ecx, esi .text:10089F3E call yyyyy .text:10089F43 push eax .text:10089F44 mov eax, esi .text:10089F46 call zzzzz .text:10089F4B add esp, 4 .text:10089F4E call ttttt .text:10089F53 call uuuuu
Which became:if( p_shuffle->i_version == 0x01000300 ) DoExtShuffle( p_bordel );
That 0x01000400 is a version check for 4th generation iPods firmwares. I also discovered at least 40 KB of new lookup tables that seem to be used for more buffer shuffling. At first I thought it was simply F4I s DRM implementation, but the shuffling calls are nested with iPod hardware information retrieval from our DRMS code, so they re really part of drms.c. Sony distributing a DRMSv3 descrambler? The only explanation I can think of is that someone took the VLC code, added support for an upcoming Apple DRMS format version and redistributed the software without letting the VLC authors know, probably violating the GPL (I only say that because I have not found the software yet, but I feel pretty safe in saying it). Since it is based on GPL software, I was already entitled to ask Sony for the source code of ECDPlayerControl.ocx. But as the copyright holder of a significant part of the software they counterfeited, maybe I have a greater chance of being heard. Not that it would be difficult to reverse-engineer it yet another time, but it would be awesome if the next opensource iTunes Music Store file player was contributed by Sony!.text:10089F2E cmp eax, 1000300h .text:10089F33 jz short DoExtShuffle .text:10089F35 cmp eax, 1000400h .text:10089F3A jnz short skip .text:10089F3C DoExtShuffle: .text:10089F3C ... .text:10089F58 skip: .text:10089F58 ...
LOCALE=en_GB it claims that week 1 of 2006 starts on Sunday 1st January, and ends on Saturday 7th January, making my week numbers one lower than the rest of the world.STDIN.to_a.sort_by rand .each l puts lAs Philipp warns, however: "Ruby is full of fun and power; one must watch out that the scripts remain readable". For a fairly toy example, this solution is still fairly readable, however I can see hair growing on this thing if your program grows large. Next, Pierre-Charles David showed his qualifications for becoming a co-author of the next edition of the Pickaxe (AKA "Programming Ruby: The Pragmatic Programmers' Guide"), with his example and explanation. He's kindly given permission for me to reproduce his e-mail in it's entireity, since it's too good to chop up:
Here is the shortest and most readable version of your "randomize stdin" script I can think of:Pierre, your explanation definitely helped, and I hope it helps others too. The third person to help me out is Decklin Foster, through a post in his blog. What particularly caught me about his solution was the neat demonstration of another feature of Ruby which I think I will really learn to love: the ability to dynamically add methods to an existing class. "Aiee!" I hear all the purists scream -- and I can see the potential for severe misuse, too. But, since every good idea seems to get deeply perverted, we may as well have some real useful features to pervert while we're at it. Decklin has the clever idea of adding methods to the Array class that shuffle the elements of the array in a random fashion. His code is beautiful in it's simplicity:#!/usr/bin/env ruby print ARGF.readlines.sort_by randARGF is a special variable representing either stdin or, in the case where file names are passed on the command line, the content of these files (think of Perl's <>). ARGF behaves like an IO object (although I think it is not one). In particular, it responds to the #readlines method which splits the receiver's content into lines and returns an array. In other words,lines = ARGF.readlinesis the idiomatic way of doinglines = [] while line = gets() do lines << line endin your example. The next part (sort_by) uses a new form of the sort method, which I think is not documented in the Pickaxe. It implements the Schwartzian transform technique. In essence, a random number is associated to each element of the array, which are then sorted based on this index. As a general style remark, note that although Ruby supports "while" and "for x in y" loops, they are rarely used, in favor of iterators and/or higher order methods. For example, to gather all the input lines in an array without using readlines, one might writelines = Array.new ARGF.each_line l lines << lorlines = ARGF.inject([]) lines, l lines << lHope it helps, and welcome to Ruby!
class Array
def swap!(a, b)
self[a], self[b] = self[b], self[a]
self
end
def shuffle!
each_index do i
j = i + rand(length - i)
swap!(i, j)
end
self
end
end
He then goes on to rewrite my bumbling example in probably the most
comprehensible manner I've yet seen:
STDIN.readlines.shuffle!.each line puts lineDecklin writes, "Now that is cool.". I couldn't have put it better myself. My thanks to Philipp, Pierre-Charles, and Decklin, for helping me along the Ruby path. So, two new Ruby Rules for me to live by:
It is funny to see how things have evolved since then. Being 6 at that time,
and PCs not being very common those days at home, I started using a computer at an age of
8 or so. It was an Amstrad PCW 8512,
a TV box sized computer which integrated a green screen monitor, two
"3" floppy bays and
a 9-pin dot matrix printer. It was powered by a 8bit Z80 processor, running at 4MHz and
had 512KB of RAM and no ROM at all. Main software was
LocoScript, a powerful word processor. It could be controlled by drop down menus
at a top toolbar, and initial screen was a file manager, in which you could manage
those text files in the floppy you booted from or a floppy in the other bay.
It had even support for some kind of multiuser support, as you could declare
in each floppy up to 7 user areas, with area 0 being a common root. Also,
it had support for limbo a place for deleted files.
Although LocoScript didn't need a separate OS to work, CPW 8512 could also
run CP/M OS,
which added programming capabilities (Maillard BASIC) and support for
spreadsheets and databases, along with some games as
Batman.
After using this system for a long time, my first PC was a 486, running
the new Windows 3.1 and later 3.11 for Workgroups version. I even installed
there a Windows 95 when it was released, and managed to create a partition
in the only 170MB HDD it had to install a test copy of IBM's
OS/2 Warp that came in a
CD bundled with PC World magazine.
Some time later my parents bought a Pentium 166MMX running Windows 95. I was 18 by then,
it was 1997, Internet was starting to be widely spread and used, and after a
couple of months at University I was installing my first Linux copy, which
was a RedHat based version. During next three years I installed different
distributions, as they were released with newer software and you could get them
in a CD with a magazine. Installing Debian Slink and having an Internet connection
available at my Student's Residence at the same time made me be able to
participate in mailing lists, send bug reports and download upgrades. I discovered
a new dimension in using Linux: collaboration.
Does "Web 2.0" mean anything? Till recently I thought it didn't, but the truth turns out to be more complicated. Originally, yes, it was meaningless. Now it seems to have acquired a meaning. And yet those who dislike the term are probably right, because if it means what I think it does, we don't need it.So what's the reasoning that means we don't need the term? Graham writes: "Web 2.0 means using the web the way it's meant to be used." There's nothing fundamentally new, but there is a groundswell of understanding of what's been there all along. For me, that's a wonderful encapsulation of both current web trends and my aspirations for XTech. "Web 2.0" is a just a handy label for this. "The Web as it was meant to be used" will strike a chord with many web practitioners today--whether it's sensible use of web services with REST, improving user interaction in web design, or open semantics and data interchange. If you're involved in using the web as it's meant to be used, consider submitting an XTech proposal.
[...]Fact? Fiction? Feasible? As they say, read the whole thing.
Google hired a pair of very bright industrial designers to figure out how to cram the greatest number of CPUs, the most storage, memory and power support into a 20- or 40-foot box. We're talking about 5000 Opteron processors and 3.5 petabytes of disk storage that can be dropped-off overnight by a tractor-trailer rig. The idea is to plant one of these puppies anywhere Google owns access to fiber, basically turning the entire Internet into a giant processing and storage grid.
While Google could put these containers anywhere, it makes the most sense to place them at Internet peering points, of which there are about 300 worldwide.
Two years ago Google had one data center. Today they are reported to have 64. Two years from now, they will have 300-plus.
[...] There will be the Internet, and then there will be the Google Internet, superimposed on top. We'll use it without even knowing.
[...] All this is based, of course, on Google's proven network and hardware expertise. Have you seen Google's Search Appliance? They ship you a 1U prebuilt server. You connect it to your network, fill out a simple configuration screen, and it scans and indexes your web site (or sites) for you. Google monitors and manages it remotely, and sucks up the data and adds it to theirs. You just plug the thing in and turn it on. It just works. You need do nothing else to keep it running. Google understands how to do this stuff. Microsoft definitely does not.
[...] Microsoft can't compete. Yahoo probably can't compete. Sun and IBM are like remora, along for the ride. And what does it all cost, maybe $1 billion? That's less than Microsoft spends on legal settlements each year.
Game over. And yet next week I'll take it one more step.
#!/bin/zsh
setopt extendedglob
zmodload -i zsh/datetime exit 1
parse_ogginfo()
local output album artist mbid title len tstamp
output=($ (f)"$(ogginfo $1)" )
album=$ $ (M)output:#*ALBUM=* #*ALBUM=
artist=$ $ (M)output:#*ARTIST=* #*ARTIST=
mbid=$ $ (M)output:#*MUSICBRAINZ_TRACKID=* #*MUSICBRAINZ_TRACKID=
title=$ $ (M)output:#*TITLE=* #*TITLE=
len=$ $ (M)output:#*Playback length:* #*Playback length:
if [[ "$len" == (#b)([0-9]##)m:([0-9.]##)s ]]
then
(( len = $match[1] * 60 + $match[2] + 1 ))
else
(( len = 0 ))
fi
typeset -i len
tstamp=$(export TZ=UTC; strftime "%Y-%m-%d %H:%M:%S" $ EPOCHSECONDS )
print "$ (qqq)artist $ (qqq)title $ (qqq)album $ (qqq)mbid $ (qqq)len $ (qqq)tstamp "
for i in "$@"
do
parse_ogginfo $i
done
There's an off-by-one error if you should happen to have a track whose length is an exact
number of seconds, and obviously the timestamps are useless if you don't run it on exactly
one file at the correct time.
Sample output:
"Too Much Joy" "Making Fun of Bums" "Son of Sam I Am" "0077f5e2-ffe8-4f5c-83c5-d2a7bdc79776" "172" "2005-11-18 17:00:10" "Too Much Joy" "Song for a Girl Who Has One" "Son of Sam I Am" "af48111b-27e3-4c2b-8c42-927864b0e1f4" "209" "2005-11-18 17:00:10" "Too Much Joy" "Clowns" "Son of Sam I Am" "5cc2cf9c-2c68-48d4-be2c-ff0cbbae17e6" "219" "2005-11-18 17:00:10" "Too Much Joy" "My Past Lives" "Son of Sam I Am" "abd67bc7-1813-421b-9145-d072e58e62e5" "241" "2005-11-18 17:00:10" "Too Much Joy" "That's a Lie (remix)" "Son of Sam I Am" "dc22b8b2-7965-4c27-9cbc-9e529b2b1c87" "143" "2005-11-18 17:00:10" "Too Much Joy" "Hugo!" "Son of Sam I Am" "e0bba321-f654-4512-b052-66d605f96194" "144" "2005-11-18 17:00:10" "Too Much Joy" "Kicking (That Gone Fishing Song)" "Son of Sam I Am" "f9a3deb2-1b99-4fab-a32f-d594606bc1df" "244" "2005-11-18 17:00:10" "Too Much Joy" "Life is Flowers" "Son of Sam I Am" "053c11b7-577d-48d0-94cd-182af0b0cc84" "218" "2005-11-18 17:00:10" "Too Much Joy" "Connecticut" "Son of Sam I Am" "ad34c9c0-08bb-482b-aa75-41f7422e8fc7" "196" "2005-11-18 17:00:10" "Too Much Joy" "Bad Dog" "Son of Sam I Am" "c0641c0f-6357-47ae-a967-f39c57546236" "196" "2005-11-18 17:00:10" "Too Much Joy" "1964" "Son of Sam I Am" "0e56e785-75ec-4fa6-adb6-5fc2e58ffb7f" "223" "2005-11-18 17:00:10" "Too Much Joy" "Worse" "Son of Sam I Am" "2e4ccf4c-ba42-4206-8e38-758105475f06" "147" "2005-11-18 17:00:10" "Too Much Joy" "Seasons in the Sun" "Son of Sam I Am" "61d7f977-ef05-4648-b913-c4826c12e425" "212" "2005-11-18 17:00:10" "Too Much Joy" "If I Was a Mekon" "Son of Sam I Am" "7ca27d50-bc12-43c8-83b7-e28cd3a3be1d" "172" "2005-11-18 17:00:10" "Too Much Joy" "Train in Vain" "Son of Sam I Am" "14b48a3e-e448-47e5-850c-b9e3e01a1d10" "108" "2005-11-18 17:00:10"
I'm still not sure that this isn't some great spoof or prank. Maybe
someone broke in and changed the front page just as it went to press?
What do we have here:
Next.