mirror of https://github.com/pwndbg/pwndbg
Add find_fake_fast test (#1286)
* Fix find_fake_fast test name * Add more find_fake_fast tests
This commit is contained in:
parent
1a0bbbf26a
commit
e6574f447f
|
@ -10,6 +10,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
void break_here(void) {}
|
void break_here(void) {}
|
||||||
|
|
||||||
|
@ -17,10 +18,79 @@ void break_here(void) {}
|
||||||
// Enough space afterwards to ensure only this fake size field is a candidate.
|
// Enough space afterwards to ensure only this fake size field is a candidate.
|
||||||
char fake_chunk[0x80] __attribute__((aligned(0x10))) = "XXXXXXXX\x7f";
|
char fake_chunk[0x80] __attribute__((aligned(0x10))) = "XXXXXXXX\x7f";
|
||||||
|
|
||||||
int main(void)
|
// This buffer will contain the fake chunk sizes
|
||||||
{
|
unsigned long buf[64] __attribute__((aligned(0x10)));
|
||||||
|
|
||||||
|
// This is the address we want the fake chunks to overlap with
|
||||||
|
unsigned long target_address;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Put the value of `size` at `distance` bytes before the address of
|
||||||
|
* `target_address`
|
||||||
|
*/
|
||||||
|
void setup_mem(unsigned long size, unsigned distance) {
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
target_address = 0;
|
||||||
|
|
||||||
|
char *chunk_size_addr = (char*)&target_address - distance;
|
||||||
|
*(unsigned long*)chunk_size_addr = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
assert((unsigned long)&target_address - (unsigned long)buf == sizeof(buf));
|
||||||
// Initialize malloc so heap commands can run.
|
// Initialize malloc so heap commands can run.
|
||||||
void* m = malloc(0x18);
|
void* m = malloc(0x18);
|
||||||
|
|
||||||
|
// A valid aligned fastbin chunk with no flags set
|
||||||
|
setup_mem(0x20, 0x8);
|
||||||
|
break_here();
|
||||||
|
|
||||||
|
// A valid aligned fastbin chunk with all flags set
|
||||||
|
setup_mem(0x2F, 0x8);
|
||||||
|
break_here();
|
||||||
|
|
||||||
|
// A valid unaligned fastbin chunk
|
||||||
|
setup_mem(0x20, 0x9);
|
||||||
|
break_here();
|
||||||
|
|
||||||
|
// A valid aligned fastbin chunk that's too close to the target address (the
|
||||||
|
// size overlaps the target address)
|
||||||
|
setup_mem(0x20, 0x0);
|
||||||
|
break_here();
|
||||||
|
|
||||||
|
// A valid unaligned fastbin chunk that's too close to the target address (the
|
||||||
|
// size overlaps the target address)
|
||||||
|
setup_mem(0x20, 0x7);
|
||||||
|
break_here();
|
||||||
|
|
||||||
|
// An invalid chunk with a size below the minimum chunk size
|
||||||
|
setup_mem(0x1F, 0x8);
|
||||||
|
break_here();
|
||||||
|
|
||||||
|
// A valid aligned fastbin chunk just in range of the target address
|
||||||
|
setup_mem(0x80, 0x78);
|
||||||
|
break_here();
|
||||||
|
|
||||||
|
// A valid unaligned fastbin chunk just in range of the target address
|
||||||
|
/* setup_mem(0x80, 0x7F); */
|
||||||
|
/* break_here(); */
|
||||||
|
|
||||||
|
// A valid aligned fastbin chunk just out of range of the target address
|
||||||
|
setup_mem(0x80, 0x80);
|
||||||
|
break_here();
|
||||||
|
|
||||||
|
// A fastbin chunk with a size greater than `global_max_fast`, less than
|
||||||
|
// `global_max_fast` bytes away from the target address
|
||||||
|
setup_mem(0x100, 0x10);
|
||||||
|
break_here();
|
||||||
|
|
||||||
|
// A fastbin chunk with a size greater than `global_max_fast`, more than
|
||||||
|
// `global_max_fast` bytes away from the target address
|
||||||
|
setup_mem(0x100, 0x90);
|
||||||
|
break_here();
|
||||||
|
|
||||||
|
// A fastbin chunk with a size greater than `global_max_fast`, just out of
|
||||||
|
// range of the target address
|
||||||
|
setup_mem(0x100, 0x100);
|
||||||
break_here();
|
break_here();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
ZIGPATH ?= ../../.zig
|
||||||
ZIGCC = $(ZIGPATH)/zig cc
|
ZIGCC = $(ZIGPATH)/zig cc
|
||||||
|
|
||||||
CC = gcc
|
CC = gcc
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
import re
|
||||||
|
|
||||||
|
import gdb
|
||||||
|
|
||||||
|
import pwndbg
|
||||||
|
import tests
|
||||||
|
|
||||||
|
HEAP_FIND_FAKE_FAST = tests.binaries.get("heap_find_fake_fast.out")
|
||||||
|
|
||||||
|
target_address = None
|
||||||
|
|
||||||
|
|
||||||
|
def check_result(result, expected_size):
|
||||||
|
ptrsize = pwndbg.gdblib.arch.ptrsize
|
||||||
|
|
||||||
|
matches = re.findall(r"\bAddr: (0x[0-9a-f]+)", result)
|
||||||
|
assert len(matches) == 1
|
||||||
|
addr = int(matches[0], 16)
|
||||||
|
|
||||||
|
matches = re.findall(r"\bsize: (0x[0-9a-f]+)", result)
|
||||||
|
assert len(matches) == 1
|
||||||
|
size = int(matches[0], 16)
|
||||||
|
|
||||||
|
assert size == expected_size
|
||||||
|
|
||||||
|
# The chunk can't start too close to the target address
|
||||||
|
assert addr <= target_address - (2 * ptrsize)
|
||||||
|
|
||||||
|
# Clear the flags
|
||||||
|
size &= ~0xF
|
||||||
|
|
||||||
|
# The chunk should overlap the target address
|
||||||
|
assert addr + ptrsize + size > target_address
|
||||||
|
|
||||||
|
|
||||||
|
def check_no_results(result):
|
||||||
|
matches = re.findall(r"\bAddr: (0x[0-9a-f]+)", result)
|
||||||
|
assert len(matches) == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_find_fake_fast_command(start_binary):
|
||||||
|
global target_address
|
||||||
|
|
||||||
|
start_binary(HEAP_FIND_FAKE_FAST)
|
||||||
|
gdb.execute("break break_here")
|
||||||
|
gdb.execute("continue")
|
||||||
|
|
||||||
|
# Ensure memory at fake_chunk's heap_info struct isn't mapped.
|
||||||
|
unmapped_heap_info = pwndbg.heap.ptmalloc.heap_for_ptr(
|
||||||
|
pwndbg.gdblib.symbol.address("fake_chunk")
|
||||||
|
)
|
||||||
|
assert pwndbg.gdblib.memory.peek(unmapped_heap_info) is None
|
||||||
|
|
||||||
|
# A gdb.MemoryError raised here indicates a regression from PR #1145
|
||||||
|
gdb.execute("find_fake_fast (void*)&fake_chunk+0x70")
|
||||||
|
|
||||||
|
target_address = pwndbg.gdblib.symbol.address("target_address")
|
||||||
|
assert target_address is not None
|
||||||
|
print(hex(target_address))
|
||||||
|
|
||||||
|
# setup_mem(0x20, 0x8)
|
||||||
|
result = gdb.execute("find_fake_fast &target_address", to_string=True)
|
||||||
|
check_result(result, 0x20)
|
||||||
|
gdb.execute("continue")
|
||||||
|
|
||||||
|
# setup_mem(0x2F, 0x8)
|
||||||
|
result = gdb.execute("find_fake_fast &target_address", to_string=True)
|
||||||
|
check_result(result, 0x2F)
|
||||||
|
gdb.execute("continue")
|
||||||
|
|
||||||
|
# setup_mem(0x20, 0x9)
|
||||||
|
result = gdb.execute("find_fake_fast &target_address", to_string=True)
|
||||||
|
check_result(result, 0x20)
|
||||||
|
gdb.execute("continue")
|
||||||
|
|
||||||
|
# setup_mem(0x20, 0x0)
|
||||||
|
result = gdb.execute("find_fake_fast &target_address", to_string=True)
|
||||||
|
check_no_results(result)
|
||||||
|
gdb.execute("continue")
|
||||||
|
|
||||||
|
# setup_mem(0x20, 0x7)
|
||||||
|
result = gdb.execute("find_fake_fast &target_address", to_string=True)
|
||||||
|
check_no_results(result)
|
||||||
|
gdb.execute("continue")
|
||||||
|
|
||||||
|
# setup_mem(0x1F, 0x8)
|
||||||
|
result = gdb.execute("find_fake_fast &target_address", to_string=True)
|
||||||
|
check_no_results(result)
|
||||||
|
gdb.execute("continue")
|
||||||
|
|
||||||
|
# setup_mem(0x80, 0x78)
|
||||||
|
result = gdb.execute("find_fake_fast &target_address", to_string=True)
|
||||||
|
check_result(result, 0x80)
|
||||||
|
gdb.execute("continue")
|
||||||
|
|
||||||
|
# setup_mem(0x80, 0x7F)
|
||||||
|
# result = gdb.execute("find_fake_fast &target_address", to_string=True)
|
||||||
|
# check_result(result, 0x80)
|
||||||
|
# gdb.execute("continue")
|
||||||
|
|
||||||
|
# setup_mem(0x80, 0x80)
|
||||||
|
result = gdb.execute("find_fake_fast &target_address", to_string=True)
|
||||||
|
check_no_results(result)
|
||||||
|
gdb.execute("continue")
|
||||||
|
|
||||||
|
# setup_mem(0x100, 0x10)
|
||||||
|
result = gdb.execute("find_fake_fast &target_address", to_string=True)
|
||||||
|
check_no_results(result)
|
||||||
|
gdb.execute("continue")
|
||||||
|
|
||||||
|
# setup_mem(0x100, 0x90)
|
||||||
|
result = gdb.execute("find_fake_fast &target_address", to_string=True)
|
||||||
|
check_no_results(result)
|
||||||
|
|
||||||
|
# setup_mem(0x100, 0x100)
|
||||||
|
result = gdb.execute("find_fake_fast &target_address", to_string=True)
|
||||||
|
check_no_results(result)
|
|
@ -1,23 +0,0 @@
|
||||||
import gdb
|
|
||||||
|
|
||||||
import pwndbg
|
|
||||||
import tests
|
|
||||||
|
|
||||||
HEAP_FIND_FAKE_FAST = tests.binaries.get("heap_find_fake_fast.out")
|
|
||||||
|
|
||||||
|
|
||||||
# Ensure find_fake_fast command doesn't error when fake chunk's heap_info
|
|
||||||
# struct isn't mapped.
|
|
||||||
def test_find_fake_fast_command(start_binary):
|
|
||||||
start_binary(HEAP_FIND_FAKE_FAST)
|
|
||||||
gdb.execute("break break_here")
|
|
||||||
gdb.execute("continue")
|
|
||||||
|
|
||||||
# Ensure memory at fake_chunk's heap_info struct isn't mapped.
|
|
||||||
unmapped_heap_info = pwndbg.heap.ptmalloc.heap_for_ptr(
|
|
||||||
pwndbg.gdblib.symbol.address("fake_chunk")
|
|
||||||
)
|
|
||||||
assert pwndbg.gdblib.memory.peek(unmapped_heap_info) is None
|
|
||||||
|
|
||||||
# A gdb.MemoryError raised here indicates a regression from PR #1145
|
|
||||||
gdb.execute("find_fake_fast (void*)&fake_chunk+0x70")
|
|
Loading…
Reference in New Issue