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

Android NDK中实现多架构SYSCALL_INLINE式内联系统调用方案咨询

实现Android多架构直接系统调用(绕过libc包装函数)

我之前刚好做过类似需求——为了避开libc里系统调用包装函数被Hook的风险,直接通过汇编触发系统调用。不同CPU架构的系统调用约定差异很大,下面是我整理的适配arm、arm64、x86、x86_64的完整实现方案,你可以直接集成到NDK项目中:

1. 核心思路

每个架构都有专属的系统调用参数传递规则和触发指令,我们需要针对每个架构编写内联汇编代码:把系统调用号和参数传入对应寄存器,触发系统调用指令后,直接返回结果,完全绕开libc的包装函数。

2. 分架构实现

我们可以用预编译指令区分不同架构,把实现封装成一个通用的syscall函数,支持最多6个参数(覆盖绝大多数系统调用的需求)。

2.1 ARM 32位(armeabi-v7a)

ARM 32位系统调用约定:

  • 前4个参数依次放入r0、r1、r2、r3寄存器
  • 系统调用号存入r7寄存器
  • 用swi #0指令触发系统调用
  • 返回值存在r0中
#include <stdint.h>
#include <stdarg.h>

static inline long syscall(int num, ...) {
    va_list args;
    long ret;
    uint32_t arg1, arg2, arg3, arg4;

    va_start(args, num);
    arg1 = va_arg(args, uint32_t);
    arg2 = va_arg(args, uint32_t);
    arg3 = va_arg(args, uint32_t);
    arg4 = va_arg(args, uint32_t);
    va_end(args);

    __asm__ volatile (
        "mov r7, %1\n"
        "mov r0, %2\n"
        "mov r1, %3\n"
        "mov r2, %4\n"
        "mov r3, %5\n"
        "swi #0\n"
        "mov %0, r0\n"
        : "=r"(ret)
        : "r"(num), "r"(arg1), "r"(arg2), "r"(arg3), "r"(arg4)
        : "r0", "r1", "r2", "r3", "r7", "memory"
    );

    return ret;
}

2.2 ARM 64位(arm64-v8a)

ARM 64位系统调用约定:

  • 前6个参数依次放入x0-x5寄存器
  • 系统调用号存入x8寄存器
  • 用svc #0指令触发系统调用
  • 返回值存在x0中
#include <stdint.h>
#include <stdarg.h>

static inline long syscall(int num, ...) {
    va_list args;
    long ret;
    uint64_t arg1, arg2, arg3, arg4, arg5, arg6;

    va_start(args, num);
    arg1 = va_arg(args, uint64_t);
    arg2 = va_arg(args, uint64_t);
    arg3 = va_arg(args, uint64_t);
    arg4 = va_arg(args, uint64_t);
    arg5 = va_arg(args, uint64_t);
    arg6 = va_arg(args, uint64_t);
    va_end(args);

    __asm__ volatile (
        "mov x8, %1\n"
        "mov x0, %2\n"
        "mov x1, %3\n"
        "mov x2, %4\n"
        "mov x3, %5\n"
        "mov x4, %6\n"
        "mov x5, %7\n"
        "svc #0\n"
        "mov %0, x0\n"
        : "=r"(ret)
        : "r"(num), "r"(arg1), "r"(arg2), "r"(arg3), "r"(arg4), "r"(arg5), "r"(arg6)
        : "x0", "x1", "x2", "x3", "x4", "x5", "x8", "memory"
    );

    return ret;
}

2.3 x86架构(x86)

x86系统调用约定:

  • 系统调用号存入eax寄存器
  • 前6个参数依次放入ebx、ecx、edx、esi、edi、ebp寄存器
  • 用int 0x80指令触发系统调用
  • 返回值存在eax中
#include <stdint.h>
#include <stdarg.h>

