Command reference

Every command Picklock accepts, with the arguments its parser declares. This page is generated from the code, so it cannot drift from what help prints at the prompt.

Commands are named namespace:command. Typing a namespace on its own (scan) prints that namespace’s page; help <command> prints one command’s arguments; and every command also answers to --help.

Process

Find a target process, attach to it, and see what it is.

picklock> ps:list chrome

+-------+------------+
| PID   | NAME       |
+-------+------------+
| 41902 | chrome.exe |
+-------+------------+
1 row in set (0.01 sec)

ps:close

Detach from the current process.

ps:close

Takes no arguments.

Closes the OS handle and drops the scan results, the pointer paths and the cached memory map. The target itself is untouched — nothing Picklock wrote to it is undone.

ps:info

Describe the attached process in detail.

ps:info

Takes no arguments.

Enumerates the memory map to report how much of the address space is mapped, so it is the slower of the two ways to look at a target.

ps:list

List the processes visible to you.

ps:list [pattern] [--pid-sort] [--case-sensitive] [--limit N] [--page N] [--all]
[pattern]

keep processes whose name contains this text; an all-digit pattern also matches that PID exactly

--pid-sort

sort by PID instead of by name

--case-sensitive

match the pattern case-sensitively

-l, --limit N

rows per page, overriding the ‘limit’ setting

-p, --page N

which page to show, counting from 1

-a, --all

print every row, ignoring the limit

Only processes your user can see are listed. Run Picklock elevated to see (and open) processes belonging to other users.

Examples

ps:list
ps:list chrome
ps:list --pid-sort --limit 50

ps:open

Attach to a process by PID or name.

ps:open [pid|name] [--pid PID] [--name NAME] [--ignore-case] [--case-sensitive] [--partial] [--strict-bitness]
[pid|name]

the PID (all digits) or the process name to attach to

--pid PID

attach by PID, when the target could be read either way

--name NAME

attach by process name, when the name is all digits

-i, --ignore-case

match the name regardless of case

--case-sensitive

match the name case-sensitively (the default on Linux and macOS)

--partial

match the name as a substring (‘chrome’ finds ‘chrome.exe’); fails when more than one process matches, listing the candidates

--strict-bitness

refuse to attach when the target’s 32/64-bit width cannot be determined, instead of guessing it from this interpreter

An all-digits target is taken as a PID, anything else as a process name; force either reading with –pid or –name.

–strict-bitness is worth using before a pointer scan, where a wrong pointer width is silent rather than loud.

Attaching replaces any previous target and clears the scan results.

Examples

ps:open 4242
ps:open notepad.exe
ps:open chrome --partial -i

ps:threads

List the target’s threads.

ps:threads [--limit N] [--page N] [--all]
-l, --limit N

rows per page, overriding the ‘limit’ setting

-p, --page N

which page to show, counting from 1

-a, --all

print every row, ignoring the limit

STATE and PRIORITY are filled in only where the platform exposes them cheaply (Linux does; Windows and macOS leave them empty).

What a TID is differs by platform, and only two of the three are a property of the thread itself:

  Linux    the POSIX task id — the same number everything else reports
  Windows  the kernel thread id — likewise
  macOS    a Mach port name, which means something only to the process that asked

That last one is the trap: on macOS two tools looking at the same process get different numbers for the same threads, and neither is wrong. It is a handle, not a name — do not carry it between tools, and do not expect it to match Activity Monitor.

Memory

Read, write and inspect the target’s memory.

picklock> memory:read game.exe+0x1234 int32

+--------------------+-------+-------+
| ADDRESS            | TYPE  | VALUE |
+--------------------+-------+-------+
| 0x00007FF6A41B1234 | int32 | 100   |
+--------------------+-------+-------+
1 row in set (0.00 sec)

memory:alloc

Allocate memory inside the target.

memory:alloc <size> [--permission N]
size

