{
	"id": "4a496732-09de-4443-b3f2-a7e0fde3afa8",
	"created_at": "2026-04-06T00:16:46.857734Z",
	"updated_at": "2026-04-10T13:12:20.867015Z",
	"deleted_at": null,
	"sha1_hash": "60c0f9e1f9c9a38a1df1c5fc07d6df8f2d746c0c",
	"title": "Unpacking RedLine Stealer",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 134983,
	"plain_text": "Unpacking RedLine Stealer\r\nPublished: 2023-01-04 · Archived: 2026-04-05 16:43:07 UTC\r\nIn this post, we are going to take a look at Redline Stealer, a well-known .NET based credential stealer. I will\r\nfocus on unpacking the managed payload and extracting it’s config, for a more detailed analysis of the payload\r\nyou can check out this post by c3rb3ru5d3d53c.\r\nDealing with the native dropper\r\nMany of the in-the-wild samples of Redline are plain .NET applications with pretty basic custom obfuscation.\r\nConsidering that many commonly used obfuscators lead to false positive AV detections this is very likely\r\nintentional. Although primarily using .NET, many samples come packed in a native x86 wrapper that will load the\r\nmanaged payload at runtime. Unpacking this native dropper is quite simple, it uses process hollowing on a\r\nlegitimate process. We can use this to our advantage; since the injection requires the process to be started in\r\nsuspended mode we can simply use a debugger to pause the execution before the process is unsuspended and\r\ndump it. The injection target might vary between versions. In my case, they inject into AppLaunch.exe which is a\r\nutility binary of .NET Framework 4.0+, that is part of the standard Windows 10 install.\r\nThe dropper dynamically resolves the functions required for process hollowing. So we will not find them in the\r\nimports but there are some artifacts from gcc’s error handling which give a hint as to which functions are used.\r\nStrings like “VirtualProtect failed…” make it easy to guess what is going on even if the actual functions are\r\ndynamically resolved. The following functions are used:\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\nCreateProcessW\r\nReadProcessMemory\r\nVirtualProtect\r\nNtWriteVirtualMemory\r\nNtSetContextThread\r\nNtResumeThread\r\nNtUnmapViewOfSection\r\nIt then performs simple process hollowing. Which we can simply dump. For this, I use x32Dbg, and set a\r\nbreakpoint on NtResumeThread then continue execuction. Once the breakpoint hits I dump the AppLaunch.exe\r\nhttps://dr4k0nia.github.io/posts/Unpacking-RedLine-Stealer/\r\nPage 1 of 5\n\nprocess, that was spawned by the dropper, using ExtremeDumper to get a perfectly working managed image from\r\nthe process. Make sure to run ExtremeDumper as Admin to find the AppLaunch process. Once we have the\r\ndumped image we can simply terminate AppLaunch.exe and our debuggee.\r\nDealing with the managed part\r\nMost of Redline’s obfuscation is focused on the strings. Not all strings are obfuscated but most of the\r\ncharacteristic ones are, especially strings that can be used to detect the malware. These obfuscated strings are\r\nconstructed at runtime from a char array and in some cases, they have random text inserted that will be removed\r\nfrom the string before it’s used.\r\nSince this was quite annoying to get rid of manually for the whole binary I decided to write a custom tool. The\r\ntool is pretty simple, it consists of two clean-up stages. The first one is to remove the array to string assignments\r\nAnd the second one is to clean the inserted text and replace operations. I also added a stage for config extraction\r\nwhich will be discussed later. As per usual I came up with a fun name for this tool: It’s called Greenline.\r\nDeobfuscating the strings\r\nWe begin by searching for all string constructors that take a char array as it’s parameter and are preceded by a call\r\ninstruction. The constructor is called using a newobj instruction, with the constructor as it’s operand. The\r\nconstructor requires a char array to be pushed on the stack before its executed. Lets look at what the code we are\r\ndealing with looks in CIL:\r\nIL_0000: nop\r\nIL_0001: ldc.i4.5\r\nIL_0002: newarr System.Char\r\nIL_0007: dup\r\nIL_0008: ldtoken \u003cPrivateImplementationDetails\u003e::DC0F42A41F058686A364AF5B6BD49175C5B2CF3C4D5AE95417448BE3517B400\r\nIL_000d: call System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(System.Array, System.RuntimeFieldH\r\nIL_0012: newobj System.String::.ctor(char[])\r\nThe first thing that happens is the array initialization. At IL_0001 the size of the array is pushed on to the stack\r\nas an integer, next a new array of type char is initialized. For the next part I need to explain how arrays in .NET\r\nhttps://dr4k0nia.github.io/posts/Unpacking-RedLine-Stealer/\r\nPage 2 of 5\n\nare actually stored.\r\nFor value type arrays like char, byte etc. that are initialized inline and have more then three elements the compiler\r\nwill generate a ![](new type named \u003cPrivateImplementationDetails\u003e . The type contains fields that point to\r\nchunks of bytes within a data section of the PE. These fields are of a struct type with a hardcoded size, telling the\r\nruntime the size of the chunk. At runtime, the\r\nSystem.Runtime.CompilerServices.RuntimeHelpers::InitializeArray method is called to perform a memory\r\ncopy of the data referenced by the field into the array’s memory location.\r\nAfter the array has been initialized it is consumed by the System.String constructor at IL_0012 . Since this CIL\r\npattern can in some cases be different or deliberately altered by an obfuscator I decided to use Echo1, a framework\r\nwith data flow analysis capabilities for CIL. With Echo we can reliably resolve the dependencies of the call to\r\nInitializeArray .\r\nIn this snippet we can see that the string constructor call is preceded by a call to InitializeArray . This call\r\ndepends on a couple more instructions. First an array object, which is made up of the instructions from 0020 to\r\n0022 the size of the array which is 19 then the type of the array object char. The dup copies the top most stack\r\nitem which is the array object and pushes it on top of the stack again, which is later used by the string constructor.\r\nNext ldtoken pushes the handle to the field in \u003cPrivateImplementationDetails\u003e onto the stack. So now we\r\nhave everything our call depends on. Echo can find these kind of dependeny relations automatically, using a\r\nsymbolic flow graph to obtain all instructions that are required by a consumer like the call in the example.\r\nUsing the obtained dependencies we can manually construct the string and patch the old CIL with just a string\r\nassignment, replacing all no longer needed instructions with NOP’s.\r\nThe second stage follows the same logic, but this time we search for all calls to the Replace method using two\r\nstring literals as arguments. We use Echo to obtain the dependencies and patch all no longer needed instructions\r\nwith NOP’s leaving us with the final deobfuscated string.\r\nThis part is probably the most interesting for the more threat intel focussed readers :D. Identifying the config of\r\nRedline is pretty simple when we have easy access to the managed types and their members. I use an exclusion-based search, iterating through the types we abort processing for all types that don’t match our criteria. A few\r\nidentifiers that I use to find the correct class:\r\nhttps://dr4k0nia.github.io/posts/Unpacking-RedLine-Stealer/\r\nPage 3 of 5\n\nIs a public static class\r\nHas a static constructor and 5 fields (the constructor is hidden in the C# view, it initializes the fields with\r\nthe values seen in the decompilation)\r\nHas the custom attribute System.Reflection.ObfuscationAttribute\r\n(Has a field named IP)\r\nAfter we find the correct class we obtain all field values by parsing the static constructor of the class, which\r\ninitializes the fields. The C2 IP and the ID are XOR encrypted and Base64 encoded so we need to decrypt and\r\ndecode them for that, I simply copied and simplified the decryption routine from Redline. After we decrypted the\r\nencrypted fields we have a fully readable config.\r\nConclusion\r\nI hope you found this little post helpful and can put it to use analyzing Redline Stealer. The tool described in this\r\npost and it’s source code are available on my GitHub, feel free to check it out. If you’re interested in .NET\r\nhttps://dr4k0nia.github.io/posts/Unpacking-RedLine-Stealer/\r\nPage 4 of 5\n\ndeobfuscation in general make sure to check out the code as it’s basic approach can be adapted for other\r\nobfuscation of this kind as well.\r\nSamples\r\nx86 compiled binary: modest-menu.exe,\r\nSHA256:0d753431639b3d2b8ecb5fb1684018b2c216fec10cc43d0609123f6f48aa98b8\r\nUnpacked child =\u003e .NET binary: Bahut.exe SHA256:\r\n98d146faabd764f5ddd4a2088dfaf075dd382358026498344c91dcb46a7dff66\r\n.NET binary: file,\r\nSHA256:714AE901F55DB2580AC4AC9048C09EFDCD562F301640A6FD8343293F1EBB36FF\r\n.NET binary: PEInjection.exe,\r\nSHA256:465FBA168502ED66E373DB521F1C0DD93CE30E69D271528051390817977B4818\r\nSource: https://dr4k0nia.github.io/posts/Unpacking-RedLine-Stealer/\r\nhttps://dr4k0nia.github.io/posts/Unpacking-RedLine-Stealer/\r\nPage 5 of 5",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://dr4k0nia.github.io/posts/Unpacking-RedLine-Stealer/"
	],
	"report_names": [
		"Unpacking-RedLine-Stealer"
	],
	"threat_actors": [
		{
			"id": "d90307b6-14a9-4d0b-9156-89e453d6eb13",
			"created_at": "2022-10-25T16:07:23.773944Z",
			"updated_at": "2026-04-10T02:00:04.746188Z",
			"deleted_at": null,
			"main_name": "Lead",
			"aliases": [
				"Casper",
				"TG-3279"
			],
			"source_name": "ETDA:Lead",
			"tools": [
				"Agentemis",
				"BleDoor",
				"Cobalt Strike",
				"CobaltStrike",
				"RbDoor",
				"RibDoor",
				"Winnti",
				"cobeacon"
			],
			"source_id": "ETDA",
			"reports": null
		}
	],
	"ts_created_at": 1775434606,
	"ts_updated_at": 1775826740,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/60c0f9e1f9c9a38a1df1c5fc07d6df8f2d746c0c.pdf",
		"text": "https://archive.orkl.eu/60c0f9e1f9c9a38a1df1c5fc07d6df8f2d746c0c.txt",
		"img": "https://archive.orkl.eu/60c0f9e1f9c9a38a1df1c5fc07d6df8f2d746c0c.jpg"
	}
}