static inline long syscall(int num, ...) {
    va_list args;
    long ret;
    uint32_t arg1, arg2, arg3, arg4, arg5, arg6;

    va_start(args, num);
    arg1 = va_arg(args, uint32_t);
    arg2 = va_arg(args, uint32_t);
    arg3 = va_arg(args, uint32_t);
    arg4 = va_arg(args, uint32_t);
    arg5 = va_arg(args, uint32_t);
    arg6 = va_arg(args, uint32_t);
    va_end(args);

    __asm__ volatile (
        "mov eax, %1\n"
        "mov ebx, %2\n"
        "mov ecx, %3\n"
        "mov edx, %4\n"
        "mov esi, %5\n"
        "mov edi, %6\n"
        "mov ebp, %7\n"
        "int $0x80\n"
        "mov %0, eax\n"
        : "=r"(ret)
        : "r"(num), "r"(arg1), "r"(arg2), "r"(arg3), "r"(arg4), "r"(arg5), "r"(arg6)
        : "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "memory"
    );

    return ret;
}

2.4 x86_64架构(x86_64)

x86_64系统调用约定:

  • 系统调用号存入rax寄存器
  • 前6个参数依次放入rdi、rsi、rdx、r10、r8、r9寄存器
  • 用syscall指令触发系统调用
  • 返回值存在rax中
#include <stdint.h>
#include <stdarg.h>

static inline long syscall(int num, ...) {
    va_list args;
    long ret;
    uint64_t arg1, arg2, arg3, arg4, arg5, arg6;

    va_start(args, num);
    arg1 = va_arg(args, uint64_t);
    arg2 = va_arg(args, uint64_t);
    arg3 = va_arg(args, uint64_t);
    arg4 = va_arg(args, uint64_t);
    arg5 = va_arg(args, uint64_t);
    arg6 = va_arg(args, uint64_t);
    va_end(args);

    __asm__ volatile (
        "mov rax, %1\n"
        "mov rdi, %2\n"
        "mov rsi, %3\n"
        "mov rdx, %4\n"
        "mov r10, %5\n"
        "mov r8, %6\n"
        "mov r9, %7\n"
        "syscall\n"
        "mov %0, rax\n"
        : "=r"(ret)
        : "r"(num), "r"(arg1), "r"(arg2), "r"(arg3), "r"(arg4), "r"(arg5), "r"(arg6)
        : "rax", "rdi", "rsi", "rdx", "r10", "r8", "r9", "memory"
    );

    return ret;
}

3. 封装成通用头文件

把上面的代码用预编译指令整合到一个头文件中,NDK编译时会自动根据目标架构选择对应的实现:

#ifndef DIRECT_SYSCALL_H
#define DIRECT_SYSCALL_H

#include <stdarg.h>
#include <stdint.h>

