{
	"id": "c2e3849c-e989-4494-a8ad-0699f8a94cbc",
	"created_at": "2026-04-06T00:16:55.275926Z",
	"updated_at": "2026-04-10T03:22:02.892455Z",
	"deleted_at": null,
	"sha1_hash": "b2702194d4ab0bd6659089c3d1d9a0ac6836c06e",
	"title": "Extracting Hancitor’s Configuration with Ghidra part 1",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 559461,
	"plain_text": "Extracting Hancitor’s Configuration with Ghidra part 1\r\nBy Crovax\r\nPublished: 2022-01-21 · Archived: 2026-04-05 20:15:30 UTC\r\nLocating the decryption function\r\nHancitor leverages the Windows native Cryptographic Service provider (CSP) context to perform its decryption\r\nroutine. Knowing that, locating the decryption function will be relatively easy.\r\nOne way, is to load the binary into Ghidra and look at import table list for one of the cryptographic functions\r\n(CryptDecrypt, CryptAcquireContextA etc) then follow the referenced function from there.\r\nNow that we have located the function leveraging the CryptDecrypt routine, we can get a better picture of how the\r\ndecryption process works. Below is the decompiled view of the function performing the decryption routine. We’ll\r\nstep through each function to determine how the decryption logic works then start programming it out.\r\nCryptAcquireContextA\r\nThe CryptAcquireContextA function initiates the call to the Cryptographic Service Provider (CSP) to determine\r\nwhat kind of CSP to use for the CryptoAPI functions. This function is straightforward as its role is just to initiate\r\nthe CSP context for use. We can determine which CSP is going to be used by the first ‘PUSH 0x0\" instruction.\r\nSince its a null value being used, the default selection is made (native windows cryptographic service provider).\r\nPress enter or click to view image in full size\r\nCryptCreateHash\r\nWhen the CryptCreateHash function is called, it creates the hashing object to be used in the cryptographic routine,\r\nand determines the type of hashing algorithm to be used. Once successful, it returns a handle to the object, for\r\nsubsequent calls to the other cryptographic functions.\r\nhttps://medium.com/@crovax/extracting-hancitors-configuration-with-ghidra-7963900494b5\r\nPage 1 of 6\n\nTo determine what hashing algorithm is being used, we can look at the ‘Algid’ value that will be pushed on to the\r\nstack. In this case, we see the ‘PUSH CALG_SHA1’ instruction is being used. So, we know that the hashing\r\nalgorithm is SHA1.\r\nPress enter or click to view image in full size\r\nCryptHashData\r\nThis function is going to hash the data passed to it, using the previously specified algorithm(SHA1). But what is\r\nbeing hashed and how do we figure it out?\r\nFirst we need to look back at the arguments being passed into the function (I have labeled it “Decryption’) to see\r\nwhat data is being passed and where its located.\r\nby looking at the arguments and their position in which they're being passed in, we need to find out what the data\r\nis expecting and where is it located. In order to find this information we can follow the data that is being passed\r\ninto the function.\r\nHint: I have already labeled it 😃\r\nAs you can see, the third argument being passed is a pointer to the ‘key’ thats going to be hashed, and the\r\nargument being passed to the right of it (8) is the key length.\r\nso we know the following:\r\nKey = b’\\xb3\\x03\\x18\\xaa\\x0a\\xd2\\x77\\xde’\r\nGet Crovax’s stories in your inbox\r\nJoin Medium for free to get updates from this writer.\r\nRemember me for faster sign in\r\nKey length = 8 bytes\r\nCryptDeriveKey\r\nhttps://medium.com/@crovax/extracting-hancitors-configuration-with-ghidra-7963900494b5\r\nPage 2 of 6\n\nThis next part is going to be a bit tricky. The CryptDeriveKey is going to accept a few parameters:\r\nhProv = handle to the cryptographic service provided being used.\r\nAlgid = algorithm for which the key is to be generated. In this case, its going to be RC4.\r\nhHash or hBaseData = handle to the hash object that points to the data.\r\ndwFlags = this is going to be key length that is going to be used. Which is the lower 16 bits of the value being\r\npassed. In our case that value is 0x00280011, so we only want the lower values or 0x0028 (we can truncate the\r\nleading zeros). So by dividing 0x28 / key length(8) that was being passed to the CryptHashData function, we\r\nknow how many bytes of the RC4 key is going to be used to decrypt the configuration data.\r\nRC4 key: 0x28 / 8 = (5 bytes)\r\nCryptDecrypt\r\nThis function is straightforward, it accepts the data to be decrypted, the key used, and the length of the data as\r\nparameters. To verify, we can once again look at the arguments that are being passed to the function.\r\nbased on the value being passed in, we can see the encrypted data length is equal to 0x2000 bytes.\r\nBelow is a graphical representation of the actions performed thus far.\r\nPress enter or click to view image in full size\r\nCreating the Ghidra script\r\nWe now understand how the decryption process works. The next step is to create a script in Ghidra to automate\r\nthis whole process, so we can extract the build/campaign id and the c2 domains from this sample.\r\nhttps://medium.com/@crovax/extracting-hancitors-configuration-with-ghidra-7963900494b5\r\nPage 3 of 6\n\nNote: the python script can be downloaded from my github (link here). Your cursor needs to be pointing to the\r\nfirst address of the encrypted data before running the script. This is due to the ‘currentAddress’ method.\r\nWe know we need to create a sha1 hash of the 8 byte key that’s being passed into the Decryption function. So we\r\ncan copy those bytes out of Ghidra and store them into a variable. The next step is to get a hash (sha1) of the key\r\nand extract the first 5 bytes (Key Hash: a956a1e6ff).\r\nimport hashlib\r\nimport binasciikey_bytes = ‘\\xb3\\x03\\x18\\xaa\\x0a\\xd2\\x77\\xde’\r\nprint ‘key length’, len(key_bytes)\r\nget_hash = hashlib.sha1()\r\nget_hash.update(key_bytes)\r\nkey_hash = get_hash.digest()[:5]\r\nNext we need to get the encrypted data using ghidra’s getBytes function, and then perform any necessary\r\nconversions on the hex values\r\ndef get_encrypted_bytes():\r\n get_addr = currentAddress\r\n get_bytes = list(getBytes(get_addr, 2000))\r\n converted_bytes = ''\r\n cByte = ''\r\n for byte in get_bytes:\r\n if byte \u003c 0:\r\n cByte = (0xff - abs(byte) + 1)\r\n else:\r\n cByte = byte\r\n converted_bytes += chr(cByte)\r\n return converted_bytes\r\nWe now have our key and the encrypted data we need to decrypt. The last step is to pass these parameters to a our\r\nrc4 decryption function to perform the remaining steps.\r\ndef rc4_decrypt(key, data):\r\n x = 0\r\n box = range(256)\r\n for i in range(256):\r\n x = (x + box[i] + ord(key[i % len(key)])) % 256\r\n box[i], box[x] = box[x], box[i]\r\n x = 0\r\n y = 0\r\n out = []\r\n for char in data:\r\n x = (x + 1) % 256\r\nhttps://medium.com/@crovax/extracting-hancitors-configuration-with-ghidra-7963900494b5\r\nPage 4 of 6\n\ny = (y + box[x]) % 256\r\n box[x], box[y] = box[y], box[x]\r\n out.append(chr(ord(char) ^ box[(box[x] + box[y]) % 256]))\r\n return ''.join(out)\r\nNow that we have our decrypted data, we just need to format the data we want and discard any null bytes.\r\nprint 'Current Address:', currentAddress\r\nprint 'Key Hash:',binascii.hexlify(key_hash)get_data = get_encrypted_bytes()config = rc4_decrypt(key\r\nbuild_id = config.split('\\x00')[0]\r\nprint 'Build_id:', build_idfor string in config.split('\\x00')[1:]:\r\n if string != '':\r\n c2 = string\r\n break\r\nc2_List = c2.split('|')for c2 in c2_List:\r\n if c2 != '':\r\n print 'c2:', c2\r\nThe output should look something like this 😃\r\nPress enter or click to view image in full size\r\nDecode_Config.py\u003e Running…\r\nkey length 8\r\nCurrent Address: 005c5018\r\nKey Hash: a956a1e6ff\r\nBuild_id: 1706_apkreb6\r\nc2: http://thestaccultur.com/8/forum[.]php\r\nc2: http://arguendinfuld.ru/8/forum[.]php\r\nc2: http://waxotheousch.ru/8/forum[.]php\r\nhttps://medium.com/@crovax/extracting-hancitors-configuration-with-ghidra-7963900494b5\r\nPage 5 of 6\n\nConclusion\r\nBy breaking down the individual functions of the decryption routine we were able to determine how hancitor was\r\ndecrypting its c2 domain configuration. We then applied the same process in creating a Ghidra script to\r\nautomatically perform the same steps statically, to reveal the encrypted data.\r\nIn part 2, we well take a similar approach and build a yara rule to test our theory and see if we can detect multiple\r\nhancitor variants.\r\nAs always, Don’t expect much, as I have no clue what I’m doing. 😃\r\nSource: https://medium.com/@crovax/extracting-hancitors-configuration-with-ghidra-7963900494b5\r\nhttps://medium.com/@crovax/extracting-hancitors-configuration-with-ghidra-7963900494b5\r\nPage 6 of 6",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://medium.com/@crovax/extracting-hancitors-configuration-with-ghidra-7963900494b5"
	],
	"report_names": [
		"extracting-hancitors-configuration-with-ghidra-7963900494b5"
	],
	"threat_actors": [],
	"ts_created_at": 1775434615,
	"ts_updated_at": 1775791322,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/b2702194d4ab0bd6659089c3d1d9a0ac6836c06e.pdf",
		"text": "https://archive.orkl.eu/b2702194d4ab0bd6659089c3d1d9a0ac6836c06e.txt",
		"img": "https://archive.orkl.eu/b2702194d4ab0bd6659089c3d1d9a0ac6836c06e.jpg"
	}
}