# Malicious Packer pkr_ce1a **[malwarology.substack.com/p/malicious-packer-pkr_ce1a](https://malwarology.substack.com/p/malicious-packer-pkr_ce1a?r=1lslzd)** Malwarology LLC ### First Stage ## Summary This [packer has been observed delivering a wide variety of malware families including](https://github.com/MBCProject/mbc-markdown/blob/master/anti-static-analysis/software-packing.md) [SmokeLoader and](https://malpedia.caad.fkie.fraunhofer.de/details/win.smokeloader) [Vidar among many others. It has been observed in the wild going back a](https://malpedia.caad.fkie.fraunhofer.de/details/win.vidar) number of years potentially to 2017. The particular variant of the packer analyzed here contains two sets of bytes with no apparent use which occur on either side of values that are integral to the decoding and unpacking process. These two byte strings are stable across many months of observed samples of this packer. What follows is a detailed analysis of the first stage of one sample of this packer which delivers a SmokeLoader payload. Until a widely recognized name or identifier can be determined for this packer, it has the designation ``` pkr_ce1a . ## Identification ``` This sample has two known filenames. The first, `6523.exe, is observed in the wild in the` path component of the URL used to distribute the file.1 The second, `povgwaoci.iwe, is` located in the `RT_VERSION resource within the` `VS_VERSIONINFO structure in a field` named `InternationalName . This field along with others in the same StringTable structure` [are not parsed by Exiftool or](https://exiftool.org/) [Cerbero Suite. This indicates that the structure is malformed or](https://cerbero.io/ea/) non-standard. Malwarology Research is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber. According to AV detection results, the correct identification of the unpacked file, _SmokeLoader, does appear. There is also one detection based on dynamic analysis:_ _Zenpack._ The import hash of this sample is shared by a group of other files.2 However, the large majority of imported functions are called in dead code located after opaque predicates. Therefore, the usefulness of this import hash is almost nothing. Closer analysis of the opaque predicates in this sample can be found below. ## Behavioral and Code Analysis Findings ----- ## Build Analysis According to the File Header, the timestamp of compilation is 2022-02-16T10:14:32Z. The linker version found in the PE32 Optional Header is 9.0. Linker Version 9.0 The compiler is identified as Visual Studio 2008 Release according to function signatures in Ghidra that match a number of library functions in the sample. One example of this detection for the `___security_init_cookie function is shown in the figure below.` Compiler Detection: Visual Studio 2008 Release The majority of the library functions found in the sample are from Microsoft Visual C++ _9.0.21022. This is identified in the sample’s rich signature._ ----- Rich Signature: VC++ 9.0.21022 ## Main Function Main Function [The instructions highlighted in yellow in the figure above are examples of junk code insertion.](https://github.com/MBCProject/mbc-markdown/blob/master/anti-static-analysis/executable-code-obfuscation.md#:~:text=analysis%20visually%20harder.-,Junk%20Code%20Insertion,-B0032.007) These are dummy instructions that are placed between relevant instructions with the goal of making signature development more difficult. The instructions at the end of the function highlighted in white are not executed. These highlight colorings are used throughout the screenshots of this analysis. ----- The first instructions in the main function calculate the size of the encoded data that contains the shellcode which is the next stage of the packer. The first part is read from a constant in the `.data section at address` `0x41cc3c . The second part is hardcoded in the main` function at address `0x406573 . The size is calculated in the next instruction by adding the` two parts together. The resulting size is written to a variable in the `.data section.` Highlighted in the figure below are the bytes before and after the first constant. These two sets of bytes are not read during the execution of the packer, and their purpose is unknown. However, they are stable across builds of this packer going back for months at least. Stable Surrounding Bytes The address where the encoded data is located goes through a similar process. The first part is read from the `.data section then written to a variable in the same section. The addition` to the second part does not occur until later in the `unpack_shellcode function. The bytes` surrounding this part are shown in the figure below. Stable Surrounding Bytes The next set of instructions handles loading `kernel32.dll and resolving the address of` `LocalAlloc` .3 These instructions taken together are unique to this packer and shared across hundreds of variants. The stray instruction at address `0x406588 is part of the` [previous logical grouping of instructions. This is an example of interleaving code that is](https://github.com/MBCProject/mbc-markdown/blob/master/anti-static-analysis/executable-code-obfuscation.md#:~:text=to%20confuse%20disassembler.-,Interleaving%20Code,-B0032.014) meant to make signature development more difficult. Resolve `LocalAlloc` ----- The call to `LocalAlloc is obfuscated by calling it from the` `eax register. This is a type of` function call obfuscation. The `uBytes parameter to the function is 63072 bytes which is the` result of the calculation described above. Obfuscated Call to `LocalAlloc` The final instructions in the main function are calls to other malicious functions and finally a call to the entry point of the decoded shellcode. The next stage of the packer starts after that call. ## Change Protection Function ----- Change Protection Function This function is a wrapper around an obfuscated call to `VirtualProtect . Starting at` address `0x4058e3 and continuing until the call to` `GetProcAddress, the name of the` function `VirtualProtect is written character-by-character, out of order, to a variable in the` ``` .data section. Building the function name in this way is an example of variable ``` recomposition. The address of this string is then used as the `lpProcName parameter to` ``` GetProcAddress . Finally, a call is made to VirtualProtect to change the protection ``` from `PAGE_READWRITE ( 0x4 ) to` `PAGE_EXECUTE_READWRITE ( 0x40 ) thus enabling` execution in the newly allocated memory. ----- The `flNewProtect parameter to the` `VirtualProtect function is also obfuscated by` adding together `0x20 and` `0x20 . This hides the` `PAGE_EXECUTE_READWRITE flag of` `0x40 from being located near the call to` `VirtualProtect . This is a form of` argument obfuscation. Obfuscated New Protect Value ## Unpack Shellcode Function This function performs three actions that are interspersed with anti-analysis code. The first action is moving the encoded data from its starting location in the `.data section to the` newly allocated memory. Move Encoded Data ----- Note the instructions at addresses `0x405aa7 and` `0x405acd . These are both` opaque predicates. An opaque predicate appears to be a conditional jump, but the conditions can only be met in one way making the jump effectively unconditional. The one at the top is basically a fake: it never jumps. The one in the middle always jumps. This one additionally [encloses a block of dead code. This packer very frequently couples dead code insertion with](https://github.com/MBCProject/mbc-markdown/blob/master/anti-static-analysis/executable-code-obfuscation.md#:~:text=.%20%5BNEEDS%20REVIEW%5D-,Dead%20Code%20Insertion,-B0032.003) opaque predicates that always jump over the dead code. The function calls in the dead code are included in the import table making identification via import hash of little utility. Later on in this function is the call to the `decode function. After that is a call to a function` which shifts the pointer to the decoded shellcode. The shift changes the offset from the start of this data to the location of the shellcode original execution point (OEP). Because the shellcode is position independent, this OEP is also offset zero of the shellcode. Both of these functions are analyzed in more detail below. The `shift_shellcode_oep function is additionally wrapped in an anti-emulator loop which` has a very high number of iterations. This slows processing in an emulator which can potentially cause a timeout and an analysis failure. Decode and Shift Shellcode OEP Functions Note the comparison instruction at address `0x406486 . During the anti-emulation loop, the` call to `shift_shellcode_oep is made once when the counter reaches` `0x770e . This is a` type of anti-emulation circumvention countermeasure. A basic method for circumventing extremely long loops that target emulators is to patch out the loop. Another is to detect the loop in the emulator and then modify the counter to leave the loop. Because the shift function is called once at a point in the loop, either of these circumventions could end up not executing this function and would leave the emulator unable to execute the shellcode correctly. ----- The `unpack_shellcode function overall contains ten opaque predicates primarily of the` same type shown above. One of them is slightly different in that it creates a dead end filled with dead code. The last instruction in the dead end is a call to `terminate . Therefore, this` appears to be a location where the execution of the packer ends. Opaque Predicate with Dead End There are a total of four anti-emulation loops similar to the one analyzed above. Two of these wrap opaque predicates which in turn wrap inserted dead code. One, however, in addition to wrapping two opaque predicates, also contains two additional anti-emulator behaviors. Both [of these are calls to unusual APIs:](https://github.com/MBCProject/mbc-markdown/blob/master/anti-behavioral-analysis/emulator-evasion.md#:~:text=non%2Dexhaustive%20emulators.-,Unusual,-/Undocumented%20API%20Calls) `GetGeoInfoA and` `GetSystemDefaultLangID . During` analysis, [Qiling emulator halted with an exception because neither of these API calls have](https://github.com/qilingframework/qiling) been implemented. Anti-Emulation: Unusual API Calls In the very first code block of the `unpack_shellcode function, a new and subsequently` unused exception handler is registered. Chances are about even that this is an antiemulation behavior or it is just junk code. If it is anti-emulation, it is targeting older emulators [based on specific versions of Unicorn Engine which do not implement access to the](https://github.com/unicorn-engine/unicorn) ----- Windows Thread Information Block (TIB). Moving the contents of `fs:0x0 as happens at` address `0x405983 would fail in that particular environment. This type of anti-emulation is` an [unimplemented opcode.](https://github.com/MBCProject/mbc-markdown/blob/master/anti-behavioral-analysis/emulator-evasion.md#:~:text=emulators%20give%20up.-,Undocumented%20Opcodes,-B0005.002) Register New SEH In the last block of the `unpack_shellcode function, before the return, the SEH is reset` back to the previous handler. This occurs right after a junk call to `LoadLibraryW from` which no functions are subsequently resolved. Last Block of `unpack_shellcode` ## Decode Function ----- Decode Function (Truncated) The data is decoded in chunks. So this function has three basic purposes: convert the encoded shellcode size to a chunk count by dividing by 8, wrapping a loop around the call to the `decode_chunk function, and then calling that function. In the middle of this function is a` very large insertion of dead code wrapped by an opaque predicate. This is highlighted in white in the figure above. It has also been truncated for the screenshot. There are two [locations in this function with junk code insertion which impedes signature development: at](https://github.com/MBCProject/mbc-markdown/blob/master/anti-static-analysis/executable-code-obfuscation.md#:~:text=analysis%20visually%20harder.-,Junk%20Code%20Insertion,-B0032.007) addresses `0x4057c1 and` `0x4057cc .` The chunks are 8 bytes long, therefore at the end of the loop after the call to ``` decode_chunk, 8 is added to the chunk pointer then the chunk count is decremented by ``` one. ----- Chunk Decode Loop Control ## Decode Chunk Function ----- Decompiled Decode Chunk Function The `decode_chunk function has four opaque predicates that each wrap dead code, and` there are two locations with junk code insertion. In addition to these, the logic of the function is quite convoluted. However, after patching out all of the opaque predicates, dead code, and junk code, a cleaner decompilation graph can be analyzed. The figure above is that graph, fully annotated and cleaned up. ----- There are three tiny functions called during the decoding algorithm: `load_data_keyB,` ``` add_key4, and, xor_mix . These simply isolate small pieces of the algorithm to impede ``` analysis and make signature development more difficult. Algorithm Isolates ## Shift Shellcode OEP Function Shift Shellcode OEP Function The `shift_shellcode_oep function is very simple. It adds` `0x3bf1 to the address of the` start of the decoded shellcode in allocated memory. This shifts the pointer from the start of the decoded data to the offset of the OEP. This is the address that is called in the main function. ----- ## Recommendations This packer is polymorphic. Variants and builds share many of the same functionality, behavior, and code features. However, they are in different order with randomization of opaque predicates, junk code, and dead code. In spite of this, detection can be achieved by focusing on the two stretches of stable bytes which were identified above. The following two YARA rules match these bytes. ``` rule Packer_pkr_ce1a_ShellcodeSizePart { meta: author = "Malwarology LLC" date = "2022-10-14" description = "Detects bytes surrounding the first part of the data size of the second stage shellcode in Packer pkr_ce1a." reference = "https://malwarology.substack.com/p/malicious-packer-pkr_ce1a" sharing = "TLP:CLEAR" exemplar = "fc04e80d343f5929aea4aac77fb12485c7b07b3a3d2fc383d68912c9ad0666da" address = "0x41cc3c" packer = "pkr_ce1a" strings: $a = { 00699AF974[4]96AACB4600 } condition: $a and uint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 0x00004550 } rule Packer_pkr_ce1a_ShellcodeAddrPart { meta: author = "Malwarology LLC" date = "2022-10-17" description = "Detects bytes surrounding the first part of the address of the second stage shellcode in Packer pkr_ce1a." reference = "https://malwarology.substack.com/p/malicious-packer-pkr_ce1a" sharing = "TLP:CLEAR" exemplar = "fc04e80d343f5929aea4aac77fb12485c7b07b3a3d2fc383d68912c9ad0666da" address = "0x41bc9c" packer = "pkr_ce1a" strings: $a = { 0094488D6A[4]F2160B6800 } condition: $a and uint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 0x00004550 } ## Supporting Data and IOCs ``` ----- ## File ``` Filename: 6523.exe ``` ``` Filename: povgwaoci.iwe ``` ``` MD5: 5663a767ac9d9b9efde3244125509cf3 ``` ``` SHA1: 84f383a3ddb9f073655e1f6383b9c1d015e26524 ``` ``` Imphash: bc57832ec1fddf960b28fd6e06cc17ba ``` ``` Timestamp: 2022-02-16T10:14:32Z ``` ``` File Type: Win32 EXE ``` ``` Magic: PE32 executable (GUI) Intel 80386, for MS Windows ``` ``` Size: 238080 ``` ``` First Seen: 2022-10-14T18:37:13Z 4 ## Distribution URL ``` ``` hxxp[://]guluiiiimnstrannaer[.]net/dl/6523.exe ``` ## Malware Behavior Catalog DEFENSE EVASION::Software Packing [F0001] ANTI-BEHAVIORAL ANALYSIS::Emulator Evasion::Undocumented Opcodes [B0005.002] ANTI-BEHAVIORAL ANALYSIS::Emulator Evasion::Unusual/Undocumented API Calls [B0005.003] ANTI-BEHAVIORAL ANALYSIS::Emulator Evasion::Extra Loops/Time Locks [B0005.004] ANTI-STATIC ANALYSIS::Disassembler Evasion::Argument Obfuscation [B0012.001] ANTI-STATIC ANALYSIS::Disassembler Evasion::Variable Recomposition [B0012.004] ----- ANTI-STATIC ANALYSIS::Executable Code Obfuscation::Dead Code Insertion [B0032.003] ANTI-STATIC ANALYSIS::Executable Code Obfuscation::Junk Code Insertion [B0032.007] ANTI-STATIC ANALYSIS::Executable Code Obfuscation::Interleaving Code [B0032.014] ## Malware Behavior Catalog Proposed Methods ANTI-BEHAVIORAL ANALYSIS::Emulator Evasion::Unimplemented Opcodes [B0005] ANTI-STATIC ANALYSIS::Executable Code Obfuscation::Opaque Predicate [B0032] ANTI-STATIC ANALYSIS::Executable Code Obfuscation::Function Call Obfuscation [B0032] ## Analyses [Intezer](https://analyze.intezer.com/analyses/4ae9acb6-01f0-4ff5-89bf-c967349e08f9) [UnpacMe](https://www.unpac.me/results/a6d0217d-02c0-4db8-9186-fc0d99137789/) 1 [Sample downloaded from hxxp[://]guluiiiimnstrannaer[.]net/dl/6523.exe](https://bazaar.abuse.ch/sample/fc04e80d343f5929aea4aac77fb12485c7b07b3a3d2fc383d68912c9ad0666da#:~:text=Sample%20downloaded%20from) 2 ``` Imphash: bc57832ec1fddf960b28fd6e06cc17ba ``` 3 [LocalAlloc function (winbase.h)](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-localalloc) 4 VirusTotal -----