在C中拦截和替换系统调用时出现的问题

nc1teljy  于 2024-01-06  发布在  其他
关注(0)|答案(1)|浏览(119)

我试图拦截所有的“syscall“为我的代码。我能够接收调用,但由于某种原因,我的实现的syscall是不等价的,因为在某些时候,程序崩溃,如果我激活的替代,而它的工作没有替代。
我这样做的原因是为了更好地理解我的程序中的哪些调用(及其依赖项)使用了哪些系统调用。我知道我可以使用诸如ptrace之类的东西,但现在对我来说,这真的是更多地理解为什么这不起作用。这是在arm64 Linux上运行的。
下面是我的系统调用替换实现:

long syscall(long number, ...){
    printf("Intercepted syscall: %lu\n", number);
    va_list original_args;
    va_start(original_args, number);

    long (*original_syscall)(long number, ...) = NULL;
    original_syscall = (long (*)(long, ...))dlsym(RTLD_NEXT, "syscall");
    long result = original_syscall(number, original_args);
    va_end(original_args);
    return result;
}

字符串
这里的日志:

Intercepted syscall: 178
Intercepted syscall: 178
Intercepted syscall: 178
Intercepted syscall: 178
Intercepted syscall: 178
Intercepted syscall: 57
Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 3606 (Thread-2)

w1e3prcc

w1e3prcc1#

你想做的事情在C中并不容易做到,你必须手动解析参数列表(因为没有标准的方法将va_list重定向到可变参数函数)。
使用汇编(未测试)可能更容易:

message:
    .asciz "Intercepted syscall: %lu\n"
func:
    .asciz "syscall"

syscall:
    stp x29, x30, [sp, -80]!
    stp x0, x1, [sp, 16]
    stp x2, x3, [sp, 32]
    stp x4, x5, [sp, 48]
    stp x6, x7, [sp, 64]
    mov x1, x0
    adr x0, message
    bl printf
    adr x1, func
    mov x0, -1
    bl dlsym
    mov x8, x0
    ldp x6, x7, [sp, 64]
    ldp x4, x5, [sp, 48]
    ldp x2, x3, [sp, 32]
    ldp x0, x1, [sp, 16]
    ldp x29, x30, [sp], 80
    br x0

字符串
这个想法是你保持参数列表不变(保留所有可能的寄存器参数x0-x7),并直接跳转到原始系统调用函数(通过br)。由于返回地址已经在x30中,因此函数将返回给我们的调用者而不是我们。这是一个优化,将already apply编译为 Package 器,但不幸的是,没有办法将varargs列表转发到C中的另一个可变参数函数。
正如@stark提到的,printf可能会执行write,这可能会导致无限递归(特别是因为stdout是行缓冲的,\n会刷新它)。唯一真实的“安全”的地方,你可以尝试记录你的数据是内存(并尝试稍后写入),但这本身会带来很多麻烦,所以我不推荐它。

相关问题