pwnlib.libc.glibc — Convenient Functions for Glibc
Some glibc related convenient functions.
- class pwnlib.libc.glibc.ExitDtorList(func: int, guard: int, obj: int, lmap: int, nextl: int)[source]
Craft a
struct dtor_listobject. glibc will invoke functions in it if it’s not null when exits. Note that to avoid program aborting, theExitDtorListpointer must be free-able. Check struct dtor_list definitions.- Parameters:
Examples
>>> context.clear(arch='amd64') >>> dtor = glibc.ExitDtorList(0x402c0, 0xdeadbeef, 0, 0, 0) >>> dtor ExitDtorList(func=0x402c0 ^ 0xdeadbeef, obj=0x0, map=0x0, next=0x0) >>> bytes(dtor).hex() '00005e7853bd0100000000000000000000000000000000000000000000000000'
- static from_bytes(data: bytes, guard: int) ExitDtorList[source]
Construct an
ExitDtorListfrom bytes object.- Parameters:
Examples
>>> context.clear(arch='amd64') >>> guard = 0xd36a59fe4e9853d8 >>> blob = bytes.fromhex('d4a611029a375619000000000000000010915555555500000000000000000000') >>> glibc.ExitDtorList.from_bytes(blob, guard) ExitDtorList(func=0x5555555552d0 ^ 0xd36a59fe4e9853d8, obj=0x0, map=0x555555559110, next=0x0)
- class pwnlib.libc.glibc.ExitFlavor(*values)[source]
Enum adapted from glibc
exit.h. Check enum definitions.Original enums are:
ef_free,ef_us,ef_on,ef_atandef_cxa.
- class pwnlib.libc.glibc.ExitFunc(flavor: ExitFlavor, func: int, guard: int, arg: int | None = None, dso: int | None = None)[source]
Craft a
struct exit_functionobject. If user has arbitrary write to libc area and knows pointer guard used inPTR_MANGLE, then the user is able to hijack control flow when process exits. Check struct exit_function definitions.- Parameters:
flavor (ExitFlavor) – Which flavor of exit func is registered.
func (int) – A pointer to function to execute.
guard (int) – Process
POINTER_GUARD.arg (int) – Optional.
onexitandcxa_exitrequire it.dso (int) – Optional.
cxa_exitrequire it. (dso_handle)
Examples
>>> context.clear(arch='amd64') >>> glibc.ExitFunc(glibc.ExitFlavor.FREE, 0, 0) ExitFunc(FREE) >>> glibc.ExitFunc(glibc.ExitFlavor.CXA, 0x401f0, 0x13371337deadbeef, 0x238900000680, 0x44008) ExitFunc(CXA, fn=0x401f0 ^ 0x13371337deadbeef, arg=0x238900000680, dso_handle=0x44008) >>> exit_func = glibc.ExitFunc(glibc.ExitFlavor.AT, 0x401f0, 0x13371337deadbeef) >>> exit_func ExitFunc(AT, fn=0x401f0 ^ 0x13371337deadbeef) >>> bytes(exit_func).hex() '03000000000000006e263e7e53bd6f26'
- static from_bytes(data: bytes, guard: int) ExitFunc[source]
Construct an
ExitFuncfrom bytes object.- Parameters:
Examples
>>> context.clear(arch='amd64') >>> guard = 0x2f21c4a298024bcd >>> blob = bytes.fromhex('0300000000000000435ea835ae9aef23') >>> glibc.ExitFunc.from_bytes(blob, guard) ExitFunc(AT, fn=0x555555555119 ^ 0x2f21c4a298024bcd) >>> blob = bytes.fromhex('0200000000000000435ea835ae9aef230000371337130000') >>> glibc.ExitFunc.from_bytes(blob, guard) ExitFunc(ON, fn=0x555555555119 ^ 0x2f21c4a298024bcd, arg=0x133713370000) >>> blob = bytes.fromhex('0000000000000000') >>> glibc.ExitFunc.from_bytes(blob, guard) ExitFunc(FREE) >>> blob = bytes.fromhex('0100000000000000') >>> glibc.ExitFunc.from_bytes(blob, guard) ExitFunc(USED)
- class pwnlib.libc.glibc.ExitFuncList(nextp: int, fns: list[ExitFunc])[source]
Craft a
struct exit_function_listobject. glibc has a static variableinitialto store most atexit objects and a pointer__exit_funcspointing toinitial. Check struct exit_function_list definitions.- Parameters:
- Variables:
idx (int) – Total size of registered exit funcs. (This field is automatically obtained via
len(funcs))
Examples
>>> context.clear(arch='i386') >>> fa = glibc.ExitFunc(glibc.ExitFlavor.FREE, 0, 0) >>> fb = glibc.ExitFunc(glibc.ExitFlavor.AT, 0x401f0, 0x13371337) >>> flist = glibc.ExitFuncList(0, [fa, fb]) >>> flist ExitFuncList(next=0x0, idx=2, fns=[ExitFunc(FREE), ExitFunc(AT, fn=0x401f0 ^ 0x13371337)]) >>> bytes(flist).hex() '00000000020000000000000000000000000000000000000003000000268e25660000000000000000'
- static from_bytes(data: bytes, guard: int) ExitFuncList[source]
Construct an
ExitFuncListfrom bytes object.- Parameters:
Examples
>>> context.clear(arch='amd64') >>> guard = 0x2d42599562d398bb >>> blob = bytes.fromhex('000000000000000001000000000000000400000000000000845ab66f5e2ad54c00000000000000000000000000000000') >>> glibc.ExitFuncList.from_bytes(blob, guard) ExitFuncList(next=0x0, idx=1, fns=[ExitFunc(CXA, fn=0x7ffff7fcaf60 ^ 0x2d42599562d398bb, arg=0x0, dso_handle=0x0)])
- pwnlib.libc.glibc.protect_ptr(word_addr: int, value: int) int[source]
Perform PROTECT_PTR in glibc heap macros to protect pointers.
REVEAL_PTRis basicallyPROTECT_PTR, and since we don’t know the address of the word, so useprotect_ptrinstead.- Parameters:
- Returns:
Protected/Revealed value.
Examples
>>> hex(glibc.protect_ptr(0x5e5555556700, 0)) '0x5e5555556' >>> ptr_addr = 0x555555559200 >>> ptr_value = 0x7ffff7f96058 >>> glibc.protect_ptr(ptr_addr, glibc.protect_ptr(ptr_addr, ptr_value)) == ptr_value True
- pwnlib.libc.glibc.ptr_demangle(guard: int, mangled: int) int[source]
Perform
PTR_DEMANGLEin glibc to demangle protected pointer.- Parameters:
- Returns:
Demangled value.
Examples
>>> with context.local(arch='amd64'): ... val = glibc.ptr_demangle(0x1f1f1f1f1f1f1f1f, 0xc03e3e3e3e3e3e3e) ... print(hex(val)) 0x7f0000000000 >>> with context.local(arch='aarch64'): ... val = glibc.ptr_demangle(0x1f1f1f1f, 0x2e2e2e2e00000000) ... print(hex(val)) 0x2e2e2e2e1f1f1f1f
- pwnlib.libc.glibc.ptr_mangle(guard: int, value: int) int[source]
Perform
PTR_MANGLEin glibc to protect pointers.- Parameters:
- Returns:
Mangled value.
Examples
>>> with context.local(arch='amd64'): ... val = glibc.ptr_mangle(0x1f1f1f1f1f1f1f1f, 0x7f0000000000) ... print(hex(val)) 0xc03e3e3e3e3e3e3e >>> with context.local(arch='arm'): ... val = glibc.ptr_mangle(0x1f1f, 0x2e2e0000) ... print(hex(val)) 0x2e2e1f1f
- pwnlib.libc.glibc.reveal_ptr_same_page(ptr_value: int) int[source]
Reveal a pointer that was mangled by protect_ptr without knowing where the pointer is stored. Only works if the leaked pointer itself is stored on the same page as its value.
- Parameters:
ptr_value (int) – The mangled pointer.
- Returns:
int – The original pointer.
Example
>>> context.clear(arch='amd64') >>> ptr_addr = 0x555555559200 >>> ptr_value = 0x555555559380 >>> glibc.reveal_ptr_same_page(glibc.protect_ptr(ptr_addr, ptr_value)) == ptr_value True >>> ptr_addr = 0x555555559200 >>> ptr_value = 0x55555556a380 >>> glibc.reveal_ptr_same_page(glibc.protect_ptr(ptr_addr, ptr_value)) == ptr_value False