Bypass Detection·Jun 6, 2026

Notepad Bypass: fa817dc1 Full Reversal & Detection

Complete static analysis of a FiveM bypass that poses as notepad.exe. The binary ships with six completely hollowed virtual PE sections and stores its entire encrypted payload in a custom .tiko section reaching 7.88/8.0 entropy. A ROL-XOR decryption cipher with key 0x32063cae decodes API strings at runtime, while the stub IAT reveals NtQuerySystemInformation anti-debug, CPU affinity manipulation, and Terminal Services cross-session messaging. No PDB path leaked — the developer stripped the debug directory.

FiveMBypass DetectionYARACustom PackerROL-XOR CipherAnti-DebugCPU Affinity AbuseWTS Cross-SessionAdmin RequiredNo PDB

Defensive use only. Detection methodologies published for server administrators, DFIR practitioners, and anti-cheat researchers. No evasion guidance is provided.

File Identity

The sample is a 64-bit Windows PE executable, 4.90 MB on disk, distributed under the filename notepad.exe to blend in with the legitimate Windows text editor. Despite the benign name, the binary has no relationship to Microsoft Notepad — it is a packed bypass loader with the entire payload encrypted inside a single custom section.

MD5340753116751ef6f5212667501a0e562
SHA-1ad4d25b43964c1c54accdcbe97a3f2ca80d15894
SHA-256b61907b9081bb5d7125264c5e60de013c02b7b866148248de603fb55f8d39a18
  • Architecture: PE32+ (x86-64), subsystem 3 (Console) — despite the notepad.exe name, no GUI window is created by the stub; the real payload may spawn one
  • Compile timestamp: 0x6514b842 2023-09-27 23:18:26 UTC — plausible; not zeroed or far-future, suggesting the developer did not manipulate it
  • Checksum: 0x00000000 (zeroed — standard for packed/modified PE files)
  • SizeOfImage: 0x0089F000 (9,109,504 bytes / ~8.7 MB) — the virtual footprint after all sections are mapped, significantly larger than the 4.9 MB on-disk file due to the six virtual sections that contain no file data but occupy address space; this value appears in Windows AppCompatCache and PcaSVC records alongside the file path and is a useful secondary indicator
  • DllCharacteristics: 0x8160 — DYNAMIC_BASE (ASLR), HIGH_ENTROPY_VA, NX_COMPAT (DEP), TERMINAL_SERVER_AWARE all set
  • Manifest: requireAdministrator — UAC elevation is demanded on launch
  • Debug directory: absent — no PDB path, no CodeView record. The developer stripped the debug directory before distribution, unlike the ApateonDecoy/Wizard sample which leaked a full PDB path
  • Rich header: not present — the DOS stub area contains no Rich marker, either stripped or never generated (uncommon for MSVC builds; may indicate use of a third-party linker or post-link PE manipulation)

PE Section Analysis — Six Hollow Sections, Single Encrypted .tiko Payload

Nine sections are declared in the section table. Six of them — .gala, .xys23, .prom, .ax512, _gbit_, and .2024 — have a raw size of zero and contain no file data. Their virtual sizes and section headers exist solely to inflate the apparent complexity of the PE for superficial scanners. All executable code, decryption routines, and the encrypted real payload are consolidated into the single .tiko section.

SectionVirtual sizeRaw sizeEntropyNotes
.gala186 KB0 bytesHollowed CODE section — header only, no file data
.xys23101 KB0 bytesHollowed DATA section — header only
.prom889 KB0 bytesHollowed RW DATA — largest virtual ghost section
.ax51210.7 KB0 bytesHollowed DATA section
_gbit_348 B0 bytesHollowed DATA section — underscore name unusual
.20242.53 MB0 bytesHollowed CODE section — year-based name, no content
.tiko4.99 MB4.90 MB7.88Entire encrypted payload + real IAT + stub code; EP here
.limco224 B512 B2.10Base relocation / IAT pointer array — near-zero entropy
.dino480 B512 B4.77Resource section — requireAdministrator manifest

