{
	"id": "a83027a4-f687-49d3-84af-209fc339540d",
	"created_at": "2026-04-06T00:20:08.127578Z",
	"updated_at": "2026-04-10T13:12:05.246037Z",
	"deleted_at": null,
	"sha1_hash": "d52c74992402c3a2f159f7de3077b0d85b3eebe9",
	"title": "Unveiling custom packers: A comprehensive guide",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1258820,
	"plain_text": "Unveiling custom packers: A comprehensive guide\r\nBy Otavio M.\r\nPublished: 2024-02-12 · Archived: 2026-04-05 15:30:22 UTC\r\nIn this article, you’ll be diving into an introduction to how packers work, some tips to unpack, and two\r\nwalkthroughs showing off how i usually deal with custom packers.\r\nHow do packers work?\r\nPackers generally have three types: Compressors, Crypters and Protectors. A Compressor, as its name says,\r\ncompress the size of the desired file, or in other words, it squeezes a file into their own unpacker process. A\r\nCrypter encrypts the payload, executes it in memory at runtime (with an option to drop the final payload on disk),\r\nand aims to evade detection from AV/EDR software, without the need of compressing the file. Protector perform\r\nboth packing and encryption of their payload. Additionally, they employ various anti-debugging and anti-reversing\r\ntechniques to make the entire unpacking process challenging for reverse engineers.\r\nThe main part of a packer is its stub, which is responsible for the unpacking routine. So, when a file is inputed, it\r\nbasically generates a stub with the payload inside it.\r\nInternally in the stub, there are 3 main forms of storing the encrypted payload:\r\nOn the file’s overlay\r\nOn the file’s last section\r\nhttps://estr3llas.github.io/unveiling-custom-packers-a-comprehensive-guide/\r\nPage 1 of 22\n\nOn a large encoded string, which is decoded and decrypted in runtime\r\nA way to identify the section which contains the packed file is looking for its size. If the raw size is\r\nsmall or set to zero, and the virtual size is large enough to store a PE or shellcode, it may likely be our\r\ntarget.\r\nIn a Crypter, the packer’s stub procedure is responsible for decrypting the payload, then running it in one of two\r\nregions: inside their own process, or in a remote process.\r\nRunning inside their own process is done, in simple terms, by allocating memory, writing data to the allocated\r\nmemory, adjusting its protection and setting the EIP register to point to that specific location. Also, some custom\r\npackers will replace their on .text section with the packed payload.\r\nThe address where the packed payload starts executing is also known as OEP, Original Entry Point.\r\nWhen the execution is within the address space of another process, it typically relies on some form of injection\r\ntechnique, like process hollowing. Commonly creating a child process (which may appear legitimate in some\r\ninstances) and running the payload on it.\r\nBut how does the stub figure out where the payload begins and ends?\r\nThe payload typically includes some kind of marker (distinction bytes), which identifies the payload’s starting and\r\nending bytes. Recognizing this, we can make those markers an signature for the packer.\r\nMoreover, the presence of polymorphic packers is notable, as they tend to generate entirely new stubs\r\neven for the same input. This dynamic behavior enhances evasion capabilities, making it challenging\r\nfor signature-based detection methods to identify and combat the packed payloads.\r\nHowever, given the scope of this article, I won’t delve into this type of packer.\r\nIdentifying packing\r\nPacking identification is not a exact science, instead, it consists of verifying a number of strikes, which lead us to\r\nassume that the file is packed. The main strikes are:\r\nEntropy (7.0+)\r\nNon-standard section names\r\nExecutable sections that are not .text/.code\r\nLack of imports\r\nLack of functionality-specific imports (A windows ransomware who doesn’t import any WinCrypt API is\r\nlikely packed for example).\r\nSections with the raw size zeroed, but a large virtual size.\r\nMissing network-related APIs\r\nPresence of an overlay\r\nLarge .rsrc section (Combined with a call to LoadResource)\r\nThe code itselfs, when opening into a disassembler, looks weird.\r\nhttps://estr3llas.github.io/unveiling-custom-packers-a-comprehensive-guide/\r\nPage 2 of 22\n\nThese are just a few strikes i use myself, obviously there are plenty more out there.\r\nUnpacking techniques\r\nAs well as identifying it, unpacking isn’t a exact science, the approach we take can vary according to the packer\r\nwe are dealing to.\r\nI usually stick with three main approaches: breakpoints on specific APIs, break on module loading or automated\r\nunpacking.\r\nAlso, the malware could have several unpacking stages, so never assume a sample is unpacked until\r\nanalyzing it further.\r\nBreakpoints on specific APIs\r\nThese are done by placing breakpoint on memory-related APIs. Examining their params and return values will\r\neventually bring us to interesting memory regions.\r\nThe APIs are usually:\r\nCreateProcessInternalW( )\r\nVirtualAlloc()\r\nVirtualAllocEx()\r\nVirtualProtect() / ZwProtectVirtualMemory()\r\nWriteProcessMemory() / NtWriteProcessMemory()\r\nResumeThread() / NtResumeThread()\r\nCryptDecrypt() / RtlDecompressBuffer()\r\nNtCreateSection() + MapViewOfSection() / ZwMapViewOfSection()\r\nUnmapViewOfSection() / ZwUnmapViewOfSection()\r\nNtWriteVirtualMemory()\r\nNtReadVirtualMemory()\r\nCreateProcessInternalW\r\nMy main targets here is VirtualAlloc, VirtualProtect, CreateProcessInternalW and ResumeThread. On\r\nVirtualAlloc, we put a breakpoint on its exit point, more precisely on the “ret 10” instruction, then following eax\r\non dump. On VirtualProtect, we check what address is into ecx, following it on memory dump. On the latter ones,\r\nwe follow the address where its marked to start the new process/thread, and dump it.\r\nAlso, it is a good practice to put breakpoints on known anti-debug APIs, so we can bypass them to\r\ncontinue our unpacking.\r\nBreak on module loading\r\nThis method is quite straight-forward: halt the debugger for every loaded DLL, examine the binary’s memory\r\nmap, and look for both RWX and RW segments, as packers commonly load modules into RW segments and later\r\nmodify permissions to RWX.\r\nhttps://estr3llas.github.io/unveiling-custom-packers-a-comprehensive-guide/\r\nPage 3 of 22\n\nWe can even use volatility for this purpose. Run the malware and take a system image. Within vol.py,\r\nuse memory.vmem procdump to search for interesting segments and memory.vmem impscan to fix the\r\nIAT.\r\nAutomated unpacking\r\nThis approach consists by using some tool to extract the packed payload. it is a core decision when dealing with\r\ndeadlines.\r\nSome of them are:\r\nUnpacMe: https://www.unpac.me/\r\npe-sieve: https://github.com/hasherezade/pe-sieve\r\nhollows-hunter: https://github.com/hasherezade/hollows_hunter\r\nShinigami: https://github.com/buzzer-re/Shinigami\r\nDon’t forget that these tools usually run the malware to unpack it, so use it on a isolated environment.\r\nHowever, when none of these methods works properly, it becomes crucial to delve into the intricacies of the\r\npacker’s procedure.\r\nTherefore, this article is committed to unveiling the inner workings of a custom packer. Our objective is to\r\nunderstand its procedures and extract the final payload.\r\nCustom Packers\r\nMost malwares makes use of known packers, like UPX, so it is quite trivial to unpack its payload. Although, in\r\nsome cases, the malware authors use their own packers, which is quite difficult to reverse engineer at glance, yet\r\nthere are some approaches which make this process easy for us.\r\nFirst, the main purpose of the packer is to unpack something. Therefore, it can be understood that a considerable\r\npart of the code we come across involves complex arithmetic, primarily aiding the unpacking procedure to\r\nuncover the payload. Being aware of this, we end up not really interested in those arithmetic’s.\r\nSecond, there will be frequent indirect calls, like: a call to a register/stack variables, a push and then a ret\r\ninstruction, jump to registers/stack variables. Understanding that, it is easier to track the packer’s control-flow and\r\ngetting into the final payload.\r\nThird and last, we will be using static and dynamic analysis, so we can resolve those indirect calls and follow\r\nalong with the static disassembler.\r\nMany custom packers will try, in some manner, to deflect the analyst’s attention, so keep in mind that\r\nthe unpacking code is one-way, meaning that it has no intention to return back from where it is called.\r\nSample #1\r\nsha256:5617238b8d3b232f0743258b89720bb04d941278253e841ee9cbf863d0985c32\r\nhttps://estr3llas.github.io/unveiling-custom-packers-a-comprehensive-guide/\r\nPage 4 of 22\n\nThe sample is a Simda Trojan, which is described by Microsoft as: “a multi-component trojan that downloads and\r\nexecutes arbitrary files. These files may include additional malware.”\r\nSimda is also known for using customized packers, which can be pretty evasive and mislead our static analysis.\r\nThe sample is a 32-bit executable compiled with Microsoft MSVC within Visual Studio 2008:\r\nWe can confirm it is packed by:\r\nMisleading strings\r\nNon-standard section names\r\nLack of imports\r\nLack of networking APIs\r\nNow we have two approaches to this sample, the naive and the savvy.\r\nhttps://estr3llas.github.io/unveiling-custom-packers-a-comprehensive-guide/\r\nPage 5 of 22\n\nNaive approach\r\nThe naive approach is using a debugger. Although it can be quicker, I call this a “naive” approach because we\r\ndon’t quite understand how is the unpacking procedure, so in a detection engineering context, it could not be the\r\nbest approach.\r\nThis approach consists of putting breakpoint on memory-related APIs and looking for interesting memory dumps.\r\nI’ll be using x64dbg for this purpose.\r\nAfter reaching the entrypoint breakpoint, start placing our API breakpoints. Go to VirtualAlloc (Ctrl + G) and\r\nplace a breakpoint on its exit point (ret 10).\r\nAfter it, place breakpoints on: VirtualProtect, CreateProcessInternalW, CreateThread, ResumeThread,\r\nIsDebuggerPresent and FindWindowA (bp [API_name]).\r\nResume its execution (F9) and VirtualAlloc will be hit, follow EAX on dump 1. After it, VirtualProtect will be hit\r\nseveral times (21 times!)\r\nHowever, as the reader might have noticed, most of the VirtualProtect calls are targeting the address\r\nrange of ~0x0400000, which can possibly be a .text replacement\r\nNone of them is relevant for us in this approach, just look at dump 1 after the first call to VirtualProtect and the\r\nreader will see our unpacked PE.\r\nBut remember, do not assume the first extraction is the final payload, packers can have several stages.\r\nTo confirm it is the final payload, open it on DiE, there are plenty of indicators:\r\nhttps://estr3llas.github.io/unveiling-custom-packers-a-comprehensive-guide/\r\nPage 6 of 22\n\nEncrypted strings\r\nanti-analysis-related strings\r\nRegister keys paths\r\nStandard section names\r\nlow entropy\r\nAnd obviously, open it on your favorite disassembler to assure yourself.\r\nThe reader may have noticed that we do not understood nothing of what was going on the unpacking phase. That’s\r\nwhy even though this approach is quicker, when it fails, you need to have a backup, which is deep diving into the\r\npacker’s code!\r\nSavvy approach\r\nThis approach consists of diving into the packer’s code and understanding the core details of it. I call it a “savvy”\r\napproach because we really get to know what’s going on, so it will be easier to write detections based on its\r\nbehavior.\r\nInitially, it’s crucial to keep two key points in mind when examining packers. First, most of the code we’ll see, is\r\nrelated to the unpacking procedure and complex arithmetic, so it isn’t really needed to fully reverse it. Second,\r\nindirect calls are expected, often guiding us towards the unpacked code.\r\nOpening it on Binary Ninja, we can see a lot of functions (3294 to be more precise), but most of them aren’t never\r\nreally called, hence we can make a quick script using the Binary Ninja API to show which of them are actually\r\ncalled anytime on the program’s lifetime:\r\nTo activate the python console, press the backtick key ( ` )\r\nhttps://estr3llas.github.io/unveiling-custom-packers-a-comprehensive-guide/\r\nPage 7 of 22\n\nfor func in bv.functions:\r\nnum_of_callers = len(func.callers)\r\nif num_of_callers \u003e 1:\r\nprint(func.return_type, func.name, func.calling_convention, func.start, num_of_callers)\r\nwhich returns:\r\nAfter that, for the sake of our analysis, we can tag all the other which aren’t called anytime in the program’s\r\nlifetime, so we don’t spend time reversing it.\r\nfor func in bv.functions:\r\nnum_of_callers = len(func.callers)\r\nif num_of_callers \u003c 1:\r\nfunc.add_tag(\"Crashes\", \"This function is never called\", here)\r\nfunc.set_comment_at(here, \"Unused\")\r\nEnding up with 3238 functions who are never called.\r\nhttps://estr3llas.github.io/unveiling-custom-packers-a-comprehensive-guide/\r\nPage 8 of 22\n\nNow, we can start our reverse engineering.\r\nAt program’s entrypoint, scroll all the way down to the function’s end addresses, the reader will see a common\r\nobfuscation technique, which pushes an address to the stack, and immediately returns, leading EIP to be set at that\r\naddress.\r\nFollowing sub_40139a, we will again encounter that type of obfuscation, which eventually will lead us to the\r\naddress 004013a6.\r\nhttps://estr3llas.github.io/unveiling-custom-packers-a-comprehensive-guide/\r\nPage 9 of 22\n\nThis sub does not do anything relevant to us. There are many calls to sub_401100, which is junk code. On the\r\nfunction’s epilogue, the reader will notice that eax register is being pushed onto the stack, then, the function\r\nreturns. This follows the same technique we saw before.\r\nWe can spot the address 0x401130 being loaded into eax. Following that address, sub_401130 comes into place:\r\nhttps://estr3llas.github.io/unveiling-custom-packers-a-comprehensive-guide/\r\nPage 10 of 22\n\nAs we saw before, ecx is being pushed onto stack, then the function returns. If we go back a few instructions,\r\ndata_4ca094 is being loaded into ecx. Looking inside data_4ca094, it is empty, so we can assume that something\r\nis loaded inside it in runtime.\r\nHow do we discover what is loaded at this location? Simple, we put a breakpoint on this address, and check it out!\r\nYet, hold on, before getting our hands into a debugger, lets wrap up what’s happening until now.\r\nCome back to the binary’s entrypoint. The reader will notice that the function which loads the content from\r\ndata_4ca094 inside ecx (sub_401130) is called plenty of times. Knowing that, we can assume that each block of\r\ncode tries to setup data_4ca094, then, if it is succesfully set up, sub_401130 is called.\r\nIf the reader looks closely, a call to LoadCursorA is made, which loads or retrieves a handle to a cursor.\r\nThe point is, a cursor can also be a bitmap, so the payload is possibly stored on a bitmap format.\r\nOpen the binary in x64dbg and put a breakpoint in push ecx (00401164):\r\nhttps://estr3llas.github.io/unveiling-custom-packers-a-comprehensive-guide/\r\nPage 11 of 22\n\nOnce stopping, check what’s inside ecx. The address 006e6ed0 (might be different for you) is loaded onto ecx, so\r\nthe next stage is at that address.\r\nLooking for this address in our disassemble, we soon notice that it doesn’t exists. This means that what’s on this\r\naddress is being loaded in runtime (as we stated before), more lilkely to be a shellcode.\r\nThe next step here is dumping the memory segment which the address within ecx is at, and opening it on a new\r\ndisassemble session.\r\nFollowing ecx on Memory Map, right click and press “Dump Memory to File”. Don’t forget to keep the segment’s\r\nbase address on the saved dump name, it might be useful in the future.\r\nNotice that this memory range is marked as ERW, which is a good indicator of the unpacked code, but\r\nnot absolute.\r\nOpening the shellcode on Binary Ninja, try to go (g) to the address that was loaded into ecx, it does not exist!\r\nThis happens because, on the debugger, we are dealing with virtual addresses, and on Binary Ninja, raw addresses.\r\nTo overcome this situation, we need to calculate what is the offset of the address within ecx, so we can follow\r\nalong with our disassembler. The calculation is simple:\r\nRVA - VA = offset\r\nSo, 006e6ed0 - 00660000 = 00086ed0.\r\nGoing to this offset (g), we will soon again encounter the same obfuscation technique, with push \u0026 ret\r\ninstructions.\r\nTo follow along, put a breakpoint on push rdx instruction.\r\nRemember, on the disassembler we are dealing with raw offsets, so we need to convert it into virtual addresses:\r\n00086fc3 + 660000 = 6e6cf3\r\nhttps://estr3llas.github.io/unveiling-custom-packers-a-comprehensive-guide/\r\nPage 12 of 22\n\nRun (F9), and we can see that the address 0042037 is loaded into edx. The address 0042037 is on the binary’s .text\r\nsection, this can lead us to believe that it is being replaced in runtime (as we were suspicious before).\r\nIn that particular case, dump the whole binary from memory again. Although, we’ll see that it does not apply to\r\nevery .text replacement, sometimes it is just a shellcode, so the reader need to dump only the address range of the\r\n.text itself.\r\nAlso, i had a better result dumping it from Process Hacker instead of x64dbg. The process is simple:\r\nRight click on the malware’s process, go to Properties, Memory tab, Open the address at 0x400000, Right click on\r\n0x400000, press Save…\r\nTo confirm it, open both unpacked samples (the naive one and the savvy one) on your disassembly, and compare\r\nthe results, you will see that they are equal.\r\nhttps://estr3llas.github.io/unveiling-custom-packers-a-comprehensive-guide/\r\nPage 13 of 22\n\nSample #2\r\nsha256:034e193f88a93ebb4ac8ca8da5b3b1429600ef04e5c124457ce0bc1830bae558\r\nThis is a Dridex sample, which is stated by malpedia as: “an evasive, information-stealing malware variant; its\r\ngoal is to acquire as many credentials as possible and return them via an encrypted tunnel to a Command-and-Control (C\u0026C) server.”\r\nDridex is also known for its sophisticated TTPs, which includes the unpacking process we are dealing today.\r\nThe binary is a 32-bit executable.\r\nhttps://estr3llas.github.io/unveiling-custom-packers-a-comprehensive-guide/\r\nPage 14 of 22\n\nTo assure it is packed, let’s list some of the strikes:\r\nOnly 3 imported DLLs (msvcrt.dll, pdh,dll, KERNEL32.dll).\r\nLacks of network APIs.\r\nNon-standard section names (y2A, .3cBjO, CONST).\r\nDoes not have any meaningful string.\r\nEntropy of 6.9\r\nAlso, looking at it on Binary Ninja:\r\nhttps://estr3llas.github.io/unveiling-custom-packers-a-comprehensive-guide/\r\nPage 15 of 22\n\nAnd due to the author’s sanity, we will be doing the navvy approach only.\r\nNavvy approach\r\nI won’t be delaying any more practical time, at this point the reader should have all the necessary knowledge to\r\nfollow along.\r\nAs we open the PE on Binary Ninja, we soon notice the same obfuscation technique used by the previous sample:\r\nFollowing eax (sub_40c2e0), we can see that it does significant stuff. It loads version.dll, gets a handle to\r\nkernel32.dll and calls other subroutines:\r\nsub_40b870 - walks kernel32.dll and stores it onto a Atom\r\nsub_40b4c0 - manipulates the previous atom\r\nIn its epilogue, it makes a call to data_411bf4, which is populated at runtime. If the reader check the code\r\nreferences to that data location, it will encounter the eax register being moved into it. Place a breakpoint on that\r\nhttps://estr3llas.github.io/unveiling-custom-packers-a-comprehensive-guide/\r\nPage 16 of 22\n\ninstruction.\r\nHitting that address, step over and then follow that location on memory dump. The reader will soon notice, by its\r\nbytes, that it is code-related.\r\nSequence of 5x… - pushes or pops\r\nC7[84/44]24 - mov value to stack\r\nTo confirm it, place a breakpoint on the call to data_411bf4. The reader will see that what’s being called is the\r\nsame content as we’ve saw before.\r\nAnother interesting point is the ud2 instruction.\r\nThis instruction means that the disassembler wasn’t able to disassemble the instructions after it, meaning that the\r\ncode doesn’t aim to return after this call. This is also a good indicator of we being on the right track to unpack it.\r\nFollowing the call, we will get into the address 0x0040afe0, which exists in our disassemble and looks like this:\r\nhttps://estr3llas.github.io/unveiling-custom-packers-a-comprehensive-guide/\r\nPage 17 of 22\n\nNow it gets trickier, if the reader go straight to the end of this subroutine, it won’t encounter any indirect call or\r\nany clue that leads us to the next stage of the unpacking procedure.\r\nI encourage the reader to look deep into this function and finding the next stage by its own before\r\ncontinuing.\r\nThis subroutine makes only 3 calls, which 2 of them are useless to us. So, the only option is the call to\r\nsub_409820.\r\nFollowing sub_409820, we can see a complex subroutine that make a lot of calls. On this situation, don’t get away\r\nfrom your focus, trying to understand what each subroutine does will only takes to a infinite rabbit hole. My\r\nstrategy here was searching for indirect calls on those subroutines. I’ve came up with two interesting ones:\r\nAgain, try it yourself before continuing.\r\nAt 0x004099d1 there is a call to a stack variable. If we put a breakpoint there, we will soon see a call to\r\nVirtualAlloc. Step over and follow eax on dump 1. After that call, it makes a call to sub_406e40, which, at\r\nhttps://estr3llas.github.io/unveiling-custom-packers-a-comprehensive-guide/\r\nPage 18 of 22\n\n00406f97, makes another call to eax. Placing a breakpoint on that address will reveal us another call to\r\nVirtualAlloc. Again, step over and follow eax on dump 2.\r\nThis is a very manual process, the reader will need to deep dive on those routines and really pay\r\nattention to get anything valuable from them.\r\nFinally, at 00409d90, there is a call to another stack value. Placing a breakpoint on it and stepping into will reveal\r\na PE file on dump 2. Dump it, but soon you will notice that it isn’t our unpacked binary. That call (at 00409d90) is\r\nmade to the previous allocated memory (dump 1). Knowing that, dump the content from dump 1 and open in your\r\ndisassembler.\r\nAs it starts the execution at the base address which was allocated (00520000 in my case), we can assume that\r\nsub_0 in the disassembler is our entrypoint.\r\nThis shellcode is huge. There are plenty of indirect calls which the reader can find them by itself as an exercise.\r\nhttps://estr3llas.github.io/unveiling-custom-packers-a-comprehensive-guide/\r\nPage 19 of 22\n\nGoing by the principle that most of it is related to the unpacking code, at the end of this subroutine there is a jump\r\nto rax. Calculate the offset and place a breakpoint on it. Hitting that address, you will see the address 0x00401a40.\r\nAs the reader must have noticed, it is the address of our original .text, meaning that our unpacking procedure is a\r\n.text replacement!\r\nDump the .text segment from memory, open it on your disassembler, and you successfully unpacked the binary!\r\nhttps://estr3llas.github.io/unveiling-custom-packers-a-comprehensive-guide/\r\nPage 20 of 22\n\nIn this particular case, dumping only the .text from memory was better than dumping the whole PE. It\r\nmay vary for the reader.\r\nTo get to the shellcode’s entrypoint, remember that it is set by its caller, so the offset a40 is our entrypoint:\r\nThat whole process summed up to the following:\r\nstart:\r\n0040c412 lea eax, [sub_40c2e0]\r\n0040c41e push eax\r\n0040c425 ret\r\n \r\n0040c2e0 sub_40c2e0:\r\n0040c3d8 call sub_40b4c0\r\n0040b4c0 sub_40b4c0:\r\n0040b658 mov dword [data_411bf4], eax ([data_411bf4] = sub_40afe0)\r\n0040c3f4 call [data_411bf4] = (sub_40afe0)\r\n \r\n0040afe0 sub_40afe0:\r\n0040b4b4 call sub_409820\r\n \r\n00409820 sub_409820:\r\n004099d1 call dword [esp+0x54] (VirtualAlloc)\r\n004099fb call sub_406e40\r\n00406e40 sub_406e40:\r\n00406f97 call eax (VirtualAlloc)\r\n00409d90 call dword [esp+0x220] (shellcode at 00450000)\r\n \r\nshellcode:\r\nhttps://estr3llas.github.io/unveiling-custom-packers-a-comprehensive-guide/\r\nPage 21 of 22\n\n00000273 (00450273) call rdx (VirtualProtect/VirtualAlloc several times)\r\n00000e0b (00450e0b) call qword [rsp+0x14]\r\n00000f58 (00450f58) jmp rax (replaced .text at 00401a40)\r\n \r\ndump!\r\nNow, feel free to apply the knowledge you gathered here on this binary.\r\nAnd that’s how i usually deal with custom packers. Although it is a pretty manual task, keep going, it is very\r\nrewarding to get the unpacked code by manually unpacking it.\r\nThank you for your time, see you on the next one. Thanks for reading!\r\nSource: https://estr3llas.github.io/unveiling-custom-packers-a-comprehensive-guide/\r\nhttps://estr3llas.github.io/unveiling-custom-packers-a-comprehensive-guide/\r\nPage 22 of 22",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://estr3llas.github.io/unveiling-custom-packers-a-comprehensive-guide/"
	],
	"report_names": [
		"unveiling-custom-packers-a-comprehensive-guide"
	],
	"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": 1775434808,
	"ts_updated_at": 1775826725,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/d52c74992402c3a2f159f7de3077b0d85b3eebe9.pdf",
		"text": "https://archive.orkl.eu/d52c74992402c3a2f159f7de3077b0d85b3eebe9.txt",
		"img": "https://archive.orkl.eu/d52c74992402c3a2f159f7de3077b0d85b3eebe9.jpg"
	}
}