Skip to content

Commit

Permalink
fix: post syscall hooks, add test
Browse files Browse the repository at this point in the history
  • Loading branch information
ndrewh committed Jul 8, 2024
1 parent 99d6b18 commit 3989500
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 5 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions lib/pyda/process.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
16 changes: 14 additions & 2 deletions tests/run_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand All @@ -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)

Expand Down
21 changes: 21 additions & 0 deletions tests/simple.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

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");
}
49 changes: 49 additions & 0 deletions tests/test_syscall.py
Original file line number Diff line number Diff line change
@@ -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()

0 comments on commit 3989500

Please sign in to comment.