Skip to content

v1.0.0

Latest

Choose a tag to compare

@github-actions github-actions released this 01 Oct 11:36
191d196

First stable release. It is the Dear ImGui desktop that was prepared as v0.8.0 (never published), validated against a real game (AssaultCube) in addition to the automated suites. Versions 0.7.0 and 0.8.0 were not published; their changes are all below.

Native desktop application

  • Replaced the Qt 6/QML desktop with a native Dear ImGui (docking) application on Win32 + Direct3D 11, built from app_imgui/. cortex.exe no longer ships Qt runtime files. The Qt/QML sources in app/ stay frozen as the parity reference and are no longer built or released.
  • Every Qt workspace and all 148 Qt controller workflows have an ImGui counterpart (app_imgui/PARITY_MATRIX.md, app_imgui/INVOKABLE_PARITY.md).
  • Dockable workspaces arranged by six presets (Memory, Debug, RE, Trace, Automation, Runtime), a two-row header with the target, the Read-only / Writes allowed toggle and debugger controls, command palette, Go To, navigation history, and a bottom panel whose tabs hide while the same content is open as a full workspace.
  • TrueType fonts (Segoe UI, Cascadia Mono / Consolas for data) and per-monitor DPI scaling, including WM_DPICHANGED.
  • Long runtime operations run on a background worker with a progress card, so the window keeps redrawing.
  • Settings and the dock layout are stored in %LOCALAPPDATA%\Cortex; a cortex.portable file beside cortex.exe keeps them next to the executable. Existing files beside the executable are copied over on first start.