The .tiko section records a Shannon entropy of 7.88 out of a theoretical maximum of 8.0. This is near-perfect randomness, consistent with AES, ChaCha20, or a custom symmetric cipher applied to the entire payload before packing. Static string scanning of this region produces no readable plaintext or API names, ruling out simple XOR obfuscation applied to a plaintext binary.

The binary's entry point (RVA 0x3C4A87, VA 0x1403C4A87) lands inside .tiko at offset 0xEA87 (59 KB into the section, 1.2% of its size). The first executed instruction is PUSH 0x19BAB67 — a seed constant passed to the root bootstrap function at 0x140853D23. This is structurally different from the Wizard variant, which embeds its bootstrap at 47.3% into its .zyw section via a CALL-slalom chain. Section names .tiko, .limco, .dino, .gala, .xys23, .prom, .ax512, _gbit_, and .2024 are all non-standard and constitute reliable static indicators — no legitimate software ships with this combination of section names.

Structurally this binary belongs to the same packer family as ApateonDecoy / Wizard bypass — both use a single high-entropy payload section, six or more hollowed virtual sections, identical dynamic API resolution logic via PE export table walking, and the same ROL-XOR decryption constant. The section names differ between samples, indicating the packer re-randomises names per build.

Entry Point & Bootstrap Sequence

Ghidra headless analysis identifies 16 functions in the visible (non-encrypted) portion of the binary. The remaining code is unreachable until the runtime decryptor unpacks the payload into memory.

The entry point at 0x1403C4A87 executes exactly three instructions before jumping to the main decryption bootstrap:

1403c4a87 PUSH 0x19bab67; bootstrap argument / seed
1403c4a8c CALL FUN_140853d23; decryption + mapping routine
1403c4a91 JMPF 0xdbae:0x841dcc38; far jump — obfuscated flow

The far jump (JMPF) after the call is deliberately placed but unreachable in practice —FUN_140853d23 does not return in the normal case. This is a common obfuscation tactic to confuse linear-sweep disassemblers into following the wrong execution path.

FUN_140853d23 (108 bytes) is the root of the bootstrap chain. It sets up the decryption key, calls into FUN_1407522af (the 1,279-byte main resolver), and orchestrates mapping the decrypted payload before transferring control. The argument 0x19bab67 pushed before the call is used internally as an initial state value for the cipher or as a hash seed — it appears nowhere else in the stub and is not a valid Windows API ordinal.

Decryption Engine — ROL-XOR Cipher with Key 0x32063cae

The core API-string and payload decryption cipher is implemented in FUN_1407522af (1,279 bytes) and reused verbatim in FUN_140752798 (373 bytes). Both functions contain the identical decryption loop at different offsets.

The cipher is a position-dependent ROL-XOR scheme:

; key init (position counter in ECX / EDI)
MOV eax, 0x32063cae; constant key
ROL eax, cl; rotate by position (0–7 bits)
ADD al, dil; mix in position index low byte
XOR al, byte ptr [rdx+rbp]; XOR against ciphertext byte
MOV byte ptr [rdx], al; write plaintext in-place
INC rbp; advance position counter

The key 0x32063cae appears at two independent call sites — once in FUN_1407522af at 0x140752502 and again in FUN_140752798 at 0x1407527d9. Its presence at both sites confirms it is the primary decryption constant and not a coincidental immediate value.

This cipher decrypts API name strings on demand: rather than storing plaintext DLL and function names in readable memory, the stub stores them encrypted and decrypts each one immediately before calling LoadLibraryA or GetProcAddress. After the call resolves, the decrypted string may be re-encrypted or discarded. This prevents memory-scanning tools from locating hidden API names at rest.

The loop iterates up to 0x104 (260) bytes per string — the maximum Windows API name length — and terminates at a null decrypted byte. The decrypted output lands in a stack buffer at rsp+0x50 before being passed to GetModuleHandleA or LoadLibraryA.

