You are on page 1of 8

Artefacts of Kik Messenger on iOS

Saturday, 25th May 2013 Bridgey the Geek <forensicgeekinthecorner@gmail.com>

Introduction
This document describes some of the key artefacts of Kik Messenger when used on iOS. It aims to identify artefacts not extracted by commonly used commercial tools. I have tried hard to make it error-free, but the odd one may have crept in. Please feel free to email me corrections.

Thank You
A big thank you to my colleague BW who brought this interesting topic to my attention (and politely allowed me take over), and to my colleague SC who provided much needed assistance on the effective use of XRY.

Tools Used
Windows was the OS of choice as it is required for the commercial tools used, specifically I used Windows 7 Professional 64-bit. As always, please respect their licences.

Commercial Tools
Tool UFED Physical Analyzer XRY Available From http://www.cellebrite.com/ http://www.msab.com/

Open-Source and/or Free Tools


Tool BlueStacks App Player SQLite Expert Personal SQLite Pre-compiled Binary for Windows Available From http://www.bluestacks.com/ http://www.sqliteexpert.com/ http://www.sqlite.org/

The Scenario
BW was investigating a case where image files had been sent from one Kik user to another Kik user as part of a conversation. He had the device used by one of the parties and wanted to identify the other party. The device he was investigating was an iPod Touch 4G (model A1367) running iOS 6.1 (10B144), with a capacity of 16GB, and not jailbroken. BW had tried to acquire a physical dump of the device using UFED Physical Analyzer, but at the time, this model was not supported. He had also tried using XRY to take a physical dump and a logical dump using a RAM disk: these also failed, the errors indicate that the device wasn't supported by this product either. He was able to use XRY to take a backup of the device. XRY didn't parse any Kik Messenger data out, that is, no data was identified as being chat, contacts, etc.

Exploring the iPod Backup


Using XRY, from the 'Export' ribbon, I chose 'File' and extracted 'All Views' ensuring I had checked 'Reflect original path' and 'Use common root'. This gave me a local working copy of the iPod file system, maintaining the folder structure.

General Preferences
It's work taking a quick look at /root/private/var/mobile/Applications/com.kik.chat/Library/ Preferences/com.kik.chat.plist. It's a binary plist file that contains a few App-wide settings, most notably the username, password (in plain text), first name, last name, phone number, email address, and install date (which is 31 years behind, more on that later).

The TCC Database


When exploring an app on iOS it's always worth a quick check of the TCC database. Located at /root/var/mobile/Library/TCC/TCC.db, this database is used to control what permissions apps have. (Some more info here: http://macops.ca/modifying-the-tcc-db/.)
C:\tools>sqlite.exeTCC.db sqlite>.tables access access_overrides sqlite>.headersON sqlite>SELECT*FROMaccess;
service kTCCServiceTwitter kTCCServicePhotos kTCCServiceAddressBook kTCCServicePhotos kTCCServiceAddressBook kTCCServicePhotos kTCCServiceAddressBook kTCCServicePhotos kTCCServicePhotos kTCCServicePhotos kTCCServicePhotos kTCCServicePhotos kTCCServicePhotos kTCCServiceTwitter kTCCServicePhotos

access_times

admin
client_type 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 allowed 0 1 1 1 1 1 1 1 1 1 1 1 1 0 1 prompt_count 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0

client com.apple.mobileslideshow com.facebook.Facebook com.skype.skype com.burbn.instagram com.flexilis.security com.tumblr.tumblr com.kik.chat com.kik.chat com.atebits.Tweetie2 com.skype.skype com.microsoft.wlx com.cardinalblue.PicCollage co.uk.barterbooks.keepcalmandcarryon com.atebits.Tweetie2 com.jollydream.camwow

This tells us that the client com.kik.chat is allowed to access to the address book service and the photos service. Note: Further testing has shown that the TCC folder and therefore the TCC.db file don't seem to be created until the user is asked to grant (or deny) permissions to an app.

The AddressBook and Photos Services


If you didn't already know, you could probably guess that an app with permission to access the Address Book can do whatever it likes with the local Address Book: create, edit, and registering to be notified of changes made externally. (More info: http://developer.apple.com/library/ios/#documentation/AddressBook/Reference/ABAddressBookRef_iPhoneOS/Refe rence/reference.html) Similarly, permission to access the Photos service allows an app to take pictures or movies, or select them via the media browser. (More info: https://developer.apple.com/LIBRARY/IOS/#documentation/AudioVideo/Conceptual/CameraAndPhotoLib_TopicsF orIOS/Introduction/Introduction.html) It is perfectly logical that Kik would want these permissions: it wants to know which contacts you might be talking with and it wants to allow you to send photos or videos. But back to the tables...

