Practical Malware Analysis — Lab 5
IDA Pro
Introduction:
I approached this lab as an opportunity to sharpen my reverse‑engineering skills using IDA Pro. In Practical Malware Analysis Lab 5, I was given a suspicious DLL Lab05–01.dll, and asked to uncover its behavior without running it. The goal was to practice static analysis techniques, identifying key functions, decoding hidden strings, mapping API calls, and using IDAPython scripts to automate de‑obfuscation.
In this investigation, I loaded the DLL into IDA Pro, used its imports and strings windows to locate network and shell operations, traced data flows to understand decision logic, and ran an IDAPython script to decrypt obfuscated data. What follows is a first‑person account of how I pieced together each clue and arrived at a comprehensive understanding of the malware’s capabilities.
Question 1: Pinpointing DllMain
The entry point (DllMain) would reveal initialization routines. I navigated to the ENTRY symbol in IDA’s Functions window. The address is 0x1000D02E
DllMain at 0x1000D02E.Question 2: Unmasking gethostbyname
Viewing the imports, searching for gethostbyname, and then looking for the address location, we find where this import is located 0x100163CC within idata
.idata at 0x100163CC..idata at 0x100163CC.Question 3: Counting the Summons
By using the jump to xrefs function while highlighting gethostbyname, we are able to find that this is run 18 times, by 9 different subroutines/functions.
Question 4: Hunting the DNS Query
By using the jump to address function, we’re able to specify the address to jump to and in this case can specify 0x10001757.
Looking at the operand before this function call, we can see that an address offset is being moved into EAX before 0Dh is added to it
By following this we can see that EAX now points to address 0x10019194
Because the pointer (EAX) is moved along 13 bytes, we now know that the DNS request will be made for:
pics.praticalmalwareanalysis.com
Question 5–6: Profiling a Subroutine
Jumping to the address at 0x10001656 we can find 24 different variables:
Looking at the previous screenshot we can find that IpThreadParameter has been identified which indicates one argument would be expected from this subroutine
Question 7–8: The Shell Command Discovery
I searched the String Window — View > Open subviews > Strings
Search through the strings window for cmd.exe, and we can find where it is located- 0x10095B34
By following the xref to the subroutine which references \cmd.exe /c
Taking a cursory look around sub_1000FF58, we see several indications of what might be happening
The offset aHiMasterDDDDDD called at 0x1001009D contains a long message which includes several strings relating to system time information, but more notably reference to a Remote Shell
Question 9: Decoding dword_1008E5C4
At address 0x100101C8 we can see a comparison statement comparing ebx to dword_1008E5C4
- Following this we can see that the output of sub_10003695 will be moved directly into dword_1008E5C4
So by looking into this routine we can find that it is comparing the dw platform ID to the value ‘2’:
This tells us that the field 2 indicates the operating system is Windows NT or later.
Question 10: The robotwork Riddle
I searched the string ‘robotwork’:
The robotwork string comparison is completed using the function memcmp, which returns 0 if the two strings are identical. The JNZ branch jumps if the result Is Not Zero. This means, if the robotwork comparison is successful, returning 0, then the jump does not execute.
Get Sapir Twig’s stories in your inbox
Join Medium for free to get updates from this writer.
Jumping to ->
There’s a registry key:
From this we can see that it is opening a registry key at: HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion. The JZ statement is once again asking “Is this false?”
Here we can see it is querying WorkTime, and WorkTime registry keys. If we look back at where this opened the registry key we can see that it is passing an argument type of “Socket” with the value ‘s’. Looking back at the start of this question we can see that this pushes ebp+s which indicates this information is sent back over the passed network socket.
Question 11: Unveiling PSLIST
By looking into the exports within this DLL we can find PSLIST. Following this and pressing SPACE leads us to the IDA Graph view.
From here we can see that one of 2 paths will be taken depending on the result of sub_100036C3, so let’s dive a bit deeper there.
So we now know it is checking whether the OS is any of these versions. Depending on the output it will either run sub_10006518 or sub_1000664C.
Taking a closer look at sub_10006518 we can see based on the API call to CreateToolhelp32Snapshot, strings, and the function name that this will allow them to grab a process listing.
Question 12: Renaming sub_10004E79
By using G to go to the address of interest (in this case sub_10004E79), we can then click View > Graphs > XRefs From to see a number of API functions within this function.
Based on this we can infer that it is more than likely the System Default Language Identifier would be sent over a network socket, and as such could name this function as LanguageIdentifier_Send.
Question 13: Tracing API Depth from DllMain
By clicking View > Graphs > User xrefs chart, and then adjusting the settings to start and end at the function DLLMain with a depth of 1, we’re able to see 4 Windows API Functions.
Some of the more notable API calls which may provide indication of functionality are: sleep winexec gethostbyname inet_nota CreateThread WSAStartup inet_addr recv send socket connect LoadLibraryA.
Question 14: Calculating the Sleep Timer
Moving back from the call to sleep, we can see that EAX is multiplied by 1000 before being pushed to the stack and called. This matches the reference to milliseconds, in that there are 1000 milliseconds in a second.
Looking up, we see that aThisIsCti30 at the offset address is moved into eax.
This means that the value of eax when it is pushed is 30. atoi converts the string to an integer, and it is multiplied by 1000. Therefore, the Sleep API function sleeps for 30 seconds.
Question 15–16: Socket Signature
Looking at this address we can see a call to socket which takes 3 parameters (protocol, type, and af) all of which are pushed to the stack prior to the call.
These depict what type of socket is created. Using Socket Documentation we can determine that in this case, it is TCP IPV4.
Question 17: VMware Evasion Check
By searching for ‘ED’ as a sequence of bytes (ALT+B) we can find only one occurrence of the instruction ‘in’.
Diving into this function we can see it is checking for the value VMXh which indicates this malware is implementing a known anti VM technique.
Looking at the Xrefs to this function we can see a reference to locating a VM in use and cancelling installation.
Question 18–21: De‑obfuscating the Payload
If we jump here using ‘G’ we find a bunch of seemingly random data.
we can see it will loop through from our current position (0x1001D988) up to 50 bytes and run an XOR command over all of them by 0x55. From this we can infer that the script will de-obfuscate the seemingly random data.
This can be done by pressing A on the string or doing so like we did earlier with CTI30. By converting all strings to ascii we wind up with gibberish still because each element still requires the XOR function.
We can also see there’s been some overlap of hex indicated by the ,27h,’ elements. By removing these and running the XOR command over all of the strings concatenated using CyberChef(https://gchq.github.io/CyberChef/) we get a hidden message.
The conversion to ASCII and manual decoding has messed up something with the capitalisation, but we can see some plaintext and determine the completed message:







