{
	"id": "cbc22ec5-2576-4315-8f6f-d0fbd3776036",
	"created_at": "2026-04-06T00:17:56.871177Z",
	"updated_at": "2026-04-10T03:24:23.643961Z",
	"deleted_at": null,
	"sha1_hash": "be6662ce50a65df43b5a3ddb1cbd1a37ca2e9f03",
	"title": "HANCITOR: Analysing The Main Loader | 0ffset Training Solutions",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 2775620,
	"plain_text": "HANCITOR: Analysing The Main Loader | 0ffset Training\r\nSolutions\r\nBy Chuong Dong\r\nPublished: 2021-12-31 · Archived: 2026-04-05 22:30:24 UTC\r\nThis post is a follow up for my last one on HANCITOR. If you haven’t checked it out, you can view it here.\r\nIn this post, we’ll take a look at the main loader of this malware family, which is used for downloading and\r\nlaunching Cobalt Strike Beacon, information stealers, and malicious shellcode.\r\nIf you’re interested in following along, you can grab the loader sample as well as the PCAP for it on Malware-Traffic-Analysis.net.\r\nSHA256: b9bafe8645a4dba7b7a9bd5132b696c0a419998d4f65fe897bb6912c2e019a7b\r\nStep 1: Unpacking\r\nHANCITOR’s first executable stage is a packed DLL. We can tell since the HANCITOR payload is typically not\r\nobfuscated and relatively short. The gelforr.dap file dropped from the maldoc stages, on the other hand, is quite\r\nlarge and has a high entropy (the measure of randomness for data in the file). This high entropy can be a good\r\nindicator for the sample containing some data obfuscation.\r\nTo dynamically unpack this, we can load the sample in our favourite debugger and try to stop the program after\r\nit’s done unpacking the final payload in memory.\r\nhttps://www.0ffset.net/reverse-engineering/malware-analysis/hancitor-analysing-the-main-loader/\r\nPage 1 of 22\n\nFirst, we can set breakpoints on VirtualAlloc and VirtualProtect as those two API calls are typically used by\r\npackers to allocate memory for the unpacked executable and change the memory’s protection to executable prior\r\nto launching. We can also set breakpoints on CreateProcessInternalW and ResumeThread to try and stop our\r\ndebugger before the final payload is launched.\r\nAt this point, we can have the debugger execute the DLL and wait until these breakpoints are hit. As the code is\r\nquite large, it takes around 30 seconds before we hit our first VirtualAlloc breakpoint. To observe if the packer\r\nwrites the unpacked executable into the newly allocated memory, we can capture the return value of the\r\nVirtualAlloc call and dump its memory before continuing the execution.\r\nThe first two allocated regions do not seem to give us anything valuable, but the third one does. The packer writes\r\nwhat seems to be a compressed PE file in it before calling VirtualProtect to change its protection.\r\nhttps://www.0ffset.net/reverse-engineering/malware-analysis/hancitor-analysing-the-main-loader/\r\nPage 2 of 22\n\nScrolling down a bit to examine this memory region, we can see that its lower part is not compressed at all. To be\r\nexact, at offset 0x4389, we can see the uncompressed PE header, which indicates the beginning of the final\r\nunpacked payload.\r\nFrom here, we can simply dump this memory region and cut out the top 0x4389 bytes using any hex editor to\r\nretrieve the unpacked executable for the next stage.\r\nhttps://www.0ffset.net/reverse-engineering/malware-analysis/hancitor-analysing-the-main-loader/\r\nPage 3 of 22\n\nWe can also use PE-bear to examine and ensure that we have fully unpacked the file. After checking that all\r\nimports are properly resolved, we will use IDA to perform static analysis on this last stage.\r\nStep 2: HANCITOR Entry Point\r\nThe HANCITOR DLL contains the following 3 exports:  BNJAFSRSQIX, SDTECHWMHHONG, and\r\nDllEntryPoint. Since the functions BNJAFSRSQIX and SDTECHWMHHONG share the same address, we\r\ncan count them as one single function.\r\nTypically, DllEntryPoint is used as the entry point function for malicious DLL files, but in HANCITOR case, this\r\nfunction does not do anything but return 1. This means that the malware does not execute its full capability when\r\nloaded using rundll32.exe without an export name specified.\r\nhttps://www.0ffset.net/reverse-engineering/malware-analysis/hancitor-analysing-the-main-loader/\r\nPage 4 of 22\n\nFrom the previous blog post, we know that the second Word document launches the rundll32.exe command to\r\nexecute the BNJAFSRSQIX export function, so it must be the real entry point for this DLL.\r\nStep 3: Extracting Victim Information\r\nBy the time this blog post is written, the C2 servers used by the sample have been taken offline, so I will use the\r\ntraffic captured by Malware-Traffic-Analysis.net in parallel with static analysis to show how the malware\r\ncommunicates with its C2 servers.\r\nTo contact C2 servers, the malware generates a string containing the victim’s information prior to encrypting and\r\nsending it to C2.\r\nFirst, HANCITOR generates a global unique identifier (GUID) for the victim. By calling GetAdaptersAddresses,\r\nit retrieves an array of addresses associated with the network adapters on the victim’s machine. It begins by XOR-ing the Media Access Control (MAC) adapter of each address together. Then, the malware retrieves the machine’s\r\nvolume serial number by calling GetVolumeInformationA and XORs it with the result to create the victim’s\r\nGUID.\r\nhttps://www.0ffset.net/reverse-engineering/malware-analysis/hancitor-analysing-the-main-loader/\r\nPage 5 of 22\n\nFollowing this, HANCITOR extracts the machine’s information by calling GetComputerNameA to retrieve the\r\ninfected computer’s name.\r\nIt also retrieves the process ID of an explorer.exe process and calls LookupAccountSidA to get the current user’s\r\naccount name and domain name.\r\nThe machine’s information is then formatted as below.\r\n\u003cComputer name\u003e @ \u003cDomain name\u003e \\ \u003cAccount name\u003e\r\nNext, HANCITOR retrieves the victim’s IP address by sending a GET request to hxxp://api[.]ipify[.]org. If the\r\nmalware is unable to contact the website, it uses 0.0.0.0 as the victim’s IP address instead.\r\nhttps://www.0ffset.net/reverse-engineering/malware-analysis/hancitor-analysing-the-main-loader/\r\nPage 6 of 22\n\nThe documented query_URL_and_get_response function is shown below. After connecting to the target server\r\nusing InternetConnectA, HANCITOR calls HttpOpenRequestA to create a GET request and\r\nHttpSendRequestA to send it to the server. The server’s response is then retrieved through InternetReadFile\r\ncalls.\r\nBeside being used for querying the victim’s IP address, this function is later used to download malware and\r\nshellcode from HANCITOR’s C2 servers.\r\nThe malware then calls DsEnumerateDomainTrustsA to enumerate and retrieve all NETBIOS and DNS domain\r\nnames.\r\nhttps://www.0ffset.net/reverse-engineering/malware-analysis/hancitor-analysing-the-main-loader/\r\nPage 7 of 22\n\nFinally, HANCITOR decrypts its configuration using RC4 before building the final victim’s information string.\r\nBelow is the content of the decoded configuration. It contains the sample’s build ID (2909_xplw) followed by the\r\nlist of C2 URLs.\r\nThe final victim’s information string is built according to one of the following formats based on the machine’s\r\narchitecture.\r\nhttps://www.0ffset.net/reverse-engineering/malware-analysis/hancitor-analysing-the-main-loader/\r\nPage 8 of 22\n\nGUID=\u003cVictim’s GUID\u003e\u0026BUILD=\u003cBuild ID\u003e\u0026INFO=\u003cMachine Information\u003e\u0026EXT=\u003cNetwork domain names\u003e\u0026IP=\u003cVictim’s IP add\r\nGUID=\u003cVictim’s GUID\u003e\u0026BUILD=\u003cBuild ID\u003e\u0026INFO=\u003cMachine Information\u003e\u0026EXT=\u003cNetwork domain names\u003e\u0026IP=\u003cVictim’s IP addr\r\nStep 4: Sending Victim Information To C2 Servers\r\nAfter retrieving the victim information, the malware iterates through the C2 URL list embedded in the config and\r\nsends the data to the servers.\r\nhttps://www.0ffset.net/reverse-engineering/malware-analysis/hancitor-analysing-the-main-loader/\r\nPage 9 of 22\n\nThe function below is used to retrieve the next address in the list by locating the separator ‘|’ between C2 URLs.\r\nThe function to send the victim’s information to the C2 servers has similar API calls to the function\r\nquery_URL_and_get_response mentioned above, but instead of a GET request, the malware is sending a POST\r\nrequest to send this data.\r\nhttps://www.0ffset.net/reverse-engineering/malware-analysis/hancitor-analysing-the-main-loader/\r\nPage 10 of 22\n\nWe can further confirm our analysis by examining the malicious traffic from the PCAP provided to us by\r\nMalware-Traffic-Analysis.net. Below is the POST request being sent to the C2 server hxxp://forkineler[.]com\r\ncontaining the victim’s information buffer as we have analyzed.\r\nhttps://www.0ffset.net/reverse-engineering/malware-analysis/hancitor-analysing-the-main-loader/\r\nPage 11 of 22\n\nStep 4: Decoding C2 Response\r\nUsing the same PCAP, we can examine the C2 response sent back from the server.\r\nThe response comes in the form of a Base64-encoded string.\r\nVZAEARZAEg4OCkBVVU4XGw8IChUUDlQID1VOSwlUGBMUBwEWQBIODgpAVVVOFxsPCAoVFA5UCA9VTktUGBMUBw==\r\nThe first 4 characters in the string are used as a simple check to ensure the response does come from the C2 server.\r\nThe malware checks if they are all uppercase letters and discards the response if the check fails.\r\nIf the response is valid, HANCITOR decodes the string using Base64 and XORs the result with the character ‘z’.\r\nWe can use CyberChef to quickly decode it and examine the content.\r\nhttps://www.0ffset.net/reverse-engineering/malware-analysis/hancitor-analysing-the-main-loader/\r\nPage 12 of 22\n\nThe decoded response can consist of one or multiple components, where each is made up of a command (‘l’) and a\r\nvalue (hxxp://4maurpont[.]ru/41s[.]bin).\r\nBefore processing each response component, HANCITOR checks if the command is in the list of available\r\ncommands ‘n’, ‘c’, ‘d’, ‘r’, ‘l’, ‘e’, and ‘b’.\r\nBeside the ‘n’ command that doesn’t perform anything, every other command instructs the malware to download\r\nshellcode or a file and execute it.\r\nhttps://www.0ffset.net/reverse-engineering/malware-analysis/hancitor-analysing-the-main-loader/\r\nPage 13 of 22\n\nStep 5: C2 commands – Downloading Executable \u0026 Remote Injection\r\nWhen the command is ‘b’, HANCITOR downloads a file from the URL specified in the response’s component\r\nand performs process injection to launch it.\r\nOne or multiple URLs separated by the character ‘|’ can be provided for the malware to download files from.\r\nAfter retrieving the file content into memory, HANCITOR decrypts it using a XOR cipher with its first 8 bytes as\r\nthe key. Next, it calls RtlDecompressBuffer to perform LZ decompression to decompress the final executable.\r\nhttps://www.0ffset.net/reverse-engineering/malware-analysis/hancitor-analysing-the-main-loader/\r\nPage 14 of 22\n\nNext, the malware injects the downloaded executable into an svchost.exe process. To do this, it first creates the\r\nprocess in a suspended state using CreateProcessA.\r\nNext, the malware calls VirtualAllocEx to allocate a buffer in the target’s memory to later inject the executable\r\npayload into it.\r\nHANCITOR then allocates a heap buffer using HeapAlloc, writes and maps the executable to it, and finally calls\r\nWriteProcessMemory to write the payload from the heap to svchost’s allocated memory.\r\nhttps://www.0ffset.net/reverse-engineering/malware-analysis/hancitor-analysing-the-main-loader/\r\nPage 15 of 22\n\nThe malware properly sets up the injected thread’s context by setting the image base address from PEB (through\r\nthe context’s EBX register) to the injected base address and the thread’s entry point (through the context’s EAX\r\nregister) to the injected entry point.\r\nFinally, it launches the executable by calling ResumeThread to resume the injected thread.\r\nStep 6: C2 commands – Downloading Executable \u0026 Self Injection\r\nhttps://www.0ffset.net/reverse-engineering/malware-analysis/hancitor-analysing-the-main-loader/\r\nPage 16 of 22\n\nWhen the command is ‘e’, HANCITOR downloads a file from the URL specified in the response’s component and\r\ninjects the executable into its own process to launch it.\r\nThe malware first downloads the file using the same downloading function from the previous command.\r\nAfter downloading, HANCITOR calls VirtualAlloc to allocate a buffer in its own memory and writes the\r\ndownloaded executable in there.\r\nNext, the malware extracts each imported DLL name through the image’s Import Directory Table and calls\r\nGetModuleHandleA or LoadLibraryA to retrieve the DLL’s base (depending if the DLL is loaded in memory).\r\nFor each imported DLL, the malware manually iterates through its own Import Address Table (IAT) to retrieve the\r\nname of each imported function. It calls GetProcAddress to get the address of the imported function and updates\r\nit in its IAT.\r\nhttps://www.0ffset.net/reverse-engineering/malware-analysis/hancitor-analysing-the-main-loader/\r\nPage 17 of 22\n\nFinally, HANCITOR can launch the injected executable through multiple methods depending on the launch flags\r\nbeing given in the code.\r\nThe first method requires calling CreateThread to launch a new thread that manually resolves the injected\r\nimage’s entry point from its headers and calls that address.\r\nThe next two simply require directly calling the image’s entry point address that is returned after writing the\r\nimage in memory.\r\nStep 7: C2 commands – Downloading \u0026 Launching Shellcode\r\nhttps://www.0ffset.net/reverse-engineering/malware-analysis/hancitor-analysing-the-main-loader/\r\nPage 18 of 22\n\nWhen the command is ‘l’, HANCITOR downloads shellcode from the URL specified in the response’s component\r\nand injects the shellcode into its own process or svchost to launch it.\r\nThe malware first downloads the file using the same downloading function from the previous two commands.\r\nHANCITOR takes in a parameter to determine if it should inject the shellcode into its own process or remotely to\r\nsvchost.\r\nTo inject into svchost, the malware first creates a suspended svchost process, calls VirtualAllocEx to allocate a\r\nbuffer in the process’s memory, and calls WriteProcessMemory to write the shellcode into the buffer.\r\nTo launch the shellcode remotely, the malware then calls CreateRemoteThread to spawn a thread that begins\r\nexecuting at the base address of the injected shellcode.\r\nTo inject into its own process, HANCITOR calls VirtualAlloc to allocate a buffer in its memory and manually\r\ncopies the shellcode byte by byte into the buffer.\r\nFor self-injection, HANCITOR has two different ways of launching the shellcode. The first is simply executing a\r\ncall instruction to transfer execution to the base address of the shellcode. The second one involves calling\r\nCreateThread to launch a thread that does basically the same thing.\r\nhttps://www.0ffset.net/reverse-engineering/malware-analysis/hancitor-analysing-the-main-loader/\r\nPage 19 of 22\n\nStep 8: C2 commands – Downloading File To Temp Directory\r\nWhen the command is ‘r’, HANCITOR downloads a file from the URL specified in the response’s component,\r\ndrops it in the Windows Temp folder, and launches it.\r\nThe malware first downloads the file using the same downloading function from the previous three commands.\r\nhttps://www.0ffset.net/reverse-engineering/malware-analysis/hancitor-analysing-the-main-loader/\r\nPage 20 of 22\n\nNext, to drop the downloaded file to the Temp directory, the malware calls GetTempPathA to retrieve the path to\r\nthe directory and GetTempFileNameA to generate a temporary file’s name in that path with the prefix of “BN”.\r\nThen, it calls CreateFileA and WriteFile to write the downloaded content to the temporary file.\r\nHANCITOR then checks the Characteristics flag in the file header to determine if the file is an executable or a\r\nDLL.\r\nIf the file is an executable, the malware launches it by calling CreateProcessA with the file’s path as the\r\ncommand line to be executed.\r\nIf the file is a DLL, the malware launches its start export function by calling CreateProcessA with a formatted\r\nrundll32.exe command as the command line.\r\nhttps://www.0ffset.net/reverse-engineering/malware-analysis/hancitor-analysing-the-main-loader/\r\nPage 21 of 22\n\nAt this point, we have fully analyzed every stage of a HANCITOR infection and understood how it can be used to\r\nload and launch malicious executable and shellcode! If you have any questions regarding the analysis, feel free to\r\nreach out to me via Twitter.\r\nSource: https://www.0ffset.net/reverse-engineering/malware-analysis/hancitor-analysing-the-main-loader/\r\nhttps://www.0ffset.net/reverse-engineering/malware-analysis/hancitor-analysing-the-main-loader/\r\nPage 22 of 22",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://www.0ffset.net/reverse-engineering/malware-analysis/hancitor-analysing-the-main-loader/"
	],
	"report_names": [
		"hancitor-analysing-the-main-loader"
	],
	"threat_actors": [
		{
			"id": "610a7295-3139-4f34-8cec-b3da40add480",
			"created_at": "2023-01-06T13:46:38.608142Z",
			"updated_at": "2026-04-10T02:00:03.03764Z",
			"deleted_at": null,
			"main_name": "Cobalt",
			"aliases": [
				"Cobalt Group",
				"Cobalt Gang",
				"GOLD KINGSWOOD",
				"COBALT SPIDER",
				"G0080",
				"Mule Libra"
			],
			"source_name": "MISPGALAXY:Cobalt",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		}
	],
	"ts_created_at": 1775434676,
	"ts_updated_at": 1775791463,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/be6662ce50a65df43b5a3ddb1cbd1a37ca2e9f03.pdf",
		"text": "https://archive.orkl.eu/be6662ce50a65df43b5a3ddb1cbd1a37ca2e9f03.txt",
		"img": "https://archive.orkl.eu/be6662ce50a65df43b5a3ddb1cbd1a37ca2e9f03.jpg"
	}
}