{
	"id": "1eb25a33-6205-495b-9197-53f62fc2f03f",
	"created_at": "2026-04-06T01:30:15.979548Z",
	"updated_at": "2026-04-10T13:12:33.726007Z",
	"deleted_at": null,
	"sha1_hash": "eeabd240a30d2e46a64da168e7354b61169d6d63",
	"title": "Malware-Analysis/SmoothOperator/SmoothOperator.md at main · dodo-sec/Malware-Analysis",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 2330542,
	"plain_text": "Malware-Analysis/SmoothOperator/SmoothOperator.md at main ·\r\ndodo-sec/Malware-Analysis\r\nBy dodo-sec\r\nArchived: 2026-04-06 01:20:18 UTC\r\nThis analysis is focused on the SmoothOperator payloads from Sentinel One. They were obtained via vx-underground and comprise two DLLs. The first stage has the hash\r\nbf939c9c261d27ee7bb92325cc588624fca75429.\r\nFirst stage\r\nThis DLL is a straightforward PE loader, with no obfuscation or encryption present. A good first step is looking\r\nfor references to VirtualProtect - there are two.\r\nFirst one looks promising, given the ERW flag being passed to it. Checking the function called afterwards\r\n( __guard_dispatch_icall_fptr ) leads us to an offset, which in turn leads to jmp rax . This is probably a jump\r\nto unpacked code or the next stage. Let's circle back to the start of the function where those calls to\r\nVirtualProtect are and see what exactly we're marking as executable and then jumping to.\r\nhttps://github.com/dodo-sec/Malware-Analysis/blob/main/SmoothOperator/SmoothOperator.md\r\nPage 1 of 7\n\nThis looks promising. A DLL named d3dcompiler_47.dll and a call to CreateFileW , followed by memory\r\nallocation of the same size as that file. Moving on, we'll see some obvious parsing of a PE file.\r\nFinally, we see a loop that starts looking for the sequence 0xFE 0xED 0xFA 0xCE at the Security directory of\r\nd3dcompiler_47.dll and moves forward. If we can find that sequence of bytes in a DLL file, we probably have\r\nd3dcompiler_47.dll - it just so happens that sequence in present in the second DLL from Sentinel One,\r\nhttps://github.com/dodo-sec/Malware-Analysis/blob/main/SmoothOperator/SmoothOperator.md\r\nPage 2 of 7\n\n20d554a80d759c50d6537dd7097fed84dd258b3e. Going forward there are several arithmetic operations followed\r\nby the aforementioned VirtualProtect and jmp rax . Instead of worrying about those, just pop the DLL into a\r\ndebugger, rename 20d554a80d759c50d6537dd7097fed84dd258b3e to d3dcompiler_47.dll and run until the jmp\r\nrax . First stage is done.\r\nSecond stage\r\nA quick glance at the debugger following the jmp to rax shows we land at some shellcode at allocated memory.\r\nThe dump window also shows the same memory region. One should be careful when dumping it though, since\r\nthere's plenty of random data preceding the shellcode and d3dcompiler_47.dll ; throwing it in Ida before getting\r\nrid of that data will make for an annoying time.\r\nOn that note, even though Ida Home supports shellcode analysis, I decided to convert this stage to a PE file. The\r\nreason is twofold: first, it means I won't have to import local types manually; second, it means I can keep the\r\ndump as is, which is advantageous because we'll be able to follow direct references to the DLL that follows the\r\nshellcode. For that end, I do a simple hack with FASM:\r\ninclude '..\\..\\fasmw17330\\include\\win64ax.inc'\r\n.code\r\nstart:\r\n file 'stage2.bin'\r\n \r\n invoke ExitProcess, 0\r\n \r\n.end start\r\nhttps://github.com/dodo-sec/Malware-Analysis/blob/main/SmoothOperator/SmoothOperator.md\r\nPage 3 of 7\n\nThe start of the shellcode features basic position independent code ( call $+5 followed by pop rcx ), which is\r\nused to get the address of the start of the DLL read into memory by the first stage into rcx . Another\r\ndisplacement is applied to get a pointer to what appears to be an User-Agent string into r8 :\r\n1200 2400 \"Mozilla/5.0 (Windows NT 10.0; Win64; x64)\r\nAppleWebKit/537.36 (KHTML, like Gecko) 3CXDesktopApp/18.11.1197\r\nChrome/102.0.5005.167 Electron/19.1.9 Safari/537.36”\r\nThe next call is to a function that will be tasked with mapping d3dcompiler_47.dll . Although it's already in\r\nmemory, it has not been mapped as an executable needs to be before it's able to run. Here's the start of it, after\r\nrenaming and adjusting types for the arguments to match what was placed in the registers preceding the call.\r\nIn another common practice with shellcode, API hashes are present. HashDB identifies the algorithm employed\r\nhere as one used by Metasploit. If one decides to look into the mw_import_by_hash function, it's important to\r\nremember that this code deals with PEB64 and TEB64 , structs that I couldn't find in Ida. I recommend this\r\nresource from BITE* to create your own struct for both. Doing this will solve you a couple hours of confused\r\ncursing at the 32 bit structures.\r\nhttps://github.com/dodo-sec/Malware-Analysis/blob/main/SmoothOperator/SmoothOperator.md\r\nPage 4 of 7\n\nNext up the actual mapping of the DLL into memory takes place. This is made evident by several snippets of code\r\nthat parse PE Section Headers relevant to the mapping process. The one below checks to see if the PE being\r\nprocessed is indeed for a 64-bit architecture; other lines deal with the PE sections and the entry point address:\r\nA bit further down, memory is allocated to match the size of the DLL (according to the value in\r\nIMAGE_NT_HEADERS64.OptionalHeader.SizeOfImage ):\r\nA very interesting sequence follows. It's responsible for resolving all imports of the third stage DLL by using\r\nLoadLibraryA and GetProcAddress . Taking note of which fields of the PE are being parsed and watching a few\r\nloops of it running will help you grasp how an import table is built when an executable is mapped.\r\nhttps://github.com/dodo-sec/Malware-Analysis/blob/main/SmoothOperator/SmoothOperator.md\r\nPage 5 of 7\n\nA lot more code follows this, mapping sections and using VirtualProtect to assign the correct protections to\r\neach one. We're almost done now!\r\nThere's then a call rbx instruction that leads to a rabbit hole of shellcode functions. Unfortunately what follows\r\nnext is something no one likes to read in an analysis like this, but I have no idea what those do. My educated\r\nguess is some combination of anti-emulation/anti-sandbox, since there are multiple uses of the cpuid instruction\r\nin there and a test following that call will skip the jump to the next stage and instead just return. If anyone is\r\ncurious, feel free to give it a look.\r\nhttps://github.com/dodo-sec/Malware-Analysis/blob/main/SmoothOperator/SmoothOperator.md\r\nPage 6 of 7\n\nAfter the return from the mysterious shellcode rabbit hole, we have only a few steps left. The code ensures it has\r\nmapped the DLL correctly by checking the size of its Data Directory and the exported functions (there is only one,\r\nDllGetClassObject ); it then maps the address of said name to r8 . Then the name of the export itself is checked\r\nby a simple ROR 13 ADD hash function, another callback to metasploit:\r\nFinally, the arguments (remember those from ages ago??) are put back into the relevant registers and there is a\r\njump to r8, which now holds the address of exported function of the third stage DLL. Its command line arguments\r\nare the User-Agent string from earlier and the constant 0xAA (thanks to the Sentinel One Report for pointing out\r\nthat this constant is the size of the User-Agent string).\r\nImportant time-saving tip:\r\nIt's only as I wrap up this write-up that I realized there is no decryption of the third stage DLL done by the\r\nshellcode, only mapping and maybe some anti-emulation shenanigans. As such, one can really speed up their\r\nanalysis by extracting the full stage 2 payload and getting rid of everything before the MZ header of the third stage\r\nDLL.\r\nSource: https://github.com/dodo-sec/Malware-Analysis/blob/main/SmoothOperator/SmoothOperator.md\r\nhttps://github.com/dodo-sec/Malware-Analysis/blob/main/SmoothOperator/SmoothOperator.md\r\nPage 7 of 7",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://github.com/dodo-sec/Malware-Analysis/blob/main/SmoothOperator/SmoothOperator.md"
	],
	"report_names": [
		"SmoothOperator.md"
	],
	"threat_actors": [],
	"ts_created_at": 1775439015,
	"ts_updated_at": 1775826753,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/eeabd240a30d2e46a64da168e7354b61169d6d63.pdf",
		"text": "https://archive.orkl.eu/eeabd240a30d2e46a64da168e7354b61169d6d63.txt",
		"img": "https://archive.orkl.eu/eeabd240a30d2e46a64da168e7354b61169d6d63.jpg"
	}
}