sqlite>SELECT*FROMaccess_times;
service kTCCServicePhotos kTCCServiceAddressBook kTCCServiceAddressBook kTCCServicePhotos kTCCServicePhotos kTCCServicePhotos kTCCServicePhotos kTCCServicePhotos kTCCServicePhotos kTCCServicePhotos kTCCServicePhotos kTCCServicePhotos kTCCServicePhotos kTCCServicePhotos kTCCServicePhotos kTCCServicePhotos kTCCServiceAddressBook kTCCServicePhotos client com.globaldelight.Camera-Plus com.flexilis.security com.kik.chat com.microsoft.wlx co.uk.barterbooks.keepcalmandcarryon com.burbn.instagram com.cardinalblue.PicCollage com.atebits.Tweetie2 com.jollydream.camwow com.apptao.retinawallpapers IncredibleApp.Wallpapers com.ticktockapps.wallhd-10000 com.bootstlab.PhotoEditorFX com.kik.chat com.tumblr.tumblr com.skype.skype com.skype.skype com.facebook.Facebook client_type 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 last_used_time 1349543933 1356472631 1356904665 1357001154 1357087473 1357167404 1357521613 1357936407 1360791755 1360958014 1361280894 1361281000 1361306949 1361636603 1361743413 1361746592 1361814217 1361814714 human_time 06/10/12 17:18:53 25/12/12 21:57:11 30/12/12 21:57:45 01/01/13 00:45:54 02/01/13 00:44:33 02/01/13 22:56:44 07/01/13 01:20:13 11/01/13 20:33:27 13/02/13 21:42:35 15/02/13 19:53:34 19/02/13 13:34:54 19/02/13 13:36:40 19/02/13 20:49:09 23/02/13 16:23:23 24/02/13 22:03:33 24/02/13 22:56:32 25/02/13 17:43:37 25/02/13 17:51:54

I added the human_time column! I'm sure you spotted that last_used_time is just a Unix timestamp. This tells us the last time that Kik made use of the address book and photos services. For completeness, the access_overrides table was empty and the admin table just contained a key/value pair: version = 4.

The Big Horde


As one might expect, the significant data for the app is located in the Applications folder, specifically /root/var/mobile/Applications/com.kik.chat/. The folder structure of this folder looks like this:

Essentially the data for the app is contained within a serious of plist and xml files and one SQLite file. The SQLite file contains the data which combines everything together and can be found at: /root/var/mobile/Applications/com.kik.chat/Documents/kik.sqlite.

kik.sqlite
Taking a look shows that this database contains eight tables:
sqlite>.tables ZKIKATTACHMENT ZKIKMESSAGE ZKIKCHAT ZKIKUSER Z_2MESSAGES Z_4MEMBERS Z_METADATA Z_PRIMARYKEY

Z_PRIMARYKEY Table
sqlite>SELECT*FROMZ_PRIMARYKEY;
Z_ENT 1 2 3 4 Z_NAME KikAttachment KikChat KikMessage KikUser Z_SUPER 0 0 0 0 Z_MAX 59 17 2339 20

This table appears to be a lookup table for the kinds of data held elsewhere in the table. For example, objects of type KikAttachment, so attachments then, have an identifier of 1. It seems that Z_MAX reflects the number of those kinds of objects that are currently stored. For example, in this database there are 59 entries in the ZKIKATTACHMENT table, 17 entries in the ZKIKCHAT table, 2339 entries in the ZKIKMESSAGE table, and of course 20 entries in the ZKIKUSER table.

ZKIKCHAT Table
Z_PK Z_ENT Z_OPT ZFLAGS ZDRAFTMESSAGE ZLASTMESSAGE ZUSER ZDATEUPDATED Primary key Always 2. Entry type from the Z_PRIMARYKEY table: 2 = KikChat. Unknown Unknown. 1, 2 = visible only. 3 = visible, unread msgs. 4 = invisible. 8 = invisible. Unknown, only seen to be null. Foreign key: holds PK of a ZKIKMESSAGE to display in the chats overview screen. Should be the most recent message of that chat. Foreign key: holds PK of the ZKIKUSER who is the other party in the chat. Probably the last time this 'chat' (whatever that is!) was updated as KIKDATE*.

Records seem to be generated in this table when the user navigates to the screen to send a message. No messages have to be typed, sent, or received in order for the record to be created. It seems that if ZLASTMESSAGE is null, the chat is empty. What if there's only a draft? ZDRAFTMESSAGE?

*KIKDATE Good old-fashioned police work


Kik stores some timestamps in a format not seen before, for example: 379285368.917033 We actually solved this by using data from the ZKIKMESSAGES table. BW had spotted a run of messages that said something like Happy New Year. A run of them surely meant that this was roughly midnight on 1 st January. So for a quick experiment we just took the integer-part and put it through a Unix timestamp converter: 378693409 = Fri, 01 Jan 1982 00:36:49 GMT
So, 1st January is good, and 00:36 is pretty good. 1982 is clearly wrong, but could it just be being shifted? By say 30 or maybe 31 years. By looking at other messages we referenced other events known to us, we were able to determine that the shift was in fact 31 years.

