typeanalysisfamilypetpack-dotnetconfidencemediumcreated2026-06-18updated2026-06-18dotnetmalware-familyloaderobfuscationdefense-evasionc2
SHA-256: ea56cf43d33bcc713bbd715bd83a1b3adb5562e8266bf47bed96ab8c54163217

petpack: ea56cf43d33b — AES-managed .NET loader with Serbian banking lure

Executive Summary

A .NET Framework 4.0 PE32+ loader compiled in August 2024. Its internal namespace is Petpack (sub-types Rock and InjectMem), and it arrives as a Serbian/Croatian banking-themed executable (kopija_bankovnog_placanja.exe — "copy of bank payment"). The sample decrypts an AES-encrypted payload at runtime using AesManaged with key material derived from a hardcoded 11-byte seed (p6D14wkm2EW), then loads it reflectively via Marshal.GetDelegateForFunctionPointer and P/Invoke LoadLibrary. No C2 strings are recoverable statically; dynamic analysis was skipped due to no CAPE Windows guest.

What It Is

Field Value
SHA-256 ea56cf43d33bcc713bbd715bd83a1b3adb5562e8266bf47bed96ab8c54163217
File type PE32+ executable (console) x86-64 Mono/.Net assembly, 2 sections ^[file.txt]
Size 1,525,360 bytes
Timestamp Mon Aug 5 16:16:25 2024 UTC ^[pefile.txt:40] ^[rabin2-info.txt:11]
CLR version v4.0.30319 (.NET Framework 4.x) ^[parse_dotnet.py]
Filename kopija_bankovnog_placanja.exe (Serbian/Croatian: "copy of bank payment") ^[triage.json:5]
YARA PE_File_Generic only ^[yara.txt]
Authenticode Timestamped via Sectigo/USERTrust chain; no code signature ^[binwalk.txt] ^[rabin2-info.txt:29]

The PE has two sections (.text, .rsrc) with moderate entropy (~6.0), no packing, and a valid but non-standard PE32+ layout: AddressOfEntryPoint = 0x0 (characteristic of .NET CIL entry). ^[pefile.txt:56]

Build / RE

Toolchain

Compiled to CIL for the .NET Framework 4.0 runtime. The module metadata contains 42 methods, 17 types, and 2 assembly references. ^[parse_dotnet.py] Version-info fields are populated with nonsense values (CompanyName: Uruparijilocumabogay, ProductName: Iwinacit, OriginalFileName: Ivijapiqocipitol). ^[exiftool.json:36-41]

Obfuscation

All type and method names in the #Strings heap are mangled with Arabic/Persian Unicode glyphs (e.g. ﴊﵩﮝپ﵃ﱛڢﰌﱠﶊﴢﰩﭤﰋﴀﲙﶣﶓﰪﮍﲨﴊٚۤ﷫ﶃڅ). Only framework API names (AesManaged, CreateDecryptor, GetString, ReadAllBytes, InjectMem, AllocConsole, FreeConsole, LoadLibrary) and the internal namespace Petpack/Rock survive as plain ASCII. ^[parse_dotnet.py] ^[strings.txt:52-75]

This is not a commercial obfuscator (no ConfuserEx, SmartAssembly, or Dotfuscator signatures). The mangling appears custom or generated by a simple name-scrambling tool.

Crypto

The binary references AesManaged (deprecated since .NET Framework 4.6 in favour of Aes), CreateDecryptor, set_Key, and set_IV. ^[parse_memberref.py] A hardcoded 11-byte ASCII string p6D14wkm2EW appears seven times in the binary, interleaved with what appears to be ciphertext or padding material. ^[strings.txt search]

The FieldRVA table has 1 row, suggesting a small embedded data blob (likely the AES key/IV or encrypted payload header) mapped directly into a static field. ^[parse_dotnet.py]

Anti-analysis

  • No debug checks, no VM detection strings, no IsDebuggerPresent.
  • No TLS callbacks, no delay imports.
  • Console-allocation APIs (AllocConsole / FreeConsole) are imported via P/Invoke, likely to create a visible window or hide console presence. ^[parse_memberref.py]

Embedded payload

