Keyhole Analysis By Jason Reaves Published: 2024-01-16 · Archived: 2026-04-05 17:00:33 UTC By: Joshua Platt, Jonathan McCay and Jason Reaves Keyhole is a multi-functional VNC/Backconnect component used extensively by IcedID/Anubis. While the malware contains functionality that has been previously reported on as typical VNC and HDESK capabilities, a general lack of technical information appears to exist around some of the expanded functionality currently present. In fact, the functionality we mapped out for the main Keyhole component rivals that of IcedID itself: Collect system information VNC HDESK Socks/Backconnect Console command detonation via cmd.exe or powershell Multiple methods of injecting explorer.exe LDAP queries File retrieval from infected systems Hijacking browser profiles Deleting browser profiles Lower security of running browsers via command line manipulation Checking for webcam existence Taking pictures with webcam Turning on microphone in registry for apps Enumerating servers and shares in network Portions of this functionality are spread out over multiple open-source reports but significant analysis appears to be missing on several noteworthy improvements. Technical Overview Initial loader piece: The initial component involves a loader that can handle both PE files or shellcode versions of the main component; they also can utilize a custom PE loader with mangled headers. Ultimately the loader is responsible for decoding and loading the core module and executing it properly. Decoding Core Module: The core module is encoded using a 256 byte array of swap values, (key). After locating the initial blob containing the key values, a parsing algorithm is implemented to create the array. https://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03 Page 1 of 18 Unparsed Key Blob: Press enter or click to view image in full size An integer is given to decide how many bytes to pull from the unparsed blob. This integer will double in size until the value exceeds 256. Adding 1 to the amount of times the integer could double before exceeding 256 will be the number of bytes pulled. Finding an integer to decide how many bytes to pull that is not 0 will result in different behavior. The first time this happens, the appropriate amount of bytes will be added followed by the addition of a null byte. All bytes until the next 0 will be grabbed, and the process repeats until the key len is 256. Python: Parse Key Press enter or click to view image in full size https://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03 Page 2 of 18 Parsed Key / Encoded Core Module Press enter or click to view image in full size https://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03 Page 3 of 18 To decode the core module, each byte in the encoded module will be used as an index value. The byte in the key at that index will replace the encoded byte. Python: Decode Core Module Press enter or click to view image in full size Subset of Strings in Decoded Core Module user32.dll bad pathname path not found Default TOP WND RtlExitUserProcess MS Shell Dlg already exists explorer.exe move test auth -err-runasinvoker mkdir disk busy __compat_layer invalid name hcddir action not found Allow CREATE AD not found Value HIDE Settings WINMM.DLL 2500 disk not found combase.dll MOVE divice not readed https://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03 Page 4 of 18 mdiclient f%0.8X User32.dll Lucida Console ntdll.dll memory alloc shell32.dll access denied open error {%0.8X-%0.4X-%0.4X-%0.4X-%0.4X%0.8X} abcedfikmnopsutw SelectObject GetCurrentObject GetObjectA CreateCompatibleDC DeleteDC CreateDIBSection CreateCompatibleBitmap GetViewportOrgEx BitBlt NetShareEnum NetApiBufferFree NetGetDCName NETAPI32.dll RtlLargeIntegerDivide RtlGetVersion NtReadVirtualMemory NtWriteVirtualMemory NtFlushInstructionCache NtProtectVirtualMemory NtAllocateVirtualMemory LoadCursorA GetAncestor CreateDesktopA GetKeyboardLayoutList GetKeyboardLayout VkKeyScanA VkKeyScanExA VkKeyScanExW MapVirtualKeyA MapVirtualKeyExA OpenClipboard CloseClipboard SetClipboardData EmptyClipboard EnumWindows SetWinEventHook GetThreadDesktop RegisterClassExA https://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03 Page 5 of 18 GetClipboardData AddClipboardFormatListener OpenInputDesktop VkKeyScanW SendInput WinExec GetPrivateProfileIntW ACTIVEDS.dll WS2_32.dll TRUE name Exec High Definition Audio Main component: The main component of Keyhole can contain encoded strings, the really interesting part is that the algorithm used is the same as a sample I analyzed in June of 2017: 1cd6f992fbeee0a66e1c329e15db71fe891ae0e845867d6d30df867babe5bed6 Old IcedID string decoding routine: https://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03 Page 6 of 18 Keyhole string decoding routine: https://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03 Page 7 of 18 Decoding the strings in Keyhole took only a small edit in my old IcedID IDA script: def gen_key(k): return(((k << 0x1d) | (k >> 3)) & 0xffffffff) for addr in XrefsTo(0x322630, flags=0): addr = addr.frm addr = idc.PrevHead(addr) while GetMnem(addr) != "push": addr = idc.PrevHead(addr) print(hex(addr)) data_addr = GetOperandValue(addr,0) xork_init = Dword(data_addr) data_addr += 4 length_delta = Word(data_addr) data_addr += 2 length = (xork_init ^ length_delta) & 0xffff out = "" https://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03 Page 8 of 18 xork = xork_init for i in range(length): xork = gen_key(xork) xork += i out += chr((Byte(data_addr) ^ (xork & 0xFF)) & 0xFF) data_addr += 1 if out[-2:] == '\x00\x00': print(out.decode('utf16')) MakeRptCmt(addr, out.decode('utf16').encode('ascii')) else: print(out) MakeRptCmt(addr, out) The main component of Keyhole also expects a parameter to be passed, this address will be the shellcode blob from the previous loader component. First a DWORD value is pulled out, which will eventually be used as the initial seed value for the XOR loop: https://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03 Page 9 of 18 Next every byte after the DWORD is pulled out and run through a XOR loop where the initial seed value is manipulated every iteration, we can also see below that the blob being decoded is 0x14e bytes in length: The decoded blob turns out to be the config for the main Keyhole component, so the loader component passes the config in itself off to the main component as a parameter. After decoding we have a few values that will be used for C2 communications: ['', '', '', '', '\xbb\xa2\xbd\x9e\x1f\x8b\x08\x08', '', '', '', '', '', '', '', '', '', '', '', '', '', '', <..snip..> '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'hdesk', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', https://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03 Page 10 of 18 '', '', '', '', '', '', '', '', '', '', '', '', '', '91.238.]50.101', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '\x90\x1f’] A few values we can see, especially the C2 address but also the C2 traffic marker of ‘\x1f\x8b\x08\x08’ and the port 0x1f90 which is 8080. Get Jason Reaves’s stories in your inbox Join Medium for free to get updates from this writer. Remember me for faster sign in Functionality As mentioned the malware will retrieve some basic information about the infected system: It can also enumerate servers and shares in the network and leverages LDAP queries in the process: https://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03 Page 11 of 18 File retrievals are limited in size to roughly 33MB: Press enter or click to view image in full size Browsers For Chrome the module can copy the User Data to a new folder in temp: https://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03 Page 12 of 18 Along with the parameter of ‘C\\’ we can see below that the folder structure will be built under temp: In this case with a flag value of 0 we end up having the profile copied to: %TEMP%\D\C\ Browser are manipulated in a similar way that old banking trojans used to do it, the module contains code for hooking NtCreateUserProcess which will then look for browsers to be spawned: https://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03 Page 13 of 18 This lets the core module manipulate the command lines of the browsers, however it does more depending on which browser is found to be executing. Chrome - Copies profile data to - %TEMP%\D\C\ - Modifies command line - --user-data-dir=” - " --ash-force-desktop --disable-3d-apis --disable-accelerated-layers --disable-accelerated-plugins --di FireFox - Reads default profile path from profiles.ini file - Copies default profile to - %TEMP%\D\F\ - Edits prefs.js - user_pref("browser.preferences.defaultPerformanceSettings.enabled", false); - user_pref("layers.acceleration.disabled", true); - Modifies command line - --no-remote -no-deelevate -profile “ Edge https://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03 Page 14 of 18 - Sets registry keys - SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers - C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe=~ WIN8RTM - Copies profile data to - %TEMP%\D\E\ - Modifies command line - --user-data-dir=” - " --ash-force-desktop --disable-3d-apis --disable-accelerated-layers --disable-accelerated-plugins --di Internet Explorer - Modifies registry - Software\Microsoft\Internet Explorer\Main - NoProtectedModeBanner=1 - TabProcGrowth=0 - Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\3 - 2500=3 - Modifies command line - -nomerge -noframemerging -nohome Keyhole can also perform injection into newly started explorer processes in a variety of ways: Press enter or click to view image in full size For BackConnect commands: https://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03 Page 15 of 18 Press enter or click to view image in full size For console command line detonation a string is expected for either powershell or cmd detonation: Press enter or click to view image in full size Also above it can be seen for commands related to the microphone, these are primarily related to manipulating registry values: Press enter or click to view image in full size https://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03 Page 16 of 18 After the modifications the explorer will be restarted. SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\microphone\NonPackaged SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\microphone SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\StuckRects3 cmd.exe /c taskkill /f /im explorer.exe && start explorer.exe YARA rule keyhole_32 { strings: $config_decode = {694d0cfd43030081c1c39e2600894d0c} condition: all of them } rule keyhole_loader { strings: $64exe = {5390 9cbb be0c c453 9d5b 5290} $64dll = {7809 7407 7305 eb03 3941} $32exe = {770c 569c c1e6 0ac1 ee09 f7d6} $32dll = {5781 f7fc 46d8 5083 c728 bf0b} condition: any of them } IOCS https://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03 Page 17 of 18 Sample hash 74aa61cc1157529fb98b757fb879616ffc2b54e4d4ff08c9b9d5b6dcec868c2a Command Line powershell.exe -c "[Console]::OutputEncoding = [Console]::InputEncoding = [System.Text.Encoding]::GetEncod cmd.exe /K chcp 65001 && c: && cd c:\ cmd.exe /c taskkill /f /im explorer.exe && start explorer.exe cmd.exe /c start /wait explorer.exe /factory, {75dff2b7-6936-4c06-a8bb-676a7b00b24b} explorer.exe shell:mycomputerfolder explorer.exe shell:mycomputerfolder Browsers with params: --user-data-dir=" " --ash-force-desktop --disable-3d-apis --disable-accelerated-layers --disable-accelerated-plugins --disable --no-remote -no-deelevate -profile File activity: %TEMP%\D\C\ %TEMP%\D\F\ %TEMP%\D\E\ References 1. https://info.phishlabs.com/blog/the-unrelenting-evolution-of-vawtrak 2. https://malpedia.caad.fkie.fraunhofer.de/details/win.vawtrak 3. https://www.justice.gov/usao-sdny/pr/russian-hacker-who-used-neverquest-malware-steal-money-victims-bank-accounts-sentenced 4. https://securityintelligence.com/new-banking-trojan-icedid-discovered-by-ibm-x-force-research/ 5. https://blog.fox-it.com/2018/08/09/bokbot-the-rebirth-of-a-banker/ 6. https://blog.nviso.eu/2023/03/20/icedids-vnc-backdoors-dark-cat-anubis-keyhole/ 7. https://www.netresec.com/?page=Blog&month=2023-10&post=Forensic-Timeline-of-an-IcedID-Infection 8. https://svch0st.medium.com/can-you-track-processes-accessing-the-camera-and-microphone-7e6885b37072 Source: https://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03 https://medium.com/walmartglobaltech/keyhole-analysis-60302922aa03 Page 18 of 18