typeanalysisfamilylummastealerconfidencemediumcreated2026-07-27
SHA-256: 90d54589bfae10deb74fa349668a5af649c546b8eddb75d5000174601920cf77

lummastealer: 90d54589 — Go 1.25.4 PE32, blizzard-tecnica.com R12 cert, custom PE parser + multi-pass decoder

Executive Summary

Signed Go infostealer sibling carrying the same blizzard-tecnica.com / R12 certificate chain observed in LummaStealer 040e0d76, but augmented with a custom in-memory PE parser and multi-pass byte-transformation decoder previously documented in the ACRStealer / OrderReshop sub-cluster. Static C2 is fully absent; network indicators are runtime-decoded via a PRNG-seeded transform. This sample is evidence of technique cross-pollination across what OpenCTI labels as distinct families.

What It Is

  • File: PE32 executable (GUI) Intel 80386, 7 sections, 2.33 MB ^[file.txt] ^[pefile.txt:1]
  • Compiler: Go 1.25.4, GOARCH=386, GOOS=windows, CGO_ENABLED=0, -trimpath=true ^[strings.txt:1616-1625] ^[strings.txt:5443-5453]
  • Module path: JuYWgOhherjqrZN (14-character randomized alphanumeric) ^[strings.txt:1618]
  • Signing: Authenticode certificate CN=blizzard-tecnica.com, issuer R12 (Let's Encrypt), embedded at IMAGE_DIRECTORY_ENTRY_SECURITY offset 0x238808 ^[strings.txt:8828] ^[binwalk.txt:10-11] ^[pefile.txt]
  • Resources: .rsrc section contains a 256×256 PNG icon (social-engineering masquerade) ^[binwalk.txt:8]
  • Family label: lummastealer — certificate matches LummaStealer sibling 040e0d76 exactly; build toolchain matches the broader ACR/Lumma/OrderRe cluster. See lummastealer for cluster overview.

How It Works

At launch the binary follows the standard Go runtime.main entry, then branches into a series of obfuscated routines before any network activity:

  1. API resolution via fused-string blob — sym.main.lvkctpxqokf builds a syscall._LazyProc_ from a monolithic .rdata blob that concatenates DLL names and API names without delimiters (VirtualAllocinvalid_slothost_is_downillegal_seekGetLengthSidGetLastErrorGetStdHandleGetTempPathWLoadLibraryW...) ^[r2:sym.main.lvkctpxqokf @ 0x489d80] ^[strings.txt:1180]. This defeats naive string extraction and YARA rules that look for standalone VirtualAlloc. See fused-string-api-decoding for the technique.

  2. Custom in-memory PE parser — sym.main.zhfogrm validates MZ (0x5A4D) and PE (0x4550) signatures, then walks section headers in memory. The function takes a base pointer and size, performs bounds-checked slice operations, and returns a structured representation of the PE layout ^[r2:sym.main.zhfogrm @ 0x489ab0]. Identical behavior to ACRStealer sibling d5655568 and OrderReshop.

  3. Multi-pass byte-transform decoder — sym.main.gyxsukxrkxtm performs a looped arithmetic decode over a byte slice: imul with hardcoded constants (0x4d4873ed, 0x54741fac), right-shifts, subtraction, XOR, and byte swaps. The output is fed into a second pass that XORs with values derived from a math/rand-seeded stream ^[r2:sym.main.gyxsukxrkxtm @ 0x489810]. This is the same algorithm class observed in OrderReshop (main.tnlzbjjyqfzrdbk).

  4. PRNG loop — sym.main.qptkpcz seeds math/rand from runtime state (likely current time), calls Float64, performs floating-point multiply-add, and feeds the result into sym.main.omqfro, which drives the decoder ^[r2:sym.main.qptkpcz @ 0x48acf0]. No hardcoded C2 URLs exist in the static image.

  5. Direct syscall wrapper — sym.main.shzldzgie wraps syscall.SyscallN with hardcoded parameter counts, suggesting intentional bypass of standard Go syscall convenience wrappers ^[r2:sym.main.shzldzgie @ 0x4899d0].

Decompiled Behavior

Entry point (sym.main.main @ 0x48cfa0): allocates a runtime.newobject buffer, performs integer math on the result, then calls into the PRNG-decoder chain before any library load. The entry does not immediately import net/http symbols — networking is deferred until after C2 decode.

Notable functions called by entry:

  • sym.main.iugvukwvbpnun — orchestrates the fused API loader and PE parser (caller of lvkctpxqokf, zhfogrm, gyxsukxrkxtm, qptkpcz)
  • sym.main.lvkctpxqokf — resolves APIs via fused blob + syscall._LazyProc_.Call
  • sym.main.zhfogrm — custom PE parser (MZ/PE validation + section enumeration)
  • sym.main.gyxsukxrkxtm — multi-pass arithmetic decoder
  • sym.main.qptkpcz — math/rand seed + float pipeline
  • sym.main.shzldzgie — raw syscall.SyscallN wrapper

Observed control flow: entry → PRNG seed → decoder → API resolution → (network, inferred). No anti-VM or debugger checks were recovered in the static image; the binary relies on string obfuscation and runtime decoding for evasion.

C2 Infrastructure

No hardcoded C2 indicators recovered statically. All network strings are runtime-decoded via the PRNG-seeded multi-pass transform. The binary statically links net/http, crypto/tls, and crypto/x509 ^[strings.txt], confirming HTTPS C2 capability. Dynamic analysis was skipped (no CAPE Windows guest available) ^[dynamic-analysis.md].

Interesting Tidbits

  • Certificate match: The blizzard-tecnica.com / R12 certificate is identical to LummaStealer 040e0d76 — same CN, same issuer, same 90-day Let's Encrypt validity pattern. This is stronger evidence than build metadata alone.
  • Technique cross-pollination: Custom PE parser + multi-pass decoder were first observed in ACRStealer sibling d5655568 and OrderReshop. Their presence here links the LummaStealer certificate cluster to the ACR/OrderRe codebase.
  • No .rsrc absence: Unlike earlier LummaStealer siblings d5647efd and e03dd36f (which have no icon resources), this sample carries a full 256×256 PNG icon — consistent with the builder's icon-toggle option noted in 040e0d76.
  • Go 1.25.4 vs 1.26.2: Latest ACRStealer siblings have moved to Go 1.26.2. This sample stays at 1.25.4, aligning with the LummaStealer build timeline rather than the newest ACRStealer builds.
  • Fused blob offset: The fused API/DLL blob sits at raw offset 0xa7eba inside .rdata ^[strings.txt:1180], immediately following Go runtime strings.

How To Mess With It (Homelab Replication)

Toolchain:

  • Go 1.25.4 for Windows 386
  • Build flags: GOOS=windows GOARCH=386 CGO_ENABLED=0 go build -ldflags="-s -w -trimpath" -o repro.exe

Recipe for fused-string API decoding:

  1. Declare a single var fused = []byte("kernel32.dllVirtualAllocGetTempPathW...")
  2. Slice substrings by (offset, length) pairs stored in a parallel table
  3. Pass each slice to syscall.LoadLibrary / syscall.GetProcAddress
  4. Verify with strings repro.exe | grep VirtualAlloc — should return nothing standalone

See fused-string-api-decoding for a working 50-line reproduction.

What you'll learn: How Go's -trimpath + randomized module paths + fused API blobs produce a binary that evades both static strings tools and naive import-table analysis.

Deployable Signatures

YARA Rule

rule LUMMA_Go1254_FusedBlob_CustomPEParser
{
    meta:
        description = "LummaStealer / ACR cluster: Go 1.25.4 signed PE32 with fused API blob and custom PE parser"
        author = "PacketPursuit"
        date = "2026-07-27"
        sha256 = "90d54589bfae10deb74fa349668a5af649c546b8eddb75d5000174601920cf77"
    strings:
        $go_build = "go1.25.4" ascii
        $trimpath = "-trimpath=true" ascii
        $mod_path = /path\t[a-zA-Z0-9]{12,20}/
        $fused1 = "VirtualAllocinvalid_slothost_is_down" ascii
        $fused2 = "GetLengthSidGetLastErrorGetStdHandleGetTempPathWLoadLibraryW" ascii
        $cert_cn = "blizzard-tecnica.com" ascii
    condition:
        uint16(0) == 0x5A4D and
        $go_build and
        $trimpath and
        $mod_path and
        ($fused1 or $fused2 or $cert_cn) and
        pe.number_of_sections >= 6
}

Sigma Rule

title: Go Infostealer Fused API Blob Resolution
description: Detects a Go process that loads multiple Windows APIs via LoadLibrary/GetProcAddress from a fused string blob instead of the import table.
status: experimental
logsource:
  product: windows
  category: process_access
detection:
  selection:
    Image|endswith: '.exe'
    CallTrace|contains:
      - 'LoadLibraryW'
      - 'GetProcAddress'
  filter:
    LoadedImage|contains:
      - 'kernel32.dll'
      - 'advapi32.dll'
      - 'ws2_32.dll'
      - 'crypt32.dll'
      - 'shell32.dll'
      - 'ntdll.dll'
  condition: selection and filter
  # In practice: a single Go PE32 process that loads 4+ DLLs via LoadLibrary within 5 seconds of launch
falsepositives:
  - Go programs that legitimately use syscall.LoadLibrary for plugin loading
level: medium

IOC List

Indicator Value Type
SHA-256 90d54589bfae10deb74fa349668a5af649c546b8eddb75d5000174601920cf77 hash
SHA-1 6648314f14c4d399ac2a72b9bc9c1b6afe1d24b1 hash
MD5 f9b997a998c7b47802f9a2fbaf95c807 hash
Certificate CN blizzard-tecnica.com cert
Certificate Issuer R12 cert
Module path JuYWgOhherjqrZN build artifact
Go version go1.25.4 build artifact
Fused blob substring VirtualAllocinvalid_slothost_is_downillegal_seek string artifact

Behavioral Fingerprint Statement

A signed PE32 GUI executable compiled with Go 1.25.4 for Windows 386, carrying a randomized module path and a .rsrc PNG icon. At runtime it allocates RWX memory, resolves Windows APIs via a fused .rdata string blob using syscall.LoadLibrary / GetProcAddress, and decodes C2 strings through a multi-pass arithmetic transform seeded by math/rand. No hardcoded C2 URLs exist in the static image; the binary relies entirely on runtime decoding. The Authenticode certificate is a 90-day Let's Encrypt DV cert for blizzard-tecnica.com.

Detection Signatures

  • MITRE ATT&CK: T1055 (Process Injection — inferred from VirtualAlloc + RWX staging), T1027 (Obfuscated Files or Information — fused strings + multi-pass decoder), T1071.001 (Application Layer Protocol: Web — HTTPS C2 inferred from crypto/tls linkage), T1564.003 (Hide Artifacts: Hidden Window — Windows GUI subsystem), T1583.001 (Acquire Infrastructure: Domains — Let's Encrypt cert for fraudulent domain)
  • Capa: Not applicable — capa signatures were unavailable during triage (capa.txt contains only install-error output) ^[capa.txt]

References

  • Artifact ID: f6427b51-8a28-48bf-86f6-310c119b9e01
  • Triage label: acrstealer (OpenCTI), reclassified to lummastealer based on certificate provenance
  • Related wiki pages: lummastealer, acrstealer, orderreshop, fused-string-api-decoding, golang-stealer-build-pattern
  • LummaStealer sibling with identical certificate: /intel/analyses/040e0d767faccb2b706ec81553b14743f1d24f508c69bb5921716bdeb14ca1cb.html
  • ACRStealer sibling with custom PE parser + multi-pass decoder: /intel/analyses/d5655568fee9c610139d41d367afc74e768e1c8baf70e37912e9ebeb27b5d411.html

Provenance

Static analysis performed 2026-07-27 on pp-hermes (Linux 6.14.8-2-pve). Tools: file 5.44, strings GNU binutils 2.42, exiftool 12.76, pefile Python library, radare2 5.9.8 (aaa analysis level 3), binwalk 2.3.4. No dynamic execution (CAPE skipped — no Windows guest). All behavioral claims trace to strings, PE structure, or r2 decompilation.