diff --git a/README.md b/README.md index 2496d0f..332e64a 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ p.regs.rax # (int) p.regs.rax = 0x1337133713371337 # Get process base -p.maps["libc.so.6"] # (int) +p.maps["libc.so.6"].base # (int) # Get current thread id (valid in hooks and thread entrypoint) p.tid # (int), starts from 1 diff --git a/lib/pyda/process.py b/lib/pyda/process.py index e355a1b..4a7ace4 100644 --- a/lib/pyda/process.py +++ b/lib/pyda/process.py @@ -40,8 +40,8 @@ def _syscall_pre_hook_dispatch(self, syscall_num): return True def _syscall_post_hook_dispatch(self, syscall_num): - if syscall_num in self._syscall_pre_hooks: - for h in self._syscall_pre_hooks[syscall_num]: + if syscall_num in self._syscall_post_hooks: + for h in self._syscall_post_hooks[syscall_num]: h(self, syscall_num) def hook(self, addr, callback): diff --git a/tests/run_tests.py b/tests/run_tests.py index 1b10931..ad9ca4f 100644 --- a/tests/run_tests.py +++ b/tests/run_tests.py @@ -53,7 +53,7 @@ def main(): ) ) - # err_hook.py tests the case where a hook throws an exception + # err_hook.py: hook throws an exception # NOTE: Hooks intentionally fail 'gracefully' and do not abort res &= run_test( "thread_1000.c", "err_hook.py", @@ -66,7 +66,7 @@ def main(): ) ) - # err_thread_entry.py tests the case where a hook throws an exception + # err_thread_entry.py: thread entry hook throws an exception # NOTE: Hooks intentionally fail 'gracefully' and do not abort res &= run_test( "thread_1000.c", "err_thread_entry.py", @@ -79,6 +79,18 @@ def main(): ) ) + res &= run_test( + "simple.c", "test_syscall.py", + ExpectedResult( + retcode=0, + checkers=[ + output_checker, + lambda o, e: o.count(b"pre syscall") == o.count(b"post syscall") + 1, # (+1 for exit) + lambda o, e: o.index(b"pre syscall") < o.index(b"post syscall"), + ] + ) + ) + if not res: exit(1) diff --git a/tests/simple.c b/tests/simple.c index e69de29..1ef76d9 100644 --- a/tests/simple.c +++ b/tests/simple.c @@ -0,0 +1,21 @@ +#include +#include +#include + +int main(int argc, char** argv) { + printf("start\n"); + void *allocs[10]; + for (int i=0; i<10; i++) { + allocs[i] = malloc(0x100); + } + for (int i=0; i<10; i++) { + free(allocs[i]); + } + for (int i=0; i<10; i++) { + allocs[i] = malloc(0x100); + } + for (int i=0; i<10; i++) { + free(allocs[i]); + } + printf("end\n"); +} \ No newline at end of file diff --git a/tests/test_syscall.py b/tests/test_syscall.py new file mode 100644 index 0000000..b43d0cb --- /dev/null +++ b/tests/test_syscall.py @@ -0,0 +1,49 @@ +from pyda import * +from pwnlib.elf.elf import ELF +from pwnlib.util.packing import u64 +import string +import sys + +p = process() + +e = ELF(p.exe_path) +e.address = p.maps[p.exe_path].base + +plt_map = { e.plt[x]: x for x in e.plt } + +def guess_arg(x): + printable_chars = bytes(string.printable, 'ascii') + + # Is pointer? + if x > 0x100000000: + try: + data = p.read(x, 0x20) + if all([c in printable_chars for c in data[:4]]): + if 0 in data: + return str(data[:data.index(0)]) + else: + return str(data[:20]) + "..." + + except Exception as e: + pass + + return hex(x) + +def syscall_pre_hook(p, num): + print(f"[pre syscall {num}] (" + ", ".join([ + f"rdi={guess_arg(p.regs.rdi)}", + f"rsi={guess_arg(p.regs.rsi)}", + f"rdx={guess_arg(p.regs.rdx)}", + f"rcx={guess_arg(p.regs.rcx)}", + ]) + ")") + +def syscall_post_hook(p, num): + print(f"[post syscall {num}]") + +for snum in range(500): + p.syscall_pre(snum, syscall_pre_hook) + +for snum in range(500): + p.syscall_post(snum, syscall_post_hook) + +p.run() \ No newline at end of file