{
	"id": "fbd579df-0dff-4ace-bda2-2553e2bf09ec",
	"created_at": "2026-04-06T00:19:15.076778Z",
	"updated_at": "2026-04-10T03:25:24.525882Z",
	"deleted_at": null,
	"sha1_hash": "171eb950f9a8fb84c9b5223e93d3f4cb5309d079",
	"title": "FinFisher exposed: A researcher’s tale of defeating traps, tricks, and complex virtual machines | Microsoft Security Blog",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1392455,
	"plain_text": "FinFisher exposed: A researcher’s tale of defeating traps, tricks,\r\nand complex virtual machines | Microsoft Security Blog\r\nBy Microsoft Threat Intelligence\r\nPublished: 2018-03-01 · Archived: 2026-04-05 12:48:26 UTC\r\nOffice 365 Advanced Threat Protection (Office 365 ATP) blocked many notable zero-day exploits in 2017. In our\r\nanalysis, one activity group stood out: NEODYMIUM. This threat actor is remarkable for two reasons:\r\nIts access to sophisticated zero-day exploits for Microsoft and Adobe software\r\nIts use of an advanced piece of government-grade surveillance spyware FinFisher, also known as FinSpy\r\nand detected by Microsoft security products as Wingbird\r\nFinFisher is such a complex piece of malware that, like other researchers, we had to devise special methods to\r\ncrack it. We needed to do this to understand the techniques FinFisher uses to compromise and persist on a\r\nmachine, and to validate the effectiveness of Office 365 ATP detonation sandbox, Windows Defender Advanced\r\nThreat Protection (Windows Defender ATP) generic detections, and other Microsoft security solutions.\r\nThis task proved to be nontrivial. FinFisher is not afraid of using all kinds of tricks, ranging from junk instructions\r\nand “spaghetti code” to multiple layers of virtual machines and several known and lesser-known anti-debug and\r\ndefensive measures. Security analysts are typically equipped with the tools to defeat a good number of similar\r\ntricks during malware investigations. However, FinFisher is in a different category of malware for the level of its\r\nanti-analysis protection. It’s a complicated puzzle that can be solved by skilled reverse engineers only with good\r\namount of time, code, automation, and creativity. The intricate anti-analysis methods reveal how much effort the\r\nFinFisher authors exerted to keep the malware hidden and difficult to analyze.\r\nThis exercise revealed tons of information about techniques used by FinFisher that we used to make Office 365\r\nATP more resistant to sandbox detection and Windows Defender ATP to catch similar techniques and generic\r\nbehaviors. Using intelligence from our in-depth investigation, Windows Defender ATP can raise alerts for\r\nmalicious behavior employed by FinFisher (such as memory injection in persistence) in different stages of the\r\nattack kill chain. Machine learning in Windows Defender ATP further flags suspicious behaviors observed related\r\nto the manipulation of legitimate Windows binaries.\r\nhttps://www.microsoft.com/security/blog/2018/03/01/finfisher-exposed-a-researchers-tale-of-defeating-traps-tricks-and-complex-virtual-machines/\r\nPage 1 of 17\n\nFigure 1. Generic Windows Defender ATP detections trigger alerts on FinFisher behavior\r\nWhile our analysis has allowed us to immediately protect our customers, we’d like to share our insights and add to\r\nthe growing number of published analyses by other talented researchers (listed below this blog post). We hope that\r\nthis blog post helps other researchers to understand and analyze FinFisher samples and that this industry-wide\r\ninformation-sharing translate to the protection of as many customers as possible.\r\nIn analyzing FinFisher, the first obfuscation problem that requires a solution is the removal of junk instructions\r\nand “spaghetti code”, which is a technique that aims to confuse disassembly programs. Spaghetti code makes the\r\nprogram flow hard to read by adding continuous code jumps, hence the name. An example of FinFisher’s\r\nspaghetti code is shown below.\r\nhttps://www.microsoft.com/security/blog/2018/03/01/finfisher-exposed-a-researchers-tale-of-defeating-traps-tricks-and-complex-virtual-machines/\r\nPage 2 of 17\n\nFigure 2. The spaghetti code in FinFisher dropper\r\nThis problem is not novel, and in common situations there are known reversing plugins that may help for this task.\r\nIn the case of FinFisher, however, we could not find a good existing interactive disassembler (IDA) plugin that\r\ncan normalize the code flow. So we decided to write our own plugin code using IDA Python. Armed with this\r\ncode, we removed this first layer of anti-analysis protection.\r\nRemoving the junk instructions revealed a readable block of code. This code starts by allocating two chunks of\r\nmemory: a global 1 MB buffer and one 64 KB buffer per thread. The big first buffer is used as index for multiple\r\nconcurrent threads. A big chunk of data is extracted from the portable executable (PE) file itself and decrypted two\r\ntimes using a custom XOR algorithm. We determined that this chunk of data contains an array of opcode\r\ninstructions ready to be interpreted by a custom virtual machine program (from this point on referenced\r\ngenerically as “VM”) implemented by FinFisher authors.\r\nhttps://www.microsoft.com/security/blog/2018/03/01/finfisher-exposed-a-researchers-tale-of-defeating-traps-tricks-and-complex-virtual-machines/\r\nPage 3 of 17\n\nFigure 3. The stages of the FinFisher multi-layered protection mechanisms\r\nStage 0: Dropper with custom virtual machine\r\nThe main dropper implements the VM dispatcher loop and can use 32 different opcodes handlers. Th 64KB buffer\r\nis used as a VM descriptor data structure to store data and the just-in-time (JIT) generated code to run. The VM\r\ndispatcher loop routine ends with a JMP to another routine. In total, there are 32 different routines, each of them\r\nimplementing a different opcode and some basic functionality that the malware program may execute.\r\nFigure 4. A snapshot of the code that processes each VM opcode and the associate interpreter\r\nThe presence of a VM and virtualized instruction blocks can be described in simpler terms: Essentially, the\r\ncreators of FinFisher interposed a layer of dynamic code translation (the virtual machine) that makes analysis\r\nusing regular tools practically impossible. Static analysis tools like IDA may not be useful in analyzing custom\r\ncode that is interpreted and executed through a VM and a new set of instructions. On the other hand, dynamic\r\nhttps://www.microsoft.com/security/blog/2018/03/01/finfisher-exposed-a-researchers-tale-of-defeating-traps-tricks-and-complex-virtual-machines/\r\nPage 4 of 17\n\nanalysis tools (like debuggers or sandbox) face the anti-debug and anti-analysis tricks hidden in the virtualized\r\ncode itself that detects sandbox environments and alters the behavior of the malware.\r\nAt this stage, the analysis can only continue by manually investigating the individual code blocks and opcode\r\nhandlers, which are highly obfuscated (also using spaghetti code). Reusing our deobfuscation tool and some other\r\ntricks, we have been able to reverse and analyze these opcodes and map them to a finite list that can be used later\r\nto automate the analysis process with some scripting.\r\nThe opcode instructions generated by this custom VM are divided into different categories:\r\n1. Logical opcodes, which implement bit-logic operators (OR, AND, NOT, XOR) and mathematical operators\r\n2. Conditional branching opcodes, which implement a code branch based on conditions (equals to JC, JE, JZ,\r\nother similar branching opcodes)\r\n3. Load/Store opcodes, which write to or read from particular addresses of the virtual address space of the\r\nprocess\r\n4. Specialized opcodes for various purposes, like execute specialized machine instruction that are not\r\nvirtualized\r\nWe are publishing below the (hopefully) complete list of opcodes used by FinFisher VM that we found during our\r\nanalysis and integrated into our de-virtualization script:\r\nINDEX MNEMONIC DESCRIPTION\r\n0x0 EXEC Execute machine code\r\n0x1 JG Jump if greater/Jump if not less or equal\r\n0x2 WRITE\r\nWrite a value into the dereferenced internal VM value (treated as\r\na pointer)\r\n0x3 JNO Jump if not overflow\r\n0x4 JLE Jump if less or equal (signed)\r\n0x5 MOV\r\nMove the value of a register into the VM descriptor (same as\r\nopcode 0x1F)\r\n0x6 JO Jump if overflow\r\n0x7 PUSH Push the internal VM value to the stack\r\n0x8 ZERO Reset the internal VM value to 0 (zero)\r\n0x9 JP Jump if parity even\r\n0xA WRITE Write into an address\r\n0xB ADD Add the value of a register to the internal VM value\r\nhttps://www.microsoft.com/security/blog/2018/03/01/finfisher-exposed-a-researchers-tale-of-defeating-traps-tricks-and-complex-virtual-machines/\r\nPage 5 of 17\n\n0xC JNS Jump if not signed\r\n0xD JL Jump if less (signed)\r\n0xE EXEC Execute machine code and branch\r\n0xF JBE Jump if below or equal or Jump if not above\r\n0x10 SHL\r\nShift left the internal value the number of times specified into the\r\nopcodes\r\n0x11 JA Jump if above/Jump if not below or equal\r\n0x12 MOV Move the internal VM value into a register\r\n0x13 JZ JMP if zero\r\n0x14 ADD Add an immediate value to the internal Vm descriptor\r\n0x15 JB Jump if below (unsigned)\r\n0x16 JS Jump if signed\r\n0x17 EXEC Execute machine code (same as opcode 0x0)\r\n0x18 JGE Jump if greater or equal/Jump if not less\r\n0x19 DEREF Write a register value into a dereferenced pointer\r\n0x1A JMP Special obfuscated “Jump if below” opcode\r\n0x1B * Resolve a pointer\r\n0x1C LOAD Load a value into the internal VM descriptor\r\n0x1D JNE Jump if not equal/Jump if not zero\r\n0x1E CALL Call an external function or a function located in the dropper\r\n0x1F MOV Move the value of a register into the VM descriptor\r\n0x20 JNB Jump if not below/Jump if above or equal/Jump if not carry\r\n0x21 JNP Jump if not parity/Jump if parity odd\r\nEach virtual instruction is stored in a special data structure that contains all the information needed to be properly\r\nread and executed by the VM. This data structure is 24 bytes and is composed of some fixed fields and a variable\r\nportion that depends on the opcode. Before interpreting the opcode, the VM decrypts the opcode’s content\r\n(through a simple XOR algorithm), which it then relocates (if needed), using the relocation fields.\r\nHere is an approximate diagram of the opcode data structure:\r\nhttps://www.microsoft.com/security/blog/2018/03/01/finfisher-exposed-a-researchers-tale-of-defeating-traps-tricks-and-complex-virtual-machines/\r\nPage 6 of 17\n\nFigure 5. A graphical representation of the data structure used to store each VM opcode\r\nThe VM handler is completely able to generate different code blocks and deal with relocated code due to address\r\nspace layout randomization (ASLR). It is also able to move code execution into different locations if needed. For\r\ninstance, in the case of the “Execute” opcode (0x17), the 32-bit code to run is stored entirely into the variable\r\nsection with the value at offset 5 specifying the number of bytes to be copied and executed. Otherwise, in the case\r\nof conditional opcodes, the variable part can contain the next JIT packet ID or the next relative virtual address\r\n(RVA) where code execution should continue.\r\nOf course, not all the opcodes are can be easily read and understood due to additional steps that the authors have\r\ntaken to make analysis extremely complicated. For example, this is how opcode 0x1A is implemented: The opcode\r\nshould represent a JB (Jump if below) function, but it’s implemented through set carry (STC) instruction followed\r\nby a JMP into the dispatcher code that will verify the carry flag condition set by STC.\r\nFigure 6. One of the obfuscation tricks included by the malware authors in a VM opcode dispatcher\r\nEven armed with the knowledge we have described so far, it still took us many hours to write a full-fledged\r\nopcode interpreter that’s able to reconstruct the real code executed by FinFisher.\r\nStage 1: Loader malware keeps sandbox and debuggers away\r\nThe first stage of FinFisher running through this complicated virtual machine is a loader malware designed to\r\nprobe the system and determine whether it’s running in a sandbox environment (typical for cloud-based detonation\r\nsolution like Office 365 ATP).\r\nThe loader first dynamically rebuilds a simple import address table (IAT), resolving all the API needed from\r\nKernel32 and NtDll libraries. It then continues executing in a spawned new thread that checks if there are\r\nadditional undesired modules inside its own virtual address space (for example, modules injected by certain\r\nhttps://www.microsoft.com/security/blog/2018/03/01/finfisher-exposed-a-researchers-tale-of-defeating-traps-tricks-and-complex-virtual-machines/\r\nPage 7 of 17\n\nsecurity solutions). It eventually kills all threads that belong to these undesired modules (using\r\nZwQueryInformationThread native API with ThreadQuerySetWin32StartAddress information class).\r\nThe first anti-sandbox technique is the loader checking the code segment. If it’s not 0x1B (for 32-bit systems) or\r\n0x23 (for 32-bit system under Wow64), the loader exits.\r\nNext, the dropper checks its own parent process for indications that it is running in a sandbox setup. It calculates\r\nthe MD5 hash of the lower-case process image name and terminates if one of the following conditions are met:\r\n1. The MD5 hash of the parent process image name is either D0C4DBFA1F3962AED583F6FCE666F8BC or\r\n3CE30F5FED4C67053379518EACFCF879\r\n2. The parent process’s full image path is equal to its own process path\r\nIf these initial checks are passed, the loader builds a complete IAT by reading four imported libraries from disk\r\n(ntdll.dll, kernel32.dll, advapi32.dll, and version.dll) and remapping them in memory. This technique makes use\r\nof debuggers and software breakpoints useless. During this stage, the loader may also call a certain API using\r\nnative system calls, which is another way to bypass breakpoints on API and security solutions using hooks.\r\nFigure 7. FinFisher loader calling native Windows API to perform anti-debugging tricks\r\nAt this point, the fun in analysis is not over. A lot of additional anti-sandbox checks are performed in this exact\r\norder:\r\n1. Check that the malware is not executed under the root folder of a drive\r\n2. Check that the malware file is readable from an external source\r\n3. Check that the hash of base path is not 3D6D62AF1A7C8053DBC8E110A530C679\r\n4. Check that the full malware path contains only human readable characters (“a-z”, “A-Z”, and “0-9”)\r\n5. Check that no node in the full path contains the MD5 string of the malware file\r\n6. Fingerprint the system and check the following registry values:\r\n1. HKLM\\SOFTWARE\\Microsoft\\Cryptography\\MachineGuid should not be “6ba1d002-21ed-4dbe-afb5-08cf8b81ca32”\r\nhttps://www.microsoft.com/security/blog/2018/03/01/finfisher-exposed-a-researchers-tale-of-defeating-traps-tricks-and-complex-virtual-machines/\r\nPage 8 of 17\n\n2. HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\DigitalProductId should not be\r\n“55274-649-6478953-23109”, “A22-00001”, or “47220”\r\n3. HARDWARE\\Description\\System\\SystemBiosDate should not contain “01/02/03”\r\n7. Check that the mutex WininetStartupMutex0 does not already exist\r\n8. Check that no DLL whose base name has hash value of 0xC9CEF3E4 is mapped into the malware address\r\nspace\r\nThe hashes in these checks are most likely correspond to sandbox or security products that the FinFisher authors\r\nwant to avoid.\r\nNext, the loader checks that it’s not running in a virtualized environment (VMWare or Hyper-V) or under a\r\ndebugger. For the hardware virtualization check, the loader obtains the hardware device list and checks if the MD5\r\nof the vendor ID is equal to a predefined list. In our tests, the malware sample was able to easily detect both\r\nVMWare and Hyper-V environments through the detection of the virtualized peripherals (for example, Vmware\r\nhas VEN_15AD as vendor ID, HyperV has VMBus as bus name). Office 365 ATP sandbox employs special\r\nmechanisms to avoid being detected by similar checks.\r\nThe loader’s anti-debugger code is based on the following three methods:\r\n1. The first call aims to destroy the debugger connection:\r\nNOTE: This call completely stops the execution of WinDbg and other debuggers\r\n2. The second call tries to detect the presence of a debugger:\r\n3. The final call tries to destroy the possibility of adding software breakpoint:\r\nFinally, if the loader is happy with all the checks done so far, based on the victim operating system (32 or 64-bit) it\r\nproceeds to decrypt a set of fake bitmap resources (stage 2) embedded in the executable and prepares the\r\nexecution of a new layer of VM decoding.\r\nEach bitmap resource is extracted, stripped of the first 0x428 bytes (BMP headers and garbage data), and\r\ncombined into one file. The block is decrypted using a customized algorithm that uses a key derived from the\r\noriginal malware dropper’s TimeDateStamp field multiplied by 5.\r\nhttps://www.microsoft.com/security/blog/2018/03/01/finfisher-exposed-a-researchers-tale-of-defeating-traps-tricks-and-complex-virtual-machines/\r\nPage 9 of 17\n\nFigure 8. The fake bitmap image embedded as resource\r\nThe 32-bit stage 2 malware uses a customized loading mechanism (i.e., the PE file has a scrambled IAT and\r\nrelocation table) and exports only one function. For the 64-bit stage 2 malware, the code execution is transferred\r\nfrom the loader using a well-known technique called Heaven’s Gate. In the next sections, for simplicity, we will\r\ncontinue the analysis only on the 64-bit payload.\r\nFigure 9. Heaven’s gate is still in use in 2017\r\nStage 2: A second multi-platform virtual machine\r\nThe 64-bit stage 2 malware implements another loader combined with another virtual machine. The architecture is\r\nquite similar to the one described previously, but the opcodes are slightly different. After reversing these opcodes,\r\nwe were able to update our interpreter script to support both 32-bit and 64-bit virtual machines used by FinFisher.\r\nINDEX MNEMONIC DESCRIPTION\r\n0x0 JMP\r\nSpecial obfuscated conditional Jump (always taken or always\r\nignored)\r\n0x1 JMP Jump to a function (same as opcode 0x10)\r\n0x2 CALL Call to the function pointed by the internal VM value\r\nhttps://www.microsoft.com/security/blog/2018/03/01/finfisher-exposed-a-researchers-tale-of-defeating-traps-tricks-and-complex-virtual-machines/\r\nPage 10 of 17\n\n0x3 CALL\r\nOptimized CALL function (like the 0x1E opcode of the 32-bit\r\nVM)\r\n0x4 EXEC Execute code and move to the next packet\r\n0x5 JMP Jump to an internal function\r\n0x6 NOP No operation, move to the next packet\r\n0x7 CALL\r\nCall an imported API (whose address is stored in the internal VM\r\nvalue)\r\n0x8 LOAD Load a value into the VM descriptor structure *\r\n0x9 STORE Store the internal VM value inside a register\r\n0xA WRITE Resolve a pointer and store the value of a register in its content\r\n0xB READ Move the value pointed by the VM internal value into a register\r\n0xC LOAD Load a value into the VM descriptor structure (not optimized)\r\n0xD CMP\r\nCompare the value pointed by the internal VM descriptor with a\r\nregister\r\n0xE CMP\r\nCompare the value pointed by the internal VM descriptor with an\r\nimmediate value\r\n0xF XCHG\r\nExchange the value pointed by the internal VM descriptor with a\r\nregister\r\n0x10 SHL Jump to a function (same as opcode 0x1)\r\nThis additional virtual machine performs the same duties as the one already described but in a 64-bit environment.\r\nIt extracts and decrypts the stage 3 malware, which is stored in encrypted resources such as fake dialog boxes. The\r\nextraction method is the same, but the encryption algorithm (also XOR) is much simpler. The new payload is\r\ndecrypted, remapped, and executed in memory, and represents the installation and persistence stage of the\r\nmalware.\r\nStage 3: Installer that takes DLL side-loading to a new level\r\nStage 3 represents the setup program for FinFisher. It is the first plain stage that does not employ a VM or\r\nobfuscation. The code supports two different installation methods: setup in a UAC-enforced environment (with\r\nlimited privileges), or an installation with full-administrative privileges enabled (in cases where the malware gains\r\nthe ability to run with elevated permissions). We were a bit disappointed that we did not see traces of a true\r\nprivilege escalation exploit after all this deobfuscation work, but it seems these FinFisher samples were designed\r\nto work just using UAC bypasses.\r\nhttps://www.microsoft.com/security/blog/2018/03/01/finfisher-exposed-a-researchers-tale-of-defeating-traps-tricks-and-complex-virtual-machines/\r\nPage 11 of 17\n\nThe setup code receives an installation command from the previous stage. In our test, this command was the value\r\n3. The malware creates a global event named 0x0A7F1FFAB12BB2 and drops some files under a folder located in\r\nC:\\ProgramData or in the user application data folder. The name of the folder and the malware configuration are\r\nread from a customized configuration file stored in the resource section of the setup program.\r\nHere the list of the files potentially dropped during the installation stage:\r\nFILE NAME STAGE DESCRIPTION\r\nd3d9.dll Stage 4\r\nMalware loader used for UAC environments with\r\nlimited privileges; also protected by VM obfuscation\r\naepic.dll, sspisrv.dll,\r\nuserenv.dll\r\nStage 4\r\nMalware loader used in presence of administrative\r\nprivileges; executed from (and injected into) a fake\r\nservice; also protected by VM obfuscation\r\nmsvcr90.dll Stage 5\r\nMalware payload injected into the explorer.exe or\r\nwinlogon.exe process; also protected by VM\r\nobfuscation\r\n\u003crandomName\u003e.cab Config Main configuration file; encrypted\r\nsetup.cab Unknown\r\nLast section of the setup executable; content still\r\nunknown\r\n\u003crandomName\u003e.7z Plugin\r\nMalware plugin used to spy the victim network\r\ncommunications\r\nwsecedit.rar Stage 6 Main malware executable\r\nAfter writing some of these files, the malware decides which kind of installation to perform based on the current\r\nprivilege provided by the hosting process (for example, if a Microsoft Office process was used as exploit vector):\r\n1. Installation process under UAC\r\nWhen running under a limited UAC account, the installer extracts d3d9.dll and creates a persistence key under\r\nHKCU\\Software\\Microsoft\\Windows\\Run. The malware sets a registry value (whose name is read from the\r\nconfiguration file) to “C:\\Windows\\system32\\rundll32.exe c:\\ProgramData\\AuditApp\\d3d9.dll, Control_Run”.\r\nBefore doing this, the malware makes a screenshot of the screen and displays it on top of all other windows for\r\nfew seconds. This indicates that the authors are trying to hide some messages showed by the system during the\r\nsetup process.\r\nWhen loaded with startup command 2, the installer can copy the original explorer.exe file inside its current\r\nrunning directory and rename d3d9.dll to uxtheme.dll. In this case the persistence is achieved by loading the\r\noriginal explorer.exe from its startup location and, using DLL side-loading, passing the execution control to the\r\nstage 4 malware (discussed in next section).\r\nhttps://www.microsoft.com/security/blog/2018/03/01/finfisher-exposed-a-researchers-tale-of-defeating-traps-tricks-and-complex-virtual-machines/\r\nPage 12 of 17\n\nFinally, the malware spawns a thread that has the goal to load, remap, and relocate the stage 5 malware. In this\r\ncontext, there is indeed no need to execute the stage 4 malware. The msvcr90.dll file is opened, read, and\r\ndecrypted, and the code execution control is transferred to the RunDll exported routine.\r\nIn the case of 32-bit systems, the malware may attempt a known UAC bypass by launching printui.exe system\r\nprocess and using token manipulation with NtFilterToken as described in this blog post.\r\n2. Installation process with administrative privilege\r\nThis installation method is more interesting because it reveals how the malware tries to achieve stealthier\r\npersistence on the machine. The method is a well-known trick used by penetration testers that was automated and\r\ngeneralized by FinFisher\r\nThe procedure starts by enumerating the KnownDlls object directory and then scanning for section objects of the\r\ncached system DLLs. Next, the malware enumerates all .exe programs in the %System% folder and looks for an\r\noriginal signed Windows binary that imports from at least one KnownDll and from a library that is not in the\r\nKnownDll directory. When a suitable .exe file candidate is found, it is copied into the malware installation folder\r\n(for example, C:\\ProgramData). At this point the malware extracts and decrypts a stub DLL from its own\r\nresources (ID 101). It then calls a routine that adds a code section to a target module. This section will contain a\r\nfake export table mimicking the same export table of the original system DLL chosen. At the time of writing, the\r\ndropper supports aepic.dll, sspisrv.dll, ftllib.dll, and userenv.dll to host the malicious FinFisher payload. Finally, a\r\nnew Windows service is created with the service path pointing to the candidate .exe located in this new directory\r\ntogether with the freshly created, benign-looking DLL.\r\nIn this way, when the service runs during boot, the original Windows executable is executed from a different\r\nlocation and it will automatically load and map the malicious DLL inside its address space, instead of using the\r\ngenuine system library. This routine is a form of generic and variable generator of DLL side-loading\r\ncombinations.\r\nhttps://www.microsoft.com/security/blog/2018/03/01/finfisher-exposed-a-researchers-tale-of-defeating-traps-tricks-and-complex-virtual-machines/\r\nPage 13 of 17\n\nFigure 10. Windows Defender ATP timeline can pinpoint the service DLL side-loading trick (in this example,\r\nusing fltlib.dll).\r\nIn the past, we have seen other activity groups like LEAD employ a similar attacker technique named “proxy-library” to achieve persistence, but not with this professionalism. The said technique brings the advantage of\r\navoiding auto-start extensibility points (ASEP) scanners and programs that checks for binaries installed as service\r\n(for the latter, the service chosen by FinFisher will show up as a clean Windows signed binary).\r\nThe malware cleans the system event logs using OpenEventLog/ClearEventLog APIs, and then terminates the\r\nsetup procedure with a call to StartService to run the stage 4 malware.\r\nhttps://www.microsoft.com/security/blog/2018/03/01/finfisher-exposed-a-researchers-tale-of-defeating-traps-tricks-and-complex-virtual-machines/\r\nPage 14 of 17\n\nFigure 11. The DLL side-loaded stage 4 malware mimicking a real export table to avoid detection\r\nStage 4: The memory loader – Fun injection with GDI function hijacking\r\nDepending on how stage 4 was launched, two different things may happen:\r\nIn the low-integrity case (under UAC) the installer simply injects the stage 5 malware into the bogus\r\nexplorer.exe process started earlier and terminates\r\nIn the high-integrity case (with administrative privileges or after UAC bypass), the code searches for the\r\nprocess hosting the Plug and Play service (usually svchost.exe) loaded in memory and injects itself into it\r\nFor the second scenario, the injection process works like this:\r\n1. The malware opens the target service process.\r\n2. It allocates and fills four chunks of memory inside the service process. One chunk contains the entire\r\nmalware DLL code (without PE headers). Another chunk is used to copy a basic Ntdll and Kernel32 import\r\naddress table. Two chunks are filled with an asynchronous procedure call (APC) routine code and a stub.\r\n3. It opens the service thread of the service process and uses the ZwQueueApcThread native API to inject an\r\nAPC.\r\nThe APC routine creates a thread in the context of the svchost.exe process that will map and execute the stage 5\r\nmalware into the winlogon.exe process.\r\nThe injection method used for winlogon.exe is also interesting and quite unusual. We believe that this method is\r\nengineered to avoid trivial detection of process injection using the well-detected CreateRemoteThread or\r\nZwQueueApcThread API.\r\nThe malware takes these steps:\r\n1. Check if the system master boot record (MBR) contains an infection marker (0xD289C989C089 8-bytes\r\nvalue at offset 0x2C), and, if so, terminate itself\r\n2. Check again if the process is attached to a debugger (using the techniques described previously)\r\n3. Read, decrypt, and map the stage 5 malware (written in the previous stage in msvcr90.dll)\r\n4. Open winlogon.exe process\r\n5. Load user32.dll system library and read the KernelCallbackTable pointer from its own process\r\nenvironment block (PEB) (Note: The KernelCallbackTable points to an array of graphic functions used by\r\nWin32 kernel subsystem module win32k.sys as call-back into user-mode.)\r\n6. Calculate the difference between this pointer and the User32 base address.\r\n7. Copy the stage 5 DLL into winlogon.exe\r\n8. Allocate a chunk of memory in winlogon.exe process and copy the same APC routine seen previously\r\n9. Read and save the original pointer of the __fnDWORD internal User32 routine (located at offset +0x10 of\r\nthe KernelCallbackTable) and replace this pointer with the address of the APC stub routine\r\nAfter this function pointer hijacking, when winlogon.exe makes any graphical call (GDI), the malicious code can\r\nexecute without using CreateRemoteThread or similar triggers that are easily detectable. After execution it takes\r\ncare of restoring the original KernelCallbackTable.\r\nhttps://www.microsoft.com/security/blog/2018/03/01/finfisher-exposed-a-researchers-tale-of-defeating-traps-tricks-and-complex-virtual-machines/\r\nPage 15 of 17\n\nStage 5: The final loader takes control\r\nThe stage 5 malware is needed only to provide one more layer of obfuscation, through the VM, of the final\r\nmalware payload and to set up a special Structured Exception Hander routine, which is inserted as\r\nWow64PrepareForException in Ntdll. This special exception handler is needed to manage some memory buffers\r\nprotection and special exceptions that are used to provide more stealthy execution.\r\nAfter the VM code has checked again the user environment, it proceeds to extract and execute the final un-obfuscated payload sample directly into winlogon.exe (alternatively, into explorer.exe) process. After the payload\r\nis extracted, decrypted, and mapped in the process memory, the malware calls the new DLL entry point, and then\r\nthe RunDll exported function. The latter implements the entire spyware program.\r\nStage 6: The payload is a modular spyware framework for further analysis\r\nOur journey to deobfuscating FinFisher has allowed us to uncover the complex anti-analysis techniques used by\r\nthis malware, as well as to use this intel to protect our customers, which is our top priority. Analysis of the\r\nadditional spyware modules is future work.\r\nIt is evident that the ultimate goal of this program is to steal information. The malware architecture is modular,\r\nwhich means that it can execute plugins. The plugins are stored in its resource section and can be protected by the\r\nsame VM. The sample we analyzed in October, for example, contains a plugin that is able to spy on internet\r\nconnections, and can even divert some SSL connections and steal data from encrypted traffic.\r\nSome FinFisher variants incorporate an MBR rootkit, the exact purpose of which is not clear. Quite possibly, this\r\nroutine targets older platforms like Windows 7 and machines not taking advantage of hardware protections like\r\nUEFI and SecureBoot, available on Windows 10. Describing this additional piece of code in detail is outside the\r\nscope of this analysis and may require a new dedicated blog post.\r\nDefense against FinFisher\r\nExposing as much of FinFisher’s riddles as possible during this painstaking analysis has allowed us to ensure our\r\ncustomers are protected against this advanced piece of malware.\r\nWindows 10 S devices are naturally protected against FinFisher and other threats thanks to the strong code\r\nintegrity policies that don’t allow unknown unsigned binaries to run (thus stopping FinFisher’s PE installer) or\r\nloaded (blocking FinFisher’s DLL persistence). On Windows 10, similar code integrity policies can be configured\r\nusing Windows Defender Application Control.\r\nOffice 365 Advanced Threat Protection secures mailboxes from email campaigns that use zero-day exploits to\r\ndeliver threats like FinFisher. Office 365 ATP blocks unsafe attachments, malicious links, and linked-to files using\r\ntime-of-click protection. Using intel from this research, we have made Office 365 ATP more resistant to\r\nFinFisher’s anti-sandbox checks.\r\nGeneric detections, advanced behavioral analytics, and machine learning technologies in Windows Defender\r\nAdvanced Threat Protection detect FinFisher’s malicious behavior throughout the attack kill chain and alert\r\nhttps://www.microsoft.com/security/blog/2018/03/01/finfisher-exposed-a-researchers-tale-of-defeating-traps-tricks-and-complex-virtual-machines/\r\nPage 16 of 17\n\nSecOps personnel. Windows Defender ATP also integrates with the Windows protection stack so that protections\r\nfrom Windows Defender AV and Windows Defender Exploit Guard are reported in Windows Defender ATP portal,\r\nenabling SecOps personnel to centrally manage security, and as well as promptly investigate and respond to\r\nhostile activity in the network.\r\nWe hope that this writeup of our journey through all the multiple layers of protection, obfuscation, and anti-analysis techniques of FinFisher will be useful to other researchers studying this malware. We believe that an\r\nindustry-wide collaboration and information-sharing is important in defending customers against this complex\r\npiece of malware. For further reading, we recommend these other great references:\r\nDevirtualizing FinSpy [PDF], Tora (2012)\r\nFinfisher rootkit analysis, Artem Baranov (2017)\r\nA Walk-Through Tutorial, with Code, on Statically Unpacking the FinSpy VM: Part One, x86\r\nDeobfuscation, Rolf Rolles (2018)\r\nFinSpy VM Part 2: VM Analysis and Bytecode Disassembly, Rolf Rolles (2018)\r\nESET’s guide to deobfuscating and devirtualizing FinFisher [PDF], Filip Kafka (2018)\r\nTo test how Windows Defender ATP can help your organization detect, investigate, and respond to advanced\r\nattacks, sign up for a free trial.\r\nAndrea Allievi, Office 365 ATP Research team\r\nwith Elia Florio, Windows Defender ATP Research team\r\nSample analyzed:\r\nMD5: a7b990d5f57b244dd17e9a937a41e7f5\r\nSHA-1: c217d48c4ac1555491348721cc7cfd1143fe0b16\r\nSHA-256: b035ca2d174e5e4fd2d66fd3c8ce4ae5c1e75cf3290af872d1adb2658852afb8\r\nTalk to us\r\nQuestions, concerns, or insights on this story? Join discussions at the Microsoft community and Windows\r\nDefender Security Intelligence.\r\nFollow us on Twitter @WDSecurity and Facebook Windows Defender Security Intelligence.\r\nSource: https://www.microsoft.com/security/blog/2018/03/01/finfisher-exposed-a-researchers-tale-of-defeating-traps-tricks-and-complex-virtu\r\nal-machines/\r\nhttps://www.microsoft.com/security/blog/2018/03/01/finfisher-exposed-a-researchers-tale-of-defeating-traps-tricks-and-complex-virtual-machines/\r\nPage 17 of 17",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"ETDA",
		"MITRE"
	],
	"references": [
		"https://www.microsoft.com/security/blog/2018/03/01/finfisher-exposed-a-researchers-tale-of-defeating-traps-tricks-and-complex-virtual-machines/"
	],
	"report_names": [
		"finfisher-exposed-a-researchers-tale-of-defeating-traps-tricks-and-complex-virtual-machines"
	],
	"threat_actors": [
		{
			"id": "27485543-d2e7-4053-a660-157489732cbb",
			"created_at": "2022-10-25T16:07:23.895403Z",
			"updated_at": "2026-04-10T02:00:04.781765Z",
			"deleted_at": null,
			"main_name": "Neodymium",
			"aliases": [
				"G0055"
			],
			"source_name": "ETDA:Neodymium",
			"tools": [
				"Wingbird"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "400a3efc-44a1-4d83-a724-cd16818328f9",
			"created_at": "2023-01-06T13:46:38.516115Z",
			"updated_at": "2026-04-10T02:00:03.008975Z",
			"deleted_at": null,
			"main_name": "NEODYMIUM",
			"aliases": [
				"G0055"
			],
			"source_name": "MISPGALAXY:NEODYMIUM",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "c11cbeb5-461f-4bd8-a86b-f57e471a664d",
			"created_at": "2022-10-25T15:50:23.257383Z",
			"updated_at": "2026-04-10T02:00:05.414047Z",
			"deleted_at": null,
			"main_name": "NEODYMIUM",
			"aliases": [
				"NEODYMIUM"
			],
			"source_name": "MITRE:NEODYMIUM",
			"tools": [
				"Wingbird"
			],
			"source_id": "MITRE",
			"reports": null
		}
	],
	"ts_created_at": 1775434755,
	"ts_updated_at": 1775791524,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/171eb950f9a8fb84c9b5223e93d3f4cb5309d079.pdf",
		"text": "https://archive.orkl.eu/171eb950f9a8fb84c9b5223e93d3f4cb5309d079.txt",
		"img": "https://archive.orkl.eu/171eb950f9a8fb84c9b5223e93d3f4cb5309d079.jpg"
	}
}