{
	"id": "d99c7721-051b-4e30-a484-098b1a56a0aa",
	"created_at": "2026-04-06T00:18:16.268769Z",
	"updated_at": "2026-04-10T03:21:40.751947Z",
	"deleted_at": null,
	"sha1_hash": "a549e97b28a2936e0f68745789e1569be71271c4",
	"title": "Unpacking Dexter POS \"Memory Dump Parsing\" Malware",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 258688,
	"plain_text": "Unpacking Dexter POS \"Memory Dump Parsing\" Malware\r\nArchived: 2026-04-05 21:59:58 UTC\r\nI'm a big fan of Dexter. As I recently mentioned during an impromptu discussion with our first group of memory\r\nanalysis training attendees, if there are only a few minutes left in an episode and he hasn't killed anyone yet, I start\r\ngetting nervous. So when I heard there's malware named dexter that has also been \"parsing memory dumps\" of\r\nspecific processes on POS (Point of Sale) systems, I was excited to take a look. How exactly does this memory\r\ndump parsing occur? Is it scanning for .vmem files on an infected VM host? Maybe walking directories of\r\nnetwork shares to find collections of past memory dumps taken by forensic teams? Perhaps acquiring a crash\r\ndump or mini-dump of the POS system itself? Turns out its none of the above, and the memory dump parsing is\r\njust a ReadProcessMemory loop, but figuring that out was nonetheless a textbook example of how to use Volatility\r\nin a reverse-engineering malware scenario.\r\nGetting started in the typical way, you can see dexter is packed. There are PE sections named .conas, .ts10, .ts20,\r\n.ts30, .ts40, and .ts50; suspiciously named exports like RenameHerbal, RenameFortation, and LoadMemberData;\r\nonly two imported APIs - GetKeyboardState and GetSystemWindowsDirectoryW; and roughly 10% of the file is\r\nrecognized by IDA as executable code (the rest is compressed/packed data).\r\nIf you needed further proof, you could check the strings:\r\n$ strings -a ~/Desktop/dexter.exe \r\n!This program cannot be run in DOS mode.\r\nIRich,\r\n.text\r\nhttps://volatility-labs.blogspot.com/2012/12/unpacking-dexter-pos-memory-dump.html\r\nPage 1 of 9\n\n`.conas\r\n.const\r\n@.data\r\n.ts050\r\n@.ts040\r\n@.ts030\r\n@.ts020\r\n@.ts010\r\niopiio\r\nworG\r\nuNqkObyOqdrSDunixUVSmOFucsNpJUJKkmpmqlUW\r\nFvlLutksfHVJWIzigOJfTfFRxxUmwtdRKhmgjhdiXlSq\r\nTZJ_QaVg_vGB\r\nOWMu_wWH_EHz\r\nSOU_GTUQ\r\nPSOsqo_Jk\r\nGetKeyboardState\r\nUSER32.dll\r\nGetSystemWindowsDirectoryW\r\nKERNEL32.dll\r\nC:\\Debugger.fgh\r\n,vr1\r\nrnyCsipvZnUURpjurWxiRqgauylOKfl3J\r\nowz{\r\ntjpudajfQwdBCBGAtjpcrTlenAyHMz\r\nnuymGmpBownDvVIErgffsrBxQskLJu\r\nhttps://volatility-labs.blogspot.com/2012/12/unpacking-dexter-pos-memory-dump.html\r\nPage 2 of 9\n\nzn|c\r\np}mOPSJqtFxbQlmrSPiThjdwfHxndtrP\r\nModuleReplace.exe\r\nLoadMemberData\r\nNothing too interesting there. If we're going to understand how this malware parses memory dumps, we'll need to\r\nunpack it first. There's the manual option of finding OEP, dumping a sample with OllyDbg or LordPE, and fixing\r\nimports with ImpREC (or something similar), but I try to save that more time consuming and technical approach\r\nfor when its really needed. In the case of dexter, and a majority of malware these days, all you need to do is run it\r\nand let it unpack itself. Being lazy never felt so good!\r\nAfter copying the malware to a VM, it was executed and resulted in the creation of two new Internet Explorer\r\nprocesses. The code has to persist on the system in some way, so if the process (dexter.exe) doesn't stay running\r\nitself, you can bet it dissolves (i.e. injects) into another process. A reasonable first guess of the targets would be\r\nthe two new IE instances: pids 1480 and 820. \r\nNow back in Volatility, working with the suspended VMs memory file, let's list processes just to orient ourselves\r\nwith this new perspective: \r\n$ ./vol.py pslist\r\nVolatile Systems Volatility Framework 2.3_alpha\r\nOffset(V)  Name                PID   PPID   Thds     Hnds  Start                                \r\n---------- ---------------- ------ ------ ------ --------  -------------------- \r\n0x81bcc830 System                4      0     59      190                                             \r\n0x81b27020 smss.exe            380      4      3       21  2012-12-03 05:35:49                      \r\n0x81a39660 csrss.exe           604    380     11      407  2012-12-03 05:35:51                      \r\n0x818fbd78 winlogon.exe        640    380     18      506  2012-12-03 05:35:53                      \r\n0x818e62a0 services.exe        684    640     15      287  2012-12-03 05:35:53                      \r\nhttps://volatility-labs.blogspot.com/2012/12/unpacking-dexter-pos-memory-dump.html\r\nPage 3 of 9\n\n0x81889150 lsass.exe           696    640     20      353  2012-12-03 05:35:53                      \r\n0x81afd458 vmacthlp.exe        848    684      1       24  2012-12-03 05:35:54                      \r\n\u003csnip\u003e                    \r\n0x81783020 ProcessHacker.e    2532    424      3       79  2012-12-12 01:49:12                      \r\n0x81b27558 IEXPLORE.EXE       1480    968      7      115  2012-12-12 01:49:21                      \r\n0x81710da0 IEXPLORE.EXE        820   1480      2       30  2012-12-12 01:49:21  \r\nThe next thing I did since code injection was suspected is run malfind on the two IE pids. It located two memory\r\nsegments - one in each IE process, same base address in both (0x150000), same protection\r\n(PAGE_EXECUTE_READWRITE), and according to the hexdump there's an MZ header at the base of the\r\nregion. \r\n$ ./vol.py malfind -p 1480,820\r\nVolatile Systems Volatility Framework 2.3_alpha\r\nProcess: IEXPLORE.EXE Pid: 1480 Address: 0x150000\r\nVad Tag: VadS Protection: PAGE_EXECUTE_READWRITE\r\nFlags: CommitCharge: 11, MemCommit: 1, PrivateMemory: 1, Protection: 6\r\n0x00150000  4d 5a 90 00 03 00 00 00 04 00 00 00 ff ff 00 00   MZ..............\r\n0x00150010  b8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00   ........@.......\r\n0x00150020  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................\r\n0x00150030  00 00 00 00 00 00 00 00 00 00 00 00 c0 00 00 00   ................\r\nProcess: IEXPLORE.EXE Pid: 820 Address: 0x150000\r\nVad Tag: VadS Protection: PAGE_EXECUTE_READWRITE\r\nFlags: CommitCharge: 11, MemCommit: 1, PrivateMemory: 1, Protection: 6\r\n0x00150000  4d 5a 90 00 03 00 00 00 04 00 00 00 ff ff 00 00   MZ..............\r\n0x00150010  b8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00   ........@.......\r\n0x00150020  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................\r\n0x00150030  00 00 00 00 00 00 00 00 00 00 00 00 c0 00 00 00   ................\r\nNow that we've quite effortlessly identified where the unpacked code is hiding, let's dump it out of memory. We'll\r\nuse the dlldump plugin for this. Although the PE at 0x15000 isn't necessarily a DLL, the dlldump plugin allows\r\nhttps://volatility-labs.blogspot.com/2012/12/unpacking-dexter-pos-memory-dump.html\r\nPage 4 of 9\n\nthe extracting/rebuilding of any PE in process memory if you supply the --base address (which we know). \r\n$ mkdir dexter \r\n$ ./vol.py dlldump -p 1480,820 --base=0x150000 -D dexter/\r\nVolatile Systems Volatility Framework 2.3_alpha\r\nProcess(V) Name          Module Base Name    Result\r\n---------- ------------- ----------- ------- ------\r\n0x81b27558 IEXPLORE.EXE  0x000150000 UNKNOWN OK: module.1480.1b27558.150000.dll\r\n0x81710da0 IEXPLORE.EXE  0x000150000 UNKNOWN OK: module.820.1710da0.150000.dll\r\nFor a quick understanding of how effective this approach can be in unpacking malware, take a look at the strings\r\nnow:\r\n$ strings -a dexter/module.1480.1b27558.150000.dll \r\n!This program cannot be run in DOS mode.\r\n.text\r\n.data\r\n.rsrc\r\nwuauclt.exe\r\nalg.exe\r\nspoolsv.exe\r\nlsass.exe\r\nwinlogon.exe\r\ncsrss.exe\r\nsmss.exe\r\nSystem\r\nexplorer.exe\r\niexplore.exe\r\nsvchost.exe\r\nABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\r\nhttps://volatility-labs.blogspot.com/2012/12/unpacking-dexter-pos-memory-dump.html\r\nPage 5 of 9\n\nSeDebugPrivilege\r\nNTDLL.DLL\r\nNtQueryInformationProcess\r\n/portal1/gateway.php\r\n11e2540739d7fbea1ab8f9aa7a107648.com\r\n7186343a80c6fa32811804d23765cda4.com\r\ne7dce8e4671f8f03a040d08bb08ec07a.com\r\ne7bc2d0fceee1bdfd691a80c783173b4.com\r\n815ad1c058df1b7ba9c0998e2aa8a7b4.com\r\n67b3dba8bc6778101892eb77249db32e.com\r\nfabcaa97871555b68aa095335975e613.com\r\nWindows 7\r\nWindows Server R2\r\nWindows Server 2008\r\nWindows Vista\r\nWindows Server 2003 R2\r\nWindows Home Server\r\nWindows Server 2003\r\nWindows XP Professional x64\r\nWindows XP\r\nWindows 2000\r\n32 Bit\r\n64 Bit\r\nhttp://%s%s\r\nContent-Type:application/x-www-form-urlencoded\r\nPOST\r\nhttps://volatility-labs.blogspot.com/2012/12/unpacking-dexter-pos-memory-dump.html\r\nPage 6 of 9\n\nMozilla/4.0(compatible; MSIE 7.0b; Windows NT 6.0)\r\nLowRiskFileTypes\r\nSoftware\\Microsoft\\Windows\\CurrentVersion\\Policies\\Associations\r\nrpcrt4.dll\r\ngdi32.dll\r\nwininet.dll\r\nurlmon.dll\r\nshell32.dll\r\nadvapi32.dll\r\nuser32.dll\r\nIsWow64Process\r\nWindowsResilienceServiceMutex\r\nSoftware\\Resilience Software\r\nSoftware\\Microsoft\\Windows\\CurrentVersion\\Run\r\n.DEFAULT\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\r\nUpdateMutex:\r\nresponse=\r\npage=\r\n\u0026ump=\r\n\u0026opt=\r\n\u0026unm=\r\n\u0026cnm=\r\n\u0026view=\r\n\u0026spec=\r\n\u0026query=\r\n\u0026val=\r\nhttps://volatility-labs.blogspot.com/2012/12/unpacking-dexter-pos-memory-dump.html\r\nPage 7 of 9\n\n\u0026var=\r\nDetectShutdownClass\r\ndownload-update-checkin:\r\nscanin:\r\nuninstall\r\nThe strings output shows a list of process names, which makes sense - the Seculert Blog mentioned that it\r\nenumerates processes. You also see it references SeDebugPrivilege, likely for the ability to call OpenProcess and\r\nread/write the memory of other processes. The ABCDEF[....] is a base64 alphabet, so you can expect it to encode\r\nsome or all of the data it POSTs to gateway.php on one of the randomly named .com domains. It would create the\r\nWindowsResilienceServiceMutex and make a run key in the Software\\Resilience Software registry key. \r\nTo solve our real question - how does this malware parse memory dumps - we need to open the unpacked file in\r\nIDA. Its import table is already fixed up, so aside from switching the ImageBase value in the PE header so RVAs\r\nare interpreted correctly by IDA, we're done unpacking before we even really started. A quick look through the\r\nunpacked file's IAT shows it calls ReadProcessMemory, and cross-referencing that leads to one function, shown\r\nbelow:\r\nWhat you see here is the \"memory dump parsing\" function. It iterates once for each active process on the system,\r\ncalling OpenProcess() to obtain a handle, then using VirtualQueryEx() to determine which memory ranges are\r\nhttps://volatility-labs.blogspot.com/2012/12/unpacking-dexter-pos-memory-dump.html\r\nPage 8 of 9\n\naccessible to the process, and reading them into a local buffer with ReadProcessMemory(). The data is then passed\r\noff to two scanning sub-functions which do the real work of deciding which data to steal from the buffer. \r\nIn summary, though I'm slightly disappointed that the memory dump parsing function is just a\r\nReadProcessMemory() loop, at least I didn't waste much time getting there. Unpacking the malware\r\nby leveraging Volatility was as easy as 1-2-3. Lastly, since some of our students in the Windows Memory\r\nForensics training requested videos of common ways we use Volatility, here's an initial example in quicktime\r\nformat showing the steps described in this blog: http://www.mnin.org/dexter.mov.zip. \r\nSource: https://volatility-labs.blogspot.com/2012/12/unpacking-dexter-pos-memory-dump.html\r\nhttps://volatility-labs.blogspot.com/2012/12/unpacking-dexter-pos-memory-dump.html\r\nPage 9 of 9",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"ETDA",
		"Malpedia"
	],
	"references": [
		"https://volatility-labs.blogspot.com/2012/12/unpacking-dexter-pos-memory-dump.html"
	],
	"report_names": [
		"unpacking-dexter-pos-memory-dump.html"
	],
	"threat_actors": [],
	"ts_created_at": 1775434696,
	"ts_updated_at": 1775791300,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/a549e97b28a2936e0f68745789e1569be71271c4.pdf",
		"text": "https://archive.orkl.eu/a549e97b28a2936e0f68745789e1569be71271c4.txt",
		"img": "https://archive.orkl.eu/a549e97b28a2936e0f68745789e1569be71271c4.jpg"
	}
}