IT Security Lab The Playground for IT Security Specialists and Pentesters

3Jan/115

Changed language does not persist when Skype is restarted: how to solve the annoying issue

You know, I like intelligent and handy software. I really do. But I hate with my all heart when the application (or the application's author?) is eee... "too smart". ;-) And what especially makes me nervous is when author calls some idiotic application's behavior "a  feature". I think Skype is a nice example of it. Look at this:

I have the default system language in Windows set up as English, but the default one for the non-Unicode programs is set to Polish. Nothing wrong with it, right. So when I start Skype for the first time it happily detects this setting and switches its language accordingly to the Polish too. Chaaarming. ;-)

Now let's imagine that I want to change the default Skype's language permanently to English (well, I much prefer English UI in all apps, ok). Seems life is easy: click the main menu, then Tools --> Change language --> English ... and the language is changed. Now try to close Skype and open it again... What you you see: the application's language is immediately switched back to Polish! Ok, you may try to attack the problem from the different side: Tools --> Options --> Tab: General setting --> Languages combo: English, then Save. Unfortunately the effect is exactly the same: when Skype is restarted - it switches the language to the one set up as the default for non-Unicode programs (in my case: Polish). God knows why this proggy has such amazing feature, but believe me - to change the language manually after each restart is becoming pretty annoying after some time.

As usual, I google the problem and quickly found out that I am not alone: look here for example http://portableapps.com/node/21644. So can we do anything? Yes we can®! :-)

I wrote a small program which runs the Skype and then simulates mouse clicks on the main menu and kind of "pseudo-manually" switches the application's language to the default one (English). This is also a nice small example how you may access the main menu of the application "B" from the code of application "A" and execute some  functionality in application "B". No worries, we are not "literally" moving the mouse cursor the the menu, but issuing some appropriate system messages - so everything is pretty elegant.

Ok, if someone needs only executables here they are (with the source code in Delphi):

Usage is very simple: extract the executable and put it to the same folder where your SkypePortable.exe or Skype.exe is located and then run. My little program runs Skype, waits until it is loaded and switches the language to English. Job done! :-)

Some technical background

Ok, so this is how it works. First of all we have to find the Skype window in the system (assure it exists, so we may get it's handle and access its child elements). This is rather trivial, so no need to explain anything. Once the window is found this is what we are doing:

var
  menu: HMenu;
  id: integer;
  s: Array[0..255] of char;
begin
  tmrMain.Enabled := false;

  h := findWindow(pchar('tSkMainForm.UnicodeClass'), nil);  //--- find Skype's window
  menu := getMenu(h); //--- find the main menu
  GetMenuString(menu, 5, @s[0], 255, MF_BYPOSITION); //--- get the text of 6th menu item (should be '&Help')

  if string(s) <> '&Help' then  //--- current language is NOT English
  begin
    menu := getMenu(h); //--- main menu
    menu := GetSubMenu(menu, 4); //--- find the 5th menu item

    //--- activate this (5th) menu item, so all subitems can be redrawn. This is IMPORTANT!
    SendMessage(h, WM_INITMENU, WPARAM(menu), 0);
    SendMessage(h, WM_INITMENUPOPUP, WPARAM(menu),0);

    menu := GetSubMenu(menu, 2); //--- find the 3rd submenu item

    id := GetMenuItemID(menu, 9); //--- 10th menu item (select "English")
    PostMessage(h, WM_COMMAND, id, 0); //--- click it! :-)
  end;

  SendMessage(h, WM_SYSCOMMAND, SC_MINIMIZE, 0);
  application.Terminate;
end;

So 1st thing we have to do - we have to check what language is set up currently. We are getting the text of the 6th menu item and checking if it is equal to "&Help" or not. Currently it's "&Pomoc", which means the current language is not English (yea, it's Polish actually).

This is the code used for checking:

  h := findWindow(pchar('tSkMainForm.UnicodeClass'), nil);  //--- find Skype's window
  menu := getMenu(h); //--- find the main menu
  GetMenuString(menu, 5, @s[0], 255, MF_BYPOSITION); //--- get the text of 6th menu item (should be '&Help')

  if string(s) <> '&Help' then  //--- current language is NOT English
  begin
  [...]
  end;

Now we have to iterate through the menus and sub-menus and run some action on the target item. Look at this code:

    menu := getMenu(h); //--- main menu
    menu := GetSubMenu(menu, 4); //--- find the 5th menu item

    //--- activate this (5th) menu item, so all subitems can be redrawn. This is IMPORTANT!
    SendMessage(h, WM_INITMENU, WPARAM(menu), 0);
    SendMessage(h, WM_INITMENUPOPUP, WPARAM(menu),0);

    menu := GetSubMenu(menu, 2); //--- find the 3rd submenu item

    id := GetMenuItemID(menu, 9); //--- 10th menu item (select "English")
    PostMessage(h, WM_COMMAND, id, 0); //--- click it! :-)

Important detail: look at strings highlighted in red: this is important element of the code as the sub-menu with the list of languages is generated "on-the-fly" once the parent menu item is activated. Without it: the 10th menu item (language "English") simply does not exist, (hence can't be called).

One more remark: the proposed solution requires Skype user interface (Visual Style of the window) get running in "Classic Windows" mode.

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... :)

7Jul/109

Read Skype Data: Chatsync and SQLite

Recently I made some research regarding the way Skype stores the conversation's log. I was nicely surprised that the chat data on the user's computer stored in a very simple form.

The data stored by Skype (I have version 4.2.0.169) seems to be stored in two places and in two completely different formats (btw: does anybody know why? kind of "backward compatibility"?):

  • .dat files in the \chatsync folder
  • SQLite database files (the interesting file: main.db)

So to access the data we need either to read it from the .dat binaries or open the database files with any SQL frontend. Simple.

1. Accessing data from the .dat files

There are plenty of Skype log readers around in Internet, but why not to try to write my own tool in such beautiful summer evening! :)

All right, so what kind of files and data we are dealing with? All conversations are stored in \chatsync folder where you have many subfolders with binary .dat files inside. Each .dat file basically is a new conversation.

So if we want to get all messages exchanged in between User 1 and User 2 we have to:

  • Create one big list of all files in all subfolders and sort them by timestamp.
  • Read conversation id from each .dat file (it is in a fixed offset 0x35 at the very beginning of each file).
  • Create sorted list of all conversations between the pair of users (User 1 <-> User 2) and (User 2 <-> User 1).
  • Read chat messages from every .dat file on such "dedicated list" and store it somewhere.

How to retrieve messages? Each chat message starts from the prefix (0x03 0x02) and ends with the null byte (0x00).

I am quite far from the idea to do a complete reverse engineering of the .dat files, but below you may find a small proof of concept (see the binary file and the source code in Delphi). When you run the application you have to provide the full path to your \chatsync folder. Here how it looks like:

The program can collect a data when the Skype is running. FYI: some of the .dat files may be locked by Skype, so the correct way to open it (in read only mode) is:

   fs := TFileStream.Create(chatSyncFName, fmOpenRead or fmShareDenyNone);

If you'd modify the source code a little and track the changes in those files (e.g.: by monitoring datetime stamp) - you can basically write a Skype conversations sniffer in an hour or so. ;)

2. Accessing SQLite database files

This is even more easy: locate the "main.db" file and open it with SQLite editor (e.g.: SQLIte Spy is good enough). Now you have very nice and elegant way to do whatever you want with the data by executing appropriate SQL query:

User 1 and User 2