首页
社区
课程
招聘
[原创]ARM平台下Shellcode开发技术原理与实现
发表于: 2025-7-13 16:23 3862

[原创]ARM平台下Shellcode开发技术原理与实现

2025-7-13 16:23
3862

在移动安全领域,ShellCode技术已经成为一个不可或缺的重要组成部分。无论是应用加固、安全防护,还是漏洞利用研究,都离不开对ShellCode的深入理解和灵活运用。本文将以简单的shellCode为例,详细介绍在ARM平台下ShellCode的实现原理和关键技术。

ShellCode本质上是一段位置无关的代码片段。根据应用场景的不同,它的用途大体上有两种:

选择哪种方案取决于具体的使用场景和安全限制。本文将重点介绍第一种方案的技术细节。

在ARM64架构下,ShellCode必须保证位置无关性。这是因为:

由于ShellCode的独立性要求,大量标准库函数无法直接使用。这要求我们:

在没有链接器支持的情况下,需要:

在ARM64架构中,系统调用使用特定的寄存器约定:

通过这种方式,我们实现了一套完整的系统调用封装框架,支持0-6个参数的系统调用。

关键属性说明:

这段代码实现了标准的ARM64函数调用约定,确保ShellCode能够正确地接收参数并返回结果。

通过读取/proc/self/maps文件获取已加载库的基址。这里参考了Dobby框架的实现,解析运行时模块信息:

解析目标SO文件的符号表以获取函数地址:

通过这种方式,我们就在ShellCode中实现了动态符号解析的功能,可以在运行时获取目标函数的地址,无需依赖系统链接器。

这些编译选项确保生成的ShellCode具有最小的体积和最大的兼容性。

本项目已在GitHub开源,欢迎大家参与讨论和改进。

本文作者:Imy

