首页
社区
课程
招聘
[原创]so文件upx壳的脱壳
发表于: 2025-5-20 23:35 1704

[原创]so文件upx壳的脱壳

2025-5-20 23:35
1704

2025/09/08更新手动修复 LOAD 段

脱壳

so文件附件

  • 写一个so加载器
1
2
3
4
5
6
7
8
9
#include <stdio.h>
#include <dlfcn.h>
 
int main(){
    void* handle = dlopen("/data/local/tmp/libalgorith_packed4.so", RTLD_NOW);
    printf("handle %p %s\n", handle, dlerror());
    dlclose(handle);
    return 0;
}
  • 将加载器和so文件发送到手机
    push

  • 设置进程选项调试so
    IDA进程选项

  • 在so入口下断点,并调试
    入口断点

  • 入口是壳的解压缩代码,一路调试到壳调用linker64的函数
    linker64

  • 根据模块映射的内存进行dump
    内存

    • 可以看到该so被映射了四块内存,其中第二块没有名字,所以我们将该内存dump时加到第一块内存

IDA dump脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <idc.idc>
/*
 * 往指定文件追加或覆盖写入二进制数据
 * @param start_addr 起始地址
 * @param end_addr 结束地址
 * @param filename 输出文件路径
 * @param append 是否追加模式,1=追加,0=覆盖
 * @return 成功返回1,失败返回0
 */
static dump_memory(start_addr, end_addr, filename, append) {
    auto size, mem;
     
    if (start_addr >= end_addr) {
        Warning("起始地址必须小于结束地址");
        return 0;
    }
     
    size = end_addr - start_addr;
    mem = GetManyBytes(start_addr, size, 0);
     
    if (mem == 0) {
        Warning("无法读取内存 0x%x - 0x%x", start_addr, end_addr);
        return 0;
    }
     
    auto file = fopen(filename, append ? "ab" : "wb"); // "ab"模式表示追加二进制写入
    if (file == 0) {
        Warning("无法打开文件: %s", filename);
        return 0;
    }
     
    auto bytes_written = 0;
    auto current_ea = start_addr;
    while (current_ea < end_addr)
    {
        auto byte_val = Byte(current_ea);
        if (byte_val == -1) break// 读取失败
         
        fputc(byte_val, file);
        bytes_written++;
        current_ea++;
         
        // 1MB打印进度
        if (bytes_written % 0x100000 == 0) {
            Message("已写入 0x%X bytes @ 0x%08X...\n", bytes_written, current_ea);
        }
    }
 
    fclose(file);
    return 1;
}
 
static main() {
    auto outfile = "C:\\combined_dump"; // 最终的文件路径
     
    // 第一次写入,如果文件存在则先覆盖(append=0
    dump_memory(0x73ea9c3000, 0x73ea9fe000, outfile, 0);
     
    // 后续写入,追加模式(append=1
    dump_memory(0x73ea9fe000, 0x73eaa02000, outfile, 1);  // 追加第2个区域
    dump_memory(0x73eaa02000, 0x73eaa04000, outfile, 1);  // 追加第3个区域
     
    Message("成功将所有块写入 %s\n", outfile);
}
  • 手动修复elf文件中的PT_LOAD段以及符号表偏移
    • 三个LOAD段根据刚刚dump的内存位置进行修正,LOAD段就是从文件需要加载到内存的数据, p_offset(文件偏移), p_vaddr(内存偏移), p_filesz(映射的文件大小), p_memsz(映射的内存大小)。

      • 第一个LOAD段在内存中的位置为 73ea9c3000 - 73ea9fe000 ,所以第一个LOAD段 p_offset 和 p_vaddr 为 0 , p_filesz 和 p_memsz 为 3b000 (73ea9fe000 - 73ea9c3000) 。
      • 第二个LOAD段内存位置为 73ea9fe000 - 73eaa02000 ,所以 p_offset 和 p_vaddr 为 3b000 , p_filesz 和 p_memsz 为 4000 (73eaa02000 - 73ea9fe000) 。 (这里我们根据原来从内存dump的顺序,将第二个LOAD段接到第一个LOAD段后面,第三个LOAD段也是同理,也就是说我们怎么从内存dump出来的,我们现在就要怎么还原回去)。
      • 第三个LOAD段内存位置为 73eaa02000 - 73eaa04000 , p_offset 和 p_vaddr 为 3f000 (3b000 + 4000) , p_filesz 和 p_memsz 为 2000 (73eaa04000 - 73eaa02000)。
    • DYNAMIC根据内存偏移,查看落在哪个LOAD段中,再修改所在的文件偏移。

      • DYNAMIC段我们知道原文件中加载到内存后,在内存的 RVA 为 3eaf8 ,我们是根据内存来dump到文件,所以将内存中的数据原样dump到文件后,DYNAMIC段的位置 p_offset 也是 3eaf8 。

LOAD

  • dump完成

[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!

最后于 2025-9-8 12:02 被xichang13编辑 ,原因: 更新内容
上传的附件:
收藏
免费 5
支持
分享
最新回复 (7)
雪    币: 7646
活跃值: (7817)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
“手动修复”,可以详细写一下,目前感觉文章和没写一样,没什么技术点
2025-5-21 18:27
0
雪    币: 8846
活跃值: (3008)
能力值: ( LV8,RANK:127 )
在线值:
发帖
回帖
粉丝
3
为什么不用  upx- d
2025-5-23 17:32
0
雪    币: 10
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
求更新怎么修复load段
2025-9-7 01:54
0
雪    币: 1254
活跃值: (768)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5
mb_dmryhnwz 求更新怎么修复load段
这个根据内存位置来修复load段,他在内存中的位置,我们是怎么dump的,我们dump下来后就要想办法让他怎么可以加载回去。
2025-9-8 11:49
1
雪    币: 1254
活跃值: (768)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
mb_rjdrqvpa “手动修复”,可以详细写一下,目前感觉文章和没写一样,没什么技术点
2025-9-8 12:06
0
雪    币: 10
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
7
xichang13 这个根据内存位置来修复load段,他在内存中的位置,我们是怎么dump的,我们dump下来后就要想办法让他怎么可以加载回去。
感谢回答
2025-9-20 16:21
0
雪    币: 10
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
8
xichang13 这个根据内存位置来修复load段,他在内存中的位置,我们是怎么dump的,我们dump下来后就要想办法让他怎么可以加载回去。
大佬有没有遇到arm64可执行二进制加了upx后ida主动启动进程调试就会提示该文件为共享库文件无法单独启动的问题
2025-9-20 16:24
0
游客
登录 | 注册 方可回帖
返回