Tutorial #2 by vman_ (aka Kaz)
Published by Tsehp 2002
Tools Needed:
5. A Brain...
Thing You Need to Know:
5. Medium reversing experience
Introduction:
Many people today use Trillian as a Instant Messenger program. It combines AOL Instant Messenger, ICQ, MSN Messenger, and Yahoo Messenger all into one. The Trillian website (http://www.trillian.cc/) describes the program as the following:
"Communicate with Flexibility and Style. Trillian is everything you need for instant messaging.Connect to ICQ, AOL Instant Messenger, MSN Messenger, Yahoo! Messenger and IRC in a single, sleek and slim interface."
Upon downloading this application, most people will notice a very large flaw with Trillian; the logging capabilities of Trillian are very weak, logs aren't encrypted in anyway whatsoever (like ICQ does), and logs are left out in the open for anyone who has access to that PC. Living in a household dormant with family members that have questionable intentions, this design flaw in Trillian presents many problems.
Our solution: Have the logs get saved in an encrypted fashion (lame xor encryption).
Analysis:
Before we start doing anything, we have to plan out our steps
*** NOTE ***: A little tidbit before we start to work... When your in Trillian, double click on someone to message them and type in the following: /runwordwraptest. Enjoy :-D
Finding Logging Routines:
We begin by sorting through the log files. Open any log file that you have sitting in your log folder, and look for any signs of log specific text. In my case, I'm going to use a part of a log file from my friend Ikara on ICQ:
Session Start (ICQ - 2592580:Tifosi): Fri Jan 25 09:03:19 2002
*** NOTE: This user is offline. Your messages will be received when he/she logs into ICQ.
Kasra: wake up you BITCH
Session Close (Tifosi): Fri Jan 25 09:04:25 2002
This basically shows us when the message window was opened, what was inside of it, and when it was closed. The 'Session Start' and 'Session Close' messages don't appear inside the message window, which means that they are only ment for log files. Knowing that, lets search for *.exe's and *.dll's that contain those words in Trillian's main folder (Start Menu -> Search -> For Files or Folders...). The only file that shows up is "talk.dll".
Our next step is to disassemble this file. Make sure you have a backup of it made and put aside in case accidents are made. Open this file in IDA, and do a search for the text "Session Start" (without quotes). It'll drop you off in sub_10035D00. There are two references in this sub routine to text with the words "Session Start" in them, both being pushed in before a call to sub_10051A0F. Judging from the strings from both references being of formatted type we have to assume that sub_10051A0F is a function like sprintf()/printf()/fprintf.
If we move up the function we reach a piece of code that opens a file appending, then saves the pointer it returns:
10035D4F push offset aA_2 ; "a+" <--- 2nd param for fopen (mode) 10035D54 push edx <--- 1st param for fopen (filename) 10035D55 call _fopen <--- call fopen function 10035D5A add esp, 8 <--- fix stack 10035D5D mov [esi+108h], eax <--- save FILE pointer 10035D63 test eax, eax <--- check to see if FILE pointer is NULL (0) 10035D65 jz loc_10035E09 <--- if it is, jump to end of sub routine
Seeing this part of the function, we see information extracted
from [esi+108h] in the two references we found. This means that sub_10051A0F
must be fprintf(), but IDA's flirt signatures didn't pick up that function for
some reason.
First Reference:
10035DA1 mov edx, [esi+108h] <--- put FILE pointer into edx 10035DA7 add esp, 8 <--- fix stack 10035DAA push eax <--- push address for the second %s 10035DAB push ecx <--- push address for the first %s 10035DAC push offset aSessionStartSS ; "Session Start (%s): %s" <--- format string 10035DB1 push edx <--- saved file ptr 10035DB2 call sub_10051A0F <--- fprintf()
Second Reference:
10035DD5 mov edx, [esi+108h] <--- put FILE pointer into edx 10035DDB add esp, 8 <--- fix stack 10035DDE push eax <--- push address for the third %s 10035DDF push edi <--- push address for the second %s 10035DE0 push ecx <--- push address for the first %s 10035DE1 push offset aSessionStart_0 ; "Session Start (%s:%s): %s" <--- format string 10035DE6 push edx <--- saved file ptr 10035DE7 call sub_10051A0F <--- fprintf()
Upon further investigation, you will notice that all other references to fprintf are for logs. Therefor we all be adding code to the fprintf routine to encrypt our log info before it gets written to the file. Trying to encrypt the string before hand will mess up the format specifications.
Manually Adding a PE Section to Talk.DLL:
In order to add extra code to our program, we will need to make extra room in the file. Each section header info is 40 bytes long. The 38 bytes consist of the following:
QWORD SectionName; DWORD SizeOfContent; DWORD RVA; DWORD SizeOfRawData; DWORD FileOffset; DWORD PointerToRelocations; // NOT USED IN EXECUTABLES DWORD PointerToLinenumbers; // NOT USED IN EXECUTABLES WORD NumberOfRelocations; // NOT USED IN EXECUTABLES WORD NumberOfLinenumbers; // NOT USED IN EXECUTABLES DWORD Characteristics;
*** NOTE ***: For those of you who don't know what a QWORD (Quad Word) is, it is a 8 bytes long. So basically it's just four WORDs. The QWORD in our list is used as a non-null terminated string. It contains the sections name.
The easiest way to do this is to view the file in a hexeditor, and look to see how many SectionNames there are, go to the end of the last one, count 40 bytes, and begin at that point. Here is a hex dump of what you should see in your hex editor:
000001F0: 00 00 00 00-00 00 00 00-2E 74 65 78-74 00 00 00 .text 00000200: 32 C0 05 00-00 10 00 00-00 D0 05 00-00 10 00 00 2+ ð 00000210: 00 00 00 00-00 00 00 00-00 00 00 00-20 00 00 60 ` 00000220: 2E 72 64 61-74 61 00 00-34 34 00 00-00 E0 05 00 .rdata 44 Ó 00000230: 00 40 00 00-00 E0 05 00-00 00 00 00-00 00 00 00 @ Ó 00000240: 00 00 00 00-40 00 00 40-2E 64 61 74-61 00 00 00 @ @.data 00000250: 74 C3 00 00-00 20 06 00-00 B0 00 00-00 20 06 00 t+ _ 00000260: 00 00 00 00-00 00 00 00-00 00 00 00-40 00 00 C0 @ + 00000270: 2E 53 48 41-52 44 41 54-08 00 00 00-00 F0 06 00 .SHARDAT 00000280: 00 10 00 00-00 D0 06 00-00 00 00 00-00 00 00 00 ð 00000290: 00 00 00 00-40 00 00 D0-2E 72 73 72-63 00 00 00 @ ð.rsrc 000002A0: E0 74 00 00-00 00 07 00-00 80 00 00-00 E0 06 00 Ót Ç Ó 000002B0: 00 00 00 00-00 00 00 00-00 00 00 00-40 00 00 40 @ @ 000002C0: 2E 72 65 6C-6F 63 00 00-AE 49 00 00-00 80 07 00 .reloc «I Ç 000002D0: 00 50 00 00-00 60 07 00-00 00 00 00-00 00 00 00 P ` 000002E0: 00 00 00 00-40 00 00 42-00 00 00 00-00 00 00 00 @ 00000300: 00 00 00 00-00 00 00 00-00 00 00 00-20 00 00 00
".text" is the first PE section we notice. It starts off in 0x1F8. There are six PE Section headers in total listed down here. Here is a more organized way of looking at them when you put them in a chart:
Section 1
|
Section 2
|
Section 3
|
Section 4
|
Section 5
|
Section 6
|
|
SectionName
|
.text | .rdata | .data | .SHARDAT | .rsrc | .reloc |
SizeOfContent | 0x0005C032 | 0x00003434 | 0x0000C374 | 0x00000008 | 0x000074E0 | 0x000049AE |
RVA | 0x00001000 | 0x0005E000 | 0x00062000 | 0x0006F000 | 0x00070000 | 0x00078000 |
SizeOfRawData | 0x0005D000 | 0x00004000 | 0x0000B000 | 0x00001000 | 0x00008000 | 0x00005000 |
FillOffset | 0x00001000 | 0x0005E000 | 0x00062000 | 0x0006D000 | 0x0006E000 | 0x00076000 |
PointerToRelocations | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 |
PointerToLineNumbers | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 |
NumberOfRelocations | 0x0000 | 0x0000 | 0x0000 | 0x0000 | 0x0000 | 0x0000 |
NumberOfLineNumbers | 0x0000 | 0x0000 | 0x0000 | 0x0000 | 0x0000 | 0x0000 |
Characteristics | 0x60000020 | 0x40000040 | 0xC0000040 | 0xD0000040 | 0x40000040 | 0x42000040 |
What we want to do is create a seventh PE Section which we'll use to inject our own code into. We'll begin by writing out the header information. The file ends at 0x0007B000 and we want our section to be 0x500 bytes long. The easiest way is to go into Hex Workshop, move to the end of the file, go to Edit -> Insert, set the "Number of Bytes" to 500 Hex, set the "Fill with the following hex byte" field to 0, and press "Ok". Make note that our section starts at 0x0007B000.
After that's done, what needs to be done is the Section Header. The last Section Header is called ".reloc". Start from the start of the name (QWORD) and move across 40 bytes (come out to 0x2E8), here is where we should start writing out our section header info. We'll name our section after me, ".kaz":
QWORD SectionName = '.kaz'; DWORD SizeOfContent = 0x500; DWORD RVA = 0x0007B000+0x2000; // Align RVA to match rest of file DWORD SizeOfRawData = 0x500; DWORD FileOffset = 0x0007B000; DWORD PointerToRelocations = 0x00000000; // NOT USED IN EXECUTABLES DWORD PointerToLinenumbers = 0x00000000; // NOT USED IN EXECUTABLES WORD NumberOfRelocations = 0x0000; // NOT USED IN EXECUTABLES WORD NumberOfLinenumbers = 0x0000; // NOT USED IN EXECUTABLES DWORD Characteristics = 0x60000020; // Same characteristics value as .text
If you look at section six's RVA and FileOffset, you will notice that it has a difference of 0x2000 bytes. We need to maintain that alignment or else our PE section will be out of whack. Also, the characteristics were set to the same characteristics as section one's, because section one has it's flags set for executable code, and that's the same thing we need for our section since we'll be executing code from it. The end result once all this crap is entered into the hex editor should look like this:
000001F0: 00 00 00 00-00 00 00 00-2E 74 65 78-74 00 00 00 .text 00000200: 32 C0 05 00-00 10 00 00-00 D0 05 00-00 10 00 00 2+ ð 00000210: 00 00 00 00-00 00 00 00-00 00 00 00-20 00 00 60 ` 00000220: 2E 72 64 61-74 61 00 00-34 34 00 00-00 E0 05 00 .rdata 44 Ó 00000230: 00 40 00 00-00 E0 05 00-00 00 00 00-00 00 00 00 @ Ó 00000240: 00 00 00 00-40 00 00 40-2E 64 61 74-61 00 00 00 @ @.data 00000250: 74 C3 00 00-00 20 06 00-00 B0 00 00-00 20 06 00 t+ _ 00000260: 00 00 00 00-00 00 00 00-00 00 00 00-40 00 00 C0 @ + 00000270: 2E 53 48 41-52 44 41 54-08 00 00 00-00 F0 06 00 .SHARDAT 00000280: 00 10 00 00-00 D0 06 00-00 00 00 00-00 00 00 00 ð 00000290: 00 00 00 00-40 00 00 D0-2E 72 73 72-63 00 00 00 @ ð.rsrc 000002A0: E0 74 00 00-00 00 07 00-00 80 00 00-00 E0 06 00 Ót Ç Ó 000002B0: 00 00 00 00-00 00 00 00-00 00 00 00-40 00 00 40 @ @ 000002C0: 2E 72 65 6C-6F 63 00 00-AE 49 00 00-00 80 07 00 .reloc «I Ç 000002D0: 00 50 00 00-00 60 07 00-00 00 00 00-00 00 00 00 P ` 000002E0: 00 00 00 00-40 00 00 42-2E 6B 61 7A-00 00 00 00 @ B.kaz 000002F0: 00 05 00 00-00 D0 07 00-00 05 00 00-00 B0 07 00 ð _ 00000300: 00 00 00 00-00 00 00 00-00 00 00 00-20 00 00 60
Now, all we have to do is change the PE Header "NumberOfSections" value from 6 to 7. It's the second WORD after the 0x00004550 ('PE'):
00000100: 50 45 00 00-4C 01 06 00-4E 29 20 3C-00 00 00 00 PE L N) <
So basically it should look like this:
00000100: 50 45 00 00-4C 01 07 00-4E 29 20 3C-00 00 00 00 PE L N) <
Ok, we basically have a new PE section added that's 0x500 bytes long, and we can add our own code into it. Now, onto the modifications.
Inside FPRINTF():
The fprintf() function in this program looks pretty standard:
10051A0F push ebx 10051A10 push esi 10051A11 mov esi, [esp+0Ch] 10051A15 push edi 10051A16 push esi 10051A17 call __lock_file 10051A1C push esi 10051A1D call __stbuf 10051A22 mov edi, eax 10051A24 lea eax, [esp+20h] 10051A28 push eax 10051A29 push dword ptr [esp+20h] 10051A2D push esi 10051A2E call unknown_libname_23 10051A33 push esi 10051A34 push edi 10051A35 mov ebx, eax 10051A37 call __ftbuf 10051A3C push esi 10051A3D call __unlock_file 10051A42 add esp, 20h 10051A45 mov eax, ebx 10051A47 pop edi 10051A48 pop esi 10051A49 pop ebx 10051A4A retn
After going over this function with SoftICE a couple of times, we notice that on address 10051A2E the format string and the values passed in for it get lumped up together in. A pointer pointing to the end of the new formatted string in ESI and the length of the new formatted string is returned in EAX. So basically what we must do is take out some of the ASM code after this call, then put a jump to our code, read the ASM code to the end of our own code section, then jump back.
Sticking it All Together:
To make room for our jump to our encryption code, we must take out certain ASM instructions and place them in the end of our encryption function. The instructions that have to be moved is everything after "call unknown_libname_23" at 10051A2E and before "push esi" at 10051A3C. The instructions that get replaced are a few nop's and a jmp.
.10051A33: 90 nop <--- no operation .10051A34: 90 nop <--- no operation .10051A35: 90 nop <--- no operation .10051A36: 90 nop <--- no operation .10051A37: E9C1B70200 jmp .01007D1FD <--- jump to the start of our encryption function
I decided to write my encryption function starting at 1007D1FD, in the middle of the ".kaz" section :-D.
Mkay, now its time to write our ASM code. Here is the asm code I wrote up to encrypt the text (Yes, I know... very cheese):
.1007D1FD: 60 pushad <--- push all registers into stack .1007D1FE: 8B0E mov ecx,[esi] <--- move end of text address into ecx .1007D200: 2BC8 sub ecx,eax <--- ecx will point to start of of string .1007D202: 33D2 xor edx,edx <--- clear out edx (used as counter) .1007D204: 803C1100 cmp b,[ecx][edx],000 <--- end of string? .1007D208: 740A je .01007D214 <--- if yes, jump out of loop .1007D20A: 80341106 xor b,[ecx][edx],006 <--- xor byte in string with 0x06 .1007D20E: 42 inc edx <--- increase counter by 1 .1007D20F: E9F0FFFFFF jmp .01007D204 <--- go back to end of string check .1007D214: 61 popad <--- bring back all the registers saved in stack .1007D215: 56 push esi <--- code moved from fprintf function .1007D216: 57 push edi <--- code moved from fprintf function .1007D217: 8BC3 mov eax,ebx <--- code moved from fprintf function .1007D219: E8CA9FFDFF call .0100571E8 <--- code moved from fprintf function (call __ftbuf) .1007D21E: E91948FDFF jmp .010051A3C <--- jump back to fprintf function
If we were to save the changes we've made right now and run Trillian, this would work like a charm. Yet there is still one more problem we have to deal with! We don't want our unencrypted logs getting mangled into our encrypted logs. The solution? Change the extension in Trillian from .log to .kaz. This is simple to do, go into your favour hex editor and do a search for ".log" (without quotes). You will eventually see "%s\%s.log", this is the only format string in the entire DLL file that contains the extension .log, so it must be the saving extension. Change the ".log" part to ".kaz" or any other three letter extension of you choice. This will make Trillian now save logs to the ".kaz"extension instead of the ".log" extension.
The C Code:
Here is a simple C code to decrypt the logs for you to read them:
#include <stdio.h> #include <string.h> int main() { char encryptedFile[256]; char decryptedFile[256]; int ch = 0; printf("hello. welcome to vman's cheesy trillian log decrypter\n\n"); printf("file to decrypt:"); gets(encryptedFile); printf("file to save as:"); gets(decryptedFile); if (strcmp(encryptedFile, "") == 0 || strcmp(decryptedFile, "") == 0) { printf("bye!\n"); return 0; } FILE *fR = fopen(encryptedFile, "rb"); FILE *fW = fopen(decryptedFile, "w"); if ( fR == 0 || fW == 0 ) { printf("uh oh! couldn't open file\n"); return 0; } while( feof(fR) == 0 ) { ch = fgetc(fR); ch ^= 0x06; fputc(ch, fW); } printf("done!\n"); fclose(fR); fclose(fW); }
Testing:
For the final test I will be using my friend Ikara on ICQ.
Log file with encrypted-logging enabled Trillian:
Ucuuoih&Urgtr&.OEW&+&43?43>6<Ro`iuo/<&@to&Lgh&43&7?<75<37&4664Mg utg<&nsdctr*&qn>c&s&usen&g&ursvob&doren9Ro`iuo<&o&lsur&gk'M gutg<&k&tceikkchbgroih*&uriv&dcoha&g&ursvob&dorenRo`iuo<&qojj&b i(((Ucuuoih&Ejiuc&.Ro`iuo/<&@to&Lgh&43&7?<72<25&4664
That same log file run under the C Code in the section above:
Session Start (ICQ - 2592580:Tifosi): Fri Jan 25 19:13:51 2002 Kasra: hubert, why are u such a stupid bitch? Tifosi: i just am! Kasra: my recommendation, stop being a stupid bitch Tifosi: will do... Session Close (Tifosi): Fri Jan 25 19:14:43 2002
As we can clearly see, the original encrypted log file looks like what your twelve year old next door neighbor would write if he was messed up on acid. So the next time someone using the same PC as you attempts to access your log files, all they'll see is a bunch of scrambled text.
Conclusion:
In conclusion, after adding this bit of code you can have your mind put at ease about idiots wanting to look through it. You can also change the encryption routine and make it into something way better. If you need to contact me, you can email me at shogo2001@yahoo.com, ICQ me at 2592580, or contact me on IRC (efnet).