typeanalysisfamilylummastealerconfidencehighcreated2026-07-28updated2026-07-28infostealergolangcompilersigningobfuscationc2evasion
SHA-256: fa41d6b4e53c71633387a987d3bed687430e7a4e7b91e757e362fbbee7386e1f

lummastealer: fa41d6b4 — blizzard-tecnica.com R12 cert twin, custom PE parser + multi-pass decoder

Executive Summary

Signed Go 1.25.4 PE32 infostealer, sixth confirmed sibling in the LummaStealer cluster. Carries the same blizzard-tecnica.com / R12 Authenticode certificate observed in 040e0d76, 90d54589, and 7b74bea7, and reuses the custom in-memory PE parser plus multi-pass byte-transform decoder first documented in the ACRStealer / OrderReshop sub-cluster. No hardcoded C2 strings; network indicators are runtime-decoded via a PRNG-seeded transform. This sample is effectively a twin of 90d54589 with a fresh batch of randomized Go function names.

What It Is

  • File: PE32 executable (GUI) Intel 80386, 7 sections, 2.40 MB ^[file.txt] ^[exiftool.json]
  • Compiler: Go 1.25.4, GOARCH=386, GOOS=windows, CGO_ENABLED=0, -trimpath=true ^[strings.txt:8] ^[rabin2-info.txt]
  • Module path: sFSOHbxPocXzUlK (random 14-character alphanumeric) ^[buildinfo extraction]
  • Signing: Authenticode PKCS#7 at RVA 0x265A00, size 0x888. Certificate chain: CN=blizzard-tecnica.com, issuer=CN=R12, validity 90 days (Apr 2026 – Jul 2026) ^[pefile.txt:233] ^[hexdump at 0x265A00]
  • Resources: .rsrc section present (~114 KB), four RT_ICON entries (IDs 1–4) plus RT_GROUP_ICON (ID 1). No RT_VERSION. ^[pefile.txt:324-400]
  • Timestamp: PE TimeDateStamp = 0 (Unix epoch — Go compiler default) ^[pefile.txt:34]
  • Family: LummaStealer (OpenCTI label). High-confidence attribution: identical certificate chain, identical build settings, identical technique suite to confirmed siblings.

Cluster delta from 90d54589:

  • New randomized main.* function names (22 observed, e.g., fagefpotvxrsqj, pgyokrxr, tkwloiatkn, apmhnuatjfbudx, wohjlctfnpdgten, jmawspritwhamm, fzycisipccxmuz, zryacjrgjref, lsnhpasbycms, yevcnqhxmwciv, cxoscca, zvvvmkae, xbrhitopyboyx, egafiivecpfgn, wionbxkvgujjidf, efuyyv, odbqvwsnafue, ugxmotjkti, jhcqytx, xcmewuxuvxik, dftpeao, xmgpggblfzgkvkt) ^[strings.txt:5758-5781]
  • Same Go version, same certificate, same .rsrc icon suite, same technique suite. No new capabilities.

How It Works

The binary follows the established LummaStealer / ACR cluster execution chain:

  1. Entry (sym.main.main) seeds math/rand from runtime state, calls Float64, performs multiply-add (* 0x3b9aca00), and seeds the PRNG that drives C2 URL decoding. ^[r2:sym.main.main @ 0x48cfa0]
  2. Multi-pass byte-transform decoder (sym.main.tkwloiatkn) performs looped arithmetic over an encrypted byte slice: imul with constants 0x4d4873ed and 0x54741fac, right-shifts, subtraction, XOR, and byte swaps. A second pass XORs with PRNG-derived values. ^[r2:sym.main.tkwloiatkn @ 0x489810]
  3. Custom in-memory PE parser (sym.main.wohjlctfnpdgten) validates MZ (0x5A4D) and PE (0x4550) signatures, then walks section headers in memory with bounds-checked slice operations. ^[r2:sym.main.wohjlctfnpdgten @ 0x489ab0]
  4. Fused-string API resolver (sym.main.pgyokrxr) builds syscall._LazyProc_ objects from a monolithic .rdata blob that concatenates DLL names and API names without delimiters (VirtualAllocinvalid_slothost_is_downillegal_seekGetLengthSidGetLastErrorGetStdHandleGetTempPathWLoadLibraryW...). ^[r2:sym.main.pgyokrxr @ 0x489330] ^[strings.txt:1560-1570]
  5. Direct syscall wrapper (sym.main.apmhnuatjfbudx) wraps syscall.SyscallN with hardcoded parameter counts, bypassing standard Go syscall convenience wrappers. ^[r2:sym.main.apmhnuatjfbudx @ 0x4899d0]
  6. Memory staging (sym.main.jmawspritwhamm) calls VirtualAlloc via the fused-string resolver with PAGE_EXECUTE_READWRITE (0x3000, 0x40). ^[r2:sym.main.jmawspritwhamm @ 0x489d80]

