Using OLPC XO as an ebook reader for O'Reilly's Safari Books Online

A year ago I received an OLPC XO (the “$100 laptop”) through their Give One Get One program. I played with it for a few days and found it essentially useless due to unstable and slow software (and lack of WPA support), so it quickly began gathering dust on a shelf (it has since improved).

Last week I was thinking about how cool it would be if Amazon’s Kindle supported O’Reilly’s Safari Books Online service, and I decided to dust off the XO to see if it could be used as an ebook reader for Safari Books. With a little help, it can.

In ebook mode you can scroll in all four directions, page up/down, and jump to the top or bottom of a page, but you cannot click the next/previous buttons within Safari Books. However, GreaseMonkey and a simple userscript can solve that.

The first step is to install the Firefox “Activity”, or a version of Linux that runs a stock Firefox. Then install GreaseMonkey. Finally, install this userscript:

This simple userscript intercepts page up and page down (the “O” and “X” game pad) buttons and maps them to “previous” and “next” actions in Safari Books, allowing you to easily switch pages in ebook mode.

Amazon S3 PHP helpers

The Amazon documentation for using S3 with PHP refers to an elusive function called “setAuthorizationHeader”. It’s apparently supposed to magically set the correct value for the Authorization header on a Pear HTTP_Request object. As far as I could tell, it didn’t actually exist — but I wanted it, so I wrote it:



require_once ‘Crypt/HMAC.php’;
require_once ‘HTTP/Request.php’;

define("S3URL", ‘’);

$s3_hasher =& new Crypt_HMAC(AWSSECRETKEYID, "sha1");

function s3_sign($StringToSign)
    global $s3_hasher;
    return hex2b64($s3_hasher->hash($StringToSign));

