
Specialized Windows Reverse Engineering & Binary Analysis Toolkit | API Deobfuscation, Call Graphs, Kernel Driver & IOCTL Analysis
Windows Binary Analysis & Reverse Engineering Toolkit
RESX is a specialized Windows SRE and Binary Analysis tool designed to provide a more modern approach to reverse-engineer's & malware analyst's workflows. RESX is specially designed to provide in-depth information about the binary you are analyzing, whether that is via triaging the process's capabilities, identifiying a packer, following API calls through a large function tree, or even reverse-engineering a kernel driver, RESX provides an extended suite of information that is aware of what API's do and which can be for what (eg; malware), driver-constructs, hypervisor-capabilities, and some shortcomings of mainstream disassembly tools.
Let's say I want to quickly figure out what this binary is doing we can invoke the calls command to get a call-graph on the Windows API's it invokes (or any other .dll, CRT, or internal functions if you have PDB). This can very quickly give us a basis and structured indicators on where to look next, depending on the program this can also reveal a significant amount of functionality without even opening a disassembler;
> resx /calls "SAMPLE.exe" ENTRY --depth 4 --only winapi --no-pdb --time
SAMPLE.exe!entry [RVA 0x000023E0, VA 0x1400023E0]
API Call Map for entry [2 of 2 call site(s) · filter: winapi]:
├── 0x23E4 CALL sub_00002770
│ ├── 0x279E CALL KERNEL32!GetSystemTimeAsFileTime
│ ├── 0x27AE CALL KERNEL32!GetCurrentThreadId
│ ├── 0x27BB CALL KERNEL32!GetCurrentProcessId
│ └── 0x27CD CALL KERNEL32!QueryPerformanceCounter
└── 0x23ED JMP sub_00002260 [tail call]
├── 0x236A CALL sub_000019E0
│ ├── 0x1A23 CALL KERNEL32!InitializeSRWLock
│ ├── 0x1A2E CALL KERNEL32!InitializeConditionVariable
│ ├── 0x1A39 CALL sub_00001160
│ │ ├── 0x1179 CALL KERNEL32!CreateWaitableTimerExW
│ │ └── 0x11B6 CALL KERNEL32!SetWaitableTimer
│ ├── 0x1A47 CALL sub_000015B0
│ │ ├── 0x15D0 CALL KERNEL32!VirtualAlloc
│ │ ├── 0x15F2 CALL KERNEL32!VirtualAlloc
│ │ └── 0x1608 CALL KERNEL32!VirtualFree
│ ├── 0x1A55 CALL sub_00001630
│ │ ├── 0x165C CALL KERNEL32!CreateThread
│ │ ├── 0x1672 CALL KERNEL32!AcquireSRWLockExclusive
│ │ ├── 0x167F CALL KERNEL32!ReleaseSRWLockExclusive
│ │ ├── 0x1689 CALL KERNEL32!WakeConditionVariable
│ │ ├── 0x1697 CALL KERNEL32!WaitForSingleObject
│ │ └── 0x16A2 CALL KERNEL32!CloseHandle
│ ├── 0x1A63 CALL sub_00001770
│ │ ├── 0x1795 CALL KERNEL32!VirtualProtect
│ │ └── 0x17C4 CALL KERNEL32!VirtualProtect
│ ├── 0x1A71 CALL sub_000017F0
│ │ ├── 0x1820 CALL KERNEL32!CreateFileMappingW
│ │ ├── 0x185A CALL KERNEL32!MapViewOfFile
│ │ ├── 0x1884 CALL KERNEL32!FlushViewOfFile
│ │ ├── 0x18A9 CALL KERNEL32!UnmapViewOfFile
│ │ └── 0x18B2 CALL KERNEL32!CloseHandle
│ ├── 0x1A7F CALL sub_000013A0
│ │ ├── 0x13BF CALL bcrypt!BCryptGenRandom
│ │ ├── 0x13E7 CALL bcrypt!BCryptOpenAlgorithmProvider
│ │ ├── 0x142D CALL bcrypt!BCryptCreateHash
│ │ ├── 0x1478 CALL bcrypt!BCryptFinishHash
│ │ ├── 0x1488 CALL bcrypt!BCryptDestroyHash
│ │ └── 0x1494 CALL bcrypt!BCryptCloseAlgorithmProvider
│ ├── 0x1A8D CALL sub_00001920
│ │ ├── 0x1936 CALL KERNEL32!WaitForSingleObject
│ │ └── 0x1945 CALL KERNEL32!CancelWaitableTimer
│ ├── 0x1AA4 CALL KERNEL32!GetLastError
│ └── 0x1AD3 CALL sub_000018D0
│ ├── 0x18EA CALL KERNEL32!VirtualFree
│ └── 0x1901 CALL KERNEL32!CloseHandle
├── 0x2371 CALL sub_00002910
│ └── 0x2916 CALL KERNEL32!GetModuleHandleW
└── 0x2393 CALL sub_00002910 [expanded above]
RESX: completed in 10ms
With one command, we've mapped out a significant amount of the program's functionality:
VirtualAlloc, VirtualFree, VirtualProtect: Dynamic memory allocation and protection manipulation.CreateThread, WaitForSingleObject, SRWLock: Multithreaded execution and synchronization.CreateWaitableTimerExW, SetWaitableTimer: Scheduled or delayed execution.CreateFileMappingW, MapViewOfFile: Memory-mapped files or shared memory.BCryptGenRandom, BCryptCreateHash: Cryptographic randomness and hashing.QueryPerformanceCounter, GetSystemTimeAsFileTime: High-resolution timing and timestamps.GetCurrentProcessId, GetCurrentThreadId, GetModuleHandleW: Process, thread, and module introspection.From this alone, we can infer that the binary performs memory management, concurrent execution, cryptographic operations, and memory-mapped I/O. The combination of memory protection changes and thread creation may warrant further investigation, particularly when analyzing packers, instrumentation frameworks, or malware.
RESX goes beyond identifying API calls. With Windows SDK integration, it can recover official parameter names, resolve Windows constants, identify function pointers, and reconstruct arguments directly from machine code, even without PDB symbols.
For example, using --args:
> resx /calls "SAMPLE.exe" ENTRY --depth 5 --only winapi --no-pdb --args
├── 0x15D0 CALL KERNEL32!VirtualAlloc
│ └── args
│ ├── lpAddress = NULL
│ ├── dwSize = 0x10000
│ ├── flAllocationType = MEM_RESERVE
│ └── flProtect = PAGE_NOACCESS
│
├── 0x165C CALL KERNEL32!CreateThread
│ └── args
│ ├── lpThreadAttributes = NULL
│ ├── dwStackSize = 0
│ ├── lpStartAddress = &fn_0x000016E0
│ ├── lpParameter = arg1
│ ├── dwCreationFlags = 0
│ └── lpThreadId = NULL
│
├── 0x13BF CALL bcrypt!BCryptGenRandom
│ └── args
│ ├── hAlgorithm = NULL
│ ├── pbBuffer = ?
│ ├── cbBuffer = 0x10
│ └── dwFlags = BCRYPT_USE_SYSTEM_PREFERRED_RNG
│
└── 0x13E7 CALL bcrypt!BCryptOpenAlgorithmProvider
└── args
├── phAlgorithm = &local_10
├── pszAlgId = L"SHA256"
├── pszImplementation = NULL
└── dwFlags = 0
From these calls alone, we can infer that the binary reserves 64 KiB of virtual address space, creates a thread at a recovered function entry point, requests 16 bytes of cryptographically secure random data, and initializes a SHA-256 hashing provider.
RESX can statically recover dynamically resolved Windows APIs, including those hidden behind API hashing, PEB loader-list traversal, manual export-table parsing, and encoded API names. This allows analysts to identify functionality that may be absent from a binary's conventional import table, without manually reversing the resolution routines.
API hashing & manual export resolution
> resx /calls "HASHED.exe" rva:0x1770 --depth 3 --only dynamic --no-pdb