【鸿蒙】实现系统调用 第二期(By LittleQ)

admin 2024年3月5日00:19:32评论11 views字数 2539阅读8分27秒阅读模式

在上一篇文章当中,研究了在鸿蒙当中如何采用内联汇编的方案来执行系统调用,这种方案呢,可以直接在so当中搜索到相关的指令,那么有没有什么方案可以避免这一点呢,那么我就想到了mmap这个函数。

mmap函数

mmap是一个Unix和类Unix操作系统(如Linux)中的一个系统调用,它允许程序员将一个文件或其他对象映射进内存。通过这种方式,文件或设备的内容可以像访问普通内存数组那样直接访问,而无需使用传统的文件读写操作。

有了,这个知识,那么,我们就可以用代码来实现这个功能了。

配置CMake

因为这里,鸿蒙我没有发现如何编译指定架构的so的方案,因此呢,这里还是要出3个文件,因此这里还是需要再CMakeLists.txt里面给配置一下。

if (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")
target_compile_definitions(entry PRIVATE AARCH64=1)
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm")
target_compile_definitions(entry PRIVATE ARM=1)
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64")
target_compile_definitions(entry PRIVATE X86_64=1)
endif ()

后续,就可以通过判断宏是否定义,来分别处理不同架构的代码了。

核心代码

这里,我们只需要从之前编译好的里面,然后直接扣出来对应的指令代码就可以了,非常的方便,这里给出指令代码。

#ifdef X86_64
    unsigned char code[0x100] = {0x550x480x890xE50x480x890xF80x480x890xF70x480x89,
                                 0xD60x480x890xCA0x4D0x890xC20x4D0x890xC80x4C0x8B,
                                 0x4D0x080x0F0x050x480x890xEC0x5D0xC30x0F0x1F0x00,
                                 0x660x660x660x2E0x0F0x1F0x840x000x000x000x000x00};
#elif AARCH64
    unsigned char code[32] = {0xE80x030x000xAA0xE00x030x010xAA0xE10x030x02,
                              0xAA0xE20x030x030xAA0xE30x030x040xAA0xE40x03,
                              0x050xAA0xE50x030x060xAA0x010x000x00};
#else ARM
    unsigned char code[0x100] = {
        0x0D0xC00xA00xE10xF00x000x2D0xE90x000x700xA00xE10x010x000xA00xE1,
        0x020x100xA00xE10x030x200xA00xE10x780x000x9C0xE80x000x000x00,
    };
#endif

然后呢,我们便可以通过mmap函数来直接分配一块可读、可写、可执行的代码,完成系统调用的功能。

    long pagesize = sysconf(_SC_PAGESIZE);
    // 分配一页内存,权限为可读可写可执行
    void *mem = mmap(NULL, pagesize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -10);

    if (mem == MAP_FAILED) {
        // 内存映射失败
    }

    memcpy(mem, code, sizeof(code));

    // 将内存位置转换为函数指针
    func_t raw_syscall = (func_t)mem;

这样,我们就完成了,对于系统调用的函数了,接下来,还是简单测试一下,测试代码和上次一样。

    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);
        }
    }
【鸿蒙】实现系统调用 第二期(By LittleQ)

发现,效果非常的nice,这就成功了,好了,本篇文章到这里就结束了。

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

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

发表评论

匿名网友 填写信息