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