--- hide: - navigation --- # Functions pwndbg provides a set of functions which can be used during expression evaluation to quickly perform common calculations. These can even be passed to other commands as arguments. Currently, they only work in gdb. To see a list of all functions, including those built into gdb, use `help function`. To see the help of any given function use `help function function_name`. Function invokation must include a preceding $ sign and must include brackets. For instance, invoke the `environ` function like so: ``` pwndbg> p $environ("LANG") $2 = (signed char *) 0x7fffffffe6da "LANG=en_US.UTF-8" ``` If the result of the function is being passed to a pwndbg command, make sure to either escape the function argument's quotes, or put the whole function call in quotes. ``` pwndbg> tele $environ("LANG") usage: telescope [-h] [-r] [-f] [-i] [address] [count] telescope: error: argument address: debugger couldn't resolve argument '$environ(LANG)': No symbol "LANG" in current context. pwndbg> tele $environ(\"LANG\") 00:0000│ 0x7fffffffe6cf ◂— 'LANG=en_US.UTF-8' 01:0008│ 0x7fffffffe6d7 ◂— 'US.UTF-8' 02:0010│ 0x7fffffffe6df ◂— 0x4e49475542454400 [...] pwndbg> tele '$environ("LANG")' 00:0000│ 0x7fffffffe6cf ◂— 'LANG=en_US.UTF-8' 01:0008│ 0x7fffffffe6d7 ◂— 'US.UTF-8' 02:0010│ 0x7fffffffe6df ◂— 0x4e49475542454400 [...] ``` ## pwndbg functions ### **rebase** ``` {.python .no-copy} rebase(addr: gdb.Value | int) -> int ``` Return address rebased onto the executable's mappings. #### Example ``` pwndbg> p/x $rebase(0xd9020) $1 = 0x55555562d020 pwndbg> vmmap 0x555555554000 0x55555556f000 r--p 1b000 0 /usr/bin/bash 0x55555556f000 0x55555562d000 r-xp be000 1b000 /usr/bin/bash 0x55555562d000 0x55555565e000 r--p 31000 d9000 /usr/bin/bash [...] pwndbg> p $rebase(0xd9020) == 0x555555554000 + 0xd9020 $2 = 1 pwndbg> tele $rebase(0xd9020) 00:0000│ 0x55555562d020 ◂— 0x204900636f6c6c61 /* 'alloc' */ 01:0008│ 0x55555562d028 ◂— 'have no name!' 02:0010│ 0x55555562d030 ◂— 0x65720021656d616e /* 'name!' */ 03:0018│ 0x55555562d038 ◂— 'adline stdin' [...] ``` ---------- ### **base** ``` {.python .no-copy} base(name_pattern: gdb.Value | str) -> int ``` Return the base address of the first memory mapping containing the given name. #### Example ``` pwndbg> p/x $base("libc") $4 = 0x7ffff7d4b000 pwndbg> vmmap libc 0x7ffff7d4a000 0x7ffff7d4b000 rw-p 1000 6e000 /usr/lib/libncursesw.so.6.5 ► 0x7ffff7d4b000 0x7ffff7d6f000 r--p 24000 0 /usr/lib/libc.so.6 ► 0x7ffff7d6f000 0x7ffff7ed6000 r-xp 167000 24000 /usr/lib/libc.so.6 ► 0x7ffff7ed6000 0x7ffff7f2b000 r--p 55000 18b000 /usr/lib/libc.so.6 ► 0x7ffff7f2b000 0x7ffff7f2f000 r--p 4000 1e0000 /usr/lib/libc.so.6 ► 0x7ffff7f2f000 0x7ffff7f31000 rw-p 2000 1e4000 /usr/lib/libc.so.6 0x7ffff7f31000 0x7ffff7f39000 rw-p 8000 0 [anon_7ffff7f31] pwndbg> tele $base(\"libc\")+0x1337 00:0000│ 0x7ffff7d4c337 ◂— 0x80480a04214000f0 01:0008│ 0x7ffff7d4c33f ◂— 0x8040c02204452040 02:0010│ 0x7ffff7d4c347 ◂— 0x20042400000200 03:0018│ 0x7ffff7d4c34f ◂— 0x20 /* ' ' */ [...] ``` Beware of accidentally matching the wrong mapping. For instance, if the loaded executable contained the string "libc" anywhere in it's path, it would've been returned. ---------- ### **hex2ptr** ``` {.python .no-copy} hex2ptr(hex_string: gdb.Value | str) -> int ``` Converts a hex string to a little-endian address and returns the address. #### Example ``` pwndbg> p/x $hex2ptr("20 74 ed f7 ff 7f") $1 = 0x7ffff7ed7420 pwndbg> p/x $hex2ptr("2074edf7ff7f") $2 = 0x7ffff7ed7420 pwndbg> distance '$base("libc")' '$hex2ptr("20 74 ed f7 ff 7f")' 0x7ffff7d4b000->0x7ffff7ed7420 is 0x18c420 bytes (0x31884 words) ``` Especially useful for quickly converting pwntools output. ---------- ### **argc** ``` {.python .no-copy} argc() -> int ``` Get the number of program arguments. Evaluates to argc. #### Example ``` pwndbg> p $argc() $1 = 2 pwndbg> argv 00:0000│ 0x7fffffffe288 —▸ 0x7fffffffe659 ◂— '/usr/bin/cat' 01:0008│ 0x7fffffffe290 —▸ 0x7fffffffe666 ◂— 'gdbinit.py' 02:0010│ 0x7fffffffe298 ◂— 0 ``` ---------- ### **argv** ``` {.python .no-copy} argv(index: gdb.Value) -> gdb.Value ``` Get the n-th program argument. Evaluate argv on the supplied value. #### Example ``` pwndbg> p $argv(0) $11 = (signed char *) 0x7fffffffe666 "/usr/bin/sh" pwndbg> argv 00:0000│ 0x7fffffffe2a8 —▸ 0x7fffffffe666 ◂— '/usr/bin/sh' 01:0008│ 0x7fffffffe2b0 ◂— 0 ``` ---------- ### **environ** ``` {.python .no-copy} environ(env_name: gdb.Value) -> gdb.Value ``` Get an environment variable by name. Evaluate getenv() on the supplied value. #### Example ``` pwndbg> p $environ("LANG") $2 = (signed char *) 0x7fffffffebfb "LANG=en_US.UTF-8" ``` ---------- ### **envp** ``` {.python .no-copy} envp(index: gdb.Value) -> gdb.Value ``` Get the n-th environment variable. Evaluate envp on the supplied value. #### Example ``` pwndbg> p $envp(0x3F) $13 = (signed char *) 0x7fffffffef7d "LANG=en_US.UTF-8" pwndbg> p $envp(0x3F) == $environ("LANG") $14 = 1 ``` ---------- ### **fsbase** ``` {.python .no-copy} fsbase(offset: gdb.Value = gdb.Value(0)) -> int ``` Get the value of the FS segment register. Only valid on x86(-64). #### Example ``` pwndbg> p/x $fsbase() $3 = 0x7ffff7cdab80 pwndbg> p $fs_base == $fsbase() $4 = 1 pwndbg> x/gx $fsbase(0x28) 0x7ffff7cdaba8: 0x4da926e1668e5a00 pwndbg> x/gx $fsbase(0x30) 0x7ffff7cdabb0: 0x190a86d93bccf0ad pwndbg> tls Thread Local Storage (TLS) base: 0x7ffff7cdab80 TLS is located at: 0x7ffff7cda000 0x7ffff7cdc000 rw-p 2000 0 [anon_7ffff7cda] Dumping the address: tcbhead_t @ 0x7ffff7cdab80 0x00007ffff7cdab80 +0x0000 tcb : 0x7ffff7cdab80 0x00007ffff7cdab88 +0x0008 dtv : 0x7ffff7cdb4f0 0x00007ffff7cdab90 +0x0010 self : 0x7ffff7cdab80 0x00007ffff7cdab98 +0x0018 multiple_threads : 0x0 0x00007ffff7cdab9c +0x001c gscope_flag : 0x0 0x00007ffff7cdaba0 +0x0020 sysinfo : 0x0 0x00007ffff7cdaba8 +0x0028 stack_guard : 0x4da926e1668e5a00 0x00007ffff7cdabb0 +0x0030 pointer_guard : 0x190a86d93bccf0ad [...] pwndbg> canary [...] Canary = 0x4da926e1668e5a00 (may be incorrect on != glibc) [...] ``` FS will usually point to the start of the TLS. If you're not providing an offset, it is usually easier to use gdb's builtin $fs_base variable. ---------- ### **gsbase** ``` {.python .no-copy} gsbase(offset: gdb.Value = gdb.Value(0)) -> int ``` Get the value of the GS segment register. Only valid on x86(-64). #### Example ``` pwndbg> p/x $gsbase() $1 = 0x0 ``` The value of the GS register is more interesting when doing kernel debugging: ``` pwndbg> p/x $gsbase() $1 = 0xffff999287a00000 pwndbg> tele $gsbase() 00:0000│ 0xffff999287a00000 ◂— 0 ... ↓ 4 skipped 05:0028│ 0xffff999287a00028 ◂— 0xd6aa9b336d52a400 06:0030│ 0xffff999287a00030 ◂— 0 07:0038│ 0xffff999287a00038 ◂— 0 pwndbg> p $gsbase() == $gs_base $2 = 1 ``` If you're not providing an offset, it is usually easier to use gdb's builtin $gs_base variable. ---------- ### **bn_sym** ``` {.python .no-copy} bn_sym(name_val: gdb.Value) -> int | None ``` Lookup a symbol's address by name from Binary Ninja. This function sees symbols like functions and global variables, but not stack local variables, use `bn_var` for that. #### Example ``` pwndbg> set integration-provider binja Pwndbg successfully connected to Binary Ninja (4.2.6455 Personal) xmlrpc: http://127.0.0.1:31337 Set which provider to use for integration features to 'binja'. pwndbg> p main No symbol "main" in current context. pwndbg> p/x $bn_sym("main") $2 = 0x555555555645 pwndbg> b *($bn_sym("main")) Breakpoint 1 at 0x555555555645 ``` ---------- ### **bn_var** ``` {.python .no-copy} bn_var(name_val: gdb.Value) -> int | None ``` Lookup a stack variable's address by name from Binary Ninja. This function doesn't see functions or global variables, use `bn_sym` for that. #### Example ``` pwndbg> set integration-provider binja Pwndbg successfully connected to Binary Ninja (4.2.6455 Personal) xmlrpc: http://127.0.0.1:31337 Set which provider to use for integration features to 'binja'. pwndbg> p user_choice No symbol "user_choice" in current context. pwndbg> p/x $bn_var("user_choice") $4 = 0x7fffffffe118 pwndbg> vmmap $4 0x7ffff7ffe000 0x7ffff7fff000 rw-p 1000 0 [anon_7ffff7ffe] ► 0x7ffffffde000 0x7ffffffff000 rw-p 21000 0 [stack] +0x20118 pwndbg> p/x $bn_var("main") TypeError: Could not convert Python object: None. Error while executing Python code. ``` ---------- ### **bn_eval** ``` {.python .no-copy} bn_eval(expr: gdb.Value) -> int | None ``` Parse and evaluate a Binary Ninja expression. Read more about binary ninja expressions here: https://api.binary.ninja/binaryninja.binaryview-module.html#binaryninja.binaryview.BinaryView.parse_expression All registers in the current register set are available as magic variables (e.g. $rip). The $piebase magic variable is also included, with the computed executable base. This function cannot see stack local variables. #### Example ``` pwndbg> set integration-provider binja Pwndbg successfully connected to Binary Ninja (4.2.6455 Personal) xmlrpc: http://127.0.0.1:31337 Set which provider to use for integration features to 'binja'. pwndbg> p/x $bn_eval("10+20") $6 = 0x30 pwndbg> p/x $bn_eval("main") $7 = 0x1645 pwndbg> p/x $rebase($bn_eval("main")) $8 = 0x555555555645 pwndbg> p some_global_var No symbol "some_global_var" in current context. pwndbg> p/x $rebase($bn_eval("some_global_var+$rax")) $9 = 0x5555555586b8 pwndbg> p $rebase($bn_eval("some_global_var+$rax")) == $bn_sym("some_global_var") + $rax $10 = 1 pwndbg> p $bn_eval("$piebase+some_global_var+$rax") == $bn_sym("some_global_var") + $rax $11 = 1 ``` ---------- ### **ida** ``` {.python .no-copy} ida(name: gdb.Value) -> int ``` Lookup a symbol's address by name from IDA. Evaluate ida.LocByName() on the supplied value. This functions doesn't see stack local variables. #### Example ``` pwndbg> set integration-provider ida Pwndbg successfully connected to Ida Pro xmlrpc: http://127.0.0.1:31337 Set which provider to use for integration features to 'ida'. pwndbg> p main No symbol "main" in current context. pwndbg> p/x $ida("main") $1 = 0x555555555645 pwndbg> b *$ida("main") Breakpoint 2 at 0x555555555645 ``` ----------