{
	"id": "a0c79074-01c7-4deb-8708-a5f54100efb0",
	"created_at": "2026-04-06T00:14:36.142107Z",
	"updated_at": "2026-04-10T03:21:19.574869Z",
	"deleted_at": null,
	"sha1_hash": "b70ce7aa5495414f0cb55bc1a945a4b0dae20cbb",
	"title": "njRAT Installed from a MSI",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 104759,
	"plain_text": "njRAT Installed from a MSI\r\nPublished: 2022-02-03 · Archived: 2026-04-05 19:12:08 UTC\r\nIn my last post I walked through the analysis of an unusual MSI file that an adversary had tacked a STRRAT Java ARchive\r\nfile to the end of the MSI contents. In this post, I want to walk through a more normal MSI sample that an adversary\r\ndesigned to delivery njRAT. If you want to follow along at home, the sample I’m working with is in MalwareBazaar here:\r\nhttps://bazaar.abuse.ch/sample/1f95063441e9d231e0e2b15365a8722c5136c2a6fe2716f3653c260093026354/.\r\nTriaging the File\r\nAs usual, let’s get started triaging with file and diec .\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n10\r\nremnux@remnux:~/cases/njrat-msi$ file mal.msi\r\nmal.msi: Composite Document File V2 Document, Little Endian, Os: Windows, Version 10.0, MSI Installer, Code page: 1252, Titl\r\nremnux@remnux:~/cases/njrat-msi$ diec mal.msi\r\nfiletype: Binary\r\narch: NOEXEC\r\nmode: Unknown\r\nendianess: LE\r\ntype: Unknown\r\n installer: Microsoft Installer(MSI)\r\nFrom the output it looks like the sample indeed has the magic bytes for a MSI. From the file output, it looks like the\r\nadversary may have used an unlicensed MSI Wrapper tool from “exemsi[.]com”. This is pretty common, there are multiple\r\nfree and paid tools to create MSI files and I’ve seen samples where adversaries would essentially download trials from\r\nmultiple vendors and switch vendors between campaigns. Let’s dive into the MSI contents!\r\nAnalyzing the MSI Contents\r\nJust like in the last post, we can use oledump.py to view the content streams within this MSI.\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n10\r\n11\r\n12\r\n13\r\n14\r\n15\r\n16\r\n17\r\n18\r\n19\r\n20\r\n21\r\n22\r\n23\r\n24\r\n25\r\n26\r\nremnux@remnux:~/cases/njrat-msi$ oledump.py mal.msi\r\n 1: 136 '\\x05DocumentSummaryInformation'\r\n 2: 588 '\\x05SummaryInformation'\r\n 3: 669935 '䌋䄱䜵䅾䞽䕠䓤䈳㼧䗨䓸䕙䊲䄵䠰'\r\n 4: 212992 '䌋䄱䜵䅾䞽䘌䗶䐲䆊䌷䑲䏍䠯'\r\n 5: 672 '䡀㬿䏲䐸䖱'\r\n 6: 8555 '䡀㼿䕷䑬㭪䗤䠤'\r\n 7: 1216 '䡀㼿䕷䑬㹪䒲䠯'\r\n 8: 38 '䡀㽿䅤䈯䠶'\r\n 9: 2064 '䡀㿿䏤䇬䗤䒬䠱'\r\n 10: 4 '䡀䄕䑸䋦䒌䇱䗬䒬䠱'\r\n 11: 48 '䡀䇊䌰㮱䈻䘦䈷䈜䘴䑨䈦'\r\n 12: 24 '䡀䇊䌰㾱㼒䔨䈸䆱䠨'\r\n 13: 42 '䡀䇊䗹䛎䆨䗸㼨䔨䈸䆱䠨'\r\n 14: 4 '䡀䈏䗤䕸㬨䐲䒳䈱䗱䠶'\r\n 15: 16 '䡀䈏䗤䕸䠨'\r\n 16: 14 '䡀䈖䌧䠤'\r\n 17: 60 '䡀䈛䌪䗶䜵'\r\n 18: 8 '䡀䌋䄱䜵'\r\n 19: 18 '䡀䌍䈵䗦䕲䠼'\r\n 20: 216 '䡀䑒䗶䏤㮯䈻䘦䈷䈜䘴䑨䈦'\r\n 21: 48 '䡀䑒䗶䏤㾯㼒䔨䈸䆱䠨'\r\n 22: 12 '䡀䒌䓰䑲䑨䠷'\r\n 23: 32 '䡀䓞䕪䇤䠨'\r\n 24: 80 '䡀䕙䓲䕨䜷'\r\n 25: 180 '䡀䘌䗶䐲䆊䌷䑲'\r\nhttps://forensicitguy.github.io/njrat-installed-from-msi/\r\nPage 1 of 5\n\nDon’t worry about the stream names being unreadable, that’s a common thing in the MSI files I’ve seen. We want to focus\r\non the first two columns. The left column is the stream number and the middle is the size of the stream contents in bytes. We\r\nwant to analyze the largest streams to the smallest until we start finding streams with no workable data. In this sample, we\r\nwant to work with streams 3, 4, 6, 7, and 9.\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n10\r\n11\r\nremnux@remnux:~/cases/njrat-msi$ oledump.py -a -s 3 mal.msi | head\r\n00000000: 4D 53 43 46 00 00 00 00 EF 38 0A 00 00 00 00 00 MSCF.....8......\r\n00000010: 2C 00 00 00 00 00 00 00 03 01 01 00 01 00 00 00 ,...............\r\n00000020: 9B 8E 00 00 47 00 00 00 15 00 00 00 00 38 0A 00 ....G........8..\r\n00000030: 00 00 00 00 00 00 3C 54 57 80 20 00 73 65 72 76 ......\u003cTW. .serv\r\n00000040: 65 72 2E 65 78 65 00 99 0A 33 F0 00 80 00 80 4D er.exe...3.....M\r\n00000050: 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 B8 Z...............\r\n00000060: 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 00 .......@........\r\n00000070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................\r\n00000080: 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 0E ................\r\n00000090: 1F BA 0E 00 B4 09 CD 21 B8 01 4C CD 21 54 68 69 .......!..L.!Thi\r\nIn stream 3 we can see the first bytes of content contain the ASCII characters MSCF . This is consistent with Cabinet Archive\r\n(CAB) files. We can dump out the stream and confirm this with file .\r\n1\r\n2\r\n3\r\n4\r\nremnux@remnux:~/cases/njrat-msi$ oledump.py -d -s 3 mal.msi \u003e 3.dat\r\nremnux@remnux:~/cases/njrat-msi$ file 3.dat\r\n3.dat: Microsoft Cabinet archive data, Windows 2000/XP setup, 669935 bytes, 1 file, at 0x2c +A \"server.exe\", ID 36507, number\r\nSure enough, it looks like we’ve dumped out a CAB file. We’ll get to that in a bit. Let’s finish looking through the other\r\nstreams.\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n10\r\n11\r\nremnux@remnux:~/cases/njrat-msi$ oledump.py -a -s 4 mal.msi | head\r\n00000000: 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 MZ..............\r\n00000010: B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 ........@.......\r\n00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................\r\n00000030: 00 00 00 00 00 00 00 00 00 00 00 00 F0 00 00 00 ................\r\n00000040: 0E 1F BA 0E 00 B4 09 CD 21 B8 01 4C CD 21 54 68 ........!..L.!Th\r\n00000050: 69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E 6E 6F is program canno\r\n00000060: 74 20 62 65 20 72 75 6E 20 69 6E 20 44 4F 53 20 t be run in DOS\r\n00000070: 6D 6F 64 65 2E 0D 0D 0A 24 00 00 00 00 00 00 00 mode....$.......\r\n00000080: FE AE 1E EC BA CF 70 BF BA CF 70 BF BA CF 70 BF ......p...p...p.\r\n00000090: B3 B7 F4 BF FA CF 70 BF B3 B7 E5 BF AF CF 70 BF ......p.......p.\r\nStream 4 looks like it contains some executable data with a MZ header and DOS stub. We can dump that out and continue.\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n10\r\n11\r\n12\r\nremnux@remnux:~/cases/njrat-msi$ oledump.py -a -s 6 mal.msi | head\r\n00000000: 4E 61 6D 65 54 61 62 6C 65 54 79 70 65 43 6F 6C NameTableTypeCol\r\n00000010: 75 6D 6E 5F 56 61 6C 69 64 61 74 69 6F 6E 56 61 umn_ValidationVa\r\n00000020: 6C 75 65 4E 50 72 6F 70 65 72 74 79 49 64 5F 53 lueNPropertyId_S\r\n00000030: 75 6D 6D 61 72 79 49 6E 66 6F 72 6D 61 74 69 6F ummaryInformatio\r\n00000040: 6E 44 65 73 63 72 69 70 74 69 6F 6E 53 65 74 43 nDescriptionSetC\r\n00000050: 61 74 65 67 6F 72 79 4B 65 79 43 6F 6C 75 6D 6E ategoryKeyColumn\r\n00000060: 4D 61 78 56 61 6C 75 65 4E 75 6C 6C 61 62 6C 65 MaxValueNullable\r\n00000070: 4B 65 79 54 61 62 6C 65 4D 69 6E 56 61 6C 75 65 KeyTableMinValue\r\n00000080: 49 64 65 6E 74 69 66 69 65 72 4E 61 6D 65 20 6F IdentifierName o\r\n00000090: 66 20 74 61 62 6C 65 4E 61 6D 65 20 6F 66 20 63 f tableName of c\r\nhttps://forensicitguy.github.io/njrat-installed-from-msi/\r\nPage 2 of 5\n\n13\r\n14\r\n15\r\n16\r\n17\r\n18\r\n19\r\n20\r\n21\r\n22\r\n23\r\n24\r\n25\r\n26\r\n27\r\n28\r\n29\r\n30\r\n31\r\n32\r\n33\r\n34\r\n35\r\nremnux@remnux:~/cases/njrat-msi$ oledump.py -a -s 7 mal.msi | head\r\n00000000: 00 00 00 00 04 00 06 00 05 00 02 00 00 00 00 00 ................\r\n00000010: 04 00 02 00 06 00 02 00 0B 00 15 00 05 00 05 00 ................\r\n00000020: 01 00 2C 00 0A 00 01 00 13 00 02 00 0B 00 06 00 ..,.............\r\n00000030: 03 00 02 00 08 00 02 00 09 00 02 00 08 00 02 00 ................\r\n00000040: 08 00 02 00 08 00 02 00 08 00 02 00 0A 00 19 00 ................\r\n00000050: 0D 00 01 00 0E 00 01 00 03 00 01 00 1E 00 01 00 ................\r\n00000060: 01 00 2A 00 15 00 01 00 15 00 01 00 36 00 01 00 ..*.........6...\r\n00000070: 24 00 01 00 F5 00 01 00 0F 00 01 00 04 00 09 00 $...............\r\n00000080: 20 00 01 00 15 00 01 00 14 00 07 00 06 00 0C 00 ...............\r\n00000090: 42 00 05 00 09 00 15 00 9F 00 05 00 08 00 0C 00 B...............\r\nremnux@remnux:~/cases/njrat-msi$ oledump.py -a -s 9 mal.msi | head\r\n00000000: 06 00 06 00 06 00 06 00 06 00 06 00 06 00 06 00 ................\r\n00000010: 06 00 06 00 0A 00 0A 00 22 00 22 00 22 00 29 00 ........\".\".\".).\r\n00000020: 29 00 29 00 2A 00 2A 00 2A 00 2B 00 2B 00 2F 00 ).).*.*.*.+.+./.\r\n00000030: 2F 00 2F 00 2F 00 2F 00 2F 00 35 00 35 00 35 00 /././././.5.5.5.\r\n00000040: 3D 00 3D 00 3D 00 3D 00 3D 00 4D 00 4D 00 4D 00 =.=.=.=.=.M.M.M.\r\n00000050: 4D 00 4D 00 4D 00 4D 00 4D 00 5C 00 5C 00 61 00 M.M.M.M.M.\\.\\.a.\r\n00000060: 61 00 61 00 61 00 61 00 61 00 61 00 61 00 6F 00 a.a.a.a.a.a.a.o.\r\n00000070: 6F 00 72 00 72 00 72 00 73 00 73 00 73 00 74 00 o.r.r.r.s.s.s.t.\r\n00000080: 74 00 77 00 77 00 77 00 77 00 77 00 77 00 82 00 t.w.w.w.w.w.w...\r\n00000090: 82 00 86 00 86 00 86 00 86 00 86 00 86 00 90 00 ................\r\nStreams 6, 7, and 9 have either some string data or not much recognizable contents. If we start running into issues, dumping\r\nstream 6 might be a decent idea to see if there are scripting commands within, but that’s not necessary right now.\r\nExtracting the contents of the CAB is really easy. Just use 7z . Extracting the contents unpacks server.exe , which\r\nappears to be a .NET binary.\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n10\r\n11\r\n12\r\n13\r\n14\r\n15\r\n16\r\n17\r\n18\r\n19\r\n20\r\n21\r\n22\r\n23\r\n24\r\n25\r\n26\r\n27\r\n28\r\n29\r\nremnux@remnux:~/cases/njrat-msi$ 7z x 3.dat\r\nExtracting archive: 3.dat\r\n--\r\nPath = 3.dat\r\nType = Cab\r\nPhysical Size = 669935\r\nMethod = None\r\nBlocks = 1\r\nVolumes = 1\r\nVolume Index = 0\r\nID = 36507\r\nEverything is Ok\r\nSize: 669696\r\nCompressed: 669935\r\nremnux@remnux:~/cases/njrat-msi$ file server.exe\r\nserver.exe: PE32 executable (GUI) Intel 80386 Mono/.Net assembly, for MS Windows\r\nremnux@remnux:~/cases/njrat-msi$ diec server.exe\r\nfiletype: PE32\r\narch: I386\r\nmode: 32-bit\r\nendianess: LE\r\ntype: GUI\r\n library: .NET(v4.0.30319)[-]\r\n compiler: VB.NET(-)[-]\r\n linker: Microsoft Linker(48.0)[GUI32]\r\nThe final step for this branch of analysis will be to decompile the .NET malware to its source. For this, I like to use\r\nilspycmd .\r\nhttps://forensicitguy.github.io/njrat-installed-from-msi/\r\nPage 3 of 5\n\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n10\r\n11\r\n12\r\n13\r\nremnux@remnux:~/cases/njrat-msi$ ilspycmd server.exe \u003e server.decompiled.cs\r\nremnux@remnux:~/cases/njrat-msi$ head server.decompiled.cs\r\nusing System;\r\nusing System.CodeDom.Compiler;\r\nusing System.Collections.Generic;\r\nusing System.ComponentModel;\r\nusing System.Configuration;\r\nusing System.Diagnostics;\r\nusing System.Drawing;\r\nusing System.Globalization;\r\nusing System.IO;\r\nusing System.Linq;\r\nSure enough, it looks like we got some readable C# code!\r\nWhat about that other EXE/DLL?\r\nThe other DLL we pulled from stream 4 might still be relevant, so let’s look into it. We can get a pretty good idea of the\r\nDLL’s functionality using a combination of pedump and strings from floss .\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n10\r\n11\r\n12\r\n13\r\n14\r\n15\r\n16\r\n17\r\n18\r\n19\r\nremnux@remnux:~/cases/njrat-msi$ pedump --exports 4.dat\r\n=== EXPORTS ===\r\n# module \"MsiCustomActions.dll\"\r\n# flags=0x0 ts=\"2021-02-07 22:37:10\" version=0.0 ord_base=1\r\n# nFuncs=10 nNames=10\r\n ORD ENTRY_VA NAME\r\n 1 a5d0 _CheckReboot@4\r\n 2 a510 _InstallFinish1@4\r\n 3 a740 _InstallFinish2@4\r\n 4 a9d0 _InstallMain@4\r\n 5 a4a0 _InstallPrepare@4\r\n 6 abc0 _InstallRollback@4\r\n 7 ac80 _SubstWrappedArguments@4\r\n 8 b280 _UninstallFinish1@4\r\n 9 b6e0 _UninstallFinish2@4\r\n a ac90 _UninstallPrepare@4\r\nThe exported functions in the DLL look like they might be related to generic installation activity. In addition, the DLL thinks\r\nit has a module name of MsiCustomActions.dll . Nothing really stands out as suspicious, let’s take a look at output from\r\nfloss that has been ranked with stringsifter .\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n10\r\n11\r\n12\r\n13\r\n14\r\n15\r\nremnux@remnux:~/cases/njrat-msi$ floss -q 4.dat | rank_strings \u003e ranked_floss.txt\r\nremnux@remnux:~/cases/njrat-msi$ less ranked_floss.txt\r\nfiles.cab\r\nC:\\ss2\\Projects\\MsiWrapper\\MsiCustomActions\\Release\\MsiCustomActions.pdb\r\n- UNREGISTERED - Wrapped using MSI Wrapper from www.exemsi.com\r\nSOFTWARE\\EXEMSI.COM\\MSI Wrapper\r\n-R files.cab -F:* files\r\nmsiwrapper.ini\r\ncmd.exe\r\nSOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\r\nSOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\\r\nmsi.dll\r\nError setting security.\r\nRemove cabinet file\r\nhttps://forensicitguy.github.io/njrat-installed-from-msi/\r\nPage 4 of 5\n\n16\r\n17\r\n18\r\n19\r\n20\r\n21\r\n22\r\n23\r\n24\r\nQuietUninstallString is\r\nUninstallString is\r\nProtection failed.\r\nRemoval of protection failed.\r\nFocus is\r\nSELECT `Data` FROM `Binary` WHERE `Name` = '%s'\r\nShellExecuteEx failed (%d).\r\nError setting security. Exit code %d.\r\n...\r\nThere are loads of strings in this binary that seem consistent with being an installation component. The debugging PDB file\r\nis named with a MSI-related path. The vendor of the MSI Wrapper is mentioned in the DLL as well. It would be nice if the\r\nbinary was signed, but we can’t always get what we want.\r\nWrapping up, if you want to dive deeper into that njRAT server.exe process, start with the decompiled code output from\r\nilspycmd and have fun. Thanks for reading!\r\nSource: https://forensicitguy.github.io/njrat-installed-from-msi/\r\nhttps://forensicitguy.github.io/njrat-installed-from-msi/\r\nPage 5 of 5",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://forensicitguy.github.io/njrat-installed-from-msi/"
	],
	"report_names": [
		"njrat-installed-from-msi"
	],
	"threat_actors": [],
	"ts_created_at": 1775434476,
	"ts_updated_at": 1775791279,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/b70ce7aa5495414f0cb55bc1a945a4b0dae20cbb.pdf",
		"text": "https://archive.orkl.eu/b70ce7aa5495414f0cb55bc1a945a4b0dae20cbb.txt",
		"img": "https://archive.orkl.eu/b70ce7aa5495414f0cb55bc1a945a4b0dae20cbb.jpg"
	}
}