Reference / x64 support

x64 support

SysAnalyzer is a 32-bit Visual Basic 6 application. The Win32 API surface a 32-bit process can use against a 64-bit target is restricted — EnumProcessModules, VirtualQueryEx, ReadProcessMemory, and CreateRemoteThread all behave differently or fail outright across the bitness boundary. To handle 64-bit targets transparently, SysAnalyzer ships a small native 64-bit helper executable that runs as a child process and feeds results back through stdout.

x64Helper.exe

x64Helper.exe is a self-contained 64-bit command-line tool. It is invoked by SysAnalyzer through the Cx64 wrapper class, which captures stdout via the GetCommandOutput helper (15- or 25-second timeout) and parses CSV lines. Most users never see it directly, but it can be run from a shell for ad-hoc 64-bit inspection.

The helper enables SeDebugPrivilege on startup and runs a 13-second internal watchdog thread to prevent indefinite hangs during malware-triggered edge cases.

Command-line interface

x64Helper.exe /command [args...]

Forward slashes and dashes are interchangeable (-inject behaves the same as /inject). All commands write CSV or status lines to stdout; the calling code looks for Error: as the failure prefix.

CommandArgsAction
/injectdecimal_pid dll_pathInject the specified DLL into a running process via CreateRemoteThread(LoadLibraryA). Pre-loads the API-logger dependency DLLs first (advapi32, ole32, oleaut32, wininet, urlmon, ws2_32) so the injected DLL's DllMain can resolve hook targets without calling LoadLibrary under loader lock.
/startwdllexe_path dll_path [args...]Launch a process suspended, pre-load the API-logger dependency DLLs, inject the given DLL, then resume. The exe is launched with STARTF_USESHOWWINDOW + SW_SHOWNORMAL + CREATE_NEW_CONSOLE so the sample's windows are visible regardless of whether SysAnalyzer launched the helper hidden. Optional args are folded into the child's command line, with quoting added for any args containing spaces.
/loadlibfile_path [export [cdecl]]LoadLibrary the given DLL into the helper process itself, optionally calling a named export. Without cdecl the export is invoked as __stdcall. Used by SysAnalyzer for "launch a 64-bit DLL directly" from the wizard's Executable field.
/dllsdecimal_pidEnumerate modules loaded into the target. Output is CSV: base,size,path, one module per line. Hex base/size, decimal-formatted size suffix.
/dumpprocessdecimal_pid out_file_pathDump the main module image of the target. Resolves the base via EnumProcessModulesEx, then writes SizeOfImage bytes to disk in 10-MB chunks (avoids large-allocation hangs).
/dumpmoduledecimal_pid hex_base hex_size out_file_pathDump an arbitrary memory range. Same chunking behavior. Refuses to overwrite an existing file.
/memmapdecimal_pid [out_file_path | -c] (or pid: -32, -64, -1)Walk the address space via VirtualQueryEx and emit CSV: va,AllocationBase,Size,AllocationProtect,Type,Protect,State,ModuleFileName. -c prints only the allocation count. Negative pid values run a system-wide scan: -32 for 32-bit processes only, -64 for 64-bit, -1 for all. Capped at 25,000 allocations per process to avoid runaway loops.
/procs[32 | 64 | strMatch]List running processes. With 32 or 64, filter by bitness. With any other string, treat as a case-insensitive substring match against the process name.
Run interactively: when the helper is launched under a debugger (or invoked manually with no caller), it prompts press any key to exit after the operation completes. SysAnalyzer's GetCommandOutput path doesn't trigger this since IsDebuggerPresent returns false in the helper's own process.

Where SysAnalyzer calls the helper

The integration points are in Cx64.cls:

MethodHelper commandCaller in SysAnalyzer
x64StartWithDll/startwdllAPI Logger launching a 64-bit target with api_log.x64.dll.
x64Inject/injectAPI Logger attaching to a running 64-bit PID.
x64LoadLib/loadlibWizard launching a 64-bit DLL as the analysis target.
GetMemoryMap/memmapRWE injection scanner, deep memory scanner, and Memory Map right-click against a 64-bit process.
GetProcessModules/dllsPer-process Analyze dumping unknown DLLs in 64-bit processes.
DumpMemory/dumpmodulePer-DLL memory dump in Analyze; right-click Dump Module; RWE region dumps.
DumpProcess/dumpprocessRight-click Dump on a 64-bit process row.

Each method first verifies the target is genuinely 64-bit (via IsWow64Process) and that the helper exists on disk; if either check fails, the wrapper returns an error string in out_injLog instead of invoking the helper.

WoW64 file-system redirection

A 32-bit process accessing C:\Windows\System32 is silently redirected to C:\Windows\SysWOW64. This breaks anything that needs to find x64Helper.exe, hand it a path under System32, or read 64-bit DLL files for PE analysis.

Cx64 wraps every file access in a DisableRedir / RevertRedir pair around Wow64DisableWow64FsRedirection / Wow64RevertWow64FsRedirection. The pair is reference-counted — nested calls are coalesced — so callers don't have to track whether they're inside an outer disable scope.

If your code calls into Cx64 from a routine that itself touched the file system under disabled redirection, this is safe. Calling raw VB Open, Dir, or FileCopy outside that scope from elsewhere is not safe and may quietly resolve the wrong file.

Helper discovery

Cx64 looks for x64Helper.exe in App.Path and walks up to four parent folders. The IDE-vs-installed layout is:

The path is resolved once at class init via GetShortPathName — the helper command line uses the 8.3 short form to avoid quoting issues with long paths and spaces.

SeDebug

The wrapper enables SeDebugPrivilege in the SysAnalyzer process at Cx64.Class_Initialize. Without it, OpenProcess against protected processes (anti-malware, system services) returns access-denied. The helper itself enables it again on its own startup.

The current state is exposed as Cx64.isSeDebugEnabled for diagnostic purposes; frmListProcess shows it in the window caption.

Failure modes

SymptomCause
Error: failed to open processInsufficient privilege (SeDebug not granted) or target is a protected process.
Error: dll file not foundPath resolved against the wrong WoW64 view, or genuinely missing. Confirm via where in a 64-bit shell.
Error: Watchdog timeoutThe helper's 13-second timer expired. The helper aborts; the wrapper sees error output. Most often hit during massive memory-map scans on processes with tens of thousands of allocations.
preload [dll]: LoadLibraryA returned NULL in targetThe dependency DLL doesn't exist on this Windows SKU (typically urlmon on stripped-down Server installs). Non-fatal — the corresponding hooks just won't install. Other hooks proceed normally.
Wrapper returns true but no dataThe 15-second GetCommandOutput timeout fired before the helper finished. Re-run with the helper directly to see full output.

Source

The helper source is a single C++ file (main.cpp) under source/x64Helper/. The VB6 wrapper is source/sysanalyzer/Cx64.cls.