number of bytes to allocate; hex accepted (e.g. 0x1000)

--permission N

platform-specific protection: a PAGE_* value on Windows (default PAGE_EXECUTE_READWRITE), a VM_PROT_* bitmask on macOS

Reserves and commits SIZE bytes in the target’s address space and prints the base address. The region stays until ‘memory:free’ releases it.

Not available on Linux, which has no cross-process allocation syscall.

Examples

memory:alloc 4096
memory:alloc 0x1000

memory:free

Release memory allocated with ‘memory:alloc’.

memory:free <address> [size]
address

base address returned by ‘memory:alloc’

[size]

region size; only needed to free a region this session did not allocate, since PyMemoryEditor remembers its own

Not available on Linux, for the same reason as ‘memory:alloc’.

Examples

memory:free 0x7ffee3a01000
memory:free 0x7ffee3a01000 4096

memory:hex

Show a range of memory as hex and text.

memory:hex <address> [length] [--width N] [--watch] [--interval S]
address

address expression: a literal, module+offset, [pointer] or #N — see ‘help address’

[length]

number of bytes to read (default 256); hex accepted

--width N

bytes per line, overriding the ‘hex_width’ setting

-w, --watch

redraw as the bytes change, until ENTER

--interval S

seconds between redraws with –watch, overriding ‘watch_interval’

The classic three-column layout: absolute address, hex bytes, printable ASCII. Length defaults to 256 bytes.

With –watch it redraws in place until you press ENTER, which turns it into a live view of a structure — a whole record changing at once, where ‘memory:watch’ follows a single value.

The read is a single call, so a range that crosses into an unmapped page fails as a whole rather than returning half the bytes.

Examples

memory:hex 0x7ffee3a01000
memory:hex game.exe+0x1000 512
memory:hex #1 64 --width 8
memory:hex #1 64 --watch

memory:modules

List the modules loaded in the target.

memory:modules [pattern] [--limit N] [--page N] [--all]
[pattern]

keep modules whose name or path contains this text

-l, --limit N

rows per page, overriding the ‘limit’ setting

-p, --page N

which page to show, counting from 1

-a, --all

print every row, ignoring the limit

A module is the main executable or a shared library (.dll / .so / .dylib). Its BASE moves on every launch under ASLR, which is why an address is best written as ‘module+offset’ — see ‘help address’.

Running this command refreshes the module table the address parser uses, so run it after the target loads a library.

Examples

memory:modules
memory:modules libc

memory:read

Read a typed value from an address.

memory:read <address> [type] [length] [--count N] [--hex]
address

address expression: a literal, module+offset, [pointer] or #N — see ‘help address’

[type]

value type; defaults to int32 (see ‘help types’)

[length]

byte width, required for the ‘string’ and ‘bytes’ types

--count N

read N consecutive values, stepping by the type’s width

--hex

print integers in hexadecimal

The type defaults to int32 — except for a ‘#N’ row, which is read the way the scan that found it read it. A byte the scan matched should not come back as a four-byte number.

‘string’ and ‘bytes’ need a length in bytes; the fixed-width types ignore one.

The address is an expression — see ‘help address’ — so a pointer chain can be read in one go.

Examples

memory:read 0x7ffee3a01000
memory:read game.exe+0x1234 int32
memory:read [game.exe+0x1a2b3c]+0x18 float
memory:read 0x7ffee3a01000 string 32
memory:read #1 int32 --count 8

memory:regions

List the target’s mapped memory regions.

memory:regions [--writable] [--executable] [--shared] [--path TEXT] [--at ADDRESS] [--limit N] [--page N] [--all]
--writable

keep only writable regions

--executable

keep only executable regions

--shared

keep only shared or file-backed mappings

--path TEXT

keep regions whose backing file path contains TEXT

--at ADDRESS

show only the region containing this address

-l, --limit N

rows per page, overriding the ‘limit’ setting

-p, --page N