#if defined(__arm__)
static inline long syscall(int num, ...) {
    va_list args;
    long ret;
    uint32_t arg1, arg2, arg3, arg4;

    va_start(args, num);
    arg1 = va_arg(args, uint32_t);
    arg2 = va_arg(args, uint32_t);
    arg3 = va_arg(args, uint32_t);
    arg4 = va_arg(args, uint32_t);
    va_end(args);

    __asm__ volatile (
        "mov r7, %1\n"
        "mov r0, %2\n"
        "mov r1, %3\n"
        "mov r2, %4\n"
        "mov r3, %5\n"
        "swi #0\n"
        "mov %0, r0\n"
        : "=r"(ret)
        : "r"(num), "r"(arg1), "r"(arg2), "r"(arg3), "r"(arg4)
        : "r0", "r1", "r2", "r3", "r7", "memory"
    );

    return ret;
}
#elif defined(__aarch64__)
static inline long syscall(int num, ...) {
    va_list args;
    long ret;
    uint64_t arg1, arg2, arg3, arg4, arg5, arg6;

    va_start(args, num);
    arg1 = va_arg(args, uint64_t);
    arg2 = va_arg(args, uint64_t);
    arg3 = va_arg(args, uint64_t);
    arg4 = va_arg(args, uint64_t);
    arg5 = va_arg(args, uint64_t);
    arg6 = va_arg(args, uint64_t);
    va_end(args);

    __asm__ volatile (
        "mov x8, %1\n"
        "mov x0, %2\n"
        "mov x1, %3\n"
        "mov x2, %4\n"
        "mov x3, %5\n"
        "mov x4, %6\n"
        "mov x5, %7\n"
        "svc #0\n"
        "mov %0, x0\n"
        : "=r"(ret)
        : "r"(num), "r"(arg1), "r"(arg2), "r"(arg3), "r"(arg4), "r"(arg5), "r"(arg6)
        : "x0", "x1", "x2", "x3", "x4", "x5", "x8", "memory"
    );

    return ret;
}
#elif defined(__i386__)
static inline long syscall(int num, ...) {
    va_list args;
    long ret;
    uint32_t arg1, arg2, arg3, arg4, arg5, arg6;

    va_start(args, num);
    arg1 = va_arg(args, uint32_t);
    arg2 = va_arg(args, uint32_t);
    arg3 = va_arg(args, uint32_t);
    arg4 = va_arg(args, uint32_t);
    arg5 = va_arg(args, uint32_t);
    arg6 = va_arg(args, uint32_t);
    va_end(args);

    __asm__ volatile (
        "mov eax, %1\n"
        "mov ebx, %2\n"
        "mov ecx, %3\n"
        "mov edx, %4\n"
        "mov esi, %5\n"
        "mov edi, %6\n"
        "mov ebp, %7\n"
        "int $0x80\n"
        "mov %0, eax\n"
        : "=r"(ret)
        : "r"(num), "r"(arg1), "r"(arg2), "r"(arg3), "r"(arg4), "r"(arg5), "r"(arg6)
        : "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "memory"
    );

    return ret;
}
#elif defined(__x86_64__)
static inline long syscall(int num, ...) {
    va_list args;
    long ret;
    uint64_t arg1, arg2, arg3, arg4, arg5, arg6;

    va_start(args, num);
    arg1 = va_arg(args, uint64_t);
    arg2 = va_arg(args, uint64_t);
    arg3 = va_arg(args, uint64_t);
    arg4 = va_arg(args, uint64_t);
    arg5 = va_arg(args, uint64_t);
    arg6 = va_arg(args, uint64_t);
    va_end(args);

    __asm__ volatile (
        "mov rax, %1\n"
        "mov rdi, %2\n"
        "mov rsi, %3\n"
        "mov rdx, %4\n"
        "mov r10, %5\n"
        "mov r8, %6\n"
        "mov r9, %7\n"
        "syscall\n"
        "mov %0, rax\n"
        : "=r"(ret)
        : "r"(num), "r"(arg1), "r"(arg2), "r"(arg3), "r"(arg4), "r"(arg5), "r"(arg6)
        : "rax", "rdi", "rsi", "rdx", "r10", "r8", "r9", "memory"
    );

    return ret;
}
#endif

#endif // DIRECT_SYSCALL_H

4. 使用示例

比如调用open系统调用,先获取对应的系统调用号(Android和Linux基本一致,可参考NDK的<asm/unistd.h>),然后直接调用我们的syscall函数:

#include "direct_syscall.h"
#include <fcntl.h>

// 从NDK的asm/unistd.h中获取对应架构的系统调用号
#ifdef __arm__
#define __NR_open 5
#elif __aarch64__
#define __NR_open 2
#elif __i386__
#define __NR_open 5
#elif __x86_64__
#define __NR_open 2
#endif

int main() {
    int fd = syscall(__NR_open, "/sdcard/test.txt", O_RDONLY);
    if (fd >= 0) {
        // 操作文件
        syscall(__NR_close, fd);
    }
    return 0;
}

注意事项

  • 系统调用号可能因Android版本或内核版本略有差异,建议直接从NDK的<asm/unistd.h>中引用,或自行确认目标版本的正确编号。
  • 对于需要超过6个参数的系统调用,需要额外处理栈传递参数的逻辑(这类系统调用极少)。
  • 编译时要确保NDK的目标架构和代码中的预编译指令匹配,比如armeabi-v7a对应__arm__,arm64-v8a对应__aarch64__等。

内容的提问来源于stack exchange,提问作者Phillip

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:54:08