ZKIKUSER Table
Z_PK Primary key

Z_ENT Z_OPT ZADDRESSBOOKID

Always 4. Entry type from the Z_PRIMARYKEY table: 4 = KikUser. Unknown Unknown, only seen to be 0. Probably the ID of the contact in the iPod's address book. A value of 0 suggests that a connection hasn't been made between the Kik contact and a contact in the address book. Unknown. 0x20h bit set = user blocked, see 'Blocking Users'. Unknown, only seen to be 0. Unknown, only seen to be 1. Unknown, only seen to be 1. Foreign key: holds the PK of the ZKIKCHAT to which they are party. Unknown, only seen to be empty. The display name chosen by the user allows extended character sets. The display name chosen by the user limited to low ASCII characters. Unknown, only seen to be empty. Even though in testing an email address was provided when setting up an account on the app. Value entered by the user as 'First Name' when creating their Kik account. Jabber ID. Equal to: ZUSERNAME followed by an _ followed by 3 seemingly random characters, all in lower-case, followed by @talk.kik.com. Value entered by the user as 'Last Name' when creating their Kik account. Profile Picture Unix timestamp; probably when profile picture was last updated. Profile Picture URL link to the actual profile picture. When accessed directly via a web browser, an XML file is returned indicating access denied. Unknown, only seen to be empty. Kik username.

ZFLAGS ZINTERNALID ZPRESENCE ZTYPE ZCHATUSER ZLASTMESSAGE ZDISPLAYNAME ZDISPLAYNAMEASCII ZEMAIL ZFIRSTNAME ZJID ZLASTNAME ZPPTIMESTAMP ZPPURL ZSTATUS ZUSERNAME

Testing showed that a user was added to this table if they were found as a result of searching. That is, it was not necessary to interact with that user in any way (for example, starting a conversation) for the record to be created. If a conversation involves more than two parties, a group user is added to this table. The ZJID value would be similar to 1099712227248_g@groups.kik.com, the ZFLAGS were seen to be set to 10.

ZKIKMESSAGE Table
Z_PK Primary key. The highest value in this column was 2339 but there were only 1849 records in the table indicating that some messages (2339 1849 = 490) had been removed. Always 3. Entry type from the Z_PRIMARYKEY table: 3 = KikMessage. Unknown Unknown. Seen: 0 = normal textual message, 4 = attachment. Unknown Unknown Unknown Indicates whether the message was sent or received. 1 = received, 2 = sent. Unknown, only seen to be null. Foreign key: holds the PK of the ZKIKCHAT of which this is the most recent message.

Z_ENT Z_OPT ZFLAGS ZINTERNALID ZSTATE ZSYSTEMSTATE ZTYPE ZDRAFTMESSAGECHAT ZLASTMESSAGECHAT

ZLASTMESSAGEUSER ZUSER ZRECEIVEDTIMESTAMP ZTIMESTAMP ZBODY ZSTANZAID

Unknown, only seen to be null. Foreign key: holds the PK of the ZKIKUSERS which is the other party for the message. Time message was received as KIKTIME (== ZTIMESTAMP when sent). The messages in a conversation are ordered by this field: most recent at the bottom. Time message was sent as KIKTIME. The content of the message stored as encoding used by database (usually UTF-8). Unknown, GUID. In the case of messages which are attachments, the GUID is used as the file name for the thumbnail of the attachment in a chat; see 'Resolving the Attachments'.

ZKIKATTACHMENT Table
Z_PK Z_ENT Z_OPT ZFLAGS ZINTERNALID ZRETRYCOUNT ZSTATE ZTYPE ZMESSAGE Primary key Always 1. Entry type from the Z_PRIMARYKEY table: 1 = KikAttachment. Unknown, only seen to be either 1 or 2. Those with 2 had a ZMESSAGE of null. Unknown, only seen to be 0. Unknown, only seen to be 0. Unknown, only seen to be 0. Unknown, only seen to be 0. Unknown, only seen to be 6 or 7. Foreign key: holds the PK of the ZMESSAGE to which this attachment is attached. Unknown, KIKTIME. GUID used to identify the actual attachment; see 'Resolving the Attachments'.

ZLASTACCESSTIMESTAMP Unknown, only seen to be null. ZTIMESTAMP ZCONTENT

Z_METADATA Table
Seen to only contain 1 row. Z_VERSION Z_UUID Z_PLIST Unknown, only seen to be 1. Unknown, GUID. BLOB containing a binary plist file.

