***********************
* intro + general CTI *
***********************
the mydoom computer worm is what got me into cybersecurity. well actually it was this video by disrupt- but the original one with the marcus hutchins story (no shade).
so POV: it's january 2004. all fashion is bedazzled. limewire is at its peak. social media didn't exist.
you wake up late for work because you were up until midnight watching american idol season 2. caffeinated, agitated, and reeking of merlot, you angrily drive to work. avril lavigne's "complicated" comes on during the commute, and you cry bc it reminds you of your ex.
you walk into your office, fall into your non-ergonomic chair, and see this email:
you don't know wtf "7-bit ASCII encoding" is, but you know how to open email attachments from your orientation. so you click on it and this pops up in notepad:
"ugh. what is this. my head is pounding. i should call her. ): "
*******************************************************
here is an archived NBC article from january 26th 2004, the day mydoom first started appearing in people's email inboxes like in the above scenario.
the naive network infrastructure and poor cybersecurity awareness of the early 2000s made mydoom's spread massive. once clicked on, it would copy itself to the system directory, plant a backdoor, then send itself to everyone in the infected computer's address book via raw SMTP packets. at one point, it was estimated that around 1 in 10 emails sent *globally* were from the mydoom worm.
the earliest variants also contained a DDoS against microsoft and the SCO group, the latter of which were pretty disliked in the computing community bc of lawsuits they were filing against linux. THAT said it's unproven that mydoom's DDoS on SCO was retaliation for this.
the original variant of mydoom stopped spreading on february 12th of that year, but others came and went. palo alto reports that it's still active as late as 2019, having found 113,037 emails containing the worm in may of that year alone. mydoom's author was also never identified!!
**************
* disclaimer *
**************
mydoom's antidebugging techniques are rudimentary in comparison to most modern malware. there's no self-injection like what princesslocker uses, or return oriented obfuscation like in PLAY's ransomware. all we have is some UPX packing and ROT13 encoded strings within the disassembly, which would only *barely* evade antivirus solutions. regardless, mydoom's purpose wasn't stealth, but propogation; as of 2025, it *still* holds the record for the fastest spreading computer worm in history. a record that (likely) won't get broken because of improved cybersecurity awareness, email spam filters, robust antivirus solutions using AI, and anti-DDoS protection like load balancing and rate limiting.
me reversing this is *mostly* nostalgia. if you want a more interesting RE read, i reversed a custom VM-based obfuscator in a separate writeup. (:
******************
* basic analysis *
******************
you can find a sample of mydoom off malwarebazaar. the sha256 hash for the specific sample i'm reversing is:
fff0ccf5feaf5d46b295f770ad398b6d572909b00e2b8bcd1b1c286c70cd9151
here is some cursory information about this binary from hybrid analysis. when ran through virustotal:
we can see most antviruses flag it as malicious. obvs, since its 2025 and most antivirus software would have a mydoom signature.
i renamed my file to "doom9151.exe" (9151 being the last four numbers in its sha256 hash) and ran the file command on it. from its output we can see its packed with UPX:
we can also confirm this by looking at it in PEBear and noting the UPX sections:
to see imports and strings, i unpacked with the UPX command line utility (sidenote: most modern malware would opt for a custom packing algorithm over something as popular as UPX):
imports include CreateProcess (obvs bc it opens notepad), CreateFile, RegSetValue, and many others. there's also quite a bit of imported functions from the windows socket library, WS2_32.dll. those are imported by ordinal though, so can't tell specifically which ones.
running strings on the unpacked binary shows some ROT13 encoded strings, domains like ".gov" and ".mil", piecemeal university addresses like "rutgers.edu", the alphabet suffixed with "+/", administrative email aliases like "contact" and "nobody" and many other things.
i took some of the ROT13 strings and used cyberchef to decode them. lots of them are just packet headers. some are mail domains, like hotmail & aol. the "sco.com" string at the bottom is soooo ominous in hindsight:
********************
* environment prep *
********************
but let's talk about running mydoom bc that's where the fun is. so, windows XP was the most popular distribution of windows at the time. as such, i'm running this on a virtual machine with a 2003 version of XP installed. the only things i had on it were procmon, process hacker, and ollydbg.
mydoom also needs the internet to work properly. but like, we're not gonna just run malware on the open internet. so, i have a second virtual machine with remnux installed. within virtualbox, the two VMs are set up inside the same internal network, visible only to one another, with remnux set up as the windows VM's default gateway and DNS server, as well as having services like HTTP and SMTP running.
for simulating network services, i used the inetsim utlity. for capturing and spoofing DNS traffic, i used fakedns. mydoom sends itself to others via raw SMTP packets, so for that i also had remnux running wireshark.
the first variant of mydoom was also set to stop all activity on february 12th of 2004. to get the payload to run, i changed the time on the windows XP VM to be february 5th, 2004:
*************************
* network communication *
*************************
shortly after running, a bunch of SMTP requests start getting captured by wireshark. mydoom resolves mail servers using the domains found in email addresses harvested from the local system (this is shown later). since fakeDNS is running on remnux, the response to any DNS MX request- you know, what computers send when they want the IP address of a Mail eXchange server- will always be the remnux's own IP address. so, all SMTP traffic coming form mydoom can be captured by inetsim, which is running a fake SMTP server on port 25 (inetsim doesn't actually send any mail tho)
SMTP is all text-based, so reading the data in captured packets is straightforward. here, we can see the victim machine (10.0.0.2) sending a "EHLO" packet to the remnux VM (10.0.0.1), which initiates the SMTP connection. the EHLO packet also includes "aol.com", indicating mydoom is impersonating mail coming from aol. we can also see packets containing "MAIL FROM" and "RCPT TO", which are other keywords in SMTP for indicating the sender and recepient of an email respectively. afterwards, we can see a bunch of data packets getting sent.
note how the remnux VM's spoofed SMTP service is properly responding with "Ok" and [ACK] packets, indicating that it is successfully tricking mydoom into thinking it's actually communicating with a mail server. opening up the TCP stream for any one of these exchanges will show us something like this:
mydoom creates random email address to imitate a real person. here, it chose "mbkvh@aol.com". the receipient is "steve@edmweb.com"- how it determined who to send the message to is a mix of scraping the infected machine and guessing, but both will be covered in the disassembly. the subject line in this message is simply "hello", and the message itself includes the string "The messsage contains Unicode characters and has been sent as a binary attachment", which is similar to what was displayed in the earlier email.
the attachment can seen at the bottom of the above screenshot. the name of it is "text.bat", and, as the headers suggest, is encoded in base64. because SMTP is entirely text-based, executable files and other non-text attachments are usually converted into base64 before being transmitted somewhere.
i copy/pasted the entire base64 portion of the message and saved it in a file called "sent.bin". when we strip out the base64 encoding, we can see the output is a PE executable. what's more, is if we compare this file to the original mydoom binary, they are identical (linux's "cmp" command performs a byte-by-byte comparison on two files and returns nothing if they are the same)
when i changed the date on windows to february 8th instead of the 5th, an attempted DDoS on sco.com occurs. again, fakeDNS tells mydoom that SCO's IP address is that of my remnux VMs, so the malicious traffic targeting SCO just ends up going to remnux. the DDoS traffic can be seen from wireshark:
note how mydoom initiates a TCP handshake with a SYN packet- which prompts remnux to respond with a SYN, ACK packet- but instead of completing the handshake, mydoom sends a RST packet, which closes the connection. this is a classic example of a syn flood DDoS attack. consider this half-complete handshake being initiated 64 times per second, for every machine infected with mydoom. lots of traffic for SCO to deal with!! their website was taken offline for a bit.
************************
* host-based artifacts *
************************
so anyway, moving onto host-based artifacts, upon running the binary we can immediately observe the creation of a few files, including "shimgapi.dll", "taskmon.exe", and "Message":
we can use the built in fc utility on the windows command line to verify that taskmon.exe is simply a copy of the mydoom binary:
a little later on in the procmon output we can see the taskmon binary is appended to the CurrentVersion\Run registry key:
hindsight is 20/20, so we know there's quite a few important host based artifacts that are easy to miss in procmon. let's start looking @ the disassembly.
*****************************************
* extracting and analyzing shimgapi.dll *
*****************************************
so first, i wanted to have all relevant artifacts before staring at disassembly for hours. as such, figuring out where shimgapi.dll was coming from was the first move.
the name "shimgapi.dll" is lightly obfuscated with some ROT13 and exists in memory under the name "data_4a244c", sandwiched between other ROT13 encoded strings and a large chunk of nonsensical data:
cross-references to this variable lead to sub_4a3962 (renamed to "shimgapi_create" below). the decompilation of this function can be seen below:
the shimgapi file is created either within the System32 or TEMP directory. afterwards, a handle to it is passed to another function, sub_4a38e0 (renamed to "shimgapi_decrypt"). the core of this function can be seen in the below disassembly:
here, every byte from the previously seen nonsensical data is XORed with some rotating key, whose value is derived from some light math operations. scripting an extractor is pretty simple:
with open("doom9151.exe", 'rb') as f:
f.seek(1536, 0) # offset to the packed nonsense data
key = 0xc7 # initial key value
for i in range(4096):
b = int.from_bytes(f.read(1))
decoded_byte = b ^ key
key = (key + ((i % 0x85) * 3)) & 0xFF # the XOR key is never larger than a byte
with open("shimgapi.dll", 'ab') as o:
o.write(int.to_bytes(decoded_byte))
the resulting file is also packed with UPX:
the DLL's start function only consists of a call to CreateThread, with the following decompiled function set as the lpStartAddress attribute:
so the aforementioned video by disrupt mentions that whenever explorer.exe runs, shimgapi.dll will be automatically loaded with it. while this is true, it's actually a bit more involved than that. the function i renamed as "register_COMObject" is what handles one of shimgapi's persistence methods:
so the component object model (COM) is a convoluted aspect of the windows OS. honestly, i'm pretty shaky on my understanding of it at the time of writing this. essentially, if some application wants to, say, embed a web browser into itself, one of the ways it can accomplish this is by calling the corresponding COM object. windows has a bunch of these objects for doing tasks similar to the one i just described. to give one more example, there's a COM object for opening internet explorer (obvs deprecated in 2025) and navigating to a specified webpage.
COM is just a way for different applications to get access to a standardized set of functions that microsoft implemented with the OS. instead of rewriting the code for embedding a web browser from scratch, it's already done for you.
all COM objects have registry keys which correspond to the DLL which implements them. all of them are stored in the registry by way of a long string of random letters and numbers, called CLSIDs (class identifiers). in the code above, we see a ROT13 encoded string which decodes to:
HKCR\CLSID\{E6FB5E20-DE35-11CF-9C87-00AA005127ED}\InprocServer32
the number in the middle:
{E6FB5E20-DE35-11CF-9C87-00AA005127ED}
is the class identifier, and refers to the microsoft shell doc object and control library, used by various legitimate programs in windows- including explorer.exe. "InprocServer32" is the registry value that tells the OS which DLL to load for this COM object. "InProcServer" means that the DLL will be loaded into the calling process' address space.
SO mydoom updates this registry key so that whenever ANY program calls this specific CLSID, that process will load shimgapi.dll into its address space. because explorer.exe uses this COM object, every time it runs shimgapi.dll gets loaded as well. you can see in the below screenshot that shimgapi was indeed written there:
got it?? cute!!! if you want any more info on COM's being used in malware, virustotal has a great blog post all about COM object hijacking. you can also obvs refer to the MSDN entry on it too for better foundational info (warning: they use lots of jargon).
the rest of shimgapi is relatively straightforward. in a "while True" loop, ports between 3127-3198 are opened up and await incoming connections. if the incoming connection contains the byte "0x85", then a secondary check is done to see if the next four byte sequence is "0x133c9ea2". if THAT check passes, then a file is downloaded from the client, saved in the %TEMP% directory, executed, then deleted. here's the decompilation of the function responsible for that process:
we can see the backdoor successfully opened by calling netstat before & after running the mydoom bin. the corresponding PID points to explorer.exe:
if i had more time, we'd be able to fiddle around with this connection to maybe, say, open calc.exe. but understanding what's going on is enough for now (:
last thing to note in shimgapi: every 500 seconds the computer has been running (deduced from a call to GetTickCount()), the register_COMObject function from above runs again. it's mydoom's attempt at making shimgapi really hard to delete.
*******************************
* reversing the mydoom binary *
*******************************
cute. so now let's look at main() from the original binary and work forwards. here's the decompilation (with vars and functions renamed):
the function named "comdlg32_check" queries the following registry key:
Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\Version
the common dialog hive refers to those little pop up boxes that appear when you click something like "file > save as" in notepad. similar pop up boxes show up when you want to, say, load an executable into ollydbg or IDA, or print something. the "version" key increments per OS update, and is innocuous by default. mydoom queries subkeys under both HKCU (current user) and HKLM (local machine) to see if it has write access to affect all users on the infected machine, or just the user it's currently logged in as.
the "zeroed_data" that gets passed as an argument also serves multiple purposes. on top of swapping between the two hKey values, it also stores the return to GetTickCount(), and later on the path to the shimgapi DLL.
before creating shimgapi and checking the current time, mydoom also checks to see if a mutex under the name "SwebSipcSmtxS0" is present on the system. if so, it's indicative of the machine having been previously infected, and it exits.
the check for "zeroed_data" equaling zero is a bit misleading in the decompilation. here's the disassembly from the beginning of main:
at no point between the creation of zeroed_data and the call to createMutex() is any change made to the first byte of zeroed_data, so the createMutex(), despite appearing at the bottom of the decomp, is actually unconditional and one of the first things called. important? nope!! but relevant insofar as understanding that decompilation can give a skewed perspective of control flow in a binary.
anyway, after the message box appears and shimgapi is created, a function i named "time_checker" is called. here's the disassembly:
that highlighted add instruction is important. eax contains the start address of the "zeroed_data" variable. when you move 0x224 addresses down, you see this:
looks like nonsense, but those first 8 bytes actually translates to a date:
D4 07 - 2004
02 - february
0c - 12
so, mydoom checks to see if the current date is before february 12th 2004. if the check passes, eax returns 0 and the actual mydoom payload starts running.
*************************************
earlier i renamed a couple of functions in the screenshot of main's decomp. together, they make up mydoom's malicious payload. "copy_self_to_sys_dir" ROT13 decodes the string "taskmon.exe" and copies the mydoom binary into a file under that name, storing it in the system32 directory. "current_version" just adds "taskmon.exe" into the CurrentVersion\Run registry key for persistance. neither of those are particularly fun so i'm glossing over them. the real meat is in these four functions:
ddos_checker
kazaa_checker
propogation_start (aka the lpStartAddress argument in the call to CreateThread)
system_scraper
so let's go one by one:
****************
* ddos_checker *
****************
the purpose of ddos_checker is simple, so i'm just gonna summarize: it just checks to see if the current date is after february 1st, done in a manner identical to the above check. if it succeeds, another function is called, which i renamed "ddos_wrapper". the decomp can be seen below:
so there's a call to InternetGetConnectedState to confirm the machine is online (this is why having the remnux VM comes in clutch). the domain "www.sco.com" is also decoded from a ROT13 string. so long as the machine is connected to the internet and a proper DNS response is retrieved from gethostbyname, the function proceeds to enter a loop of 64 iterations, each one creating a thread whose start address sits at the function i renamed "do_ddos". as the name suggests, all this function does is send an HTTP GET request to www.sco.com in an infinite loop. so, 64 threads, all with infinite loops requesting sco's website. pretty nasty.
*****************
* kazaa checker *
*****************
kazaa was a file sharing platform popular in the 2000s. it's also considered adware by microsoft. lmao.
but yeah it was apparently pretty notorious for sharing illegally downloaded files and came packed with multiple types of malware. granted, that's just what i found from a cursory search online, so a grain of salt is necessary.
BBBBBBBBBBBBBBBBBBBBBBBBBBB
BMB---------------------B B
BBB---------------------BBB
BBB---------------------BBB
BBB---------------------BBB
BBB---------------------BBB
BBB---------------------BBB
BBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBB++++++++++++++++BBBBBB
BBBBB++BBBBB+++++++++BBBBBB
BBBBB++BBBBB+++++++++BBBBBB
BBBBB++BBBBB+++++++++BBBBBB
BBBBB++++++++++++++++BBBBBB
(to be continued)