mirror of https://github.com/pwndbg/pwndbg.git
Rewrite some unreliable methods for the heap heuristics (#1579)
* Refactor `pwndbg.glibc` - Add type hints - Use `info sharedlibrary` to find libc - Update the regex of libc filename - Rename `get_data_address()` to `get_data_section_address()` * Add a function to dump libc ELF file's .data section * Use the new methods to find `main_arena` and `mp_` With ELF of libc, we can use the default value of `main_arena` and `mp_` to find their address * Drop some unreliable methods for the heap heuristics * Update the tests for the heap heuristics * Show `main_arena` address in the `arenas` command output * Make the heap hueristics support statically linked targets * Drop some deprecated TLS functions and refactor the command - Drop some deprecated TLS functions for the deprecated heap heuristics - Don't call `pthread_self()` in the `tls` command without `-p` option - Show the page of TLS in the `tls` command output * Update the hint for the heap heuristics for multi-threaded * Fix the wrong usage of the exception * Fix the outdated description * Return the default global_max_fast when we cannot find the address * Enhance the output of `arena` and `mp` - Show the address of the arena we print in the output of `arena` command if we didn't specify the address by ourselves. - Avoid the bug that `arena` command might get an error if thread_arena doesn't allocate yet. - Show the address of `mp_` in the output of the `mp` command * Remove wrong hint * Support using brute-force to find the address of main_arena If the user allows, brute-force the left and right sides of the TLS address to find the closest possible value to the TLS address. * Refactor the code about thread_arena and add the new brute-force strategy In the .got section, brute-force search for possible TLS-reference values to find possible thread_arena locations * Add tests for thread_arena and global_max_fast - Check if we can get default global_max_fast - Check if we can use brute-force to find thread_arena * Update the output of `arenas` * Add the test for the `tls` command Add two tests for the `tls` command: ``` test_tls_address_and_command[x86-64] PASSED test_tls_address_and_command[i386] PASSED ``` * Update and refactor the heuristics for `thread_arena` and `tcache` - We provide an option for users to brute force `tcache` like what we did for `thread_arena` - Cache `thread_arena` even when we are single-threaded - Refactor the code for `thread_arena`, to make it work for `tcache` as well - Update the tests for `tcache` - Remove some redundant hint * Fix the wrong cache mechanism Cache the address of the arena instead of the instance of `Arena`, because `Arena` will cache the value of the field, resulting in getting the old value the next time the same property is used * Update the description of some configs about heap heuristics * Handling the case when tcache is NULL * Handling the case when thread_arena is NULL * Fix a bug that occurred when the TLS address could not be found * Fix #1550 * Show tid only if no address is specified * Update pwndbg/commands/__init__.py * Update pwndbg/commands/heap.py * Update pwndbg/commands/heap.py * Update pwndbg/commands/heap.py * Update pwndbg/commands/heap.py * Update pwndbg/commands/heap.py * Update pwndbg/commands/heap.py Co-authored-by: Disconnect3d <dominik.b.czarnota@gmail.com> * Fix lint * Move some code into `pwndbg.gdblib.elf` --------- Co-authored-by: Disconnect3d <dominik.b.czarnota@gmail.com>pull/1590/head
parent
8b7dd56e97
commit
449070557d
@ -1,21 +1,45 @@
|
||||
"""
|
||||
Command to print the information of the current Thread Local Storage (TLS).
|
||||
"""
|
||||
import argparse
|
||||
|
||||
import pwndbg.commands
|
||||
import pwndbg.gdblib.tls
|
||||
from pwndbg.color import message
|
||||
from pwndbg.commands import CommandCategory
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
formatter_class=argparse.RawTextHelpFormatter,
|
||||
description="Print out base address of the current Thread Local Storage (TLS).",
|
||||
)
|
||||
|
||||
@pwndbg.commands.ArgparsedCommand(
|
||||
"Print out base address of the current Thread Local Storage (TLS).",
|
||||
category=CommandCategory.LINUX,
|
||||
parser.add_argument(
|
||||
"-p",
|
||||
"--pthread-self",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="Try to get the address of TLS by calling pthread_self().",
|
||||
)
|
||||
|
||||
|
||||
@pwndbg.commands.ArgparsedCommand(parser, category=CommandCategory.LINUX)
|
||||
@pwndbg.commands.OnlyWhenRunning
|
||||
def tls() -> None:
|
||||
tls_base = pwndbg.gdblib.tls.address
|
||||
if tls_base:
|
||||
def tls(pthread_self=False) -> None:
|
||||
tls_base = (
|
||||
pwndbg.gdblib.tls.find_address_with_register()
|
||||
if not pthread_self
|
||||
else pwndbg.gdblib.tls.find_address_with_pthread_self()
|
||||
)
|
||||
if pwndbg.gdblib.memory.is_readable_address(tls_base):
|
||||
print(message.success("Thread Local Storage (TLS) base: %#x" % tls_base))
|
||||
else:
|
||||
print(message.error("Couldn't find Thread Local Storage (TLS) base."))
|
||||
print(message.success("TLS is located at:"))
|
||||
print(message.notice(pwndbg.gdblib.vmmap.find(tls_base)))
|
||||
return
|
||||
print(message.error("Couldn't find Thread Local Storage (TLS) base."))
|
||||
if not pthread_self:
|
||||
print(
|
||||
message.notice(
|
||||
"You can try to use -p/--pthread option to get the address of TLS by calling pthread_self().\n"
|
||||
"(This might cause problems if the pthread_self() is not in libc or not initialized yet.)"
|
||||
)
|
||||
)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,10 @@
|
||||
void *tls_address;
|
||||
|
||||
void break_here(void) {}
|
||||
|
||||
int main(){
|
||||
// TODO: This only works for i386, we should support arm/aarch64 in the future
|
||||
asm("movl %%gs:0, %0" : "=r" (tls_address));
|
||||
break_here();
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
void *tls_address;
|
||||
|
||||
void break_here(void) {}
|
||||
|
||||
int main(){
|
||||
// TODO: This only works for x86-64, we should support arm/aarch64 in the future
|
||||
asm("movq %%fs:0, %0" : "=r" (tls_address));
|
||||
break_here();
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
import gdb
|
||||
import pytest
|
||||
|
||||
import pwndbg.gdblib.tls
|
||||
import pwndbg.gdblib.vmmap
|
||||
import tests
|
||||
|
||||
TLS_X86_64_BINARY = tests.binaries.get("tls.x86-64.out")
|
||||
TLS_I386_BINARY = tests.binaries.get("tls.i386.out")
|
||||
|
||||
|
||||
# TODO: Support other architectures
|
||||
@pytest.mark.parametrize("binary", [TLS_X86_64_BINARY, TLS_I386_BINARY], ids=["x86-64", "i386"])
|
||||
def test_tls_address_and_command(start_binary, binary):
|
||||
try:
|
||||
start_binary(binary)
|
||||
except gdb.error:
|
||||
pytest.skip("This device does not support this test")
|
||||
gdb.execute("break break_here")
|
||||
gdb.execute("continue")
|
||||
|
||||
expected_tls_address = int(gdb.parse_and_eval("(void *)tls_address"))
|
||||
|
||||
assert pwndbg.gdblib.tls.find_address_with_register() == expected_tls_address
|
||||
|
||||
assert pwndbg.gdblib.tls.find_address_with_pthread_self() == expected_tls_address
|
||||
|
||||
assert (
|
||||
gdb.execute("tls", to_string=True)
|
||||
== f"""Thread Local Storage (TLS) base: {expected_tls_address:#x}
|
||||
TLS is located at:
|
||||
{pwndbg.gdblib.vmmap.find(expected_tls_address)}\n"""
|
||||
)
|
||||
|
||||
assert (
|
||||
gdb.execute("tls --pthread-self", to_string=True)
|
||||
== f"""Thread Local Storage (TLS) base: {expected_tls_address:#x}
|
||||
TLS is located at:
|
||||
{pwndbg.gdblib.vmmap.find(expected_tls_address)}\n"""
|
||||
)
|
||||
Loading…
Reference in new issue