From arc-probe
Read and write process memory for all data types via CLI, TCP, or HTTP bridge. Includes safety rules, address formats, and examples for low-level access.
npx claudepluginhub vzco/arc-probe --plugin arc-probeThis skill uses the workspace's default tool permissions.
Read and write process memory. Covers every data type, all three command delivery methods, safety rules, and copy-paste examples.
Provides reverse engineering reference for ARC Probe: safe memory read/write, address validation heuristics, instruction patching (NOP/INT3/RET), and binary identification. For process probing sessions.
Guides acquiring and analyzing memory dumps with Volatility 3, WinPmem, LiME on Windows/Linux/macOS/VMs for incident response and malware analysis.
Solves CTF pwn challenges by discovering and exploiting memory corruption vulnerabilities like buffer overflows, format strings, heap exploits, ROP to read flags.
Share bugs, ideas, or general feedback.
Read and write process memory. Covers every data type, all three command delivery methods, safety rules, and copy-paste examples.
ARC Probe commands can be sent three ways. Use whichever is available:
probe.exe <command>
Returns JSON to stdout. Exit code 0 = success, 1 = error.
probe.exe "read_int 0x7FFB0A8D0000+0x354"
# {"ok":true,"data":{"value":100}}
probe.exe "write_int 0x055EA1C28FE8+0x50 1"
# {"ok":true,"data":{"bytes_written":4}}
If probe.exe is not in PATH, use the full path to the build directory.
Connect to 127.0.0.1:9998 and send commands as newline-terminated strings:
$tcp = New-Object System.Net.Sockets.TcpClient('127.0.0.1', 9998)
$s = $tcp.GetStream()
$w = New-Object System.IO.StreamWriter($s); $w.AutoFlush = $true
$r = New-Object System.IO.StreamReader($s)
$w.WriteLine('read_int 0x7FFB0A8D0000+0x354')
$r.ReadLine()
$tcp.Close()
curl -s -X POST http://localhost:9996 \
-H "Content-Type: application/json" \
-d '{"action":"probe","command":"read_int 0x7FFB0A8D0000+0x354"}'
The bridge wraps the response: {"ok":true,"data":{"ok":true,"data":{...}}}. Outer ok = bridge status, inner = probe response.
All addresses are hexadecimal. Accepted formats:
| Format | Example |
|---|---|
| With 0x prefix | 0x7FF612340000 |
| Without prefix | 7FF612340000 |
| Module-relative | client.dll+0x2E76FE8 |
| Offset arithmetic | 0x055EA1C28FE8+0x50 |
To get module bases: modules list
read <addr> <size>
Returns up to 4096 bytes as a hex string. Use for opcode bytes, raw binary data, or when you need exact byte values.
probe.exe "read 0x7FFB0A8D0000 16"
# {"ok":true,"data":{"hex":"4D5A9000030000000400...","size":16}}
read_ptr <addr>
Reads an 8-byte (64-bit) pointer value. Use for following pointer fields in structs, reading vtable pointers, or any 8-byte address.
probe.exe "read_ptr 0x055EA1C28FE8"
# {"ok":true,"data":{"value":"0x7FFB22EA1000"}}
read_int <addr>
Reads a signed 32-bit integer. Use for health, team numbers, enum values, counts, flags.
probe.exe "read_int 0x055EA1C28FE8+0x354"
# {"ok":true,"data":{"value":100}}
read_float <addr>
Reads a 32-bit float. Use for positions, angles, speed, cooldown timers.
probe.exe "read_float 0x055EA1C28FE8+0x40"
# {"ok":true,"data":{"value":1234.5}}
read_string <addr> [max_length]
Reads a null-terminated ASCII string. Default max 256 bytes. Use for entity names, class names, debug text.
probe.exe "read_string 0x7FFB22EA4098"
# {"ok":true,"data":{"value":"player_controller","length":17}}
read_chain <addr> <off1> <off2> ...
Each offset: add to current address, dereference (read 8-byte pointer), move to result. Last value is the final read. Use for navigating nested structs.
# EntityList → first chunk → first entity pointer
probe.exe "read_chain client.dll+0x3862C28 0x10 0x0"
# {"ok":true,"data":{"value":"0x055EA1C28FE8"}}
dump <addr> <size>
Max 256 bytes. Returns formatted hex dump with ASCII sidebar. Use for visual inspection of unknown memory.
probe.exe "dump 0x055EA1C28FE8 64"
CRITICAL SAFETY RULES:
write <addr> <hex_bytes>
Writes raw bytes. Use for patching instructions (NOP = 90, INT3 = CC), writing arbitrary byte sequences.
# Read original bytes first!
probe.exe "read 0x7FFB21234000 5"
# {"ok":true,"data":{"hex":"E8AB123400"}}
# NOP out a 5-byte CALL instruction
probe.exe "write 0x7FFB21234000 9090909090"
# {"ok":true,"data":{"bytes_written":5}}
# RESTORE original bytes when done
probe.exe "write 0x7FFB21234000 E8AB123400"
write_int <addr> <value>
Writes a signed 32-bit integer. Use for health, flags, counters, enum values.
# Read current value
probe.exe "read_int 0x055EA1C28FE8+0x354"
# {"ok":true,"data":{"value":100}}
# Set health to 999
probe.exe "write_int 0x055EA1C28FE8+0x354 999"
# {"ok":true,"data":{"bytes_written":4}}
# Enable a bool (stored as int32)
probe.exe "write_int 0x055EA1C29038 1"
# {"ok":true,"data":{"bytes_written":4}}
write_float <addr> <value>
Writes a 32-bit float. Use for positions, speed multipliers, timers.
# Read current position
probe.exe "read_float 0x055EA1C28FE8+0x40"
# {"ok":true,"data":{"value":1234.5}}
# Modify position
probe.exe "write_float 0x055EA1C28FE8+0x40 5000.0"
write_ptr <addr> <value>
Writes an 8-byte pointer value. Use for redirecting pointers, modifying vtable entries (dangerous).
# Read current pointer
probe.exe "read_ptr 0x055EA1C28FE8+0x330"
# {"ok":true,"data":{"value":"0x055EB2340000"}}
# Overwrite pointer (be very careful!)
probe.exe "write_ptr 0x055EA1C28FE8+0x330 0x055EB2350000"
# Read current value
probe.exe "read_int 0x055EA1C29038"
# 0 = off
# Enable it
probe.exe "write_int 0x055EA1C29038 1"
# Disable it
probe.exe "write_int 0x055EA1C29038 0"
# Read max health
probe.exe "read_int 0x055EA1C28FE8+0x350"
# {"ok":true,"data":{"value":625}}
# Read current health
probe.exe "read_int 0x055EA1C28FE8+0x354"
# {"ok":true,"data":{"value":100}}
# Set current = max
probe.exe "write_int 0x055EA1C28FE8+0x354 625"
# Read the CALL instruction bytes (5 bytes for E8 calls)
probe.exe "read 0x7FFB21234000 5"
# Save: E8 AB 12 34 00
# NOP it out
probe.exe "write 0x7FFB21234000 9090909090"
# Restore later
probe.exe "write 0x7FFB21234000 E8AB123400"
curl -s -X POST http://localhost:9996 -H "Content-Type: application/json" -d '{
"action":"batch","actions":[
{"action":"activity","status":"working","message":"Writing memory..."},
{"action":"probe","command":"read_float 0x055EA1C28FE8+0x40"},
{"action":"probe","command":"write_float 0x055EA1C28FE8+0x40 5000.0"},
{"action":"probe","command":"read_float 0x055EA1C28FE8+0x40"},
{"action":"activity","status":"idle","message":"Done"}
]
}'
| Error | Cause | Fix |
|---|---|---|
"error":"Invalid address" | Address format wrong | Use hex with or without 0x prefix |
"error":"Read failed" | Address not readable | Verify with dump first; entity may be dead or freed |
"error":"Write failed" | Address not writable | Code sections are read-only; data/heap is writable |
"error":"Connection refused" | Probe not running | Inject DLL first, or check port 9998 |
"error":"Size exceeds maximum" | Read >4096 bytes | Split into multiple reads |
modules list gives you base addresses — add offsets to get absolute addresseshwbp set <addr> w 4) let you find what code writes to an address — useful for finding where to patchwatch <addr> <size> polls for changes — use this to verify your writes are stickingint32 (4 bytes) and sometimes as uint8 (1 byte) — check the schema dump