No manifest resource or RCData payload is evident in static analysis. The .rsrc section contains only the standard UAC manifest and timestamping certificates. ^[binwalk.txt] The encrypted payload is likely supplied as an external file (the ReadAllBytes API strongly suggests file-based staging) or appended to the binary beyond the certificate block. The PAPADDINGXX strings after the certificate block (offset 0xa0c0d) suggest trailing data that may include the ciphertext.

Notable methods

  • InjectMem — name recovered from #US heap; suggests in-memory PE injection or reflective mapping. ^[parse_dotnet.py]
  • Petpack.Strept — recovered from #US heap; possibly a class/type name (Strept ≈ "streptococ" fragment, or truncated). ^[parse_dotnet.py]
  • Entry-point method (MethodDef 6, RVA 0x327d) is a tiny 8-byte stub that chains three .ctor calls before returning. ^[dump_il.py]

Deploy / ATT&CK

Static-only inference (CAPE skipped — no Windows guest available). ^[dynamic-analysis.md]

Tactic Technique Evidence
DEFENSE EVASION T1620 Reflective Code Loading LoadLibrary P/Invoke, InjectMem naming, GetDelegateForFunctionPointer, Marshal usage. ^[capa.txt] ^[parse_memberref.py]
DEFENSE EVASION T1027 Obfuscated Files or Information AES-encrypted payload, Unicode name mangling.
EXECUTION T1059 Command and Scripting Interpreter .NET assembly loaded reflectively; AesManaged + CreateDecryptor decrypts and executes. ^[capa.txt]
EXECUTION T1106 Execution via API LoadLibrary, AllocConsole, FreeConsole via P/Invoke. ^[parse_memberref.py]
PERSISTENCE Not observed statically. No registry, schtasks, or startup strings.
C2 Not observed statically. No hardcoded URLs, IPs, or domain names.

Attribution

  • Linguistic: The filename and lure theme are Serbian/Croatian (kopija bankovnog plaćanja = "copy of bank payment"). The target geography is likely the Balkans.
  • Build date: August 2024 — relatively fresh at time of collection (May 2026).
  • Namespace: Petpack is not a known public malware family. No siblings found in the corpus.
  • Confidence: Medium. This is a single-sample observation with no CAPE confirmation.

C2 Infrastructure

None recoverable statically. The sample may fetch its payload from a remote URL at runtime (not present in strings), or it may be designed to receive the encrypted payload as a companion file. ReadAllBytes implies local file reading; network C2 is unproven.

Interesting Tidbits

  1. The hardcoded seed p6D14wkm2EW is an 11-byte mixed-alphanumeric string that repeats seven times with different trailing bytes — likely used to derive a 128-bit or 256-bit AES key via a KDF or simple expansion. ^[strings.txt search]
  2. The #US (user string) heap contains three plaintext literals: something, p6D14wkm2EW, and Petpack.Strept — a rare leak of internal naming through the user-string table. ^[parse_dotnet.py]
  3. The assembly references two empty-named assemblies ('' v0.0.0.0) — possibly merged or obfuscated dependencies. ^[parse_memberref.py]
  4. The PE carries a valid Authenticode timestamp (Sectigo/USERTrust) but no actual code signature, giving it superficial legitimacy without a revocable cert. ^[binwalk.txt]
  5. AesManaged was deprecated in favour of Aes in .NET Framework 4.6 (2015). Using the older API suggests the builder targets broad compatibility or the author simply copied an older template.

How To Mess With It (Homelab Replication)

Goal: Build a minimal .NET AES-loader that decrypts a payload from disk and loads it via Assembly.Load.

  1. Toolchain: Visual Studio or dotnet new console --framework net40.
  2. Code skeleton:
    byte[] key = Encoding.UTF8.GetBytes("p6D14wkm2EW".PadRight(32, 'X'));
    byte[] iv = new byte[16];
    byte[] cipher = File.ReadAllBytes("stage2.bin");
    using (AesManaged aes = new AesManaged()) {
        aes.Key = key;
        aes.IV = iv;
        ICryptoTransform decryptor = aes.CreateDecryptor();
        byte[] plain = decryptor.TransformFinalBlock(cipher, 0, cipher.Length);
        Assembly.Load(plain).EntryPoint.Invoke(null, null);
    }
    
  3. Verification: Compile, run capa — should hit compiled to the .NET platform, invoke .NET assembly method, read file in .NET.

