You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ARM64 Linux下syscall拦截替换导致程序崩溃问题排查

问题描述

尝试拦截程序中所有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)
问题分析与修复

核心错误原因

直接将va_list类型变量传递给原始syscall函数是完全错误的。syscall是可变参数函数(声明为...),它期望接收栈上的原始参数序列,而非va_list指针。这种错误的参数传递会彻底破坏ARM64的寄存器/栈帧布局,导致后续调用(比如日志中触发崩溃的syscall 57——clone创建线程)时出现致命错误,最终触发SIGABRT。

修复方案

ARM64 Linux的syscall最多支持6个参数(通过x0-x5寄存器传递),我们可以从va_list中逐个取出参数后再调用原始syscall,同时优化dlsym的调用时机避免重复开销:

#define _GNU_SOURCE
#include <stdio.h>
#include <stdarg.h>
#include <dlfcn.h>

// 提前初始化原始syscall函数指针,避免每次调用重复dlsym
static long (*original_syscall)(long, long, long, long, long, long, ...) = NULL;

__attribute__((constructor))
void init_original_syscall() {
    original_syscall = (long (*)(long, long, long, long, long, long, ...))dlsym(RTLD_NEXT, "syscall");
}

long syscall(long number, ...) {
    printf("Intercepted syscall: %lu\n", number);
    
    va_list args;
    va_start(args, number);
    
    // 按ARM64 syscall参数规则取出最多6个参数
    long arg1 = va_arg(args, long);
    long arg2 = va_arg(args, long);
    long arg3 = va_arg(args, long);
    long arg4 = va_arg(args, long);
    long arg5 = va_arg(args, long);
    long arg6 = va_arg(args, long);
    
    // 传递展开后的参数调用原始syscall
    long result = original_syscall(number, arg1, arg2, arg3, arg4, arg5, arg6);
    
    va_end(args);
    return result;
}

补充说明

日志中的syscall 57对应ARM64的clone系统调用,用于创建线程。线程创建对栈帧和参数的正确性要求极高,参数传递错误会直接导致线程初始化失败,触发SIGABRT信号。修复参数传递逻辑后,该问题即可解决。

内容的提问来源于stack exchange,提问作者Papers.ch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 15:44:54