summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTheron <tspiegl@gmail.com>2020-06-28 22:12:15 -0500
committerTheron <tspiegl@gmail.com>2020-06-28 22:12:15 -0500
commit9b9e1489608f774dfe18e9e165e3fdd9df2c6242 (patch)
tree36a935bf9730a839e0771f5769a23d38f33bc8e2
parenta89c9d7fa750915030981de9be487035cda0ff17 (diff)
working on arm64
-rw-r--r--Makefile2
-rw-r--r--src/arm32/registers.c6
-rw-r--r--src/arm64/registers.c104
3 files changed, 109 insertions, 3 deletions
diff --git a/Makefile b/Makefile
index 2f05bbb..5c35b6d 100644
--- a/Makefile
+++ b/Makefile
@@ -5,6 +5,8 @@ SOURCES = $(addprefix src/, whatfiles.c attach.c utilities.c hashmap.c strings.c
ARCH = $(shell uname -m)
ifeq ($(findstring arm,$(ARCH)), arm)
ARCH_DIR = arm32
+else ifeq ($(findstring aarch64,$(ARCH)), aarch64)
+ ARCH_DIR = arm64
else
ARCH_DIR = x86_64
endif
diff --git a/src/arm32/registers.c b/src/arm32/registers.c
index d4eeb4d..1b7392a 100644
--- a/src/arm32/registers.c
+++ b/src/arm32/registers.c
@@ -96,17 +96,17 @@ bool step_syscall(pid_t current_pid, int proc_status, HashMap map)
}
// can't get some registers for some reason
- if (regs.ARM_ORIG_r0 != -1) {
+ if (regs.ARM_r7 != -1) {
could_read = true;
// If it's the same PID performing the same syscall (has same orig_rax) as last time, we don't care. Just means it's exiting the syscall.
// Might want to keep for debug mode? This might result in missing some output, in the case where two threads of the same process enter the same syscall before either exits,
// because they will both return the same PID to wait() when given SIGTRAP as part of the syscall-enter-exit loop. Might also result in double-printing,
// because if two threads (that report the same PID) enter two different syscalls before either exits, the "last" syscall for the PID won't be the entry by that thread.
- if (!is_exiting(current_pid, regs.ARM_ORIG_r0) /*|| Debug*/) {
+ if (!is_exiting(current_pid, regs.ARM_r7) /*|| Debug*/) {
check_syscall(current_pid, (void*)&regs, map);
}
LastSyscall.pid = current_pid;
- LastSyscall.syscall = regs.ARM_ORIG_r0;
+ LastSyscall.syscall = regs.ARM_r7;
check_ptrace_event(current_pid, proc_status, map);
// continue, catching next entry or exit from syscall
res = ptrace(PTRACE_SYSCALL, current_pid, 0, 0);
diff --git a/src/arm64/registers.c b/src/arm64/registers.c
new file mode 100644
index 0000000..3ddf4aa
--- /dev/null
+++ b/src/arm64/registers.c
@@ -0,0 +1,104 @@
+
+#include <sys/ptrace.h>
+#include <linux/ptrace.h>
+#include <linux/elf.h> // for NT_PRSTATUS
+#include <linux/uio.h> // for struct iovec
+
+#include <sys/user.h>
+#include <sys/syscall.h>
+#include <sys/wait.h>
+
+#include "../hashmap.h"
+#include "../whatfiles.h"
+
+void check_syscall(pid_t current_pid, void *registers, HashMap map)
+{
+ struct user_pt_regs *regs = (struct user_pt_regs*)registers;
+ struct String filename = {0};
+ struct String output = {0};
+ init_string(&filename, 64);
+ init_string(&output, 64);
+ char mode[MODE_LEN] = {0};
+
+ pid_t parent_tid, child_tid;
+ unsigned long flags;
+ unsigned long newsp;
+
+ size_t index;
+ HashError err = find_index(current_pid, map, &index);
+ if (err) DEBUG("unknown pid %d, syscall %lld\n", current_pid, regs->regs[8]);
+
+ switch (regs->regs[8])
+ {
+ case SYS_execve:
+ DEBUG("PID %d exec'd. x8: %lld\n", current_pid, regs->regs[8]);
+ if (peek_filename(current_pid, regs->regs[0], &filename)) {
+ DEBUG("associated process %d with name \"%s\"\n", current_pid, filename.data);
+ set_name(current_pid, filename.data, map);
+ }
+ break;
+ case SYS_clone:
+ flags = regs->regs[0];
+ newsp = regs->regs[1];
+ parent_tid = ptrace(PTRACE_PEEKDATA, current_pid, (void*)regs->regs[2], 0);
+ child_tid = ptrace(PTRACE_PEEKDATA, current_pid, (void*)regs->regs[4], 0);
+ DEBUG("PID %d cloned. x8: %lld, flags: 0x%ld, newsp: 0x%ld, parent pid: %d, child pid: %d\n",
+ current_pid, regs->regs[8], flags, newsp, parent_tid, child_tid);
+ break;
+ case SYS_openat:
+ peek_filename(current_pid, regs->regs[1], &filename);
+ get_mode(regs->regs[3], mode);
+ build_output(mode, "openat()", regs->regs[2], current_pid, &filename, &output, map);
+ OUTPUT("%s", output.data);
+ break;
+ case SYS_unlinkat:
+ peek_filename(current_pid, regs->regs[1], &filename);
+ build_output("delete", "unlinkat()", 0, current_pid, &filename, &output, map);
+ OUTPUT("%s", output.data);
+ break;
+ default:
+ // DEBUG("syscall: %lld, pid: %d, %s\n", regs->ARM_r7, current_pid, proc_name);
+ break;
+ }
+ free(filename.data);
+ free(output.data);
+}
+
+
+bool step_syscall(pid_t current_pid, int proc_status, HashMap map)
+{
+ long res;
+ struct user_pt_regs regs = {0};
+ struct iovec iovec = { &regs, sizeof(regs) };
+ bool could_read = false;
+ // get current register values
+ // TODO: make this fault tolerant to a dead PID
+ res = ptrace(PTRACE_GETREGSET, current_pid, NT_PRSTATUS, &iovec);
+ if (res == -1L) {
+ DEBUG("CURRENT PID: %d, failed to get registers\n", current_pid);
+ }
+
+ // can't get some registers for some reason
+ if (regs.regs[8] != -1) {
+ could_read = true;
+ // If it's the same PID performing the same syscall (has same orig_rax) as last time, we don't care. Just means it's exiting the syscall.
+ // Might want to keep for debug mode? This might result in missing some output, in the case where two threads of the same process enter the same syscall before either exits,
+ // because they will both return the same PID to wait() when given SIGTRAP as part of the syscall-enter-exit loop. Might also result in double-printing,
+ // because if two threads (that report the same PID) enter two different syscalls before either exits, the "last" syscall for the PID won't be the entry by that thread.
+ if (!is_exiting(current_pid, regs.regs[8]) /*|| Debug*/) {
+ check_syscall(current_pid, (void*)&regs, map);
+ }
+ LastSyscall.pid = current_pid;
+ LastSyscall.syscall = regs.regs[8];
+ check_ptrace_event(current_pid, proc_status, map);
+ // continue, catching next entry or exit from syscall
+ res = ptrace(PTRACE_SYSCALL, current_pid, 0, 0);
+ if (res == -1L) DEBUG("ptrace() failed to resume");
+ } else {
+ DEBUG("can't get registers, detaching from %d\n", current_pid);
+ res = ptrace(PTRACE_DETACH, current_pid, 0, 0); // "Under Linux, a tracee can be detached in this way regardless of which method was used to initiate tracing."
+ if (res == -1L) DEBUG("ptrace() failed to detach from %d\n", current_pid);
+ }
+ return could_read;
+}
+