{
	"id": "fa434c63-2f55-424c-bc2e-a501578b1812",
	"created_at": "2026-04-06T00:10:46.046386Z",
	"updated_at": "2026-04-10T03:22:07.121126Z",
	"deleted_at": null,
	"sha1_hash": "be7cc1d66df340b2471c22c8281f855311b58ad4",
	"title": "Keyhole Analysis",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 3117659,
	"plain_text": "Keyhole Analysis\r\nBy Jason Reaves\r\nPublished: 2024-01-16 · Archived: 2026-04-05 17:00:33 UTC\r\nBy: Joshua Platt, Jonathan McCay and Jason Reaves\r\nKeyhole is a multi-functional VNC/Backconnect component used extensively by IcedID/Anubis. While the malware\r\ncontains functionality that has been previously reported on as typical VNC and HDESK capabilities, a general lack of\r\ntechnical information appears to exist around some of the expanded functionality currently present. In fact, the\r\nfunctionality we mapped out for the main Keyhole component rivals that of IcedID itself:\r\nCollect system information\r\nVNC\r\nHDESK\r\nSocks/Backconnect\r\nConsole command detonation via cmd.exe or powershell\r\nMultiple methods of injecting explorer.exe\r\nLDAP queries\r\nFile retrieval from infected systems\r\nHijacking browser profiles\r\nDeleting browser profiles\r\nLower security of running browsers via command line manipulation\r\nChecking for webcam existence\r\nTaking pictures with webcam\r\nTurning on microphone in registry for apps\r\nEnumerating servers and shares in network\r\nPortions of this functionality are spread out over multiple open-source reports but significant analysis appears to be\r\nmissing on several noteworthy improvements.\r\nTechnical Overview\r\nInitial loader piece:\r\nThe initial component involves a loader that can handle both PE files or shellcode versions of the main component; they\r\nalso can utilize a custom PE loader with mangled headers. Ultimately the loader is responsible for decoding and loading\r\nthe core module and executing it properly.\r\nDecoding Core Module:\r\nThe core module is encoded using a 256 byte array of swap values, (key). After locating the initial blob containing the\r\nkey values, a parsing algorithm is implemented to create the array.\r\nhttps://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03\r\nPage 1 of 18\n\nUnparsed Key Blob:\r\nPress enter or click to view image in full size\r\nAn integer is given to decide how many bytes to pull from the unparsed blob. This integer will double in size until the\r\nvalue exceeds 256. Adding 1 to the amount of times the integer could double before exceeding 256 will be the number of\r\nbytes pulled.\r\nFinding an integer to decide how many bytes to pull that is not 0 will result in different behavior. The first time this\r\nhappens, the appropriate amount of bytes will be added followed by the addition of a null byte. All bytes until the next 0\r\nwill be grabbed, and the process repeats until the key len is 256.\r\nPython: Parse Key\r\nPress enter or click to view image in full size\r\nhttps://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03\r\nPage 2 of 18\n\nParsed Key / Encoded Core Module\r\nPress enter or click to view image in full size\r\nhttps://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03\r\nPage 3 of 18\n\nTo decode the core module, each byte in the encoded module will be used as an index value. The byte in the key at that\r\nindex will replace the encoded byte.\r\nPython: Decode Core Module\r\nPress enter or click to view image in full size\r\nSubset of Strings in Decoded Core Module\r\nuser32.dll\r\nbad pathname\r\npath not found\r\nDefault\r\nTOP WND\r\nRtlExitUserProcess\r\nMS Shell Dlg\r\nalready exists\r\nexplorer.exe\r\nmove\r\ntest\r\nauth\r\n-err-runasinvoker\r\nmkdir\r\ndisk\r\nbusy\r\n__compat_layer\r\ninvalid name\r\nhcddir\r\naction not found\r\nAllow\r\nCREATE\r\nAD not found\r\nValue\r\nHIDE\r\nSettings\r\nWINMM.DLL\r\n2500\r\ndisk not found\r\ncombase.dll\r\nMOVE\r\ndivice not readed\r\nhttps://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03\r\nPage 4 of 18\n\nmdiclient\r\nf%0.8X\r\nUser32.dll\r\nLucida Console\r\nntdll.dll\r\nmemory alloc\r\nshell32.dll\r\naccess denied\r\nopen\r\nerror\r\n{%0.8X-%0.4X-%0.4X-%0.4X-%0.4X%0.8X}\r\nabcedfikmnopsutw\r\nSelectObject\r\nGetCurrentObject\r\nGetObjectA\r\nCreateCompatibleDC\r\nDeleteDC\r\nCreateDIBSection\r\nCreateCompatibleBitmap\r\nGetViewportOrgEx\r\nBitBlt\r\nNetShareEnum\r\nNetApiBufferFree\r\nNetGetDCName\r\nNETAPI32.dll\r\nRtlLargeIntegerDivide\r\nRtlGetVersion\r\nNtReadVirtualMemory\r\nNtWriteVirtualMemory\r\nNtFlushInstructionCache\r\nNtProtectVirtualMemory\r\nNtAllocateVirtualMemory\r\nLoadCursorA\r\nGetAncestor\r\nCreateDesktopA\r\nGetKeyboardLayoutList\r\nGetKeyboardLayout\r\nVkKeyScanA\r\nVkKeyScanExA\r\nVkKeyScanExW\r\nMapVirtualKeyA\r\nMapVirtualKeyExA\r\nOpenClipboard\r\nCloseClipboard\r\nSetClipboardData\r\nEmptyClipboard\r\nEnumWindows\r\nSetWinEventHook\r\nGetThreadDesktop\r\nRegisterClassExA\r\nhttps://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03\r\nPage 5 of 18\n\nGetClipboardData\r\nAddClipboardFormatListener\r\nOpenInputDesktop\r\nVkKeyScanW\r\nSendInput\r\nWinExec\r\nGetPrivateProfileIntW\r\nACTIVEDS.dll\r\nWS2_32.dll\r\nTRUE\r\nname\r\nExec\r\nHigh Definition Audio\r\nMain component:\r\nThe main component of Keyhole can contain encoded strings, the really interesting part is that the algorithm used is the\r\nsame as a sample I analyzed in June of 2017:\r\n1cd6f992fbeee0a66e1c329e15db71fe891ae0e845867d6d30df867babe5bed6\r\nOld IcedID string decoding routine:\r\nhttps://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03\r\nPage 6 of 18\n\nKeyhole string decoding routine:\r\nhttps://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03\r\nPage 7 of 18\n\nDecoding the strings in Keyhole took only a small edit in my old IcedID IDA script:\r\ndef gen_key(k):\r\n return(((k \u003c\u003c 0x1d) | (k \u003e\u003e 3)) \u0026 0xffffffff)\r\nfor addr in XrefsTo(0x322630, flags=0):\r\n addr = addr.frm\r\n addr = idc.PrevHead(addr)\r\n while GetMnem(addr) != \"push\":\r\n addr = idc.PrevHead(addr)\r\n print(hex(addr))\r\n data_addr = GetOperandValue(addr,0)\r\n xork_init = Dword(data_addr)\r\n data_addr += 4\r\n length_delta = Word(data_addr)\r\n data_addr += 2\r\n length = (xork_init ^ length_delta) \u0026 0xffff\r\n out = \"\"\r\nhttps://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03\r\nPage 8 of 18\n\nxork = xork_init\r\n for i in range(length):\r\n xork = gen_key(xork)\r\n xork += i\r\n out += chr((Byte(data_addr) ^ (xork \u0026 0xFF)) \u0026 0xFF)\r\n data_addr += 1\r\n if out[-2:] == '\\x00\\x00':\r\n print(out.decode('utf16'))\r\n MakeRptCmt(addr, out.decode('utf16').encode('ascii'))\r\n else:\r\n print(out)\r\n MakeRptCmt(addr, out)\r\nThe main component of Keyhole also expects a parameter to be passed, this address will be the shellcode blob from the\r\nprevious loader component.\r\nFirst a DWORD value is pulled out, which will eventually be used as the initial seed value for the XOR loop:\r\nhttps://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03\r\nPage 9 of 18\n\nNext every byte after the DWORD is pulled out and run through a XOR loop where the initial seed value is manipulated\r\nevery iteration, we can also see below that the blob being decoded is 0x14e bytes in length:\r\nThe decoded blob turns out to be the config for the main Keyhole component, so the loader component passes the config\r\nin itself off to the main component as a parameter. After decoding we have a few values that will be used for C2\r\ncommunications:\r\n['', '', '', '', '\\xbb\\xa2\\xbd\\x9e\\x1f\\x8b\\x08\\x08',\r\n'', '', '', '', '', '', '', '', '', '', '', '', '', '',\r\n\u003c..snip..\u003e\r\n'', '', '', '', '', '', '', '', '', '', '', '', '', '',\r\n'', '', '', '', '', '', '', '', '', 'hdesk', '', '', '',\r\n'', '', '', '', '', '', '', '', '', '', '', '', '', '',\r\n'', '', '', '', '', '', '', '', '', '', '', '', '', '',\r\n'', '', '', '', '', '', '', '', '', '', '', '', '', '',\r\nhttps://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03\r\nPage 10 of 18\n\n'', '', '', '', '', '', '', '', '', '', '', '', '',\r\n'91.238.]50.101', '', '', '', '', '', '', '', '', '',\r\n'', '', '', '', '', '', '', '', '', '', '', '', '', '',\r\n'', '', '', '', '', '', '', '', '', '', '', '', '', '',\r\n'', '', '', '', '', '', '', '', '', '', '', '', '', '\\x90\\x1f’]\r\nA few values we can see, especially the C2 address but also the C2 traffic marker of ‘\\x1f\\x8b\\x08\\x08’ and the port\r\n0x1f90 which is 8080.\r\nGet Jason Reaves’s stories in your inbox\r\nJoin Medium for free to get updates from this writer.\r\nRemember me for faster sign in\r\nFunctionality\r\nAs mentioned the malware will retrieve some basic information about the infected system:\r\nIt can also enumerate servers and shares in the network and leverages LDAP queries in the process:\r\nhttps://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03\r\nPage 11 of 18\n\nFile retrievals are limited in size to roughly 33MB:\r\nPress enter or click to view image in full size\r\nBrowsers\r\nFor Chrome the module can copy the User Data to a new folder in temp:\r\nhttps://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03\r\nPage 12 of 18\n\nAlong with the parameter of ‘C\\\\’ we can see below that the folder structure will be built under temp:\r\nIn this case with a flag value of 0 we end up having the profile copied to:\r\n%TEMP%\\D\\C\\\r\nBrowser are manipulated in a similar way that old banking trojans used to do it, the module contains code for hooking\r\nNtCreateUserProcess which will then look for browsers to be spawned:\r\nhttps://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03\r\nPage 13 of 18\n\nThis lets the core module manipulate the command lines of the browsers, however it does more depending on which\r\nbrowser is found to be executing.\r\nChrome\r\n- Copies profile data to\r\n - %TEMP%\\D\\C\\\r\n- Modifies command line\r\n - --user-data-dir=”\r\n - \" --ash-force-desktop --disable-3d-apis --disable-accelerated-layers --disable-accelerated-plugins --di\r\nFireFox\r\n- Reads default profile path from profiles.ini file\r\n- Copies default profile to\r\n - %TEMP%\\D\\F\\\r\n- Edits prefs.js\r\n - user_pref(\"browser.preferences.defaultPerformanceSettings.enabled\", false);\r\n - user_pref(\"layers.acceleration.disabled\", true);\r\n- Modifies command line\r\n - --no-remote -no-deelevate -profile “\r\nEdge\r\nhttps://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03\r\nPage 14 of 18\n\n- Sets registry keys\r\n - SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers\r\n - C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe=~ WIN8RTM\r\n- Copies profile data to\r\n - %TEMP%\\D\\E\\\r\n- Modifies command line\r\n - --user-data-dir=”\r\n - \" --ash-force-desktop --disable-3d-apis --disable-accelerated-layers --disable-accelerated-plugins --di\r\nInternet Explorer\r\n- Modifies registry\r\n - Software\\Microsoft\\Internet Explorer\\Main\r\n - NoProtectedModeBanner=1\r\n - TabProcGrowth=0\r\n - Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Zones\\3\r\n - 2500=3\r\n- Modifies command line\r\n - -nomerge -noframemerging -nohome\r\nKeyhole can also perform injection into newly started explorer processes in a variety of ways:\r\nPress enter or click to view image in full size\r\nFor BackConnect commands:\r\nhttps://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03\r\nPage 15 of 18\n\nPress enter or click to view image in full size\r\nFor console command line detonation a string is expected for either powershell or cmd detonation:\r\nPress enter or click to view image in full size\r\nAlso above it can be seen for commands related to the microphone, these are primarily related to manipulating registry\r\nvalues:\r\nPress enter or click to view image in full size\r\nhttps://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03\r\nPage 16 of 18\n\nAfter the modifications the explorer will be restarted.\r\nSOFTWARE\\Microsoft\\Windows\\CurrentVersion\\CapabilityAccessManager\\ConsentStore\\microphone\\NonPackaged\r\nSOFTWARE\\Microsoft\\Windows\\CurrentVersion\\CapabilityAccessManager\\ConsentStore\\microphone\r\nSOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StuckRects3\r\ncmd.exe /c taskkill /f /im explorer.exe \u0026\u0026 start explorer.exe\r\nYARA\r\nrule keyhole_32\r\n{\r\nstrings:\r\n$config_decode = {694d0cfd43030081c1c39e2600894d0c}\r\ncondition:\r\nall of them\r\n}\r\nrule keyhole_loader\r\n{\r\nstrings:\r\n$64exe = {5390 9cbb be0c c453 9d5b 5290}\r\n$64dll = {7809 7407 7305 eb03 3941}\r\n$32exe = {770c 569c c1e6 0ac1 ee09 f7d6}\r\n$32dll = {5781 f7fc 46d8 5083 c728 bf0b}\r\ncondition:\r\nany of them\r\n}\r\nIOCS\r\nhttps://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03\r\nPage 17 of 18\n\nSample hash\r\n74aa61cc1157529fb98b757fb879616ffc2b54e4d4ff08c9b9d5b6dcec868c2a\r\nCommand Line\r\npowershell.exe -c \"[Console]::OutputEncoding = [Console]::InputEncoding = [System.Text.Encoding]::GetEncod\r\ncmd.exe /K chcp 65001 \u0026\u0026 c: \u0026\u0026 cd c:\\\r\ncmd.exe /c taskkill /f /im explorer.exe \u0026\u0026 start explorer.exe\r\ncmd.exe /c start /wait explorer.exe /factory, {75dff2b7-6936-4c06-a8bb-676a7b00b24b}\r\nexplorer.exe shell:mycomputerfolder\r\nexplorer.exe shell:mycomputerfolder\r\nBrowsers with params:\r\n--user-data-dir=\"\r\n\"\r\n --ash-force-desktop --disable-3d-apis --disable-accelerated-layers --disable-accelerated-plugins --disable\r\n--no-remote -no-deelevate -profile\r\nFile activity:\r\n%TEMP%\\D\\C\\\r\n%TEMP%\\D\\F\\\r\n%TEMP%\\D\\E\\\r\nReferences\r\n1. https://info.phishlabs.com/blog/the-unrelenting-evolution-of-vawtrak\r\n2. https://malpedia.caad.fkie.fraunhofer.de/details/win.vawtrak\r\n3. https://www.justice.gov/usao-sdny/pr/russian-hacker-who-used-neverquest-malware-steal-money-victims-bank-accounts-sentenced\r\n4. https://securityintelligence.com/new-banking-trojan-icedid-discovered-by-ibm-x-force-research/\r\n5. https://blog.fox-it.com/2018/08/09/bokbot-the-rebirth-of-a-banker/\r\n6. https://blog.nviso.eu/2023/03/20/icedids-vnc-backdoors-dark-cat-anubis-keyhole/\r\n7. https://www.netresec.com/?page=Blog\u0026month=2023-10\u0026post=Forensic-Timeline-of-an-IcedID-Infection\r\n8. https://svch0st.medium.com/can-you-track-processes-accessing-the-camera-and-microphone-7e6885b37072\r\nSource: https://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03\r\nhttps://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03\r\nPage 18 of 18",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03"
	],
	"report_names": [
		"keyhole-analysis-60302922aa03"
	],
	"threat_actors": [],
	"ts_created_at": 1775434246,
	"ts_updated_at": 1775791327,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/be7cc1d66df340b2471c22c8281f855311b58ad4.pdf",
		"text": "https://archive.orkl.eu/be7cc1d66df340b2471c22c8281f855311b58ad4.txt",
		"img": "https://archive.orkl.eu/be7cc1d66df340b2471c22c8281f855311b58ad4.jpg"
	}
}