Dynamic API Resolution — PE Export Table Walk + Hash Comparison

In addition to decrypting API names before passing them to GetProcAddress, the binary implements a manual PE export table walker in FUN_1407522af. This allows it to resolve exports from already-loaded modules without ever calling GetProcAddress — bypassing API-level hooks placed by EDR products.

The walker sequence, confirmed by disassembly:

; validate MZ + PE signature
MOV eax, 0x5A4D; 'MZ'
CMP word ptr [rcx], ax
MOVSXD rax, dword ptr [rcx + 0x3c]; e_lfanew
CMP dword ptr [rax + rcx], 0x4550; 'PE\0\0'
; load export directory
MOV r8d, dword ptr [rax + rcx + 0x88]; export dir RVA (PE32+ offset)
; binary search over NumberOfNames
LEA r11d, [rax - 1]; r11 = NumNames - 1
MOV ebx, edi; ebx = low = 0
; mid = (low+high)/2 via SAR 1
SAR eax, 1
MOV r8d, dword ptr [r9 + rax*4]; AddressOfNames[mid]

The walker performs a binary search over the export name pointer array, comparing each candidate name against the decrypted target string one character at a time. When a match is found, it resolves the corresponding ordinal and function address. This technique completely avoids the hooked GetProcAddress entry point while still finding the correct function.

When a module is not already loaded, the stub falls back to LoadLibraryA via the decrypted name path (call site at 0x1406131A7), loads it, then re-enters the walk loop against the newly loaded DLL. The resolver recurses into itself (CALL 0x1407522af at 0x1407528D7) to handle nested dependencies.

Import Analysis — Stub IAT Reveals Intended Capabilities

The visible import table (located inside .tiko) contains 19 imports across five DLLs. This is the minimum surface needed to bootstrap the runtime — every other API used by the real payload is resolved dynamically and leaves no trace in the static import table.

Dynamic resolution bootstrap (KERNEL32.dll)

  • LoadLibraryA — load arbitrary DLLs by decrypted name
  • GetProcAddress — named export resolution fallback
  • GetModuleHandleA — locate already-loaded modules without LoadLibrary overhead

These three APIs together reconstruct the entire Windows API surface at runtime. All remaining capability is hidden behind these three entry points.

Anti-debug / anti-sandbox (ntdll.dll + KERNEL32.dll + USER32.dll)

  • ntdll!NtQuerySystemInformation — queried directly from ntdll to bypass higher-level KERNEL32 hooks; with class SystemKernelDebuggerInformation (0x23) this detects kernel debuggers; with SystemProcessInformation it enumerates running processes to check for sandbox agents
  • KERNEL32!GetSystemTimeAsFileTime — high-resolution timing used to detect time-acceleration in sandboxes; if elapsed time between two calls is implausibly small the binary halts
  • KERNEL32!Sleep — deliberate delay to outlast sandbox analysis windows; many automated sandboxes do not wait past 60–90 seconds
  • USER32!GetProcessWindowStation + USER32!GetUserObjectInformationW — checks whether the process is running inside an interactive desktop session; sandbox and headless environments typically return a non-interactive window station (WinSta0 vs service window stations)

CPU affinity manipulation (KERNEL32.dll)

  • GetProcessAffinityMask — read the current process and system CPU affinity masks
  • SetProcessAffinityMask — restrict the process to specific CPU cores
  • SetThreadAffinityMask — restrict individual threads to specific cores

Affinity manipulation serves multiple goals: (1) single-core sandboxes often expose only one CPU bit in the affinity mask, which the binary can detect; (2) pinning decryption threads to specific cores can frustrate time-based analysis tools; (3) in the real payload, affinity control may be used to interfere with game anti-cheat threads that run on specific cores.

Cross-session messaging (WTSAPI32.dll)

  • WTSSendMessageW — sends a message box to a specific Terminal Services / Remote Desktop session. Unlike MessageBoxW which targets the calling session, WTSSendMessageW can target any active session by session ID, including Session 0 (services) or other logged-in users