项目开源地址:[ef4K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6u0d9f1W2u0L8h3#2E0P5i4W2&6i4K6u0r3b7i4u0E0f1$3S2W2L8r3I4o6L8$3c8W2i4K6g2p5

声明:本文仅供安全研究和学习交流使用

// ARM64内联汇编系统调用实现
static inline long syscall3(long number, long arg1, long arg2, long arg3) {
    register long x8 __asm__("x8") = number;  // 系统调用号
    register long x0 __asm__("x0") = arg1;    // 第一个参数
    register long x1 __asm__("x1") = arg2;    // 第二个参数 
    register long x2 __asm__("x2") = arg3;    // 第三个参数
    __asm__ volatile("svc #0" : "+r"(x0) : "r"(x8), "r"(x1), "r"(x2) : "memory");
    return x0;  // 返回值
}
 
// 基于系统调用的文件操作
ssize_t sys_write(int fd, const void *buf, size_t count) {
    return syscall3(SYS_write, fd, (long)buf, count);
}
// ARM64内联汇编系统调用实现
static inline long syscall3(long number, long arg1, long arg2, long arg3) {
    register long x8 __asm__("x8") = number;  // 系统调用号
    register long x0 __asm__("x0") = arg1;    // 第一个参数
    register long x1 __asm__("x1") = arg2;    // 第二个参数 
    register long x2 __asm__("x2") = arg3;    // 第三个参数
    __asm__ volatile("svc #0" : "+r"(x0) : "r"(x8), "r"(x1), "r"(x2) : "memory");
    return x0;  // 返回值
}
 
// 基于系统调用的文件操作
ssize_t sys_write(int fd, const void *buf, size_t count) {
    return syscall3(SYS_write, fd, (long)buf, count);
}
void __attribute__((naked, noreturn, section(".text._start"))) _start(void) {
void __attribute__((naked, noreturn, section(".text._start"))) _start(void) {
#ifdef ARCH_ARM64
__asm__ volatile (
    // 保存链接寄存器和帧指针
    "stp x29, x30, [sp, #-16]!\n"
    "mov x29, sp\n"
     
    // 调用主函数
    "bl shellcode_main_refactored\n"
     
    // 恢复寄存器并返回
    "mov sp, x29\n"
    "ldp x29, x30, [sp], #16\n"
    "ret\n"
    :
    :
    : "memory", "x0", "x29", "x30"
);
#endif
#ifdef ARCH_ARM64
__asm__ volatile (
    // 保存链接寄存器和帧指针
    "stp x29, x30, [sp, #-16]!\n"
    "mov x29, sp\n"
     
    // 调用主函数
    "bl shellcode_main_refactored\n"
     
    // 恢复寄存器并返回
    "mov sp, x29\n"
    "ldp x29, x30, [sp], #16\n"
    "ret\n"
    :
    :
    : "memory", "x0", "x29", "x30"
);
#endif
typedef struct {
    char path[MAX_PATH_LEN];
    uintptr_t load_address;
} dobby_runtime_module_t;
 
int dobby_get_runtime_module(const char* name, dobby_runtime_module_t* module) {
    // 解析 /proc/self/maps 找到目标库
    // 返回库的加载基址
}
typedef struct {
    char path[MAX_PATH_LEN];
    uintptr_t load_address;
} dobby_runtime_module_t;
 
int dobby_get_runtime_module(const char* name, dobby_runtime_module_t* module) {
    // 解析 /proc/self/maps 找到目标库
    // 返回库的加载基址
}
int dobby_resolve_symbol(const char* lib_name, const char* symbol_name, uintptr_t* symbol_address) {
    dobby_runtime_module_t module;
     
    // 1. 获取库的运行时信息
    if (dobby_get_runtime_module(lib_name, &module) != MAPS_PARSER_SUCCESS) {
        return RESOLVER_ERR_NOT_FOUND;
    }
     
    // 2. 解析ELF符号表
    // 3. 计算符号的实际地址 = 基址 + 偏移
     
    return RESOLVER_SUCCESS;
}
int dobby_resolve_symbol(const char* lib_name, const char* symbol_name, uintptr_t* symbol_address) {
    dobby_runtime_module_t module;
     
    // 1. 获取库的运行时信息
    if (dobby_get_runtime_module(lib_name, &module) != MAPS_PARSER_SUCCESS) {
        return RESOLVER_ERR_NOT_FOUND;
    }
     
    // 2. 解析ELF符号表
    // 3. 计算符号的实际地址 = 基址 + 偏移
     
    return RESOLVER_SUCCESS;
}
uintptr_t shellcode_main_refactored() {
    // 目标配置
    static const char* TARGET_LIBRARY = "libxxx.so";
    static const char* TARGET_SYMBOL = "xxx";
     
    uintptr_t symbol_addr;
    int result = dobby_resolve_symbol(TARGET_LIBRARY, TARGET_SYMBOL, &symbol_addr);
     
    if (result != RESOLVER_SUCCESS) {
        return (uintptr_t)result;
    }
     
    // 调用解析到的函数
    typedef void (*ioctl_func)();
    ioctl_func target_func = (ioctl_func)symbol_addr;
    target_func();
     
    return symbol_addr;
}
uintptr_t shellcode_main_refactored() {
    // 目标配置
    static const char* TARGET_LIBRARY = "libxxx.so";
    static const char* TARGET_SYMBOL = "xxx";

传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2025-7-13 16:38 被IIImmmyyy编辑 ,原因:
收藏
免费 9
支持
分享
最新回复 (5)
雪    币: 5899
活跃值: (10367)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
有空再研究,
2025-7-13 17:12
0
雪    币: 162
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
大佬有考虑写一个trace工具吗,我打算搞这个
2025-7-13 17:32
0
雪    币: 1194
活跃值: (7005)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
4
不错
2025-7-13 20:25
0
雪    币: 673
活跃值: (4768)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
mb_cfjwplfo 大佬有考虑写一个trace工具吗,我打算搞这个
你准备基于什么写
2025-7-18 09:30
0
雪    币: 225
活跃值: (935)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
暂无考虑,目前精力在写反编译引擎
2025-7-18 21:39
0
游客
登录 | 注册 方可回帖
返回