【鸿蒙】实现系统调用(SVC)(By LittleQ)

admin 2024年2月1日21:01:35评论11 views字数 3204阅读10分40秒阅读模式

之前在Android当中,有内联汇编的系统调用方案,然后呢,有了鸿蒙,于是乎就想这里能不能直接内联汇编实现系统调用呢,想到这个想法,那就尝试一下吧。

使用环境

我这里只有9的API,因此这里基于API 9进行测试,对于大于API 9的版本,因为我拿不到对应的sdk,因此无法测试,对于高版本文档,我这也看不了,因此也没办法查阅。

【鸿蒙】实现系统调用(SVC)(By LittleQ)

具体环境如上图所示。

实现方案

这里通过.s文件来实现汇编代码,目录结构如下。

【鸿蒙】实现系统调用(SVC)(By LittleQ)

至于为啥我要写三个汇编文件,那肯定不是因为我非常勤快,是因为我没找到只编译特定处理器so的方案,然后呢,如果不提供cpu架构的汇编代码,编译会不过,因此,只能写三个了,好在不麻烦,下面来详细看一下,需要添加那些东西。

修改cmake文件

# 这里开启汇编的支持
set(can_use_assembler TRUE)
enable_language(ASM)

# 根据cpu架构选择不同的汇编代码
if (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")
set(syscall asm/syscall64.s)
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm")
set(syscall asm/syscall32.s)
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64")
set(syscall asm/syscallx86.s)
endif ()

汇编代码

  • arm64
    .text
.global raw_syscall
.type raw_syscall,@function

raw_syscall:
MOV X8, X0
MOV X0, X1
MOV X1, X2
MOV X2, X3
MOV X3, X4
MOV X4, X5
MOV X5, X6
SVC 0
RET
  • arm
    .text
.global raw_syscall
.type raw_syscall,%function

raw_syscall:
MOV R12, SP
STMFD SP!, {R4-R7}
MOV R7, R0
MOV R0, R1
MOV R1, R2
MOV R2, R3
LDMIA R12, {R3-R6}
SVC 0
LDMFD SP!, {R4-R7}
mov pc, lr
  • x86_64
.global raw_syscall
.type raw_syscall,@function
raw_syscall:
push %rbp
mov %rsp, %rbp

mov %rdi, %rax
mov %rsi, %rdi
mov %rdx, %rsi
mov %rcx, %rdx
mov %r8, %r10
mov %r9, %r8
mov 8(%rbp), %r9

syscall

mov %rbp, %rsp
pop %rbp

ret

然后呢,有了这些代码,就可以正常调用系统调用了,在之前呢,我们需要先定义一个c的函数。

extern "C" {
__inline__ __attribute__((always_inline)) long raw_syscall(long __number, ...);
}

要注意,这个要按照c导出,否则会找不到符号。

编写测试

有了系统调用,我们简单写个测试的代码,就获取下文件的属性吧。

首先,我们在ets层创建一个文件,至于为啥在ets层创建,那单纯是因为ets创建简单,简简单单写个代码。

let context = getContext();
let pathDir = context.filesDir;
hilog.info(0"LQ->""dir: %{public}s", pathDir);
let filePath = pathDir + "/test.txt";
let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
fs.write(file.fd, "hello, world").then((writeLen) => {
    fs.closeSync(file);
    testNapi.readFile(filePath);
}).catch((err) => {
    // ... 处理错误
});

然后,定义下native层调用的函数,也就是readFile。

export const readFile: (path: string) => void;

接着来实现以下这个函数吧。

static napi_value ReadFile(napi_env env, napi_callback_info info) {
    size_t argc = 1;
    napi_value argv[1] = {NULL};

    void *data;

    // 获取JavaScript传递的参数
    napi_get_cb_info(env, info, &argc, argv, nullptr, &data);

    // 获取字符串的长度
    size_t str_length;
    napi_get_value_string_utf8(env, argv[0], nullptr0, &str_length);

    // 因为这个长度不包括, 因此分配缓冲区,加1是为了容纳终止字符 ''
    char *buffer = new char[str_length + 1];

    napi_get_value_string_utf8(env, argv[0], buffer, str_length + 1, &str_length);

    LOGD("file path: %{public}s", buffer);

    struct stat _stat = {0};

    int fd = static_cast<int>(raw_syscall(__NR_openat, AT_FDCWD,
                                           reinterpret_cast<const char *>(buffer),
                                           O_RDONLY | O_CLOEXEC,
                                           0640));
    LOGD("fd1 => %{public}x", fd);
    if (fd > 0) {
        if (raw_syscall(__NR_fstat, fd, &_stat) == 0) {
            LOGD("tv_nsec => %{public}ld", _stat.st_atim.tv_nsec);
        }
    }

    napi_value ret;
    napi_create_int32(env, 0, &ret);
    return ret;
}

简单调用一下,然后发现这个是好用的。

【鸿蒙】实现系统调用(SVC)(By LittleQ)

总结

本篇文章呢,利用内联汇编的方案,在鸿蒙当中实现了系统调用,上面的代码仅供参考,因为我没有真机,因此不保证真机能跑,关键是穷,好了,本篇文章到这里就结束了,溜了,溜了~~

参考资料

  • https://mp.weixin.qq.com/s/xXpmRuohn3WtTdVL-sedsQ[1]

Reference

[1]

https://mp.weixin.qq.com/s/xXpmRuohn3WtTdVL-sedsQ: https://mp.weixin.qq.com/s/xXpmRuohn3WtTdVL-sedsQ

【鸿蒙】实现系统调用(SVC)(By LittleQ)


原文始发于微信公众号(安全后厨):【鸿蒙】实现系统调用(SVC)(By LittleQ)

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年2月1日21:01:35
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【鸿蒙】实现系统调用(SVC)(By LittleQ)https://cn-sec.com/archives/2442650.html

发表评论

匿名网友 填写信息