{
	"id": "e1e1bd32-48dc-4493-8842-3b08dcc89e2f",
	"created_at": "2026-04-06T00:19:23.516656Z",
	"updated_at": "2026-04-10T03:21:09.053219Z",
	"deleted_at": null,
	"sha1_hash": "33f39e89d391825dc297c23d80680b631e17b8dc",
	"title": "Quick analysis CobaltStrike loader and shellcode",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 491528,
	"plain_text": "Quick analysis CobaltStrike loader and shellcode\r\nPublished: 2021-09-06 · Archived: 2026-04-05 14:30:52 UTC\r\nI saw this hash 2569cc660d2ae0102aa74c98d78bb9409ded24101a0eeec15af29d59917265f3 shared at\r\nmalwareresearchgroup.slack.com. It was submitted to VT at 2021-09-01 19:47:50 and 37 security vendors\r\nflagged this file as malicious.\r\n1. Analyze loader\r\nThis loader is 64-bit Dll, compiled by MinGW and has one exported function:\r\nWith the help of IDA, we can see the ServiceMain function will spawn a new thread (I renamed to\r\nf_spawn_shellcode_thread ):\r\nThe f_spawn_shellcode_thread function does the following tasks:\r\nInit xor_key is “ jKfXmEkWYshKkZdPhJYS ”\r\nAllocate heap buffer for storing encrypted shellcode bytes and assign values to this buffer based on the\r\nglobal byte array has been declared from the beginning.\r\nPeform loop to decode the shellcode.\r\nhttps://kienmanowar.wordpress.com/2021/09/06/quick-analysis-cobaltstrike-loader-and-shellcode/\r\nPage 1 of 8\n\nSpawn new thread to execute the decoded shellcode.\r\nI wrote a short script to do shellcode extraction for later analysis:\r\nimport sys\r\nimport pefile\r\nxor_key = \"jKfXmEkWYshKkZdPhJYS\"\r\ndef decode_sc(data, key):\r\n key_len = len(key)\r\n data_len = len(data)\r\n decrypted = bytearray(data_len)\r\n for i in range(0, data_len):\r\n decrypted[i] = data[i] ^ key[i%key_len]\r\n \r\n print(\"Decode Done!\")\r\n return decrypted\r\ndef extract_sc(input_file):\r\n encrypted_sc = []\r\n try:\r\n print(\"\\r\\nFile: \" + input_file)\r\n pe = pefile.PE(input_file)\r\n for section in pe.sections:\r\n if b'.rdata\\x00\\x00' in section.Name:\r\n rdata_section = bytearray(section.get_data())\r\n \r\n size = 0\r\n for i in rdata_section:\r\n if rdata_section[size] == 0x00 and rdata_section[size+1] == 0x00:\r\n break\r\nhttps://kienmanowar.wordpress.com/2021/09/06/quick-analysis-cobaltstrike-loader-and-shellcode/\r\nPage 2 of 8\n\nelse:\r\n size += 1\r\n print(\"Encrypted bytes size: \" + str(size - 24) + \" bytes\")\r\n encrypted_bytes = rdata_section[24:size+1]\r\n for i in range(len(encrypted_bytes)):\r\n if ((i \u0026 1) == 0):\r\n encrypted_sc.append(encrypted_bytes[i])\r\n key = xor_key.encode('ascii')\r\n decrypted_sc = decode_sc(encrypted_sc, key)\r\n with open(sys.argv[1]+\"-decrypted\", \"wb\") as out_file:\r\n out_file.write(decrypted_sc)\r\n print(\"Shellcode extracted at \" + sys.argv[1]+\"-decrypted!\\r\\n\")\r\n print(\"Extract Shellcode Done!\")\r\n except Exception as e:\r\n print(\"Error: \" + str(e))\r\nif __name__ == '__main__':\r\n if len(sys.argv) == 2:\r\n extract_sc(sys.argv[1])\r\n else:\r\n print(\"Usage: cobalt_extract_sc.py \u003ccobalt_loader_dll\u003e\")\r\nAfter run script, I got the shellcode like the figure bellow:\r\nhttps://kienmanowar.wordpress.com/2021/09/06/quick-analysis-cobaltstrike-loader-and-shellcode/\r\nPage 3 of 8\n\n2. Analyze shellcode\r\nIf we load the raw shellcode into IDA and convert to asm code, it will look like the figure bellow. At the first\r\nbeginning of this code, we can see the pattern code that shellcode use to locate the fields of PEB structure. This\r\nmakes me think that it will use PEB to looking up the addresses of the API functions in the Dll used by shelllcode.\r\nhttps://kienmanowar.wordpress.com/2021/09/06/quick-analysis-cobaltstrike-loader-and-shellcode/\r\nPage 4 of 8\n\nGo into sub_D2 , the first statement assigns the return address to the rbp register. And we know that this\r\naddress is 0xA (push r9) . Then we see the string value ‘ wininet ’ is load to r14 register at 0xD5 . We see a\r\nvalue is assigned to the r10 ( 726774Ch; 726774Ch ) register and following is a call to the address pointed by the\r\nrbp register. At that time, I think these are hash values related to api functions, shellcode will perform\r\ncalculations to compare with these values from which to get the related API address.\r\nFor the convenience of analysis and debugging, I converted the shellcode to an exe. Finally, I got the following\r\npseudocode related to finding the address of the API function and calling API through jmp rax command:\r\nhttps://kienmanowar.wordpress.com/2021/09/06/quick-analysis-cobaltstrike-loader-and-shellcode/\r\nPage 5 of 8\n\nBased on the above pseudocode, we can see that the shellcode will calculate two hash values, the first value is\r\nbased on the name of the Dll, the second value is based on the name of the API function of that Dll. These two\r\nvalues are added together and compared with the pre-computed hash value.\r\nYou can write scripts to recover API functions or to save time, I always use shellcode_hashes_search_plugin.py of\r\nFLARE Team. Details can be found in this article. Final result after using the plugin:\r\nshellcode_hash: Starting up\r\n[INFO] Starting up (shellcode_hash_search:run)\r\nshellcode_hash: Processing current segment only: 0x140001000 - 0x140003000\r\n[INFO] Processing current segment only: 0x140001000 - 0x140003000 (shellcode_hash_search:proces\r\nshellcode_hash: 0x1400020e7: ror13AddHash32AddDll:0x0726774c kernel32.dll!LoadLibraryA\r\n[INFO] 0x1400020e7: ror13AddHash32AddDll:0x0726774c kernel32.dll!LoadLibraryA (shellcode_hash_searc\r\nshellcode_hash: 0x1400020ff: ror13AddHash32AddDll:0xa779563a wininet.dll!InternetOpenA\r\n[INFO] 0x1400020ff: ror13AddHash32AddDll:0xa779563a wininet.dll!InternetOpenA (shellcode_hash_searc\r\nshellcode_hash: 0x140002121: ror13AddHash32AddDll:0xc69f8957 wininet.dll!InternetConnectA\r\n[INFO] 0x140002121: ror13AddHash32AddDll:0xc69f8957 wininet.dll!InternetConnectA (shellcode_ha\r\nshellcode_hash: 0x140002140: ror13AddHash32AddDll:0x3b2e55eb wininet.dll!HttpOpenRequestA\r\n[INFO] 0x140002140: ror13AddHash32AddDll:0x3b2e55eb wininet.dll!HttpOpenRequestA (shellcode_ha\r\nshellcode_hash: 0x14000216a: ror13AddHash32AddDll:0x869e4675 wininet.dll!InternetSetOptionA\r\n[INFO] 0x14000216a: ror13AddHash32AddDll:0x869e4675 wininet.dll!InternetSetOptionA (shellcode_ha\r\nhttps://kienmanowar.wordpress.com/2021/09/06/quick-analysis-cobaltstrike-loader-and-shellcode/\r\nPage 6 of 8\n\nshellcode_hash: 0x140002184: ror13AddHash32AddDll:0x7b18062d wininet.dll!HttpSendRequestA\r\n[INFO] 0x140002184: ror13AddHash32AddDll:0x7b18062d wininet.dll!HttpSendRequestA (shellcode_ha\r\nshellcode_hash: 0x140002329: ror13AddHash32AddDll:0x56a2b5f0 kernel32.dll!ExitProcess\r\n[INFO] 0x140002329: ror13AddHash32AddDll:0x56a2b5f0 kernel32.dll!ExitProcess (shellcode_hash_searc\r\nshellcode_hash: 0x140002345: ror13AddHash32AddDll:0xe553a458 kernel32.dll!VirtualAlloc\r\n[INFO] 0x140002345: ror13AddHash32AddDll:0xe553a458 kernel32.dll!VirtualAlloc (shellcode_hash_searc\r\nshellcode_hash: 0x140002363: ror13AddHash32AddDll:0xe2899612 wininet.dll!InternetReadFile\r\n[INFO] 0x140002363: ror13AddHash32AddDll:0xe2899612 wininet.dll!InternetReadFile (shellcode_ha\r\nshellcode_hash: Done\r\n[INFO] Done (shellcode_hash_search:run)\r\nAt this point, we can do debugging for further analysis, however, for quickly I use hasherezade’s tiny_tracer tool\r\nto trace the shellcode:\r\nhttps://kienmanowar.wordpress.com/2021/09/06/quick-analysis-cobaltstrike-loader-and-shellcode/\r\nPage 7 of 8\n\nEnd!\r\nSource: https://kienmanowar.wordpress.com/2021/09/06/quick-analysis-cobaltstrike-loader-and-shellcode/\r\nhttps://kienmanowar.wordpress.com/2021/09/06/quick-analysis-cobaltstrike-loader-and-shellcode/\r\nPage 8 of 8",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://kienmanowar.wordpress.com/2021/09/06/quick-analysis-cobaltstrike-loader-and-shellcode/"
	],
	"report_names": [
		"quick-analysis-cobaltstrike-loader-and-shellcode"
	],
	"threat_actors": [],
	"ts_created_at": 1775434763,
	"ts_updated_at": 1775791269,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/33f39e89d391825dc297c23d80680b631e17b8dc.pdf",
		"text": "https://archive.orkl.eu/33f39e89d391825dc297c23d80680b631e17b8dc.txt",
		"img": "https://archive.orkl.eu/33f39e89d391825dc297c23d80680b631e17b8dc.jpg"
	}
}