Thursday, January 1, 2009

Reverse engineering a nonpublic API

I have been a user of for quite a while. For those who don't know what it is, it's an online dictionary that is not free, however it's the best one yet, supporting danish (my main language). The site has a quick word translate widget for Windows, but nothing for Mac OS X which has been bothering me for some time.

Recently I learned how to develope widgets for Mac OS X and I wanted to make my own widget. I emailed their staff asking for an API, however they couldn't really help except for giving me ideas (sounds like they are not against the idea either). So I started brainstorming.
I came to the thought that there must be some way to find out what the Windows Widget did, to get its information. I was certain that the information was at itself so I found out what to do.
I wanted to know the link, which the program accessed so I figured I could modify my hosts file, stored in C:\Windows\System32\drivers\etc\hosts . This file allows you to tie IPs to hostnames. So I tied to (localhost) which means that the program will try to access the webserver on my local computer, instead of's own webserver.

I needed to catch the program's intentions, so I installed WAMP which means Windows+Apache+MySQL+PHP. Which is the most common website setup. So now the program will connect to my webserver.
Since I did not know where on the webserver, the program wanted acccess, I had to catch it in any case, so I enabled mod_rewrite on the server, and added a .htaccess file with the following contents:
RewriteEngine On
RewriteCond %{REQUEST_URI} !=/test.php [NC]
RewriteRule ^(.*)$ /test.php?file=$1

which basically tells the webserver that whatever page is requested, will be sent to my test.php file, which then would log what the program had to say. So I made my test.php file:
<?php// start output
// print everything form-posted
echo "Post ";
echo "\n";
// print everything in-url posted
echo "Get ";
echo "\n";
// get everything outputted
$d = ob_get_contents();
// clean output
// start logging
$saved = false;
$n = 0;
while($saved == false) {
$name = 'log_'.$n.'.txt';
if(!file_exists($name)) {
$saved = true;

To understand the code, read the comments (//) in the code. This file just logs everything you tell it.

I then opened the program and instantly a new logfile was created, containing the following contents:
Post Array
[username] => MyUsername
[password] => MyPassword
[key] =>
Get Array
[file] => plus/login3.php

This told me everything I needed to know. The program sends the username and password I had defined in the settings of the program, and sent it to
The program then gave me an error, saying that it was missing a header, so I installed Live HTTP Headers in FireFox to see which headers the website sent when logging in, but first I had to fake the login myself. So I created a HTML form to connect to login3.php :
<form method="POST" action=""><input type="text" name="username" />
<input type="password" name="password" />
<input type="submit" value="Login" />

I read through the headers and found this:
Set-Cookie: PHPSESSID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx (removed for security)

This is the header that tells you to basically know that you are logged in, which is what the program wanted to know.
So I just added session_start() to my test.php file and the program didn't complain anymore.

Now I needed to know what to do next, when I pressed "Login" on my little form I got the following details:
00x######## (I hid the numbers cause I didn't want to reveal my account)
daen=- Dansk-Engelsk
enda=- Engelsk-Dansk
a000=Auto. Dansk/Engelsk
dasp=- Dansk-Spansk
ddno=- Den Danske Netordbog
dase=- Dansk-Svensk

This just tells you what dictionaries you have permission to use. So I edited my test.php file and added this:
if(isset($_POST['username'])) {
echo '0
daen=- Dansk-Engelsk
enda=- Engelsk-Dansk
a000=Auto. Dansk/Engelsk
dasp=- Dansk-Spansk
ddno=- Den Danske Netordbog
dase=- Dansk-Svensk

This will be the response, when the program logs on to my fake server.

So now, I wanted to know what the program wanted to do next, so I restarted the program, it logged in successfully (my fake server didn't check passwords, so it's easy to remember the login) and then I typed in a word to look up in the dictionary, and instantly a new log file appeared in my web root:
Post Array
[dict] => daen (danish -> english)
[word] => words (what I entered)
[PHPSESSID] => xxxxxxxxxxxxxxxxxxxxxxx (removed for security))

Get Array
[file] => plus/opslag3.php

So now I know how to send the query to the server about which dictionary to use and which word to translate and I will have to send my Session ID aswell, to .

I went to edit my test.php file to fake this part of the server aswell, I added this to my code:
if(isset($_POST['word'])) {
echo 'You have looked up the word '.$_POST['word'];

I now opened up the dictionary program from, it logged in, I typed a word and voila:

I have later found out that the widget contacts and posts the session id to keep the php session alive.

I will now begin to develope my Mac OS X widget..

No comments:

Post a Comment