Monday, 14 December 2009

bot1.exe part6


The next step taken by the bot, after updating the registry, is the creation of a thread.
This thread will execute the function at address 0x41D0BB and the call to CreateThread has the creation flags set to 0 (so the thread will run immediatly upon creation).
This is the code of the newly created thread function:

0041D0BB  sub_41D0BB proc near                    
0041D0BB  push    esi
0041D0BC  xor     esi, esi
0041D0BE  loc_41D0BE:                             
0041D0BE  push    1
0041D0C0  push    esi
0041D0C1  push    esi
0041D0C2  push    esi
0041D0C3  push    esi
0041D0C4  push    esi
0041D0C5  call    thread_routine1_core
0041D0CA  add     esp, 18h
0041D0CD  push    ds:dword_45E438
0041D0D3  call    ds:Sleep
0041D0D9  jmp     short loc_41D0BE
0041D0D9  sub_41D0BB endp

As we can see, "thread_routine1_core" will be running on an infinite loop and this is the only thing sub_41D0BB will do.

After some variable initialization and preliminary checks, "thread_routine1_core" calls a function I named GrantSeDebugPrivilege with arguments ("SeDebugPrivilege",1) :

0041CD75  push    ebp
0041CD76  lea     ebp, [esp-60h]
0041CD7A  sub     esp, 554h
0041CD80  push    ebx
0041CD81  push    esi
0041CD82  push    edi
0041CD83  xor     ebx, ebx
0041CD85  push    49h
0041CD87  xor     eax, eax
0041CD89  cmp     ds:CreateToolhelp32Snapshot, ebx
0041CD8F  pop     ecx
0041CD90  lea     edi, [ebp+60h+var_12C]
0041CD96  mov     [ebp+60h+var_130], ebx
0041CD9C  rep stosd
0041CD9E  mov     ecx, 88h
0041CDA3  lea     edi, [ebp+60h+var_350]
0041CDA9  mov     [ebp+60h+var_354], ebx
0041CDAF  rep stosd
0041CDB1  jz      loc_41CF87
0041CDB7  cmp     ds:Process32First, ebx
0041CDBD  jz      loc_41CF87
0041CDC3  cmp     ds:Process32Next, ebx
0041CDC9  jz      loc_41CF87
0041CDCF  push    1
0041CDD1  push    offset aSedebugprivi_1          ; "SeDebugPrivilege"
0041CDD6  call    GrantSeDebugPrivilege

GrantSeDebugPrivilege will open a process token relative to the current process with desired access set to TOKEN_ADJUST_PRIVILEGES (Required to enable or disable the privileges in an access token.) | TOKEN_QUERY (Required to query an access token) (= 0x28):

0041CD10  lea     eax, [ebp+var_4]
0041CD13  push    eax
0041CD14  push    28h
0041CD16  call    ds:GetCurrentProcess
0041CD1C  push    eax
0041CD1D  call    ds:OpenProcessToken
0041CD23  test    eax, eax

It will then lookup the value of the privilege named "SeDebugPrivilige", and grant that privilege to the current process:

0041CD2E  push    [ebp+arg_0]
0041CD31  xor     esi, esi
0041CD33  push    esi
0041CD34  call    ds:LookupPrivilegeValueA
0041CD3A  test    eax, eax
0041CD3C  jz      short loc_41CD67
0041CD3E  cmp     [ebp+arg_4], esi
0041CD41 +mov     [ebp+var_14], 1
0041CD48  jz      short loc_41CD50
0041CD4A  or      [ebp+var_8], 2
0041CD4E  jmp     short loc_41CD54
0041CD50  loc_41CD50:                             
0041CD50  and     [ebp+var_8], 0FFFFFFFDh

0041CD54  loc_41CD54:                             
0041CD54  push    esi
0041CD55  push    esi
0041CD56  push    esi
0041CD57  lea     eax, [ebp+var_14]
0041CD5A  push    eax
0041CD5B  push    esi
0041CD5C  push    [ebp+var_4]
0041CD5F  call    ds:AdjustTokenPrivileges
0041CD65  mov     esi, eax
0041CD67
0041CD67  loc_41CD67:                             
0041CD67  push    [ebp+var_4]
0041CD6A  call    ds:CloseHandle
0041CD70  mov     eax, esi

Here we can read:
"
By setting the SeDebugPrivilege privilege on the running process, you can obtain the process handle of any running application. When obtaining the handle to a process, you can then specify the PROCESS_ALL_ACCESS flag, which will allow the calling of various Win32 APIs upon that process handle, which you normally could not do. Some of the Win32 APIs that could be successfully called include the following: ...
"
According to this, the thread's next actions will probably need access to handles from other processes, so this is the reason why SeDebugPrivilege is granted to our process.

Once GrantSeDebugPrivilege returns, thread_routine1_core will call CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0) (0 indicates current process). With these two arguments, the call to CreateToolhelp32Snapshot will enumerate all processes.

0041CDDD 53                push    ebx
0041CDDE 6A 0F             push    0Fh
0041CDE0 FF 15 B0 F6 45 00 call    ds:CreateToolhelp32Snapshot

After this, the list of all processes will be iterated. The way thread_routine1_core was called (thread_routine1_core(0,0,0,0,0,1)) makes the following jz's instructions jump:

0041CE3B  loc_41CE3B:                             
0041CE3B  xor     eax, eax
0041CE3D  cmp     [ebp+60h+arg_10], eax
0041CE40  jz      short loc_41CE9F
...
0041CE9F  loc_41CE9F:
0041CE9F  cmp     [ebp+60h+arg_C], eax
0041CEA2  jnz     loc_41CF46
0041CEA8  cmp     [ebp+60h+arg_4], eax
0041CEAB  jz      loc_41CF5B

and at 41CF5B:

0041CF5B  loc_41CF5B:
0041CF5B             
0041CF5B  lea     eax, [ebp+60h+var_130]
0041CF61  push    eax
0041CF62  push    [ebp+60h+var_8]
0041CF65  call    ds:Process32Next
0041CF6B  test    eax, eax
0041CF6D  jnz     loc_41CE3B
0041CF73  xor     ebx, ebx

when Process32Next returns 0, the snapshot handle will be closed and the procedure will terminate.
It should be noted that thread_routine1_core will be called from somewhere else in the application, and it will be further analyzed at that point.

In addition to this auxiliar thread, another thread is created. The second auxiliary thread will wait for connections on port 113 and return the string ' : USERID : UNIX : xxxx" where xxxx is a random string generated by a call to sub_40AF58.

No comments:

Post a Comment