--- 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 invocation 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 ### **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 ``` ---------- ### **base** ``` {.python .no-copy} base(name_pattern: gdb.Value | str) ``` 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. ---------- ### **bn_eval** ``` {.python .no-copy} bn_eval(expr: gdb.Value) -> int ``` 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:43717 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 ``` ---------- ### **bn_sym** ``` {.python .no-copy} bn_sym(name_val: gdb.Value) -> int ``` 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:43717 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 ``` 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:43717 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. ``` ---------- ### **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. ---------- ### **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. ---------- ### **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:43718 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 ``` ---------- ### **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' [...] ``` ----------