which page to show, counting from 1

-a, --all

print every row, ignoring the limit

The memory map is re-read on every call, so it reflects allocations the target made since the last look.

The PERMS column reads like /proc//maps: rwx plus ‘s’ for a shared/file-backed mapping or ‘p’ for a private one.

Examples

memory:regions --writable
memory:regions --at 0x7ffee3a01000
memory:regions --path libc

memory:watch

Poll an address and print it as it changes.

memory:watch <address> [type] [length] [--interval S] [--count N] [--all]
address

address expression: a literal, module+offset, [pointer] or #N — see ‘help address’

[type]

value type; defaults to int32 (see ‘help types’)

[length]

byte width, required for the ‘string’ and ‘bytes’ types

--interval S

seconds between reads, overriding the ‘watch_interval’ setting

--count N

stop after N samples; without it, watch runs until you press ENTER

-a, --all

print every sample, not only the ones whose value changed

Reads the address on a timer and prints a line per sample. Press ENTER to stop; Ctrl+C is left to mean what it means everywhere else, which is leaving the shell.

By default only samples whose value differs from the previous one are printed, which turns the terminal into a change log — so a value that is not moving shows one line and then nothing, and ‘–all’ is how you tell that apart from a watch that has stopped.

A ‘#N’ row is watched with the type the scan used, not int32.

This is the terminal answer to a cheat table: leave it running in one window while the target does its thing.

Examples

memory:watch game.exe+0x1234 int32
memory:watch [base+0x10]+0x8 float --interval 0.1
memory:watch #1 int32 --count 20 --all

memory:write

Write a typed value to an address.

memory:write <address> <type> <value> [--length N] [--null-terminated]
address

address expression: a literal, module+offset, [pointer] or #N — see ‘help address’

type

value type (see ‘help types’)

value

the value to write, parsed according to the type: integers accept 0x/0o/0b prefixes, booleans accept true/false/on/off, ‘bytes’ takes hex (‘DE AD BE EF’) and ‘string’ takes the text verbatim

--length N

buffer width for string/bytes; defaults to the natural width of the value given

--null-terminated

append a NUL after a string, for C-string writes

There is no confirmation and no undo. Writing into a live process can crash it — read the address first if you are not sure of it.

Examples

memory:write 0x7ffee3a01000 int32 100
memory:write game.exe+0x1234 float 99.5
memory:write #2 bytes 'DE AD BE EF'
memory:write 0x7ffee3a01000 string Picklock --null-terminated

Scanning

Search memory for a value, then narrow what you found.

picklock> scan:value int32 100 --writable
Showing 20 of 3184 rows — writable regions only (1.42 sec)

picklock> scan:next 95
+-----+--------------------+-------+
| ROW | ADDRESS            | VALUE |
+-----+--------------------+-------+
|  #1 | 0x00000201A4C0F118 | 95    |
+-----+--------------------+-------+
1 row in set (0.02 sec)

scan:aob

Scan for a byte pattern with wildcards (AOB).

scan:aob <pattern> [--max N]
pattern

IDA-style signature: hex bytes separated by spaces, with ‘?’ or ‘??’ for any single byte. Quote it, since it contains spaces

--max N

stop after N hits, overriding the ‘max_results’ setting

This is how you find code that moves between builds: the opcodes stay put while the operands change, so you wildcard the operands. The result set holds the address of each match and can be refined with ‘scan:next’ or read with ‘memory:read #1’.

Examples

scan:aob "48 8B ? ? 00 00"
scan:aob "DE AD BE EF"

scan:drop

Remove the named result rows.

scan:drop <row> [row ...]
row [row ...]

