{
	"id": "de5a64fb-88e0-4d8c-b9f9-85687d9da212",
	"created_at": "2026-04-06T00:10:04.228443Z",
	"updated_at": "2026-04-10T03:20:33.90832Z",
	"deleted_at": null,
	"sha1_hash": "202d3b0aab7a357097da120044bfafdaac1e6b6a",
	"title": "StealC Malware Analysis Part 3",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1568766,
	"plain_text": "StealC Malware Analysis Part 3\r\nArchived: 2026-04-05 15:51:46 UTC\r\n06 - Analysis of StealC (Stage 4)\r\nIn the first article of the series, we saw how to unpack the first stage pkr_ce1a manually and using an emulator\r\n(MIASM). In the second article we have extracted the C2 of the loader and unpacked the last stage using MIASM.\r\nNow let's take a look at the StealC malware and recover some IOCs.\r\nSample information\r\nBelow is the information concerning the last stage we are going to analyze:\r\nType Data\r\nSHA256 18f53dd06e6d9d5dfe1b60c4834a185a1cf73ba449c349b6b43c753753256f62\r\nSHA1 a952b1ed963346d5029a9acb3987d5e3a65c47a3\r\nMD5 8022ef84cfe9deb72b1c66cd17cac1cd\r\nFile size 153 088 bytes\r\nFirst\r\nseen\r\nN/A\r\nMIME\r\ntype\r\napplication/x-dosexec\r\nimphash 1ef0d6e4c3554a91026b47d9a27bf6db\r\nssdeep 3072:ivyLlG8KPgpJSG61doHN4NoQiUukOoy9bzyRy2GxhGJuU:ivyhJryZoIohvkOpt+M2GzAu\r\nAt the time of writing, the sample has not been made public on sample-sharing platforms such as VirusTotal.\r\nDetect the sample family\r\nFirst, we can look at the entropy of the file to see if it is packaged:\r\nhttps://blog.lexfo.fr/StealC_malware_analysis_part3.html\r\nPage 1 of 9\n\nDetect It Easy - Entropy of StealC sample (stage 4)\r\nThe latter is not packaged, as its entropy is not high.\r\nWe don't know which family of malware it is yet. A loader? A beacon? To find out, we can run a Yara scan. If you\r\ndon't have a Yara rules database, you can find some on GitHub repositories such as Yara-Rules (no longer\r\nmaintained), or on specialized platforms such as Malpedia.\r\nIf you run a scan on all Malpedia's Yara rules, you should come across a positively matching rule named\r\nwin_stealc_auto :\r\n$ yara -s win.stealc_auto.yar syncUpd_exe_miasm_unpacked.bin\r\nwin_stealc_auto syncUpd_exe_miasm_unpacked.bin\r\n0x135df:$sequence_0: FF 15 38 4F 62 00 85 C0 75 07 C6 85 E0 FE FF FF 43\r\n0xde4c:$sequence_1: 68 6F D7 41 00 E8 EA 82 00 00 E8 65 E7 FF FF 83 C4 74\r\n0xc760:$sequence_2: 50 E8 3A 9A 00 00 E8 D5 F2 FF FF 83 C4 74\r\n0xc81c:$sequence_2: 50 E8 DE 40 FF FF E8 D9 EC FF FF 83 C4 74\r\n0xc8ca:$sequence_2: 50 E8 70 98 00 00 E8 EB FC FF FF 83 C4 74\r\n0xaf51:$sequence_3: E8 4A B2 00 00 E8 D5 E4 FF FF 81 C4 80 00 00 00 E9 53 03 00 00\r\n0xb03c:$sequence_3: E8 5F B1 00 00 E8 EA E3 FF FF 81 C4 80 00 00 00 E9 68 02 00 00\r\n0xd558:$sequence_4: 50 E8 42 8C 00 00 E8 DD F3 FF FF 81 C4 84 00 00 00\r\n0xd5d4:$sequence_4: 50 E8 C6 8B 00 00 E8 61 F3 FF FF 81 C4 84 00 00 00\r\n0xd650:$sequence_4: 50 E8 4A 8B 00 00 E8 E5 F2 FF FF 81 C4 84 00 00 00\r\n0x124c7:$sequence_5: E8 44 25 FF FF 83 C4 60 E8 7C E2 FF FF 83 C4 0C\r\n0x10692:$sequence_6: E8 09 5B 00 00 E8 A4 4A FF FF 83 C4 18 6A 3C\r\n0x149d6:$sequence_7: FF 15 88 50 62 00 50 FF 15 20 50 62 00 8B 55 08 89 02\r\n0x149dc:$sequence_8: 50 FF 15 20 50 62 00 8B 55 08 89 02\r\nIt seems that the executable matches 9 out of 10 sequences, which is a very good score. We can therefore strongly\r\nassume that this is the final StealC malware. Malpedia has a dedicated page about it.\r\nOur aim is to recover C2 from the malicious program, and several methods can be used:\r\nSandbox\r\nEmulation\r\nStatic analysis\r\nIn this article, we will use the Static method.\r\nhttps://blog.lexfo.fr/StealC_malware_analysis_part3.html\r\nPage 2 of 9\n\nAutomate string decryption\r\nOpen the sample with your favorite disassembler. By wandering through the various functions, you should be able\r\nto identify methods calling sub_4043b0 which seems to take 3 parameters: a sequence of bytes, a string, then an\r\ninteger (which seems to correspond to the length of the string):\r\nBinary Ninja - Function with lot of call with strings arguments\r\nIf we unpack the sub_4043b0 function, we can see that the malware uses a military encryption algorithm ( xor ).\r\nWe can rename the function and its variables:\r\nhttps://blog.lexfo.fr/StealC_malware_analysis_part3.html\r\nPage 3 of 9\n\nFunction that XOR strings\r\nThe function we just renamed simple_crypto_xor is used by two other functions in the program:\r\nhttps://blog.lexfo.fr/StealC_malware_analysis_part3.html\r\nPage 4 of 9\n\nBinary Ninja - XREF of simple_crypto_xor\r\nWe can then rename the variables according to the bytes decoded with our disassembler's API. First, we'll try to\r\nrecover the address of the function that performs the XOR operations, based on the calls to the LocalAlloc and\r\nstrlen functions:\r\ndef get_most_called_function_sorted():\r\n funcs = bv.functions\r\n call_function_counter = {}\r\n for func in funcs:\r\n callers = func.callers\r\n #print(\"\\nFunction {} is called from {} known locations.\".format(func.name, len(callers)))\r\n call_function_counter[func] = len(callers)\r\n return sorted(((v, k) for k, v in call_function_counter.items()), reverse=True)\r\ndef get_xor_str_func():\r\n most_called_functions = get_most_called_function_sorted()\r\n for func in most_called_functions:\r\n if func[0] \u003c 260:\r\n # xor func must have more than 100 callers\r\n break\r\n if not func_has_call_func_by_name(func[1], \"LocalAlloc\"):\r\n continue\r\n if not func_has_call_func_by_name(func[1], \"strlen\"):\r\n continue\r\n return func[1]\r\n return None\r\ndef func_has_call_func_by_name(func, func_name: str):\r\n for inst in func.mlil.instructions:\r\n if not isinstance(inst, Localcall):\r\n continue\r\n if str(inst.dest) == func_name:\r\n return True\r\n return False\r\nOnce we have the address of our simple_crypto_xor function, we can try to identify the functions that call it,\r\nretrieve the arguments sent as parameters and then decode them. Once decoded, we can then rename the\r\ndestination variables to make them easier to read:\r\n[...]\r\nxored_str = None\r\ndef xorme(secret_string, key, key_len):\r\n final = \"\"\r\n for i in range(0, key_len):\r\nhttps://blog.lexfo.fr/StealC_malware_analysis_part3.html\r\nPage 5 of 9\n\nfinal = f\"{final}{chr(secret_string[i] ^ key[i])}\"\r\n return final\r\ndef visitor_xored_func(_a, inst, _c, _d) -\u003e bool:\r\n global xored_str\r\n if isinstance(inst, Localcall):\r\n ptr_secret_string = int(inst.params[0].value)\r\n key = inst.params[1].string[0].encode()\r\n key_len = int(inst.params[2].value)\r\n secret_string = bv.read(ptr_secret_string, key_len)\r\n xored_str = xorme(secret_string, key, key_len)\r\ndef main():\r\n global xored_str\r\n xor_func = get_xor_str_func()\r\n if not xor_func:\r\n print(\"Error: StealC xor func not found\")\r\n return\r\n print(f\"Xor function at @{xor_func.address_ranges}\")\r\n xor_func_callers = []\r\n callers = xor_func.callers\r\n for caller in callers:\r\n if caller in xor_func_callers:\r\n continue\r\n xor_func_callers.append(caller)\r\n for inst in caller.hlil.instructions:\r\n xored_str = None\r\n inst.visit(visitor_xored_func)\r\n if xored_str:\r\n try:\r\n dst = inst.dest.get_expr(0).get_int(0)\r\n var = bv.get_data_var_at(dst)\r\n print(f\"New string identified : {xored_str}\")\r\n xored_str_cleaned = xored_str.replace(\"/\", \"-\").replace(\"%\", \"\").replace(\":\", \"\").replace(\"\r\n var.name = f\"str_{xored_str_cleaned}\" #Rename variable\r\n except:\r\n pass\r\nmain()\r\nThis produces the following result:\r\nhttps://blog.lexfo.fr/StealC_malware_analysis_part3.html\r\nPage 6 of 9\n\nBinary Ninja - Script that decode xored strings and rename variables\r\nLists of decoded strings are available here.\r\nLooking at the decoded strings, we learn a lot more about our malware! Some notable features:\r\nIt seems to use the HTTP protocol to communicate\r\nAn IP address is decoded: 185[.]172.128.150\r\nA web page: c698e1bc8a2f5e6d.php\r\nA directory on the web server: /b7d0cfdb1d966bdd/\r\nPossibly anti-vm: VMwareVMware\r\nPossible recovery of identifiers in web browsers\r\nPossible login recovery in software such as Discord, Steam Pidgin, Outlook, Telegram, Tox...\r\nRecovery of elements of the system configuration of the machine running the program\r\nPotential recovery of cryptocurrency wallets\r\nFrom the strings alone, we can deduce that specific method will be loaded into memory and then called. We won't\r\nbe performing a Stealer (StealC) analysis.\r\nStatic sample analysis\r\nYou can continue the analysis by tracing function calls back to the decoded strings. For example, our\r\nstr_CreateToolhelp32Snapshot variable appears to be loaded into memory:\r\nhttps://blog.lexfo.fr/StealC_malware_analysis_part3.html\r\nPage 7 of 9\n\nFunction that use GetProcAddress on de-xored string\r\nWe rename the variable to handle_CreateToolhelp32Snapshot , we look for cross references to this handle and\r\nwe can see its call later in the program:\r\nUsage of methods after renaming them\r\nNow that you've got all the marbles, you should be able to automate the renaming of the various functions loaded\r\nin memory, and study the part of the malware you're interested in. Our bndb file is available here.\r\nYou'll find here the code used to retrieve the complete C2 used by the StealC malware we've just studied.\r\n07 - Conclusion\r\nIn this series of articles (part1, part2, part3), we have outlined various techniques for analyzing a malware sample\r\nactive in 2024. We hope that this article has permit you to understand some of the methods used to:\r\nidentify some packers\r\nunpack in manual and automated ways\r\nwrite detection rules (Yara)\r\nextract the interesting parts, such as C2, to help you protect your company and those around you.\r\nYou have handled a disassembler and a debugger for Stage 1 unpacking. You also got an overview of the MIASM\r\nframework and the possibilities offered by its jitter sandbox. You have seen some methods used by malicious\r\nactors to make analysis more difficult, using anti-emulation techniques. We've also seen how to automate most of\r\nour actions, such as extracting and decrypting shellcode from program resources. You've also had a taste of how to\r\nautomate tedious tasks such as renaming encrypted variables in your favorite disassembler.\r\nYou should be able to set out on your own in search of new samples to analyze, and have the perseverance to\r\novercome the technical problems you'll encounter, given a few liters of coffee and time.\r\nThanks to zbetcheckin for sharing the initial sample with the community. Thanks also to the MIASM contributors\r\nwho produced a very practical and functional tool in our case. Thanks to the Binary Ninja developers and\r\ncommunity for the various exchanges we were able to have. Thanks to the malware researchers who share their\r\nresearch on threats targeting cyberspace.\r\nWe hope this series of articles has motivated you to continue analyzing malicious code! Please don't hesitate to\r\ncontact us if you'd like us to clarify any aspect of the articles, or if you have any questions we'd be happy to\r\nanswer. We can also support you in malware analysis, or train you in this area.\r\nhttps://blog.lexfo.fr/StealC_malware_analysis_part3.html\r\nPage 8 of 9\n\nWe will shortly be publishing an article dedicated to the packer pkr_ce1a aka AceCryptor which protects\r\nmalicious binaries like StealC seen in these articles. Stay tuned !\r\nSource: https://blog.lexfo.fr/StealC_malware_analysis_part3.html\r\nhttps://blog.lexfo.fr/StealC_malware_analysis_part3.html\r\nPage 9 of 9",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://blog.lexfo.fr/StealC_malware_analysis_part3.html"
	],
	"report_names": [
		"StealC_malware_analysis_part3.html"
	],
	"threat_actors": [],
	"ts_created_at": 1775434204,
	"ts_updated_at": 1775791233,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/202d3b0aab7a357097da120044bfafdaac1e6b6a.pdf",
		"text": "https://archive.orkl.eu/202d3b0aab7a357097da120044bfafdaac1e6b6a.txt",
		"img": "https://archive.orkl.eu/202d3b0aab7a357097da120044bfafdaac1e6b6a.jpg"
	}
}