function hex2b64($str)
    $raw = ;
    for ($i = 0; $i < strlen($str); $i += 2) {
        $raw .= chr(hexdec(substr($str, $i, 2)));
    return base64_encode($raw);

function setAuthorizationHeader($request)
    $headers = $request->_requestHeaders;
    $HTTP_Verb      = $request->_method;
    $Content_MD5    = $headers[‘content-md5’];
    $Content_Type   = $headers[‘content-type’];

    // Get the date, or set it if not already:
    if (!isset($headers[‘date’])) {
        $Date = gmdate("D, d M Y H:i:s T");
        $request->addHeader("date", $Date);
    else {
        $Date = $headers[‘date’];
    // Canonicalize the Amazon headers:
    $CanonicalizedAmzHeaders = ;
    $amz_headers = array();
    foreach ($headers as $key => $value) {
        if (substr($key, 0, 6) == ‘x-amz-‘) {
            if (isset($amz_headers[$key]))
                $amz_headers[$key] .= ‘,’ . $value;
                $amz_headers[$key] = $value;
    foreach ($amz_headers as $key => $value)
        $CanonicalizedAmzHeaders .= $key . ‘:’ . $value . "\n";
    // Canonicalize the resource string
    $CanonicalizedResource    = ;
    $host = $request->_generateHostHeader();
    if ($host != ‘’) {
        $pos = strpos($host, ‘’);
        $CanonicalizedResource .= ‘/’ . ($pos === false) ? $host : substr($host, 0, $pos);
    $CanonicalizedResource .= $request->_url->path;
    // TODO: sub-resources "?acl", "?location", "?logging", or "?torrent"

    // Build the string to sign:
    $StringToSign = $HTTP_Verb . "\n" .
                    $Content_MD5 . "\n" .
                    $Content_Type . "\n" .
                    $Date . "\n" .
                    $CanonicalizedAmzHeaders .
    $Signature = s3_sign($StringToSign);
    $Authorization = "AWS" . " " . AWSACCESSKEYID . ":" . $Signature;
    // Set the Authorization header:
    $request->addHeader("Authorization", $Authorization);

function s3AuthURL($Resource, $HTTP_Verb = ‘GET’, $seconds = 120)
    // Calculate expiration time:
    $Expires = time() + $seconds;

    // Build the string to sign:
    $StringToSign = $HTTP_Verb . "\n" .
                    "\n" .
                    "\n" .
                    $Expires . "\n" .

    $Signature = s3_sign($StringToSign);

    // Build the authorized URL:
    return  S3URL . $Resource .
            ‘?AWSAccessKeyId=’  . AWSACCESSKEYID .
            ‘&Expires=’         . $Expires .
            ‘&Signature=’       . urlencode($Signature);


Note: this hasn’t been tested extensively, so use it at your own risk. Post a comment or contact me at if you find any bugs. Also, IANAPHPE.

Just replace the XX’s with your keys and it should work with this sample code.

There’s also a function for creating query string authorized URLs.

Overriding library functions in Mac OS X, the easy way: DYLD_INSERT_LIBRARIES

Back at MacHack 2003 Jonathan Rentzsch talked about how to override functions and inject code in Mac OS X using [several neat tricks]( He also released a framework called [mach_star]( which has two components: mach_override and mach_inject. These are great, but overkill for some simple cases.

A much easier way of doing library function overrides is using the DYLD_INSERT_LIBRARIES environment variable (analogous to LD_PRELOAD on Linux). The concept is simple: at load time the dynamic linker (dyld) will load any dynamic libraries specified in DYLD_INSERT_LIBRARIES before any libraries the executable wants loaded. By naming a function the same as one in a library function it will override any calls to the original.

The original function is also loaded, and can be retrieved using the dlsym(RTLD_NEXT, “function_name”); function. This allows a simple method of wrapping existing library functions.

Here’s a simple example which prints out the path of every file opened using the “fopen” function (lib_overrides.c):

#include <stdio.h>
#include <unistd.h>
#include <dlfcn.h>

// for caching the original fopen implementation
FILE * (*original_fopen) (const char *, const char *) = NULL;

// our fopen override implmentation
FILE * fopen(const char * filename, const char * mode)
    // if we haven’t already, retrieve the original fopen implementation
    if (!original_fopen)
        original_fopen = dlsym(RTLD_NEXT, "fopen");

    // do our own processing; in this case just print the parameters
    printf("== fopen: {%s,%s} ==\n", filename, mode);
    // call the original fopen with the same arugments
    FILE* f = original_fopen(filename, mode);
    // return the result
    return f;

And a simple test program (overrides_test.c):

#include <stdio.h>
#include <string.h>

int main(int argc, char const *argv[])
    char hello[] = "hello world";
    FILE *fp = fopen("hello.txt", "w");
    if (fp) {
        fwrite(hello, 1, strlen(hello), fp);

    return 0;

Compiled and tested:

tlrobinson$ gcc -Wall -o lib_overrides.dylib -dynamiclib lib_overrides.c
tlrobinson$ gcc -Wall -o overrides_test overrides_test.c
tlrobinson$ DYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES=lib_overrides.dylib overrides_test
== fopen: {hello.txt,w} ==

There are certainly scenarios far more interesting than this, though!

Ad-blocking and

Recently it [came to the attention of the Digg masses]( that some slimy SEO guy was advocating web site owners block *every* Firefox user simply because Firefox allows ad-blocking plugins, and doesn’t provide web site owners with any way to block users of such plugins.

I find this incredibly silly for a number of reasons. The number of Firefox users who use such plugins is likely very small. By blocking *all* Firefox users, you not only keep the ad-blocking users away (who most likely wouldn’t click on your ads anyway), but also the much larger number of users who *might* click on your ads. Mmmmkay…

Even if he’s doing this out of principle, or to make a point, he apparently doesn’t realize that *every* popular browser has ad-blocking software available. See below.

Personally, I’ve realized that I’m completely web ad blind. After 10+ years of web browsing, I’ve subconsciously conditioned myself to ignore all web advertising, unless it’s something truly obnoxious like Flash ads with sound, etc.

That said, this guy has inspired me to install both ad blocking software, and plugin to change the browser’s user-agent string to get around silly browser-specific filters (although if a site resorts to blocking certain browsers, do you really want to support them?).

### Ad Blocking ###

Firefox: [Adblock Plus](, also available from the Firefox plugin directory.

Safari: [PithHelmet](

### User-Agent Changing ###

Firefox: [User Agent Switcher](

Safari: built in, enable Safari “Debug” menu by entering the following on the command line:
defaults write IncludeDebugMenu 1

Update: the ad-blocking debate got picked up by [at least one mainstream newpaper](, surely causing a surge of new Ad-block users… not quite what the slimy SEO guy had in mind. Karma?

Skype outage

Users of the popular VoIP network, Skype, have been experiencing widespread outages for more than a day now. And of course thanks to Murphy’s Law I happened to pick today to try to get my family set up on Skype.

So far I’ve heard three theories as to what is going on.

– Skype says the problem is [a deficiency in an algorithm within Skype networking software](, whatever that means. After reading a little about the [great lengths Skype goes to]( in order to obfuscate their network protocol and prevent reverse engineering, it wouldn’t surprise me if they spent more time protecting the protocol than making sure it works well…

– A [Microsoft update caused the outage](

– A [remote DoS exploit]( that was published on was responsible:

# Simle Code by Maranax Porex ;D
# Ya Skaypeg!!

for ($i=256; $i>xCCCCC; $i=$i+256){
    $eot=‘AAAA’ x $i;

sub call_sp(){
    $str="\"C:\\Program Files\\Skype\\Phone\\Skype.exe\" \"/uri:$eot\"";

Now, I don’t know much about Perl, Skype, or Windows… but I can tell you this little piece of code generates a series of strings containing a Windows path to the Skype.exe followed by a parameter starting with “/uri:” and ending with reaaaallly long strings of A’s:

"C:\Program Files\Skype\Phone\Skype.exe" "/uri:AAAAAAAAAA...AAAAAAAAAA"

…starting with 256 copies of “AAAA”, incrementing by 256 until it reaches 0xCCCCC (that’s 838,860). The problem is, the code doesn’t do anything with the strings, it simply assigns them to a variable and continues on with the next iteration.

Edit: actually, the condition in the for loop, “$i>xCCCCC;”, effectively always evaluates to true, thus the loop will repeat infinitely. The “correct” condition would have been “$i<0xCCCCC;". Yet another sign this thing is fake?

If it were actually complete, it would be a really simple command line argument [fuzzer]( basically executing Skype.exe with varying length “uri:” arguments. And if, in fact, this type of thing could take down the entire Skype network, well, Skype definitely needs to put more effort into the security and robustness of their program, rather than trying to prevent reverse engineering of their protocol.

Perhaps leaving the tool incomplete was a deliberate attempt by the writer to demonstrate the vulnerability exists without quite providing a working tool, or perhaps the exploit is a hoax. I don’t know Russian, so I can’t tell if there’s more information on

It will be interesting to see what the real reason for the outage is. Of course, with the Skype protocol so locked down, we may never know what the real reason is…

Update: [according to Skype](, the outage was caused by the massive number of Windows machines rebooting and reconnecting to Skype after a Microsoft update, and a flaw in Skype’s “self-healing” ability. Microsoft effectively DDoS’d Skype…


I had a great weekend in Las Vegas at [DEF CON 15]( Met lots of cool people, saw lots of interesting presentations, ate lots of good food, and spent way too much money doing it all.

Perhaps my favorite moment of the conference was when DEF CON organizer [Jeff Moss]( lured Michelle Madigan, the undercover NBC Dateline reporter, to a room full of thousands of DEF CON attendees, and well… watch for yourself…

Some of the more interesting talks I saw:

### Day 1 ###

– The Church of WiFi’s “Wireless Extravaganza”, an overview of their current WiFi and Bluetooth projects.
– Steve Dunker on police procedure.
– H.D. Moore’s “Tactical Exploitation” (also the talk in which the Dateline reported was outed).
– Jeff Moss on “CiscoGate”, the story of the Michael Lynn / Cisco / ISS / Black Hat debacle in 2006.
– David Hulton’s “Faster PwninG Assured”, using FPGA’s to crack Bluetooth PINs and WinZip / Apple DMG encryption.
– Johnnie Long on “No-Tech Hacking”.

### Day 2 ###

– Dan Kaminsky’s “Black Ops 2007”, various web vulnerabilities.
– Zac Francken’s talk hacking access control readers like HID Prox cards.
– Brett Neilson on modern radio scanning (which is inspiring me to get back into scanning).
– David Gustin overview of “hardware hacking for software geeks”.

[Joe Grand]( one-upped himself with the DEF CON badges this year. Last year the badge was a PCB with two blinking LEDs. This year it has 95 LEDs that can display scrolling text or a P.O.V., and can be reprogrammed by the user using the two capacitive touch sensing buttons.


The PCB also has pads and traces for accelerometer and ZigBee wireless transceiver chips. It would have been awesome if everyone’s badge already had them… imagine 6,000 DEF CON attendees’ badges wirelessly transmitting their accelerometer data. With a bunch of receivers placed around the conference hall, you could make some pretty neat maps. Oh well, there’s always next year!


OpenWRT on Linksys WRT54GL

As suggested by my friend and [SCEC](/projects/scecvdo) coworker [Kevin Milner](, I finally installed the GNU/Linux based OpenWRT replacement firmware on my house’s Linksys WRT54GL wireless router tonight. It gives you a minimal Linux distribution with most of the features of the WRT54GL’s original firmware built in, plus the ability to add a whole lot more.

It’s extremely easy to install. See page 10 of the [slides]( [pdf] from Ted Faber’s [USC LUG]( talk.

There a couple minor things to watch out for:

* If you use WPA (which you should, since WEP can now be broken in [less than a minute]( you need to install an additional package, nas. OpenWRT has a simple package management system, ipkg, to do this for you.

* No, the web interface does *not* have port forwarding configuration. Instead you need to use the slightly more complicated, but much more powerful, iptables. This involves editing a configuration file.

* The only account set up by default is the root account, so when trying to log in you must use “root” as the user, not “admin” as with the original firmware. Be sure to set your password immediately after installation.

See the [configuration documentation]( for details on these things and a lot more.

If you want to dabble with Linux and learn a little about networking (and you have a [compatible router]( I highly recommend trying out OpenWRT.