typeanalysisfamilyunclassified-pe32-nfe-loaderconfidencemediumcreated2026-06-06updated2026-06-06peloaderdropperdefense-evasionmitre-attckcompilerevasion
SHA-256: ac20be185f5e5d931516336e80d7c3fd3adda6519418877de50181acf6986873

unclassified-pe32-nfe-loader: ac20be18 — 4 KB MinGW launcher stub for core.dll

Executive Summary

A 4 KB PE32 launcher stub built with MinGW GCC 15.1.0, sharing an exact compilation timestamp with the unclassified-pe32-nfe-loader payload DLL (ded59ec4). Loads core.dll from the same directory and dispatches its MainCall export, gating execution on GetSystemMetrics / GetDesktopWindow values XOR-folded with 0x41. No C2, no persistence, no payload encryption — a pure two-stage loader designed to detach the malicious DLL from the initial dropper fingerprint.

What It Is

Field Value
SHA-256 ac20be185f5e5d931516336e80d7c3fd3adda6519418877de50181acf6986873
Filename jotkyalz.exe ^[triage.json:5]
Type PE32 executable (GUI) Intel 80386, stripped ^[file.txt]
Size 4,096 bytes ^[triage.json:13]
Compiler GCC: (i686-posix-dwarf-rev0, Built by MinGW-Builds project) 15.1.0 ^[strings.txt:14]
Linker 2.44 (PE Optional Header) ^[pefile.txt:51]
Compiled Fri May 15 06:16:29 2026 UTC ^[pefile.txt:39]
Base 0x18000000 ^[rabin2-info.txt]
Signed No ^[rabin2-info.txt:27]
PDB None (stripped to external PDB) ^[file.txt]
Sections .pko, .rdata, .eh_fram, .bss, .idata, .rsrc, .reloc (7 sections) ^[pefile.txt]

Family ascription: Medium-confidence sibling of ded59ec4 (unclassified-pe32-nfe-loader). Evidence: byte-identical compilation timestamp (0x6A06BA3D), matching MinGW toolchain, shared core.dll/MainCall strings, and complementary functionality (this binary loads the DLL that ded59ec4 implements). ^[pefile.txt:39] ^[/intel/analyses/ded59ec4522cc19e2ae926ba1938452f70d8739d687154b9150141dc79af294c.html]

How It Works

Launcher Logic Flow

  1. Environment probe. Calls GetSystemMetrics(0) (screen width in pixels) and GetDesktopWindow() (desktop window handle). ^[r2:entry0] ^[pefile.txt:297]
  2. Anti-sandbox gate. XORs the two results together, stores the value in .bss at 0x18004000, then XORs the stored value with 0x41. ^[r2:entry0]
  3. DLL load. Calls LoadLibraryA("core.dll"). The string lives in .rdata at RVA 0x2001. ^[r2:entry0] ^[strings.txt:7]
  4. Export resolution. Calls GetProcAddress(hMod, "MainCall"). The export-name string is at RVA 0x2009. ^[r2:entry0] ^[strings.txt:8]
  5. Dispatch. If GetProcAddress succeeds, calls the resolved function pointer with lpCmdLine (or a pointer to .rdata base if the command line is empty). ^[r2:entry0]
  6. Failure path. If LoadLibraryA or GetProcAddress fails, calls FreeLibrary (on whatever handle it has) and returns status code 2 (ENTRY_NOT_FOUND). ^[r2:entry0]

IAT Profile

The binary imports exactly five APIs — the absolute minimum needed for this workflow: ^[pefile.txt:275]

DLL API Use
KERNEL32.dll FreeLibrary Cleanup on failure
KERNEL32.dll GetProcAddress Resolve MainCall export
KERNEL32.dll LoadLibraryA Load core.dll
USER32.dll GetDesktopWindow Environment probe / gate input
USER32.dll GetSystemMetrics Environment probe / gate input

No network APIs, no file-write APIs, no registry APIs — everything else is delegated to core.dll.

Decompiled Behavior

Entry point (entry0 @ 0x18001060):

push esi
push ebx
sub esp, 0x14

// GetSystemMetrics(0) — screen width
mov dword [esp], 0
call dword [sym.imp.USER32.dll_GetSystemMetrics]
mov esi, eax          // esi = screen width

// GetDesktopWindow() — desktop HWND
call dword [sym.imp.USER32.dll_GetDesktopWindow]