This is unusual in a FiveM bypass context. Likely uses: displaying a status dialog in a specific session after injection completes, or probing which sessions are active as part of environment fingerprinting. Requires SeImpersonatePrivilege or matching session ownership.

Memory & process utilities (KERNEL32.dll + ADVAPI32.dll)

  • LocalAlloc / LocalFree — heap allocation for decrypted buffers
  • GetModuleFileNameW — retrieves the binary's own on-disk path; used for self-deletion or path-based checks (confirming it is running from the expected location)
  • FreeLibrary — unloads modules loaded during resolution (cleanup after dynamic loading)
  • ExitProcess — clean process termination if anti-debug checks fire
  • ADVAPI32!RegCloseKey — registry key handle cleanup after reading from the registry
  • KERNEL32!GetCurrentThreadId — obtains the calling thread ID; used in thread-local storage (TLS) callbacks or for timing measurements

Export Table Abuse — Encrypted Binary Blob as Export Name

The PE export directory declares exactly one export (ordinal 1, base 1). The function address RVA is 0x00000000 — a null pointer that would crash if actually called. The export exists purely to anchor the export name entry.

The “name” of this export, instead of a readable ASCII identifier, is a 3,100-byte binary blob with Shannon entropy of 7.94/8.0 — statistically indistinguishable from random data. This is encrypted content embedded where export name strings normally live. Tools that parse the export table looking for DLL name or function name strings will either crash, truncate at the first unexpected byte, or display garbage.

Export count1 (ordinal base 1)
Func address0x00000000 (null — never called)
Name blob size3,100 bytes
Name entropy7.9425 / 8.0

The 3,100-byte blob is almost certainly a configuration block, decryption table, or secondary payload fragment stored in the export name slot because it is a convenient location that many parsers overlook or mishandle. The loader accesses it by navigating the export directory directly via the PE walk routine — not via any normal name-resolution API.

Anti-Analysis Techniques — Full Breakdown

The stub layer implements multiple independent anti-analysis and anti-debug measures before the real payload is mapped. Each technique targets a different analysis environment.

1 — Kernel debugger detection via NtQuerySystemInformation

NtQuerySystemInformation is imported directly from ntdll.dll rather than going through IsDebuggerPresent or CheckRemoteDebuggerPresent in KERNEL32. This bypasses any hooks that security tools place on the higher-level KERNEL32 wrappers. Querying with class 0x23 (SystemKernelDebuggerInformation) checks the kernel debug flag at the lowest possible level.

2 — Window station / interactive desktop check

GetProcessWindowStation retrieves the process window station handle, then GetUserObjectInformationW with UOI_NAME reads its name. An interactive user session has station name WinSta0. Sandboxes running under service accounts or headless environments return different names (Service-0x0-xxx$, etc.). If the name does not match an expected interactive session, the binary exits cleanly via ExitProcess.

3 — CPU core count fingerprinting

GetProcessAffinityMask returns the process affinity mask. By counting set bits, the binary determines how many CPU cores are available. Most sandboxes expose only 1–2 cores. A typical gaming machine has 8–32 cores. If the popcount of the affinity mask falls below a threshold, the binary treats the environment as a sandbox and terminates.

4 — Timing / sleep evasion

GetSystemTimeAsFileTime is called before and after a Sleep of a known duration. The delta is compared against the expected elapsed wall-clock time. Sandboxes that accelerate time (by advancing system clocks) or that patch Sleep to return immediately will produce a suspiciously small delta, triggering abort.

5 — Registry query (ADVAPI32!RegCloseKey)

The presence of RegCloseKey in the stub IAT — but no RegOpenKey or RegQueryValue — indicates those open/query functions are resolved dynamically. The registry is likely queried for sandbox-specific keys (e.g., VirtualBox guest additions, VMware, Sandboxie registry artifacts) or for license/HWID validation.

