{
	"id": "876a9ae0-546e-4baa-9994-f81067881ee5",
	"created_at": "2026-04-06T00:18:58.167653Z",
	"updated_at": "2026-04-10T03:26:17.712184Z",
	"deleted_at": null,
	"sha1_hash": "5e5c0b51807a32e995a36da3d57c9de40727101d",
	"title": "Revisiting the NSIS-based crypter",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 568871,
	"plain_text": "Revisiting the NSIS-based crypter\r\nPublished: 2021-05-31 · Archived: 2026-04-05 16:24:27 UTC\r\nNSIS (Nullsoft Scriptable Install System) is a framework dedicated to creating software installers. It allows to\r\nbundle various elements of an application together (i.e. the main executable, used DLLs, configs), along with a\r\nscript that controls where are they going to be extracted, and what their execution order is. It is a free and\r\npowerful tool, making distribution of software easier. Unfortunately, its qualities are known not only to legitimate\r\ndevelopers but also to malware distributors.\r\nFor several years we have been observing malware distributed via NSIS-based crypters. The outer layer made of a\r\npopular and legitimate tool makes for a perfect cover. The flexibility of the installer allows to implement various\r\nideas for obfuscating malicious elements. We wrote about unpacking them in the past. With time their internal\r\nstructure has evolved, so we decided to revisit them and describe the inside again using samples from some of the\r\nFormbook stealer campaigns.\r\nSamples\r\nThis analysis is based on the following samples:\r\n8F80426CEC76E7C9573A9C58072399AF\r\ncarrying a Formbook sample: 05dc8c8d912a58a5dde38859e741b2c0\r\n98061CCF694005A78FCF0FBC8810D137\r\ncarrying a Formbook sample: f34bd301f4f4d53e2d069b4842bca672\r\nInside\r\nLike every NSIS-based installer, this executable is an archive that can be unpacked with the help of 7zip. The\r\nolder versions of 7zip (i.e. 15.05) were also able to extract the NSIS script: [NSIS].nsi. Unfortunately, in the newer\r\nreleases script extraction is no longer supported.\r\nOnce we unpack the file, we can see several elements, as well as directories typical for NSIS:\r\nArticle continues below this ad.\r\nhttps://blog.malwarebytes.com/threat-analysis/2021/05/revisiting-the-nsis-based-crypter/\r\nPage 1 of 17\n\nThe System.dll is a DLL typical for any NSIS installer, responsible for executing the commands from the script. It\r\nis the first component of the archive to be loaded. We can find it in each of the samples.\r\nWhat is more interesting are the files in the main directory. The first one, 1 KB in size, is a shellcode. It starts\r\nfrom bytes:\r\n0x55, 0x8B, 0xEC, 0x81, 0xEC\r\nhttps://blog.malwarebytes.com/threat-analysis/2021/05/revisiting-the-nsis-based-crypter/\r\nPage 2 of 17\n\nAnalogous shellcode can be found in the second sample from this campaign.\r\nIn the same directory there are two other files. One of them is around 7 KB, and the next: much bigger. Both of\r\nthem are encrypted, and to find out what they contain we need to analyze the full chain of loading.\r\nLooking inside the NSIS script we can see the performed actions that are very simple:\r\nFunction .onInit InitPluginsDir\r\nSetOutPath $INSTDIR File 5e9ikl8w3iif7ipp6 File 3ugs67ip868x5n File tjdorfrldbgdlq System::Alloc 1024 Pop\r\n$0 System::Call “kernel32::CreateFile(t’$INSTDIRtjdorfrldbgdlq’, i 0x80000000, i 0, p 0, i 3, i 0, i 0)i.r10”\r\nSystem::Call “kernel32::VirtualProtect(i r0, i 1024, i 0x40, p0)p.r1” System::Call “kernel32::ReadFile(i r10, i r0, i\r\n1024, t., i 0) i .r3” System::Call ::$0() Call func_80 […]\r\nThe first file of the set (containing the shellcode) is read into the executable memory. Then, the loaded module is\r\njust called.\r\nShellcode #1 – functionality\r\nIf we load those shellcodes into IDA we can see their functionality very clearly, as they are not obfuscated.\r\nShellcode from sample #1:\r\nhttps://blog.malwarebytes.com/threat-analysis/2021/05/revisiting-the-nsis-based-crypter/\r\nPage 3 of 17\n\nShellcode from sample #2\r\nhttps://blog.malwarebytes.com/threat-analysis/2021/05/revisiting-the-nsis-based-crypter/\r\nPage 4 of 17\n\nAlthough the code is a bit different in both, they can be divided with the same steps and building blocks.\r\n1. The name of the next file is loaded as a stack-based wide string\r\n2. The base of kernel32.dll is fetched from PEB\r\n3. A set of function from kernel32.dll is retrieved – each of them by the name’s checksums. Functions are\r\nalways the same – dedicated to reading the file from the disk: CreateFileW, GetTempPathW, lstrcatW,\r\nReadFile, VirtualAlloc, GetTempPathW.\r\n4. The function GetTempPathW is used to retrieve the path to the %TEMP% directory, where all the\r\ncomponents from the archive were automatically extracted at runtime of the NSIS file\r\n5. The name of the next file is concatenated to the the %TEMP% path\r\n6. Memory is allocated for the file content, and the file is read into this buffer\r\nhttps://blog.malwarebytes.com/threat-analysis/2021/05/revisiting-the-nsis-based-crypter/\r\nPage 5 of 17\n\n7. A custom decryption algorithm is being applied on the buffer (the algorithm is different for different\r\nsamples). The buffer turns out to be a next shellcode\r\n8. Finally, the next shellcode is executed\r\nThe hashing function used for import resolving follows the same pattern in both cases, yet the constant used to\r\ninitialize it (denoted as HASH_INIT) is different across the\r\nsamples.https://gist.github.com/hshrzd/578770a5261d422e1e112cdd3d8ed75e#file-nsis_calc_hash-cpp\r\nThe algorithm used for the buffer decryption differs across the samples.\r\nhttps://blog.malwarebytes.com/threat-analysis/2021/05/revisiting-the-nsis-based-crypter/\r\nPage 6 of 17\n\nShellcode #2 – functionality\r\nThis shellcode is used for decrypting and loading the final payload (PE file) from the third of the encrypted files.\r\nIt is unpacked and ran by the previous layer. In the analyzed cases, this element was around 7-8 KB.\r\nThis shellcode is similarly structured as the previous one. It starts by preparation of the strings: stack-based strings\r\nare being pushed. One of them is the name of the next file that is going to be loaded. Also, the key that will be\r\nused for the decryption is prepared.\r\nhttps://blog.malwarebytes.com/threat-analysis/2021/05/revisiting-the-nsis-based-crypter/\r\nPage 7 of 17\n\nThe next step is loading of the imported functions. As before, they are resolved by their hashes.\r\nhttps://blog.malwarebytes.com/threat-analysis/2021/05/revisiting-the-nsis-based-crypter/\r\nPage 8 of 17\n\nThen the functions are used to load and decrypt the payload. If loading the next stage has failed, the installer will\r\nrestart itself.\r\nThe decryption function is custom, similar (but not identical) to\r\nRC4:https://gist.github.com/hshrzd/578770a5261d422e1e112cdd3d8ed75e#file-nsis_decrypt-cpp\r\nhttps://blog.malwarebytes.com/threat-analysis/2021/05/revisiting-the-nsis-based-crypter/\r\nPage 9 of 17\n\nThis algorithm is common to both analyzed samples – yet the decryption key differs.\r\nLoading PE\r\nAfter the PE is decrypted, the function for its loading is deployed.\r\nThe payload is implanted into a newly created suspended process (a new instance of the current executable) using\r\none of the most popular techniques of PE injection: Process Hollowing (a.k.a. RunPE). The content of the payload\r\nis mapped into the new process using low level APIs: NtCreateSection, NtMapViewOfSection. Then, the Entry\r\nPoint is redirected to the new executable via SetThreadContext, and finally the execution is resumed with\r\nNtResumeThread.\r\nThe authors used several common techniques to obfuscate this process.\r\nAs before, the used functions are loaded by their checksums. The PE loading function makes a use of the\r\nfollowing set:\r\nThe low-level functions, directly related with performing the injection, are called via raw syscalls retrieved\r\ndirectly from NTDLL. Also in this case, functions has been resolved by their hashes.\r\nList of used functions (with corresponding hashes).\r\n 4b1a50d1 : NtCreateSection e0ddd5cb : NtMapViewOfSection 20b0f111 : NtResumeThread 81af6d4e : NtUnmapViewOf\r\nThe code used to resolve the hashes is available here: hash_resolver.cpp.\r\nhttps://blog.malwarebytes.com/threat-analysis/2021/05/revisiting-the-nsis-based-crypter/\r\nPage 10 of 17\n\nManual syscalls calling\r\nIn order to make the injection stealthier, the loader uses a common technique of “stealing syscalls”, also known\r\nas “hell’s gate”. This technique is based on the fact that some low-level DLLs, such as NTDLL, contain numbers\r\nof raw syscalls. By extracting the syscalls, and executing them manually, the malware can use the API of the\r\noperating system, without a need of calling functions from the DLL. That allows to bypass some monitoring in the\r\nsituation if the system DLLs are hooked.\r\nFirstly, a fresh copy of NTDLL is loaded from the file on the disk, an manually mapped. Then, a function defined\r\nby its hash is retrieved (using the same hashing algorithm that was used to retrieve imports from normally loaded\r\nDLLs):\r\nhttps://blog.malwarebytes.com/threat-analysis/2021/05/revisiting-the-nsis-based-crypter/\r\nPage 11 of 17\n\nAfter the pointer to the beginning of the function is fetched, a small disassembling loop is used to find the familiar\r\npattern: moving the ID of the syscall into EAX register.\r\nhttps://blog.malwarebytes.com/threat-analysis/2021/05/revisiting-the-nsis-based-crypter/\r\nPage 12 of 17\n\nThe syscall ID is returned for further use.\r\nOnce the syscall number has been extracted, the malware intends to execute it from its own code. However, a 32-\r\nbit application cannot make direct syscalls on 64-bit system, since it is not native. In such cases, syscalls are\r\nusually made via Wow64 emulation layer. In order to make them directly, the authors of the malware switch to the\r\n64-bit mode first: using a technique called “Heaven’s Gate”.\r\nThe malware comes with two variants of the stub executing a syscall. The decision for which of the versions\r\nshould be applied is made based on the check if the process runs as Wow64 (emulated 32 bit on 64 bit Windows):\r\nIf the process runs on a 32-bit system, the syscall can be made in a direct way, using SYSENTER:\r\nIf the system is 64-bit, the malware (that is 32-bit) switches into 64-bit mode via “Heaven’s Gate”.\r\nhttps://blog.malwarebytes.com/threat-analysis/2021/05/revisiting-the-nsis-based-crypter/\r\nPage 13 of 17\n\nOnce the execution mode is changed into 64 bit, the syscall is called, its results stored, and the application can\r\nswitch back to 32-bit mode to continue normal execution.\r\nEvolution\r\nThis crypter has been around for several years, and during this time it went through several phases of evolution. In\r\nthis part of the analysis we will compare it with the earlier version from February of this year, described in the\r\nfollowing writeup.\r\nIn contrast to the current one, the version from February contained a malicious component in the form of a DLL.\r\nWe can also find a second, encrypted component, which carries the payload.\r\nhttps://blog.malwarebytes.com/threat-analysis/2021/05/revisiting-the-nsis-based-crypter/\r\nPage 14 of 17\n\nThe extracted NSIS script contains a different sequence of commands:\r\nFunction .onInit SetOutPath $INSTDIR File $INSTDIRo15bmldpqdxcin.dll File $INSTDIRemvmcmzr.n System::Ca\r\nIn this case, the standard NSIS component (System.dll) is used to call the function exported from the DLL,\r\npassing the path to the encrypted component as a parameter.\r\nLooking inside the exported function we can find a significant similarity to the Shellcode #1 which was described\r\nin the former part of this writeup.\r\nAs before, we can see decryption of the next stage with the help of a custom algorithm. This time, the next stage is\r\ncontained in a buffer hardcoded in the DLL (rather than stored in a separate file). It contains a very similar\r\nfunction dedicated to decrypting and loading the final payload. Yet, we can see some minor differences.\r\nhttps://blog.malwarebytes.com/threat-analysis/2021/05/revisiting-the-nsis-based-crypter/\r\nPage 15 of 17\n\nFirst of all, the file name is passed dynamically rather than hardcoded.\r\nSecond, we can see a check against blacklisted processes. Their names are hashed, and compared to the hardcoded\r\nlist of hashes (i.e. 0x26090612 -\u003e “avgui.exe”). This type of checks are among common evasion techniques.\r\nHowever, in this case, detection of a forbidden process only delays execution, and does not suspend it or\r\nterminate. Possibly it is a bug in the implementation, and the if statement was intended to be a while loop instead.\r\nNevertheless, the authors decided to give up the check in the latest version.\r\nApart from those details, this stage is identical to the Shellcode #2 from the newer version.\r\nPopular and persistent\r\nThis packer has been around for many years, and probably will stay with us for some years to come. Its structure\r\nshows that it is created by experienced authors, using well known, yet not trivial techniques. Its evolution is slow\r\nbut steady. Usage of a popular installation engine makes it easy to blend in with legitimate applications.\r\nIts popularity and diversity of payloads suggests that it is not linked to one specific actor, but rather sold as an\r\nindependent component on one of many underground forums.\r\nAppendix\r\nhttps://blog.malwarebytes.com/threat-analysis/2021/05/revisiting-the-nsis-based-crypter/\r\nPage 16 of 17\n\nOther materials about previous versions of NSIS-based crypters:\r\nhttps://yoroi.company/research/yes-cyber-adversaries-are-still-using-formbook-in-2021/\r\nhttps://www.welivesecurity.com/2021/01/12/operation-spalax-targeted-malware-attacks-colombia/\r\nhttps://news.sophos.com/en-us/2020/05/14/raticate/\r\nhttps://www.mcafee.com/blogs/other-blogs/mcafee-labs/ransomware-families-use-nsis-installers-to-avoid-detection-analysis/\r\nhttps://www.microsoft.com/security/blog/2017/03/15/ransomware-operators-are-hiding-malware-deeper-in-installer-packages/\r\nhttps://isc.sans.edu/forums/diary/Quick+analysis+of+malware+created+with+NSIS/23703/\r\nSource: https://blog.malwarebytes.com/threat-analysis/2021/05/revisiting-the-nsis-based-crypter/\r\nhttps://blog.malwarebytes.com/threat-analysis/2021/05/revisiting-the-nsis-based-crypter/\r\nPage 17 of 17",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://blog.malwarebytes.com/threat-analysis/2021/05/revisiting-the-nsis-based-crypter/"
	],
	"report_names": [
		"revisiting-the-nsis-based-crypter"
	],
	"threat_actors": [
		{
			"id": "64d750e4-67db-4461-bae2-6e75bfced852",
			"created_at": "2022-10-25T16:07:24.01415Z",
			"updated_at": "2026-04-10T02:00:04.839502Z",
			"deleted_at": null,
			"main_name": "Operation Spalax",
			"aliases": [],
			"source_name": "ETDA:Operation Spalax",
			"tools": [
				"AsyncRAT",
				"Bladabindi",
				"Jorik",
				"Remcos",
				"RemcosRAT",
				"Remvio",
				"Socmer",
				"njRAT"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "0d07b30c-4393-4071-82fb-22f51f7749e0",
			"created_at": "2022-10-25T16:07:24.097096Z",
			"updated_at": "2026-04-10T02:00:04.865146Z",
			"deleted_at": null,
			"main_name": "RATicate",
			"aliases": [],
			"source_name": "ETDA:RATicate",
			"tools": [
				"AgenTesla",
				"Agent Tesla",
				"AgentTesla",
				"BetaBot",
				"BlackRAT",
				"BlackRemote",
				"Bladabindi",
				"CloudEyE",
				"ForeIT",
				"Formbook",
				"GuLoader",
				"Jorik",
				"Loki",
				"Loki.Rat",
				"LokiBot",
				"LokiPWS",
				"NSIS",
				"Negasteal",
				"NetWeird",
				"NetWire",
				"NetWire RAT",
				"NetWire RC",
				"NetWired RC",
				"Neurevt",
				"Nullsoft Scriptable Install System",
				"Origin Logger",
				"Recam",
				"Remcos",
				"RemcosRAT",
				"Remvio",
				"Socmer",
				"ZPAQ",
				"njRAT",
				"vbdropper",
				"win.xloader"
			],
			"source_id": "ETDA",
			"reports": null
		}
	],
	"ts_created_at": 1775434738,
	"ts_updated_at": 1775791577,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/5e5c0b51807a32e995a36da3d57c9de40727101d.pdf",
		"text": "https://archive.orkl.eu/5e5c0b51807a32e995a36da3d57c9de40727101d.txt",
		"img": "https://archive.orkl.eu/5e5c0b51807a32e995a36da3d57c9de40727101d.jpg"
	}
}