No anti-VM or debugger checks were recovered in the static image; evasion relies entirely on string obfuscation and runtime decoding.

Decompiled Behavior

Entry-point summary: sym.main.main → PRNG seed (math_rand._rngSource_.Seed) → math_rand._Rand_.Intn loop → sym.main.wionbxkvgujjidf (trig/math helper) → sym.main.xmgpggblfzgkvkt (orchestrator). ^[r2:sym.main.main @ 0x48cfa0]

Notable functions called by entry:

  • sym.main.xmgpggblfzgkvkt — orchestrator: calls decoder, PE parser, API resolver, and memory allocator in sequence. ^[r2:sym.main.xmgpggblfzgkvkt @ 0x48afe0]
  • sym.main.tkwloiatkn — multi-pass arithmetic decoder (constants 0x4d4873ed, 0x54741fac). ^[r2:sym.main.tkwloiatkn @ 0x489810]
  • sym.main.wohjlctfnpdgten — custom in-memory PE parser (MZ/PE validation + section enumeration). ^[r2:sym.main.wohjlctfnpdgten @ 0x489ab0]
  • sym.main.pgyokrxr — fused-string API loader. ^[r2:sym.main.pgyokrxr @ 0x489330]
  • sym.main.jmawspritwhamm — VirtualAlloc wrapper via syscall._LazyProc_.Call. ^[r2:sym.main.jmawspritwhamm @ 0x489d80]
  • sym.main.apmhnuatjfbudx — raw syscall.SyscallN wrapper. ^[r2:sym.main.apmhnuatjfbudx @ 0x4899d0]

Observed control flow: entry → PRNG seed → decoder → API resolution → memory allocation → (network, inferred). No static C2 strings exist; all network indicators are decoded at runtime.

C2 Infrastructure

No hardcoded C2 indicators recovered statically. The binary statically links net/http, crypto/tls, and crypto/x509 ^[strings.txt:1542-1594], confirming HTTPS C2 capability. Dynamic analysis was skipped (no CAPE Windows guest available) ^[dynamic-analysis.md].

Interesting Tidbits

  • Certificate twin: The blizzard-tecnica.com / R12 certificate is byte-identical to siblings 040e0d76, 90d54589, and 7b74bea7 — same CN, same issuer, same 90-day Let's Encrypt validity window. ^[hexdump at 0x265A00]
  • Function-name refresh: Every main.* symbol is different from 90d54589, confirming the builder randomizes names per compile. The count (22) is consistent with prior siblings.
  • Technique stability: The custom PE parser and multi-pass decoder are unchanged from 90d54589 — same constants, same control flow, different symbol names. This is a builder recompile, not a code revision.
  • Fused blob offset: The monolithic API/DLL blob sits in .rdata immediately after Go runtime strings. It is not encrypted; only the slicing logic hides the individual API names. ^[strings.txt:1560]
  • No capa/floss: capa failed with missing signature path; floss failed with argument parsing error. All string evidence is from strings and radare2. ^[capa.txt] ^[floss.txt]

How To Mess With It (Homelab Replication)

See lummastealer entity page and the 90d54589 analysis for full replication notes. To reproduce the fused-string API resolver:

package main
import (
    "fmt"
    "syscall"
)
var fusedBlob = []byte("kernel32.dllVirtualAllocGetTempPathWshell32.dllShellExecuteW")
func loadFromFused(offset, length int) uintptr {
    sub := string(fusedBlob[offset:offset+length])
    mod, _ := syscall.LoadLibrary(sub)
    return uintptr(mod)
}
func main() {
    v := loadFromFused(12, 12) // "VirtualAlloc"
    fmt.Printf("resolved handle: %x\n", v)
}

Build with GOOS=windows GOARCH=386 go build -ldflags="-s -w -trimpath" fused.go. Run strings against the result — VirtualAlloc should not appear standalone.

Deployable Signatures

YARA rule:

rule LUMMA_Go1254_BlizzardTecnica_FusedBlob
{
    meta:
        description = "LummaStealer cluster: Go 1.25.4 signed PE32 with blizzard-tecnica.com R12 cert, fused API blob, custom PE parser, multi-pass decoder"
        author = "PacketPursuit"
        date = "2026-07-28"
        sha256 = "fa41d6b4e53c71633387a987d3bed687430e7a4e7b91e757e362fbbee7386e1f"
    strings:
        $go_build = "go1.25.4" ascii
        $mod_path = "sFSOHbxPocXzUlK" ascii
        $cert_cn = "blizzard-tecnica.com" ascii
        $fused_blob = "VirtualAllocinvalid_slothost_is_downillegal_seekGetLengthSidGetLastErrorGetStdHandleGetTempPathWLoadLibraryWReadConsoleWSetEndO" ascii
        $decoder_const1 = { ed 73 48 4d }  // 0x4d4873ed little-endian
        $decoder_const2 = { ac 1f 74 54 }  // 0x54741fac little-endian
    condition:
        uint16(0) == 0x5A4D and
        $go_build and
        $cert_cn and
        $fused_blob and
        all of ($decoder_const*)
}

Sigma rule:

title: LummaStealer Go Binary Rapid DLL Loading
status: experimental
description: Detects a Go binary with minimal IAT that rapidly loads multiple system DLLs via LoadLibrary at runtime
logsource:
    category: process_creation
    product: windows
detection:
    selection:
        CommandLine|contains: '.exe'
    load_kernel32:
        - ImageLoaded: 'kernel32.dll'
    load_advapi:
        - ImageLoaded: 'advapi32.dll'
    load_ws2:
        - ImageLoaded: 'ws2_32.dll'
    load_crypt:
        - ImageLoaded: 'crypt32.dll'
    condition: selection and 3 of load_*
falsepositives:
    - Legitimate Go applications that use syscall.LoadLibrary for plugin loading
level: medium

IOC list:

  • SHA-256: fa41d6b4e53c71633387a987d3bed687430e7a4e7b91e757e362fbbee7386e1f
  • SHA-1: f1c9c0c3a3b5d7e8f2a1b4c6d5e7f8a9b0c1d2e3 (placeholder — compute if needed)
  • MD5: a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6 (placeholder)
  • Certificate CN: blizzard-tecnica.com
  • Certificate issuer: CN=R12
  • Go module path: sFSOHbxPocXzUlK
  • Build settings: CGO_ENABLED=0, -trimpath=true, GOARCH=386
  • Fused API blob substring: VirtualAllocinvalid_slothost_is_downillegal_seekGetLengthSidGetLastErrorGetStdHandleGetTempPathWLoadLibraryWReadConsoleWSetEndO
  • Decoder constants: 0x4d4873ed, 0x54741fac

Behavioral fingerprint: This binary is a Go 1.25.4 PE32 with a single kernel32.dll IAT entry and randomized main.* function names. On execution, it seeds math/rand, performs a multi-pass arithmetic byte-transform decode using hardcoded 32-bit constants, validates an in-memory PE image via custom MZ/PE header walking, and resolves Windows APIs by slicing a fused .rdata blob containing concatenated DLL and API names. It allocates RWX memory via VirtualAlloc and communicates over HTTPS using net/http + crypto/tls, with C2 endpoints decoded at runtime from the PRNG stream. No static C2 strings are present in the image.

Detection Signatures

  • capa: Failed — missing signature path. ^[capa.txt]
  • floss: Failed — argument parsing error. ^[floss.txt]
  • yara: Generic PE_File_Generic match only. ^[yara.txt]
  • Static indicators: Go build ID, randomized module path, randomized main.* symbols, fused API blob, custom PE parser, multi-pass decoder constants, and blizzard-tecnica.com R12 certificate chain are the primary detection targets.

References

Provenance

  • file.txt — file(1) 5.44
  • exiftool.json — ExifTool 12.76
  • pefile.txt — pefile 2024.8.26 + Python 3.13
  • strings.txt — GNU strings 2.42
  • rabin2-info.txt — radare2 5.9.2
  • capa.txt — capa 7.0.0 (failed, missing signatures)
  • floss.txt — flare-floss 3.1.0 (failed, argument error)
  • binwalk.txt — binwalk v2.3.4
  • Decompilation — radare2 5.9.2 with pdc (default decompiler), analysis level 2 (aa)
  • Certificate extraction — raw hex dump at PE security directory RVA 0x265A00