6 — Export table obfuscation / parser confusion

The 3,100-byte encrypted blob stored as the export function name causes many PE parsers and automated tools to misrepresent or skip the export directory. This is a deliberate measure to degrade analysis quality in tools that are not hardened against malformed export names.

7 — No PDB / stripped debug directory

Unlike the ApateonDecoy/Wizard sample (which leaked DecoyLoader.pdb with the developer's username apx), this binary has no debug directory at all. The developer either configured /DEBUG:NONE at link time or stripped the debug directory post-build. This eliminates one of the most useful static attribution vectors.

Timestamp Analysis

The COFF header timestamp is 0x6514b842, which decodes to 2023-09-27 23:18:26 UTC. Unlike the ApateonDecoy/Wizard sample (timestamped 2026-01-01 — manipulated to a future date), this timestamp falls within a plausible range for a real build date. It is not zeroed, not in the distant future, and corresponds to a Wednesday evening in late September 2023.

  • The timestamp alone does not prove the binary was compiled on that date — MSVC timestamps can be set arbitrarily — but its plausibility suggests less attention to anti-forensics in this dimension
  • Assuming the timestamp is authentic, the binary predates the ApateonDecoy/Wizard sample by roughly 27 months, suggesting a shared packer codebase that has been reused and distributed over an extended period
  • SizeOfImage 0x89F000 appears in Windows AppCompatCache/PcaSVC shimcache records paired with the executable path — this value combined with the SHA-256 hash provides a reliable historical detection artifact even after the file is deleted

Stub Function Map — All 16 Visible Functions

Ghidra headless analysis identifies 16 functions in the non-encrypted stub layer. The bulk of functionality lives in the encrypted .tiko payload and is only visible after runtime decryption. Functions are listed by address, size, and role.

AddressSizeNameRole
0x1403C4A8717 BentryEntry point — PUSH seed → CALL bootstrap → JMPF (dead code)
0x1406252EB15 BFUN_1406252ebFinal loader trampoline — CALL RAX (resolved fn ptr), stack cleanup, JMP to resolver
0x1407522AF1279 BFUN_1407522afMain API resolver — MZ/PE validation, export table walk, binary search, ROL-XOR decryptor, LoadLibraryA fallback, recursive entry
0x140752798373 BFUN_140752798GetProcAddress caller — second ROL-XOR loop (key 0x32063cae), ordinal-by-number fallback, self-recursive for nested resolution
0x1407556AF87 BFUN_1407556afStack frame switcher — saves RBP/RSP, aligns stack, JMPs to JMP-R8 trampoline
0x1407557B75 Bthunk_FUN_1407bcf28Thunk — short JMP to FUN_1407bcf28
0x1407938F79 BFUN_1407938f7NOT+ROL obfuscation stub — NOT ECX, ROL ECX,1, JMP to FUN_140860bb7
0x1407AC0B62 BFUN_1407ac0b6PUSH RBP + RET — minimal stub, used as call target to capture return address
0x1407BCF2817 BFUN_1407bcf28Stack bounds check — LEA R9,[RSP+0x140], CMP RBX R9, JMP to stack switcher
0x140817C0F3 BFUN_140817c0fJMP R8 — indirect dispatcher
0x140836B1521 BFUN_140836b15ADD R11,4 (advance ptr), CMC, XOR ECX R9D obfuscation, JMP to NOT+ROL stub
0x1408370FA14 BFUN_1408370faMOVSXD RCX, pointer arithmetic ADD R8 RCX, JMP thunk
0x140853D23108 BFUN_140853d23Root bootstrap — called from entry point; sets up decryption context, drives loader chain
0x140860BB741 BFUN_140860bb7INC+BSWAP+XOR obfuscation trampoline, MOD stack, JMP to PUSH RBP stub
0x14086CE7C179 BFUN_14086ce7cROR/XOR/NEG arithmetic on stack value — appears to be a hash function or checksum stub
0x140876C626 BFUN_140876c62CLD + JMP — clears direction flag, dispatches to next stage

The patterned obfuscation stubs (FUN_1407938f7, FUN_140860bb7, FUN_14086ce7c, etc.) exist to break up the control flow graph and prevent disassemblers from cleanly following execution. They interleave meaningless arithmetic operations (CMC, STC, CLC, BSWAP on partially-used registers) with the real logic. This is a known obfuscation technique called junk instruction insertion — the junk instructions have no net effect on program state but dramatically increase the number of nodes in the control flow graph.

Packer Family — Same Architecture as ApateonDecoy/Wizard

This binary and the ApateonDecoy/Wizard bypass sample share a common packer architecture. The following structural features match exactly:

  • Single high-entropy payload section (7.82 in Wizard's .zyw vs 7.88 in this sample's .tiko) containing all executable code
  • Six or more hollowed virtual sections with no raw file data
  • Identical ROL-XOR decryption cipher with key 0x32063cae present in both samples at corresponding function positions
  • Manual PE export table walker for API resolution, bypassing hooked GetProcAddress
  • Import stub limited to {LoadLibraryA, GetProcAddress, GetModuleHandleA} plus capability imports
  • requireAdministrator UAC manifest in both samples
  • Entry point inside the encrypted payload section
  • Zeroed PE checksum

Section names differ between samples (.zyw / .3L9 / .64X vs .tiko / .limco / .dino / .gala, etc.), indicating the packer re-randomises or regenerates section names per build. The underlying packer code and decryption key, however, are consistent — suggesting either the same individual built both, or a shared packer-as-a-service tool is in use.

Primary Indicators of Compromise

SHA-256b61907b9081bb5d7125264c5e60de013c02b7b866148248de603fb55f8d39a18
SHA-1ad4d25b43964c1c54accdcbe97a3f2ca80d15894
MD5340753116751ef6f5212667501a0e562
Filenamenotepad.exe (spoofed — not the real Windows notepad)
File size5,142,528 bytes (4.90 MB)
Timestamp0x6514b842 → 2023-09-27 23:18:26 UTC
SizeOfImage0x0089F000 (AppCompatCache artifact)
Decrypt key0x32063cae (ROL-XOR constant — shared with ApateonDecoy/Wizard)
.tiko entropy7.8848 / 8.0
Export blob3,100 bytes, entropy 7.9425 — encrypted payload fragment
EP VA0x1403C4A87 (first instruction: PUSH 0x19bab67)
  • Behavioural: demands UAC elevation, enumerates CPU cores via affinity mask, queries window station name, calls WTSSendMessageW cross-session, reads registry keys dynamically
  • Memory: at runtime the decrypted payload will be mapped into a newly allocated RWX region; look for unsigned executable pages not backed by a file on disk
  • Network: not determinable from static analysis — the real payload is encrypted

YARA Detection Rule

The following rule targets both this specific sample and future builds from the same packer family. Two variants are provided — a tight single-sample rule and a broader family rule.

rule NotepadBypass_fa817dc1_Exact {
    meta:
        description = "Exact match: notepad.exe bypass (fa817dc1)"
        hash_sha256 = "b61907b9081bb5d7125264c5e60de013c02b7b866148248de603fb55f8d39a18"
        date = "2026-06-06"

    strings:
        // ROL-XOR decryption key constant (little-endian DWORD)
        $key = { AE 3C 06 32 }
        // Bootstrap seed pushed at entry point
        $seed = { 68 67 AB B9 01 }
        // Section name strings
        $sec_tiko  = ".tiko"  ascii wide
        $sec_limco = ".limco" ascii wide
        $sec_gala  = ".gala"  ascii wide

    condition:
        uint16(0) == 0x5A4D and filesize < 8MB and
        $key and $seed and ($sec_tiko or $sec_limco or $sec_gala)
}

rule NotepadBypass_PseudoPacker_Family {
    meta:
        description = "PseudoPacker family — covers fa817dc1 and ApateonDecoy/Wizard variants"
        author = "Clubhouse AC Research"
        date = "2026-06-06"
        reference = "https://clubhouseac.shop/research/notepad-bypass-detection"

    strings:
        // Shared ROL-XOR key constant
        $rolxor_key = { AE 3C 06 32 }
        // Export table abuse: null function RVA in export directory
        // Manual PE walk: MZ signature check pattern
        $mz_check = { B8 4D 5A 00 00 66 3B 01 }
        // PE sig check immediate
        $pe_check = { 81 3C 08 50 45 00 00 }
        // ApateonDecoy section names
        $sec_zyw   = ".zyw"   ascii
        $sec_3l9   = ".3L9"   ascii
        // This sample section names
        $sec_tiko  = ".tiko"  ascii
        $sec_limco = ".limco" ascii

    condition:
        uint16(0) == 0x5A4D and filesize < 25MB and
        $rolxor_key and
        ($mz_check or $pe_check) and
        ($sec_zyw or $sec_3l9 or $sec_tiko or $sec_limco)
}

Screenshare Detection Methodology

1

File identity — hash and filename check

Check any process named notepad.exe running from an unexpected path (outside C:\Windows\System32\ or C:\Windows\SysWOW64\) against the SHA-256 hash. The real Windows notepad carries a valid Microsoft digital signature — right-click → Properties → Digital Signatures. This file has no signature.

2

PE section names — instant fingerprint

In CFF Explorer or PE-bear: open the section table. Legitimate software never ships sections named .tiko, .limco, .dino, .gala, .xys23, .prom, .ax512, or _gbit_. Any one of these names is sufficient grounds for a ban.

3

Entropy check — single high-entropy section

In Detect-It-Easy or Entropy Analyser: the .tiko section shows 7.88 entropy. Six sections have zero raw data (hollow). This pattern — one near-8.0 section plus multiple empty sections — is the packer signature. A legitimate Notepad binary has multiple moderate-entropy sections.

4

Import table — suspicious stub IAT

Open the import table in any PE viewer. The presence of ntdll!NtQuerySystemInformation, WTSAPI32!WTSSendMessageW, and all three affinity APIs alongside LoadLibraryA / GetProcAddress in a binary claiming to be Notepad is immediately suspicious. Notepad's real import table is entirely different.

5

Manifest — requireAdministrator

Check the embedded manifest in the resource section. The bypass demands administrator rights. The legitimate Windows Notepad runs as a standard user and does not request elevation.

6

Digital signature — absent

The real notepad.exe carries a valid Microsoft Authenticode signature. This binary has no signature at all. Verify in Properties → Digital Signatures or via sigcheck.exe -i notepad.exe. An unsigned Notepad binary is conclusive evidence of tampering.

Detection Notes — Shared Packer Intelligence

Because this binary and ApateonDecoy/Wizard share the decryption key 0x32063cae, a single YARA rule targeting the key constant catches both samples and likely all other builds from the same packer family. Adding the PE export table walk pattern (MZ signature check immediate + PE\0\0 check) narrows false positives without missing variants that change section names.

  • AppCompatCache / ShimCache: the SizeOfImage value 0x89F000 and the file path are cached by Windows PCA service even after the file is deleted. Querying SRUM, Prefetch (NOTEPAD.EXE-XXXXXXXX.pf), and AppCompatCache with path and size allows post-incident detection on endpoints where the file has been cleaned up
  • Memory forensics: the decrypted payload, once mapped at runtime, will appear as an unsigned PE image in memory. Tools like Volatility3 windows.malfind or windows.dlllist will identify the unsigned module
  • Behaviour: a call to WTSSendMessageW from an unsigned process claiming to be Notepad is an extremely high-fidelity detection signal — no legitimate Notepad variant makes this call
  • Affinity manipulation: calls to SetProcessAffinityMask immediately after startup (before any user interaction) from an alleged text editor should be flagged