{
	"id": "444fec37-dc27-4616-8f01-f74ff3db3410",
	"created_at": "2026-04-06T01:32:29.99176Z",
	"updated_at": "2026-04-10T03:20:45.200092Z",
	"deleted_at": null,
	"sha1_hash": "bf60766e3fc0f3b662ed8ddb77e0881cf801258d",
	"title": "Data Talks: Deeper Down the Rabbit Hole: Second-Stage Attack and a Fileless Finale",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 2167876,
	"plain_text": "Data Talks: Deeper Down the Rabbit Hole: Second-Stage Attack\r\nand a Fileless Finale\r\nBy Dr Josh Stroschein\r\nPublished: 2018-11-05 · Archived: 2026-04-06 01:00:17 UTC\r\nIn our last blog, “Following a Trail of Confusion: PowerShell in Malicious Office Documents”, we systematically\r\nunraveled multiple layers of obfuscation initiated by a weaponized first-stage Microsoft Word document to reveal a\r\nsurreptitious download script and a malicious second-stage binary file dropped onto the victim PC. For those who\r\nwish to follow the analysis through to its conclusion, the sample MD5 is 6c8e800f14f927de051a3788083635e5 and\r\na VirusTotal report is here.\r\nPicking Up Where Word Drops Off\r\nSuppose the weaponized Word document was successful, bypassing all existing layered defenses, and now the next\r\nstage begins. This is the native code program that is now running in memory, and with it come additional\r\ncapabilities to compromise the host computer. As with our previous analysis, we have to figure out what type of\r\ncode obfuscation we’re dealing with it. With native code programs—portable executable (PE) files in the case of\r\nMicrosoft Windows—the first layer is usually packing. Packing is a well-known technique that essentially takes the\r\nmalicious program and wraps it inside another program. You can think of it like a zip or another archive, where if\r\nwe analyze the zip file, we won’t get any information about the content it contains.\r\nBromium Secure Platform shows the original malicious document, the request to retrieve this sample, and the\r\nprocess it invoked.\r\nSigns of Packing\r\nBefore jumping right into IDA Pro and tackling the disassembly, it’s often worthwhile to perform initial static\r\nanalysis of the PE file to get some ideas on packing and other potential code obfuscation techniques. PE parsing\r\nhttps://www.bromium.com/second-stage-attack-analysis/\r\nPage 1 of 13\n\nutilities can be valuable for getting an initial look at the characteristics of the file. Strings are a good first indicator,\r\nand the presence or lack of strings can provide critical insight into the program. Strings are an important part of any\r\nprogram as they are routinely needed for such functionality as making HTTP requests, writing files to disk, looking\r\nfor processes, and creating files in the file system. Malware authors will often attempt to obfuscate these strings,\r\nand an added benefit of packing is that the strings are compressed and encrypted inside, obscuring their discovery.\r\nThis sample presents some strings, but most of these come from the functions that it is importing. Outside of that,\r\nthere are no further indicators such as command and control (C2) URLs or IPs, indications of file or process\r\nactivity, or evidence of intended behavior such as a ransom note.\r\nSample of strings output using strings utility\r\nSections of the PE file are also worth investigating. Sections provide structure to the PE file for such items as the\r\nexecutable code and hard-coded data. In addition, they may provide evidence of malware that is packed. There are\r\nusually two strong indicators: the name of the section and the entropy of the section. Section names are arbitrary,\r\nbut some packers use consistent naming and allow for easier detection. Entropy is a measure of the randomness in a\r\nsequence of bytes, which make up the content of the sections. This is usually measured on a scale from zero to\r\neight, with eight being the highest measure of entropy. Programs that contain sections with high entropy are more\r\nsuspect for packing and other obfuscation techniques, since this garbled code tends to be more random and less\r\ndeliberate.\r\nDumpbin output of PE file sections\r\nWhile there are other indicators to consider, it appears this program is packed and will require deeper investigation.\r\nhttps://www.bromium.com/second-stage-attack-analysis/\r\nPage 2 of 13\n\nPACKING ANALYSIS AND CODE OBFUSCATION\r\nNow we can turn to IDA Pro to start analyzing the code of this program. Upon loading the file, IDA provides\r\nfurther indications that the sample is packed.\r\nIDA Pro dialog indicating potential packing\r\nThis program begins with a lot of instructions, most of them unnecessary. One way to try to filter through this code\r\nis to see how the registers, variables, and functions are being used. In this first code block, there are several\r\nfunction calls where the return value (in EAX) is being used in a compare/conditional jump combination. The\r\nconditional jump goes to loc_407257.\r\nIf we navigate to that location, we end up in an infinite loop. This is helpful, as we can now start to visually filter\r\nout this noise and attempt to find the true purpose of this code. Since we suspect that we are looking at purely\r\npacking code, we don’t want to spend a lot of time analyzing how this code works but find the point at which it’s\r\ndone. This will allow us to focus on whatever is unpacked. With unpacking code, I’ve often found that you can\r\nconcentrate on the end of the functions and look for abnormal returns or control transfers. This function ends with a\r\nfunction call, which is far from a normal epilogue.\r\nTracing into function sub_407027, we can investigate the code at the end. It appears there are two possible paths\r\nfor it to go, both with unconventional methods of going there.\r\nhttps://www.bromium.com/second-stage-attack-analysis/\r\nPage 3 of 13\n\nThis function uses a technique of pushing a DWORD value onto the stack and then jumping to ESP. What is\r\npushed onto the stack is actually an address: 0x4071B1. This technique has actually prevented IDA from\r\nidentifying the correct location and continuing with disassembly. If we go to that location manually, however, we\r\ncan tell IDA to disassemble this code.\r\nUnanalyzed JMP target\r\nDisassembled location 0x4071B1\r\nOnce the data at this location is disassembled, we reveal a call instruction with a call target of dword_40A34C. The\r\nvalue of this DWORD is not hard-coded, which means it is populated during runtime. Instead of continuing with\r\nstatic-analysis, we can now turn to WinDbg for dynamic analysis to see where this call goes.\r\nSwitching to Dynamic Analysis\r\nSetting a breakpoint on that call instruction reveals that the call target is to location 0x4071c4.\r\nSince IDA was unable to find this location during static analysis, it initially shows up as data instead of\r\ninstructions.\r\nhttps://www.bromium.com/second-stage-attack-analysis/\r\nPage 4 of 13\n\nInvoking IDA’s analysis reveals the disassembled instructions:\r\nIt’s easy to get lost in the assembly here and important to keep the big picture in mind. This code is all likely\r\nunpacking code, so let’s analyze it a little further down to see how it ends. There is a strange indirect call to ESI at\r\n0x407244.\r\nhttps://www.bromium.com/second-stage-attack-analysis/\r\nPage 5 of 13\n\nIf we continue execution to this point, we can see where it intends to lead. In this case, it’s to an address not in the\r\noriginal image – 0x57000 for this run. This address will change, as it’s a region of read-write-execute memory that\r\nis allocated during runtime.\r\nThis tells us that the previous code was responsible for not only allocating this memory, but also for staging\r\nshellcode for execution. Using a tool like Process Hacker, we can extract this shellcode from memory and\r\ndisassemble it.\r\nTracing the Shellcode\r\nFortunately, we know the entry point is at the beginning of the binary content from our dynamic analysis. Once this\r\nshellcode is disassembled, there will be a considerable amount of code to analyze. Let’s stick with the same\r\napproach we used to get here in the first place and analyze instructions toward the end of the shellcode. This\r\nshellcode ends with a PUSH/RET technique. The location the author wants to return to is pushed on the stack just\r\nbefore the return instruction.\r\nThis goes further into the shellcode. However, if we trace to the end of this code, there is a jmp esi. ESI contains an\r\naddress of 0x406FC0. This is a good sign, as it is taking execution back to an address in the original address space\r\nof the program. But is it the same code? By comparing the original data at the location to what is now in memory, a\r\ndifferent result means that unpacking could be complete.\r\nOriginal:\r\nhttps://www.bromium.com/second-stage-attack-analysis/\r\nPage 6 of 13\n\nIn memory:\r\nThe Plot Thickens\r\nUnfortunately, the malware is not yet ready to reveal what it is up to. Prior to performing a deep technical analysis,\r\nautomated dynamic analysis was used to understand as much of this program’s behavior as possible. This malware\r\nmakes a request to hxxps://real-estate-advisors[.win] and starts another process. This is likely the point at which\r\nthe malware receives code for its true intended purpose. However, if we let the program run from this point, the\r\nrequest isn’t made and no additional processes are created. Not only do we now know that it’s not done\r\nunpacking/deobfuscating, it is also exhibiting anti-analysis techniques not observed in our manual sandbox\r\nenvironment.\r\nLooking at the cross-reference graph from sub_406FC0, there is a considerable amount of code. How do we\r\novercome this mess? One method is to start by setting breakpoints on expected. For example, CreateProcessA or\r\nInternetOpenURLA. Letting this code run ends in a call to TerminateProcess, and in this case none of these\r\nbreakpoints were hit. This could indicate a few things, including anti-analysis techniques. Instead of trying to\r\nanalyze this function from the top-down, focusing on the call instructions towards the end of the function may\r\nspeed up analysis. Especially if this involves more unpacking, then the earlier function calls will likely be for\r\nmemory allocation and more unpacking, and the later function calls for executing the unpacked code. This function\r\nends with three function calls and after inspecting them, the call to sub_5200 appears to be the most promising.\r\nAgain, we’re faced with a significant amount of code and a limited amount of time for analysis, so let’s focus on\r\nthe end of the function. Toward the end of this function is another indirect function call. These are usually\r\ninteresting as they may indicate a dynamically-generated address.\r\nIndirect function call at offset 0x5D65\r\nAs it turns out, this is the call to ExitProcess, so somewhere before this call is not only any anti-analysis, but also\r\nthe next stage of functionality.\r\nhttps://www.bromium.com/second-stage-attack-analysis/\r\nPage 7 of 13\n\nAfter spending some time analyzing this function, another promising location presents itself:\r\nCall instruction to offset 0x51B0 at location 0x5C00\r\nThis function is limited in functionality, but it ultimately proves to be the location responsible for the next stage of\r\nthis malware.\r\nThe call $+5 is a common shell code technique to get the address of the stack, as the call instruction will push the\r\naddress of the next instruction (add [esp+10h+var_10], 5) onto the stack and then add 5 to it. The push instruction\r\nwill push the address 0x51D5 onto the stack, once 5 is added to it the address that this function will return to is\r\nhttps://www.bromium.com/second-stage-attack-analysis/\r\nPage 8 of 13\n\n0x51D6. This takes execution to the first instruction after the return. Since IDA was not able to follow this logic,\r\nwe need to disassemble the code at this location.\r\nThere’s a call to DWORD_0, which actually represents the beginning of this section of code (.TEXT section). We\r\ncan resume our dynamic analysis to continue to trace this code.\r\nSetting the appropriate breakpoints, I stopped at the RETF to ensure that my analysis of where this code was going\r\nto return to was correct.\r\nAnd the value on top of the stack is:\r\nHowever, if you trace into this RETF the program doesn’t go to the address we expect:\r\nWhat happened? Turns out, RETF takes two values off of the stack: one value for the segment and a second value\r\nfor the return address. Notice the PUSH 33h before the RETF, this will force the CPU into 64-bit mode instead of\r\n32-bit! Since I was using a 32-bit instance of WinDbg, I was getting unexpected results. Switching to a 64-bit\r\ninstance of WinDbg allows us to trace into this RETF.\r\nIt’s a call to 0x401000. We have to go back to our original shellcode. IDA wasn’t able to find a reference to this\r\nlocation, so the code was never disassembled. Keep in mind that I extracted this as shellcode from the .text section,\r\nso an offset of 0 is equivalent to a virtual address of 0x401000. We also know something else that is very\r\nhttps://www.bromium.com/second-stage-attack-analysis/\r\nPage 9 of 13\n\nimportant–this is 64-bit code. Opening this code with the 64-bit version of IDA gives us an accurate disassembly\r\nlisting.\r\nDisassembled 64-bit shellcode, function graph, and call graph\r\nOne of the first things to determine is if we can find any API calls. This code doesn’t have an extensive call graph,\r\nbut one function, Sub_F90, stands out simply due to the number of times it is called.\r\nhttps://www.bromium.com/second-stage-attack-analysis/\r\nPage 10 of 13\n\nSub_F90 may be responsible for resolving APIs. Setting a breakpoint on this function allows us to investigate the\r\nreturn value in the EAX register. Sure enough, they’re function pointers! Some of the more relevant ones are:\r\nNtAllocateVirtualMemory, NtWirteVirtualMemory, and RtlCreateUserThread. Following these API calls, it\r\neventually becomes clear that the code is attempting to load a DLL via the CreateUserThread method. During\r\nexecution, the DLL is copied directly into memory and never touches disk! It’s unpacked purely in memory and\r\nthen loaded into the current process by the createthread call. As this is a “fileless” stage of the attack, extracting this\r\nDLL from memory provides the opportunity to continue our analysis.\r\nCloser to the End\r\nThis DLL has only one export, which is DllEntryPoint (or DLLMain). This is called by the thread created in the\r\nprevious stage, and it reveals yet another round of complicated code.\r\nSimilar to the last stage, I was able to identify the function responsible for resolving APIs. In this code,\r\nsub_180011820 returns a function pointer in the RAX register.\r\nhttps://www.bromium.com/second-stage-attack-analysis/\r\nPage 11 of 13\n\nTracing this allows visibility into the different APIs being called, and that is where the majority of the anti-analysis\r\nis employed. For example, there is a call to CreateToolhelpSnapshot32, which is then used to look for evidence of\r\nsandbox/analysis processes. Each process name is converted to a multibyte string, changed to upper-case, and then\r\nused to create a CRC32 checksum. The checksum value is compared to a list of pre-computed values to avoid using\r\nany strings in the sample, a deliberate obfuscation technique used to avoid clear-text strings which are easily\r\ndiscovered.\r\nArray of DWORD pre-computed checksum values\r\nR8 contains a pointer to pre-computed checksum and compared with dynamically computed checksum from process\r\nname in EBX\r\nThis code also looks for manufacturer information through a call to GetSystemFirmwareTable. Bypassing these\r\nchecks allows the program to finally deliver its intended payload—to make a request for another stage to\r\nhxxps://real-estate-advisors[.win]/vwrdhrbisero/sqyeqten3/niejln3i/tag1h/luyb/45014rvw/4w5unn5vx4di.jpg!\r\nThis resource is retrieved from a command and control node and then is used to create yet another process.\r\nHowever, this server has now gone offline, but not before its ultimate payload was categorized as a malicious\r\nbanking trojan by the anti-malware community.\r\nhttps://www.virustotal.com/#/file/ee32c4e0a4b345029d8b0f5c6534fa9fc41e795cc937d3f3fd743dcb0a1cea35/detection\r\nhttps://www.bromium.com/second-stage-attack-analysis/\r\nPage 12 of 13\n\nDespite all of the obfuscation and anti-analysis we have examined together—and the fact that we utilized multiple\r\ntools to reveal the complete picture—every stage of this malware would have been safely contained within the\r\nBromium Secure Platform in an isolated micro-virtual machine. Detection failed to stop the initial stages of the\r\nattack, which gave the attacker complete freedom to place secondary payloads onto the victim’s PC. This one was a\r\nbanking trojan, but next time it could be something entirely different or completely new. Attackers never stop\r\ninnovating—and they are always a step or two ahead of detection-focused defenders—so consider application\r\nisolation and control using virtualization-based security to protect your endpoints against whatever they come up\r\nwith next.\r\nSource: https://www.bromium.com/second-stage-attack-analysis/\r\nhttps://www.bromium.com/second-stage-attack-analysis/\r\nPage 13 of 13\n\nthis malware. The call $+5 is a common shell code technique to get the address of the stack, as the call instruction will push the\naddress of the next instruction (add [esp+10h+var_10], 5) onto the stack and then add 5 to it. The push instruction\nwill push the address 0x51D5 onto the stack, once 5 is added to it the address that this function will return to is\n   Page 8 of 13",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://www.bromium.com/second-stage-attack-analysis/"
	],
	"report_names": [
		"second-stage-attack-analysis"
	],
	"threat_actors": [],
	"ts_created_at": 1775439149,
	"ts_updated_at": 1775791245,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/bf60766e3fc0f3b662ed8ddb77e0881cf801258d.pdf",
		"text": "https://archive.orkl.eu/bf60766e3fc0f3b662ed8ddb77e0881cf801258d.txt",
		"img": "https://archive.orkl.eu/bf60766e3fc0f3b662ed8ddb77e0881cf801258d.jpg"
	}
}