row numbers from ‘results’, singly or as ranges: 1 4 7-9 (a ‘#’ prefix is optional)

The inverse of ‘keep’. Ranges work the same way.

Examples

scan:drop 2
scan:drop 5-12

scan:keep

Keep only the named result rows.

scan:keep <row> [row ...]
row [row ...]

row numbers from ‘results’, singly or as ranges: 1 4 7-9 (a ‘#’ prefix is optional)

Use it when you can see which candidates are real and would rather not invent a comparison that happens to exclude the others.

Examples

scan:keep 1
scan:keep 1 3 7-9

scan:next

Narrow the results with another comparison.

scan:next [value] [--eq VALUE] [--ne VALUE] [--gt VALUE] [--lt VALUE] [--ge VALUE] [--le VALUE] [--between A B] [--not-between A B] [--changed] [--unchanged] [--increased] [--decreased] [--increased-by VALUE] [--decreased-by VALUE]
[value]

the value to keep; the same as –eq VALUE

--eq VALUE

keep values equal to VALUE — the same as giving VALUE on its own

--ne VALUE

keep values different from VALUE

--gt VALUE

keep values greater than VALUE

--lt VALUE

keep values smaller than VALUE

--ge VALUE

keep values greater than or equal to VALUE

--le VALUE

keep values smaller than or equal to VALUE

--between A B

keep values inside the range A…B, inclusive

--not-between A B

keep values outside the range A…B

--changed

keep addresses whose value differs from the last reading

--unchanged

keep addresses whose value equals the last reading

--increased

keep addresses whose value grew since the last reading

--decreased

keep addresses whose value shrank since the last reading

--increased-by VALUE

keep addresses that grew by exactly VALUE

--decreased-by VALUE

keep addresses that shrank by exactly VALUE

Re-reads every address in the result set and keeps the ones that still match. A bare value means equality: ‘scan:next 95’ keeps the addresses now holding 95.

The comparisons that need no value of their own are for when you cannot see it — a health bar with no number. They measure each address against what the last scan read there, so making the value move in the target and then asking for ‘–decreased’ narrows the set without you ever knowing the number.

Addresses that have become unreadable (the target freed them) are dropped.

Examples

scan:next 95
scan:next --changed
scan:next --decreased
scan:next --gt 50
scan:next --between 10 20

scan:regex

Scan for text matching a regular expression.

scan:regex <pattern> [--length N] [--max N]
pattern

a regular expression, UTF-8 encoded and matched against raw memory

--length N

the widest match to expect, in bytes (default 64); also how many bytes are read back for the VALUE column

--max N

stop after N hits, overriding the ‘max_results’ setting

Because the match runs over bytes, a metacharacter spans one byte: ‘.’ matches any single byte and ‘\d’ is ASCII-only, so quantify with care around non-ASCII text.

A regex has no fixed width, which is why –length matters: it is what lets a match straddling an internal chunk boundary still be found.

Examples

scan:regex "Player[0-9]+"
scan:regex "https?://[a-z.]+" --length 128

scan:reset

Discard the current scan results.

scan:reset

Takes no arguments.

Clears the result set so the next ‘scan’ starts a fresh cycle. The attached process is left alone.

scan:results

Show the current result set, re-read.

scan:results [--export FILE] [--limit N] [--page N] [--all]
--export FILE

write every result to a JSON file instead of paging through them

-l, --limit N

rows per page, overriding the ‘limit’ setting

-p, --page N

which page to show, counting from 1

-a, --all

print every row, ignoring the limit

Reads every address again, so the VALUE column is what the target holds now, not what it held when the scan ran. The PREVIOUS column shows the value the last scan recorded — the one ‘scan:next changed’ and friends compare against — and is filled in only where the two differ.

Row numbers are what ‘#N’ refers to in an address, and they keep counting across pages: row #21 is the first on page 2 of twenty.

–export writes every result to a JSON file — all of them, not the page on screen — with the scan’s type and width alongside, so the file says what its numbers mean.

Examples

scan:results
scan:results --all
scan:results --page 3 --limit 10
scan:results --export found.json

scan:value

Search the whole address space for a value.

scan:value <type> [value] [--eq VALUE] [--ne VALUE] [--gt VALUE] [--lt VALUE] [--ge VALUE] [--le VALUE] [--between A B] [--not-between A B] [--writable] [--all-regions] [--length N] [--max N]
type

value type to search for (see ‘help types’)

[value]

the value to search for; the same as –eq VALUE

--eq VALUE

keep values equal to VALUE — the same as giving VALUE on its own

--ne VALUE

keep values different from VALUE

--gt VALUE

keep values greater than VALUE

--lt VALUE

keep values smaller than VALUE

--ge VALUE

keep values greater than or equal to VALUE

--le VALUE

keep values smaller than or equal to VALUE

--between A B

keep values inside the range A…B, inclusive

--not-between A B

keep values outside the range A…B

--writable

scan only writable regions — much faster, and where a changing value almost always lives

--all-regions

scan everything, overriding the ‘writable_only’ setting

--length N

buffer width for string/bytes scans

--max N

stop after N hits, overriding the ‘max_results’ setting

The first scan of a cycle. Every matching address is kept as the result set that ‘scan:next’, ‘scan:results’ and the ‘#N’ address form work on.

A bare value means equality, which is what a scan almost always is; every other comparison is named by its flag, so the value slot only ever holds a value.

Ctrl+C stops a scan and keeps what it had already found.

Examples

scan:value int32 100
scan:value float 99.5 --writable
scan:value int32 --between 100 200
scan:value string Picklock
scan:value int32 --gt 1000

Aliases

Give a command a shorter name of your own.

picklock> alias:add r memory:read
r = memory:read

picklock> alias:add find-text scan:value string
find-text = scan:value string

picklock> find-text Picklock
(runs 'scan:value string Picklock')

alias:add

Give a command a shorter name.

alias:add <name> <command> [command ...]
name

the word you want to type

command [command ...]

the command it stands for, and any arguments that always go with it

The alias replaces the first word of a line, and anything else you type follows what it stands for — so with ‘find-text’ set to ‘scan:value string’, typing ‘find-text Picklock’ runs ‘scan:value string Picklock’.

A name already taken by a command or another alias is refused rather than shadowing it, and the command an alias points at has to exist, so a typo is caught here rather than the next time you use it.

Aliases are remembered between runs — they are the one thing Picklock stores on disk. ‘alias:list’ says where.

Examples

alias:add r memory:read
alias:add find-text scan:value string
alias:add w memory:write

alias:list

Show the aliases defined in this session.

alias:list

Takes no arguments.

Only the ones you have added. The shell’s own shortcuts — ‘quit’, ‘cls’, ‘\h’, ‘.’ — are part of the commands themselves and are listed with them, in ‘help ’.

They are stored in a file, whose path is printed under the table. Setting PICKLOCK_CONFIG_DIR moves it — useful for keeping a throwaway set apart from the one you rely on.

alias:remove

Forget an alias.

alias:remove <name>
name

the alias to forget

Only aliases you added can be removed; the shell’s own shortcuts are part of their commands.

Examples

alias:remove r

Configuration

Show or change how Picklock behaves.

picklock> config:set writable_only on
writable_only = on

picklock> config:list

+---------+-------+------------------------------------+
| SETTING | VALUE | DESCRIPTION                        |
+---------+-------+------------------------------------+
| limit   |    20 | Rows printed per result table ...  |
+---------+-------+------------------------------------+

config:list

Show the settings and their current values.

config:list

Takes no arguments — the whole table, every time. There are eight of them and they fit on a screen, so picking one out would be a filter for a list that does not need filtering.

A change is remembered between runs, so the shell comes back the way you left it. Only what you changed is stored, so a default that moves in a later release still reaches you — and ‘config:reset’ puts one back, which restarting no longer does.

The path is printed under the table.

config:reset

Put a setting back to its default.

config:reset [name]
[name]

the setting to put back; omit it to reset every one

Settings are remembered between runs, so restarting no longer undoes one. This is what undoes it — for a single setting, or for all of them at once.

A setting back at its default is dropped from the stored file rather than written out as a default, so a default that moves in a later release reaches you.

Examples

config:reset limit
config:reset

config:set

Change one of the settings.

config:set <name> [value]
name

the setting to change; ‘name=value’ in one word also works

[value]

its new value — on/off for a switch, a number otherwise

‘config:set limit 50’ and ‘config:set limit=50’ do the same thing.

The change lasts for the session and no longer. Run ‘config:list’ to see what can be set, and what each one does.

Examples

config:set limit 50
config:set hex on
config:set writable_only=true

Pointers

Follow pointer chains, and find ones that survive a restart.

picklock> pointer:scan #1 --depth 3
+-----+-------------------+---------+--------------------+
| ROW | BASE              | OFFSETS | TARGET             |
+-----+-------------------+---------+--------------------+
|  #1 | game.exe+0x3BA228 | 0x3E8   | 0x00000201A4C0F118 |
+-----+-------------------+---------+--------------------+
1 row in set (6.18 sec)

pointer:deref

Walk a pointer chain and print the address it lands on.

pointer:deref <base> [offset ...]
base

the static base of the chain, as an address expression — usually module+offset (see ‘help address’)

[offset ...]

offsets to walk, in order; hex accepted. The last one is added without a final read, matching the Cheat Engine convention

Reads the pointer at BASE, adds the first offset, reads the pointer there, and so on; the last offset is added without a final read — the Cheat Engine convention, so a chain copied from a cheat table works unchanged.

Examples

pointer:deref game.exe+0x1a2b3c 0x10 0x8
pointer:deref 0x7ffee3a01000 0x18

pointer:diff

Intersect pointer-path files from several runs.

pointer:diff [file ...]
[file ...]

two or more JSON files written by ‘pointer:save’, one per run of the target

Keeps only the paths present in every file, compared by their portable recipe (module, module offset, offsets) rather than by absolute address. Two or three runs of the same target usually leave a handful of paths standing, and those are the reliable ones.

The result replaces the paths currently held, so ‘pointer:save’ can write it straight back out.

Examples

pointer:diff run1.json run2.json
pointer:diff run1.json run2.json run3.json

pointer:load

Load pointer paths from a file.

pointer:load <file>
file

path of a JSON file written by ‘pointer:save’

Replaces the paths currently held. Each base is rebased onto the module addresses of the running target, so a file saved before a restart resolves correctly after it.

Examples

pointer:load health.json

pointer:paths

Show the pointer paths currently held.

pointer:paths [--limit N] [--page N] [--all]
-l, --limit N

rows per page, overriding the ‘limit’ setting

-p, --page N

which page to show, counting from 1

-a, --all

print every row, ignoring the limit

Lists the paths from the last ‘pointer:scan’, ‘pointer:load’, ‘pointer:rescan’ or ‘pointer:diff’. TARGET is where each one resolves right now, so a path that has gone stale shows as ‘(unresolved)’.

pointer:read

Read or write the value at the end of a pointer chain.

pointer:read <base> [offset ...] [--type TYPE] [--length N] [--write VALUE]
base

the static base of the chain, as an address expression — usually module+offset (see ‘help address’)

[offset ...]

offsets to walk, in order; hex accepted. The last one is added without a final read, matching the Cheat Engine convention

--type TYPE

value type at the end of the chain; defaults to int32

--length N

byte width, required for the ‘string’ and ‘bytes’ types

--write VALUE

write this value at the end of the chain instead of reading it

The one-line form of ‘pointer:deref’ followed by ‘memory:read’.

The chain is re-walked on every call, which is the point: it keeps working after the target reallocates whatever the last link pointed at.

Examples

pointer:read game.exe+0x1a2b3c 0x10 0x8 --type int32
pointer:read game.exe+0x1a2b3c 0x10 --write 999

pointer:rescan

Keep only the paths that still reach an address.

pointer:rescan <address> [file]
address

the address the surviving paths must reach, as an address expression — usually ‘#1’ from the scan that found it again

[file]

rescan the paths in this file; without it, the paths currently held are rescanned

The step that separates a real pointer path from a coincidence. Restart the target, find the value’s new address, then rescan the saved paths against it: the ones that still land on the address are the ones that describe the structure rather than that one run.

Examples

pointer:rescan #1
pointer:rescan 0x7ffee3a01000 health.json

pointer:save

Save the current pointer paths to a file.

pointer:save <file>
file

path of the JSON file to write

Writes the paths as JSON, keeping the module name and module-relative offset of each base so the file survives ASLR and can be re-used after the target restarts.

Examples

pointer:save health.json

pointer:scan

Find static pointer paths that reach an address.

pointer:scan <address> [--depth N] [--max-offset N] [--max N] [--unaligned] [--all-regions]
address

the address to find paths to, as an address expression — usually ‘#1’ straight from a scan

--depth N

maximum number of links in a chain (default 3). Each extra level costs a lot of time and memory

--max-offset N

largest offset to consider (default 1024)

--max N

stop after N paths

--unaligned

also consider pointers not on a pointer-size boundary — slower, and rarely needed

--all-regions

include non-writable regions in the pointer map

Builds a map of every pointer in the target and walks it backwards from ADDRESS until it reaches a static base inside a module. The paths found replace whatever ‘pointer:paths’ was showing.

This is the expensive command in Picklock: minutes and hundreds of megabytes on a large target. Ctrl+C stops it and keeps the paths found so far.

A path is only worth trusting once it has survived a restart: save the paths, restart the target, find the address again, and run ‘pointer:rescan’ — see ‘help pointer:rescan’.

Examples

pointer:scan #1
pointer:scan 0x7ffee3a01000 --depth 4 --max 200

The session itself

The handful of words you type between doing real work. These have no namespace: they are not a subject to go looking through.

clear

Clear the terminal.

clear

Also answers to cls.

Takes no arguments.

Wipes the screen and the scrollback, the way the shell’s own ‘clear’ does. Nothing about the session changes: the process stays attached, the scan results and pointer paths are all still there.

To discard the scan results instead, that is ‘reset’ (scan:reset).

Does nothing when the output is redirected — escape codes in a log file would be vandalism rather than tidying.

exit

Leave the shell.

exit

Also answers to quit.

Takes no arguments.

Detaches from the target first. Ctrl+C and Ctrl+D at the prompt do the same thing, except for the status they exit with: 130 for Ctrl+C, the conventional ‘interrupted’ value, and 0 for the other two.

Ctrl+C means something different during a command — it abandons that command and returns to the prompt, keeping whatever a scan had already found. So interrupting a scan costs one keystroke and leaving costs two.

help

List the commands, or describe one.

help [topic]

Also answers to ?, \h.

[topic]

a command name, or one of the topics ‘types’, ‘address’ and ‘scanning’. Omit it to list every command

With a command name, prints that command’s usage, every argument and flag it accepts, and examples. Typing ‘ –help’ does the same thing.

The argument list is generated from the command’s own parser, so it is always what the command actually accepts.

Examples

help
help scan
help address

source

Run the commands in a file.

source <file>

Also answers to \..

file

a text file of commands, one per line; blank lines and lines starting with ‘#’ or ‘–’ are ignored

Reads the file and runs each line as if it had been typed.

A failing line stops the script — a setup that half-ran is worse than one that says where it stopped.

Examples

source setup.txt

version

Print the Picklock, PyMemoryEditor, Python and platform versions.

version

Takes no arguments.

The four lines to quote in a bug report. Picklock is a client, so which PyMemoryEditor is underneath matters as much as which Picklock is on top — the two move independently.