Deployable Signatures

YARA

rule Petpack_DotNet_Loader {
    meta:
        description = "Detects Petpack .NET AES loader family"
        author = "pp-hermes"
        date = "2026-06-18"
        sha256 = "ea56cf43d33bcc713bbd715bd83a1b3adb5562e8266bf47bed96ab8c54163217"
    strings:
        $namespace1 = "Petpack" ascii wide
        $namespace2 = "Petpack.dll" ascii wide
        $inject = "InjectMem" ascii wide
        $aes = "AesManaged" ascii wide
        $seed = "p6D14wkm2EW" ascii wide
        $str_read = "ReadAllBytes" ascii wide
        $str_create = "CreateDecryptor" ascii wide
        $str_delegate = "GetDelegateForFunctionPointer" ascii wide
        $str_loadlib = "LoadLibrary" ascii wide
    condition:
        uint16(0) == 0x5A4D and
        ($namespace1 or $namespace2) and
        ($inject or $seed) and
        any of ($aes, $str_read, $str_create) and
        filesize < 3MB
}

Behavioral Hunt Query (KQL / Microsoft Defender)

DeviceProcessEvents
| where InitiatingProcessFileName =~ "kopija_bankovnog_placanja.exe"
   or FileName contains "Petpack"
   or ProcessCommandLine contains "p6D14wkm2EW"
| union (DeviceFileEvents
         | where FileName contains "stage2.bin"
            or FileName contains "kopija_bankovnog_placanja")
| union (DeviceNetworkEvents
         | where InitiatingProcessFileName =~ "kopija_bankovnog_placanja.exe")

IOCs

Type Value Notes
SHA-256 ea56cf43d33bcc713bbd715bd83a1b3adb5562e8266bf47bed96ab8c54163217 Primary sample
Filename kopija_bankovnog_placanja.exe Lure
String p6D14wkm2EW Likely AES key seed
Namespace Petpack / Petpack.Rock / Petpack.Strept Internal .NET namespace
P/Invoke kernel32.dll::LoadLibrary Reflective loading
P/Invoke kernel32.dll::AllocConsole / FreeConsole Console manipulation
Timestamp Mon Aug 5 16:16:25 2024 UTC Compilation time

Behavioral Fingerprint

This binary is a .NET Framework console application that imports kernel32.dll via P/Invoke for AllocConsole, FreeConsole, and LoadLibrary. At launch it initialises one or more AesManaged instances using a hardcoded key seed (p6D14wkm2EW), reads an encrypted payload from disk via ReadAllBytes, decrypts it in-memory, and reflectively loads the resulting assembly via Assembly.Load or Marshal.GetDelegateForFunctionPointer. No network C2 is hardcoded; payload delivery is either file-based or runtime-resolved. The binary carries a Sectigo/USERTrust timestamp block but no Authenticode signature.

Detection Signatures

ATT&CK Technique Detection Source
T1620 Reflective Code Loading capa static analysis ^[capa.txt]
T1059 Command and Scripting Interpreter capa static analysis ^[capa.txt]
T1027 Obfuscated Files or Information AES payload + name mangling
T1106 Native API P/Invoke LoadLibrary, AllocConsole

References

Provenance

  • file.txtfile command output (PE32+ Mono/.Net assembly)
  • pefile.txt — pefile 2023.2.7 header dump
  • rabin2-info.txt — radare2 binary header summary
  • capa.txt — Mandiant flare-capa v7 static capability detection
  • exiftool.json — ExifTool 12.76 version-info extraction
  • strings.txt — GNU strings extraction (1333 lines)
  • binwalk.txt — Binwalk embedded-artefact scan (certificate block, XML manifest)
  • dynamic-analysis.md — CAPE sandbox status (skipped, no Windows guest)
  • triage.json — OpenCTI triage metadata
  • parse_dotnet.py / parse_memberref.py / dump_il.py — Custom Python CLR metadata parsers
  • floss.txt — FireEye flare-floss (failed: CLI argument error)

Analysis completed 2026-06-18. Static-only; no CAPE detonation. Confidence: medium.