-
Notifications
You must be signed in to change notification settings - Fork 186
Search Opcodes and Watchpoints
These two features help you find code that interacts with specific memory addresses or matches certain instruction patterns.
The Search Instructions feature lets you find assembly instructions that match a pattern across a memory region. This is useful for locating specific types of operations like function calls, memory accesses or comparisons.
Open it from the Memory Viewer menu: Tools -> Search Instructions
The dialog (titled Search for Instructions) has these fields:
-
Search: The pattern to search for. The input field has placeholder text
Enter a string or a python regex - Case sensitive: Checkbox. When checked, the search distinguishes between uppercase and lowercase letters. When unchecked, case is ignored
- Regex: Checkbox. When checked, treats the search pattern as a regular expression. When unchecked, performs a simple substring search
- Start: The starting address to search from. Defaults to the start of the current memory region
- End: The ending address to search to. Defaults to the end of the current memory region
- Search(Enter): Button that starts the search. You can also press Enter to search
- Help: Icon button (no text label) that shows regex examples
The Help button shows these regex examples:
-
call|rax - search for instructions that contain
callorrax. -
[re]cx - search for both
rcxandecx -
[rsp] - search for instructions that contain
[rsp](use backslash to escape special characters like brackets)
If you enter an invalid regex pattern, you'll see Invalid Regex in an error dialog.
Results appear in a table with two columns:
- Address: The memory address where the instruction was found
- Instruction: The assembly instruction text
Double-click any result to jump to that address in the disassembly pane. You can also right click for a context menu:
- Copy Address: Copies the instruction address to clipboard
- Copy Instruction: Copies the instruction text to clipboard
Watchpoints let you find which instructions access a specific memory address. This is one of the most powerful techniques for finding game code because instead of searching for a value, you're searching for the code that uses it.
PINCE has two ways to set watchpoints with different behaviors:
Right click an entry in the address table and select one of these:
- Find out what writes to this address
- Find out what reads this address
- Find out what accesses this address
This opens a Track Watchpoint widget that records every instruction that accesses the address while the game runs. The widget keeps running and collecting data until you stop it.
The Track Watchpoint widget has this layout:
- Left pane: A table with two columns (Count and Address) showing each unique instruction that triggered the watchpoint and how many times it fired
- Right pane: A text browser showing register values (integer and float) from when that instruction triggered
- Bottom pane: A text browser showing disassembly around the triggering instruction
- Buttons: Refresh (updates the display) and Stop (stops the watchpoint). After stopping, the Stop button changes to Close
Double-click any row in the results table to jump to that instruction in the disassembly pane.
Right click in the hex dump pane of the Memory Viewer and select Set Watchpoint, then choose:
- Write Only
- Read Only
- Both
These are traditional hardware watchpoints that pause execution when the watched address is accessed. If setting the watchpoint fails, you'll see Failed to set watchpoint at address {address}.
- Write Only: Triggers when code writes to the address (modifies the value)
- Read Only: Triggers when code reads from the address
- Both: Triggers when code reads from or writes to the address
Use Write Only to find code that modifies a value (like health decreasing). Use Read Only to find code that uses a value (like checking if health is zero). Use Both to find all code that interacts with the address.
Typical workflow:
- Find the address of a value you want to modify (like health)
- Right click it in the address table and select Find out what writes to this address
- Play the game and let the value change (take damage)
- The Track Watchpoint widget shows all instructions that wrote to that address
- Click each row to see the register values and disassembly
- Look for the instruction that decreases health (like
sub [rax], edxor similar) - Double click the row to jump to that instruction in the disassembly pane
- Modify that instruction to change the behavior (like replacing it with NOPs)
- Track watchpoints don't slow down the game as much as hardware watchpoints because they record data and continue execution instead of pausing
- Hardware watchpoints pause the game on every memory access, which can make the game unplayable. Only use them for short periods
- If you get too many results, try to be more specific about when the value changes. For example, only trigger the watchpoint when health decreases by a specific amount
- Use Read Only watchpoints to find code that checks a value (like "if health <= 0, game over")
- Use Write Only watchpoints to find code that modifies a value (like "health = health - damage")