Z_2MESSAGES
Z_2CHAT Foreign key: holds the PK of a ZKIKCHAT. Z_3MESSAGES Foreign key: holds the PK of a ZKIKMESSAGE. This is a join table. Each record is a ZKIKCHAT and ZKIKMESSAGE pair. Each pair means that message ZKIKMESSAGE belongs in chat ZKIKCHAT. Testing showed that deleting a conversation only actually emptied this table for the particular ZKIKCHAT; the actual messages were still available in the ZKIKMESSAGE table.

Z_4MEMBERS
Z_4MEMBERSINVERSE Foreign key: holds the PK of a ZKIKUSER that is a group. Z_4MEMBERS Foreign key: holds the PK of a ZKIKUSER that is a member of the group.

This is a join table. Each record is a ZKIKUSER and ZKIKUSER pair. The ZKIKUSER listed under

Z_4MEMBERSINVERSE will be a group, the ZKIKUSER listed under Z_4MEMBERS will be a normal user. The pairing means that the user is a member of the group.

Entity Relationship Diagram


ZKIKCHAT Z_PK Z_USER ZKIKUSER Z_PK Z_CHATUSER Z_2MESSAGES Z_2CHAT Z_3MESSAGES ZKIKMESSAGE Z_PK Z_USER Z_4MEMBERS Z_4MEMBERSINVERSE Z_4MEMBERS ZKIKATTACHMENT Z_PK Z_MESSAGE

Each of the other four tables are not related to any other table, but each of ZKIKCHAT, ZKIKUSER, ZKIKMESSAGE and ZKIKATTACHMENT do have a Z_ENT which is a lookup based on Z_PRIMARYKEY.Z_ENT.

Resolving the Attachments


The attachments are identified by a GUID. Every GUID has a corresponding GUID in the folder /root/var/mobile/Applications/com.kik.chat/Documents/attachments. For example, a GUID of 3F2504E0-4F89-11D3-9A0C-0305E82C3301 would have an associated plist file of: /root/var/mobile/Applications/com.kik.chat/Documents/attachments/3F2504E0 4F8911D39A0C0305E82C3301.plist. This plist files seem to contain at least the below key-value pairs. <GUID> represents the GUID in question. id app-id image app-name app-pkg file-name allow-forward file-size file-url <GUID> ID of the app that generated the attachment. E.g. com.kik.ext.gallery, com.kik.ext.camera 1. base64-encoded icon of the attachment 2. base64-encoded preview of the attachment (only seen to be a JPG) Name of the app that is the source of the attachment. E.g. Gallery, Camera, Sketch. Name of the app package that sent the attachment. E.g. kik.android, com.kik.ext.gallery Name of the attachment. E.g. <GUID>.jpg, TMPFile.jpg Whether the attachment can be forwarded on via the 'forward' button. True or False. Size in bytes of the attachment. https://platform.kik.com/content/files/<GUID>?t=A_LONG_BASE64_STRING

Files in /root/var/mobile/Applications/com.kik.chat/Documents/ content_manager/data_cache/, seem to be previews of sent attachments. Files in /root/var/mobile/Applications/com.kik.chat/Documents/convothumbs are named as a GUID. This GUID can be found in the corresponding ZKIKMESSAGE.ZSTANZAID.

Orphaned Attachments
The column ZKIKATTACHMENT.ZKIKMESSAGE identifies the message to which the attachment belongs. In some test data, three of 59 attachments had NULL as the value for this column.

Blocking a User
Table ZKIKCHAT: Z_OPT changed from 5 to 6. Z_FLAGS changed from 2 to 26. Table ZKIKUSER: Z_OPT changed from 67 to 70. ZFLAGS changed from 1 to 33.

Chat Presentation
/root/var/mobile/Applications/com.kik.chat/Documents/caching/bubbleHeights.XML: GUID is ZKIKMESSAGE.ZSTANZAID.

A Note on Testing
During testing, I discovered that when I attached the iPod to my Linux Mint 14 (Nadia) workstation via USB, it presented as two devices: iPodTouch and DocumentsoniPodTouch. Documents of iPod Touch only had one folder:

Navigating into this folder, the structure, and more specifically, the kik.sqlite file could be located:

By copying the SQLite file to the local file system, it could be changed and then simply drag-and-dropped back to the iPod again. It's necessary to restart the Kik Messenger app on the iPod to get it to re-read the database. You can shut down the Kik app just as you would shut down any app on an iPod Touch/iPhone: double-tap the home key and the apps will display across the bottom as a mini toolbar. Tap on hold on Kik Messenger (or whichever app is being closed). The icons will then wobble and display a 'no entry' sign. Tapping the 'no entry' sign will close the app. To exit the wobbles, tap the home key. Tap the home key one more time to exit the 'task manager'. Opening Kik Messenger will now cause it to read the SQLite database again.