// XOR gate: store screen width in .bss, then XOR with desktop handle
mov edx, dword [section..bss]
mov dword [esp], str.core.dll
xor esi, edx
mov dword [section..bss], esi
mov edx, dword [section..bss]
xor eax, edx
mov dword [section..bss], eax
mov eax, dword [section..bss]
xor eax, 0x41
mov dword [section..bss], eax

// LoadLibraryA("core.dll")
call dword [sym.imp.KERNEL32.dll_LoadLibraryA]
mov esi, eax
sub esp, 4
mov eax, 1
test esi, esi
jz  fail_path

// GetProcAddress(esi, "MainCall")
lea eax, [str.MainCall]
mov dword [esp+4], eax
mov dword [esp], esi
call dword [sym.imp.KERNEL32.dll_GetProcAddress]
sub esp, 8
test eax, eax
jz  fail_path

// Call MainCall with lpCmdLine (or .rdata base if zero)
mov ebx, dword [arg_28h]   // lpCmdLine
test ebx, ebx
mov edx, section..rdata
cmove ebx, edx
mov dword [esp], ebx
call eax                   // dispatch to MainCall

fail_path:
mov dword [esp], esi
call dword [sym.imp.KERNEL32.dll_FreeLibrary]
mov eax, 2
sub esp, 4

Control-flow notes: The gate logic is brittle — .bss is zero-initialized, so GetSystemMetrics(0) ^ 0 yields the raw screen width, then desktop_handle ^ screen_width ^ 0x41 is stored. The result is never used as a branch condition; it is simply written to .bss and the code proceeds regardless. This suggests the gate may be a stub or placeholder (the real gate could live inside core.dll), or the XOR loop is intended as an anti-static obfuscation trick rather than a runtime sandbox guard. ^[r2:entry0]

C2 Infrastructure

None. No network APIs, no URLs, no IPs, no mutexes. The binary is a pure local loader.

Interesting Tidbits

  • Build twin: The TimeDateStamp field (0x6A06BA3D) is byte-identical to ded59ec4, indicating these two binaries were produced by the same build invocation (same Makefile / CMake / batch script) on May 15 2026 at 06:16:29 UTC. ^[pefile.txt:39]
  • Self-description paradox: The .rdata string block contains the text "Application launcher v1.0", "Initialization sequence: load -> resolve -> dispatch -> exit", and status-code definitions (OK=0, MODULE_NOT_FOUND=1, ENTRY_NOT_FOUND=2). For a 4 KB stub this is unusually verbose and readable — the author either does not expect static analysis or is testing detection pipelines with obvious keywords. ^[strings.txt:9-13]
  • .pko section name: The code section is named .pko instead of the standard .text. This is not a normal MinGW/GCC default; it was renamed post-link or via a custom linker script. It serves as a minor fingerprint for this build cluster. ^[pefile.txt:84]
  • High null-padding: File size is exactly 4,096 bytes (one page), yet ~45% is null padding, and pefile warns that "Byte 0x00 makes up 64.5% of the file's contents." This is consistent with a minimal object file padded to the nearest alignment boundary. ^[pefile.txt:3]
  • No TLS, no exceptions, no bound imports: The PE is stripped to the absolute essentials — no debug directory, no bound imports, no load config, no COM descriptor. The only data directory present is imports, resources (XML manifest), and base relocations. ^[pefile.txt:224-273]

How To Mess With It (Homelab Replication)

Toolchain: MinGW-w64 i686-posix-dwarf-rev0 GCC 13.x/15.x with GNU ld 2.44 Target: PE32 executable, Windows GUI subsystem

  1. Write a minimal C launcher:
#include <windows.h>

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmdLine, int nShow) {
    DWORD sm = GetSystemMetrics(0);
    HWND  desk = GetDesktopWindow();
    DWORD gate = sm ^ (DWORD)desk ^ 0x41;

    HMODULE hMod = LoadLibraryA("core.dll");
    if (!hMod) return 1;

    typedef void (*MainCall_t)(LPCSTR);
    MainCall_t MainCall = (MainCall_t)GetProcAddress(hMod, "MainCall");
    if (!MainCall) { FreeLibrary(hMod); return 2; }

    MainCall(lpCmdLine ? lpCmdLine : "");
    FreeLibrary(hMod);
    return 0;
}
  1. Compile with:
i686-w64-mingw32-gcc -mwindows -s -o launcher.exe launcher.c
  1. Rename .text to .pko with a hex editor or objcopy:
objcopy --rename-section .text=.pko launcher.exe
  1. Verification: Run rabin2 -I launcher.exe and confirm lang: c, linker 2.44, 7 sections, and 5 imports matching the profile. Compare ssdeep output to the sample (expect identical match on a near-clone).

Deployable Signatures

YARA — MinGW Launcher Stub

rule unclassified_pe32_nfe_loader_launcher : loader {
    meta:
        description = "4 KB MinGW launcher stub loading core.dll / MainCall"
        author      = "Titus"
        date        = "2026-06-06"
        sha256      = "ac20be185f5e5d931516336e80d7c3fd3adda6519418877de50181acf6986873"
    strings:
        $s1 = "core.dll" ascii wide
        $s2 = "MainCall" ascii wide
        $s3 = "Application launcher v1.0" ascii
        $s4 = "Initialization sequence: load -> resolve -> dispatch -> exit" ascii
        $s5 = "GCC: (i686-posix-dwarf-rev0, Built by MinGW-Builds project) 15.1.0" ascii
        $s6 = "Status codes: OK=0, MODULE_NOT_FOUND=1, ENTRY_NOT_FOUND=2" ascii
    condition:
        uint16(0) == 0x5A4D and
        filesize < 8KB and
        (pe.imports("KERNEL32.dll", "LoadLibraryA") and
         pe.imports("KERNEL32.dll", "GetProcAddress") and
         pe.imports("USER32.dll", "GetSystemMetrics") and
         pe.imports("USER32.dll", "GetDesktopWindow")) and
        3 of ($s*)
}

Sigma — Small PE Loading core.dll

title: MinGW Launcher Stub Loading core.dll
logsource:
    product: windows
    service: sysmon
detection:
    selection:
        EventID: 7
        ImageLoaded|endswith: 'core.dll'
        Image|endswith:
            - '.exe'
    filter:
        - ImageSize|lt: 8192
    condition: selection and filter
falsepositives:
    - Legitimate custom launchers named core.dll (very rare)
level: high

IOC List

Indicator Value Type
SHA-256 ac20be185f5e5d931516336e80d7c3fd3adda6519418877de50181acf6986873 Hash
Filename jotkyalz.exe Filename
DLL target core.dll String
Export target MainCall String
Compiler MinGW-Builds GCC 15.1.0 i686-posix-dwarf-rev0 Toolchain
Compilation 0x6A06BA3D (Fri May 15 06:16:29 2026 UTC) Timestamp
Section name .pko PE section

Behavioral Fingerprint

This binary is a minimal PE32 (< 8 KB) with exactly five imports: LoadLibraryA, GetProcAddress, FreeLibrary from KERNEL32.dll, and GetDesktopWindow, GetSystemMetrics from USER32.dll. On execution it probes the desktop environment, loads a companion DLL named core.dll, resolves the export MainCall, and transfers control. No file writes, no registry changes, and no network traffic occur from the launcher itself — all behavior is delegated to the loaded DLL.

Detection Signatures

ATT&CK ID Technique Evidence
T1105 Ingress Tool Transfer Loads core.dll as second-stage payload
T1129 Shared Modules Reflective / standard LoadLibraryAGetProcAddress → call chain
T1497.001 System Checks GetSystemMetrics(0) + GetDesktopWindow() probe before payload load
T1027.002 Software Packing Stripped minimal PE with non-standard .pko section name

References

  • SHA-256: ac20be185f5e5d931516336e80d7c3fd3adda6519418877de50181acf6986873
  • Family: unclassified-pe32-nfe-loader
  • Sibling analysis: /intel/analyses/ded59ec4522cc19e2ae926ba1938452f70d8739d687154b9150141dc79af294c.html
  • OpenCTI artifact: 382964fc-b02a-49b6-adc6-f24d84833ff1

Provenance

  • file.txtfile command output (PE32 executable)
  • pefile.txt — pefile parser (timestamps, sections, imports, directories)
  • strings.txtstrings extraction (ASCII/UTF-16 printable strings)
  • rabin2-info.txt — radare2 rabin2 -I header summary
  • r2:entry0 — radare2 decompilation of entry point at 0x18001060
  • exiftool.json — ExifTool PE metadata
  • binwalk.txtbinwalk -E entropy scan (no embedded archives)
  • triage.json — Triage pipeline metadata (deep tier, no family attribution)
  • floss.txt — flare-floss run failed (tool invocation error, no decoded strings)
  • capa.txt — flare-capa run failed (missing signature database)
  • Tool versions: radare2 (latest stable as of 2026-06-06), pefile, binwalk, ExifTool 12.76