Memory tools, address list and assembler (Cheat Engine parity)

  • Value scanner rebuilt to Cheat Engine's level: byte / 2 / 4 / 8 bytes, float, double, string (with UTF-16 and case options), array of bytes with wildcards, and All numeric. Exact / bigger / smaller / between / unknown-initial first scans; next scans for increased, decreased, changed, unchanged, same-as-first and by deltas; hex, unsigned, not, compare-to-first, float rounding. Memory-scan options with writable / executable / copy-on-write tristates, MEM_PRIVATE / MEM_IMAGE / MEM_MAPPED region types, fast scan and alignment, an address range or a module, optional pause while scanning, worker threads, and a result cap. Results colour changed values, show previous / first / module+offset, and support multi-select add / save / remove / copy.

  • Address list with Cheat Engine's features: freeze (always / allow increase / allow decrease) at a configurable interval, static module+offset and multi-level pointer entries, and full Cheat Engine address expressions ([[game.exe+10]+20]+8, "name"+offset, + - *). Group headers that collapse, drag-and-drop reordering and "Group selected", description colours, dropdown value lists, "Change address", multi-entry "Change value", and Enter / Space / Delete / Ctrl+A/C/V keys. The clipboard uses Cheat Engine's own table format, so entries copy and paste both ways. A draggable splitter shares the height between the scanner and the list, which now survives a target change.

  • Per-entry hotkeys: system-wide shortcuts on a single entry or a whole group — toggle freeze, freeze, unfreeze, set value, increase / decrease by — registered alongside the Settings hotkeys, with shared chords running every bound entry. Read from and written to .CT files.

  • Cheat tables (.CT): open and save Cheat Engine tables with groups, pointers, strings and byte arrays, description colours, collapsed groups, dropdown lists, per-entry hotkeys and user-defined symbols. Auto Assembler scripts are reported, not run; a table's Lua script is offered to the Lua engine for review instead of running on its own.

  • Address expressions everywhere (address list, Go To, memory viewer, memory tools): module names, module exports, forwarded exports, module!export and user-defined symbols, shared with the Lua engine and cheat tables. Memory tools gains a Symbols tab to register symbols and search every module's exports.

  • Memory tools panels: memory regions, PE headers (sections, directories, exports with forwarders, imports), string search, code caves, AOB signature generation (Zydis), and a pointer scanner with rescan, save / load and "add path to the list".

  • Memory viewer rewritten: a 64 KB window with display types, changed bytes in red, in-place hex typing, a data inspector, and text / byte find.

  • What accesses / writes: hardware data and execute breakpoints in log mode, decoding the accessing instruction and grouping instruction watches by effective address with a live value.

  • Lua engine (Cheat Engine compatible, no runtime injected): read*/write*, getAddress(Safe), AOBScan(Unique/ModuleUnique), enumModules, getModuleSize, pause / unpause, byte-table conversions, registerSymbol, getNameFromAddress, inModule, inSystemModule and more, sandboxed with a time limit and cancel. Writes and pausing require Writes allowed.

  • Assembler and Auto Assembler: an x86/x64 text assembler on the Zydis encoder — Intel syntax, hex-by-default numbers (#decimal, (float)x), labels and forward references, auto-short jumps, db/dw/dd/dq/nop data, symbol and label resolution, and a far jmp/call fallback. A Memory tools Assembler tab assembles and writes bytes, or performs a code injection trampoline: a cave is allocated near the site, the new code runs, the replaced instructions are relocated (relative branches and RIP-relative operands keep their targets) and control returns after them, with a Restore. Global hotkeys, process pause / resume, auto-attach and a system-wide attach-foreground shortcut round out the parity.

  • Auto Assembler scripts run: a Cheat Engine script interpreter with [ENABLE] / [DISABLE], alloc / globalalloc / dealloc, label / registersymbol / unregistersymbol, define, aobscan / aobscanmodule, assert, fullaccess and createthread, resolved over several passes. Script entries live in the address list beside the values, with a checkbox that runs [ENABLE] and [DISABLE], and are read from and written to .CT files.

  • Speedhack: the target's timing functions are hooked so the clock they report is scaled. Each hook calls the real function through a trampoline and rescales around the value seen on the first call, so time never jumps backwards when the multiplier changes.

  • Grouped scan: a pattern of values that sit close together (4:64 f:1.5 2:14), with per-element types, a bare * that skips one byte and 4:* for a field whose value is unknown. Hits carry the offset of every element.

  • Memory dumps: a range of memory is written to a file and a file is put back where it came from, with unreadable pages saved as zeros and counted.

  • User-defined value types: a named type reads its own width, takes its bits and shows raw * scale + offset, which covers a big-endian field, a scaled value or a bitfield. Types are saved to a file, picked from an address list entry's Change type, and stored in a .CT as Cheat Engine's Custom.

  • Dissect data structures: the same bytes are read at one or more instances and each offset is described — a pointer, a float, some text, a number — with the fields that disagree between instances highlighted.

  • Pointer spider: every plausible pointer out of one address is followed level by level, the opposite of the pointer scanner; a path goes to the address list as a pointer entry.

  • The Memory tools are picked from one combo grouped by Inspect / Search / Code / Names / Files, and are also under Tools > Memory tools, instead of a row of buttons that grew to two lines. The header is one line: the Workspace preset buttons are gone (the Workspace menu has them) and Go to, Pause target, the debugger controls and the session chips sit beside the target.

  • The pointer spider has a graph view — a column per level, one node per object, edges labelled with their offset, pan and zoom — beside the list.

Fixes

  • What accesses / writes no longer kills or freezes the game. The Windows debugger cleared DR6 while changing the debug registers, so a hit already on its way reached the handler with no slot and the single-step exception was passed to the game, which died; that happened on Stop and on adding a second watch. A trap on a slot with no breakpoint is now disarmed and swallowed, DR6 is preserved, and any single-step is swallowed while a hardware breakpoint exists. Every hit also copied the breakpoint's whole log and read and wrote the thread context six times while the game stood still; it is now one read and one write. The list no longer re-counts the last entry, sorts every frame or reads memory per row per frame, shows hits per second, and a watch stops itself after 20000 hits (editable) so a busy address cannot freeze the game. The injected debugger no longer walks the stack with dbghelp on every hardware hit and drops a trap raised inside its own handler.

  • Pause target no longer pauses Cortex. The runtime answers from a thread inside the target, so with every thread suspended each call waited out its timeout and froze the window. While paused, runtime calls fail at once and the debugger refuses to attach; the connection is kept, so Resume needs no reconnect.

  • The write permission is enforced for every mutating application call, not only when the runtime is first loaded: an already connected runtime no longer receives mutation_permission while the UI is read-only.

  • The Debugger reads registers and stack before the debugger is attached.

  • A newly tracked RE object shows its resolved address and liveness immediately.

  • The desktop finds the runtime token when the runtime was injected from the application root instead of runtime/<arch>.

  • Value scans report when the result limit was reached.

  • cortex inject <pid> works on 32-bit targets: it reads the target's architecture, uses runtime\x86\cortex_core.dll through the private x86 helper, and refuses a DLL of the wrong architecture with a clear message instead of failing inside the target. Without a DLL path it no longer looks in the current directory.

  • Every injection path loads dbghelp.dll, opengl32.dll (and d3d8.dll for 32-bit targets) from System32 before the runtime when the target has not loaded them, so a copy of the wrong architecture or a proxy DLL in the game's folder can no longer break or hijack the runtime's imports.

  • The portable bundle carries one runtime per architecture, in runtime/x64 and runtime/x86; the extra x64 copy at the bundle root is gone.

MCP

  • The tool manifest now lists debug_breakpoint_trigger_set, debug_breakpoint_trigger_clear and symbols_module.
  • MCP server metadata reports version 1.0.0.

Build and validation

  • app_imgui/main.cpp is split by concern (application state, UI, CLI, GUI test modes, window loop); the GUI test modes can be left out with -DCORTEX_IMGUI_TEST_MODES=OFF.
  • Command-line tools expose named entry points instead of renaming main() through compile definitions; standalone builds define CORTEX_STANDALONE_TOOL. The desktop debugger backends moved to host/debugger/ and the Windows icon to resources/windows/.
  • Application models share RuntimeModelBase over a RuntimeTransport interface and are unit-tested against a scripted transport (cortex_app_models_tests).
  • The integrated E2E validates /schema/validate and calls every read-only GET tool of the manifest, failing on any 5xx.
  • The P1-P4, prompt-contract and diagnostics M1-M7 workflows are grouped as jobs of .github/workflows/contracts.yml.