首页
社区
课程
招聘
frida hook init_array自吐新解
发表于: 2024-1-8 00:48 8972

frida hook init_array自吐新解

2024-1-8 00:48
8972

前言

frida的CModule是一个极其强大的模块,本文将使用CModule来完成init_array的信息输出

简单来说,就是借助CModulesoinfo结构体进行解析

实现

经过对比分析历代soinfo结构体的定义,可以确定从Android 8 ~ 14,结构体中init_array的位置都很稳定

于是通过下面的头文件中提取必要的内容,在CModule中定义一个soinfo结构体,这样frida就能自动完成相关偏移的处理

接着定义一个函数,接受一个soinfo指针参数和一个callback函数,优雅地输出init_array信息

1
2
3
void tell_init_info(soinfo* ptr, void (*cb)(int, void*, void*)) {
    cb(ptr->init_array_count_, ptr->init_array_, ptr->init_func_);
}

那么哪里最早能获取到soinfo指针呢?答案是soinfo->call_constructors,这个函数符号一直很稳定

为了获取soname,则选择主动调用soinfo->get_soname,这个函数符号同样很稳定

  • __dl__ZN6soinfo17call_constructorsEv
  • __dl__ZNK6soinfo10get_sonameEv

在callback回到frida hook后,再借助frida的JavaScript API解析init_array数组,代码片段如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Interceptor.attach(call_constructors_addr,{
    onEnter: function(args){
        let soinfo = args[0];
        let soname = get_soname(soinfo).readCString();
        tell_init_info(soinfo, new NativeCallback((count, init_array_ptr, init_func) => {
            console.log(`[call_constructors] ${soname} count:${count}`);
            console.log(`[call_constructors] init_array_ptr:${init_array_ptr}`);
            console.log(`[call_constructors] init_func:${init_func} -> ${get_addr_info(init_func)}`);
            for (let index = 0; index < count; index++) {
                let init_array_func = init_array_ptr.add(Process.pointerSize * index).readPointer();
                let func_info = get_addr_info(init_array_func);
                console.log(`[call_constructors] init_array:${index} ${init_array_func} -> ${func_info}`);
            }
        }, "void", ["int", "pointer", "pointer"]));
    }
});

Tips: CModule对象是有作用域的,所以通常赋给一个全局变量,以保证一直可用,否则可能引起崩溃

其他:对于Android 5/6/7,同样可以这样处理,据对比差异主要是ElfW(Addr) base;之前会多一个ElfW(Addr) entry;

效果示例:

脚本已完成32/64位的兼容,理论上适用于Android 8 ~ 14,测试Android 10通过

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
let cm_include = `
#include <stdio.h>
#include <gum/gumprocess.h>
`
 
let cm_code = `
#if defined(__LP64__)
#define USE_RELA 1
#endif
 
// http://aosp.app/android-14.0.0_r1/xref/bionic/libc/include/link.h
#if defined(__LP64__)
#define ElfW(type) Elf64_ ## type
#else
#define ElfW(type) Elf32_ ## type
#endif
 
// http://aosp.app/android-14.0.0_r1/xref/bionic/libc/kernel/uapi/asm-generic/int-ll64.h
typedef signed char __s8;
typedef unsigned char __u8;
typedef signed short __s16;
typedef unsigned short __u16;
typedef signed int __s32;
typedef unsigned int __u32;
typedef signed long long __s64;
typedef unsigned long long __u64;
 
// http://aosp.app/android-14.0.0_r1/xref/bionic/libc/kernel/uapi/linux/elf.h
typedef __u32 Elf32_Addr;
typedef __u16 Elf32_Half;
typedef __u32 Elf32_Off;
typedef __s32 Elf32_Sword;
typedef __u32 Elf32_Word;
typedef __u64 Elf64_Addr;
typedef __u16 Elf64_Half;
typedef __s16 Elf64_SHalf;
typedef __u64 Elf64_Off;
typedef __s32 Elf64_Sword;
typedef __u32 Elf64_Word;
typedef __u64 Elf64_Xword;
typedef __s64 Elf64_Sxword;
 
typedef struct dynamic {
  Elf32_Sword d_tag;
  union {
    Elf32_Sword d_val;
    Elf32_Addr d_ptr;
  } d_un;
} Elf32_Dyn;
typedef struct {
  Elf64_Sxword d_tag;
  union {
    Elf64_Xword d_val;
    Elf64_Addr d_ptr;
  } d_un;
} Elf64_Dyn;
typedef struct elf32_rel {
  Elf32_Addr r_offset;
  Elf32_Word r_info;
} Elf32_Rel;
typedef struct elf64_rel {
  Elf64_Addr r_offset;
  Elf64_Xword r_info;
} Elf64_Rel;
typedef struct elf32_rela {
  Elf32_Addr r_offset;
  Elf32_Word r_info;
  Elf32_Sword r_addend;
} Elf32_Rela;
typedef struct elf64_rela {
  Elf64_Addr r_offset;
  Elf64_Xword r_info;
  Elf64_Sxword r_addend;
} Elf64_Rela;
typedef struct elf32_sym {
  Elf32_Word st_name;
  Elf32_Addr st_value;
  Elf32_Word st_size;
  unsigned char st_info;
  unsigned char st_other;
  Elf32_Half st_shndx;
} Elf32_Sym;
typedef struct elf64_sym {
  Elf64_Word st_name;
  unsigned char st_info;
  unsigned char st_other;
  Elf64_Half st_shndx;
  Elf64_Addr st_value;
  Elf64_Xword st_size;
} Elf64_Sym;
typedef struct elf32_phdr {
  Elf32_Word p_type;
  Elf32_Off p_offset;
  Elf32_Addr p_vaddr;
  Elf32_Addr p_paddr;
  Elf32_Word p_filesz;
  Elf32_Word p_memsz;
  Elf32_Word p_flags;
  Elf32_Word p_align;
} Elf32_Phdr;
typedef struct elf64_phdr {
  Elf64_Word p_type;
  Elf64_Word p_flags;
  Elf64_Off p_offset;
  Elf64_Addr p_vaddr;
  Elf64_Addr p_paddr;
  Elf64_Xword p_filesz;
  Elf64_Xword p_memsz;
  Elf64_Xword p_align;
} Elf64_Phdr;
 
// http://aosp.app/android-14.0.0_r1/xref/bionic/linker/linker_soinfo.h
typedef void (*linker_dtor_function_t)();
typedef void (*linker_ctor_function_t)(int, char**, char**);
 
#if defined(__work_around_b_24465209__)
#define SOINFO_NAME_LEN 128
#endif
 
typedef struct {
  #if defined(__work_around_b_24465209__)
    char old_name_[SOINFO_NAME_LEN];
  #endif
    const ElfW(Phdr)* phdr;
    size_t phnum;
  #if defined(__work_around_b_24465209__)
    ElfW(Addr) unused0; // DO NOT USE, maintained for compatibility.
  #endif
    ElfW(Addr) base;
    size_t size;
   
  #if defined(__work_around_b_24465209__)
    uint32_t unused1;  // DO NOT USE, maintained for compatibility.
  #endif
   
    ElfW(Dyn)* dynamic;
   
  #if defined(__work_around_b_24465209__)
    uint32_t unused2; // DO NOT USE, maintained for compatibility
    uint32_t unused3; // DO NOT USE, maintained for compatibility
  #endif
   
    void* next;
    uint32_t flags_;
   
    const char* strtab_;
    ElfW(Sym)* symtab_;
   
    size_t nbucket_;
    size_t nchain_;
    uint32_t* bucket_;
    uint32_t* chain_;
   
  #if !defined(__LP64__)
    ElfW(Addr)** unused4; // DO NOT USE, maintained for compatibility
  #endif
   
  #if defined(USE_RELA)
    ElfW(Rela)* plt_rela_;
    size_t plt_rela_count_;
   
    ElfW(Rela)* rela_;
    size_t rela_count_;
  #else
    ElfW(Rel)* plt_rel_;
    size_t plt_rel_count_;
   
    ElfW(Rel)* rel_;
    size_t rel_count_;
  #endif
   
    linker_ctor_function_t* preinit_array_;
    size_t preinit_array_count_;
   
    linker_ctor_function_t* init_array_;
    size_t init_array_count_;
    linker_dtor_function_t* fini_array_;
    size_t fini_array_count_;
   
    linker_ctor_function_t init_func_;
    linker_dtor_function_t fini_func_;
} soinfo;
 
void tell_init_info(soinfo* ptr, void (*cb)(int, void*, void*)) {
    cb(ptr->init_array_count_, ptr->init_array_, ptr->init_func_);
}
`
 
let cm = null;
let tell_init_info = null;
 
function setup_cmodule() {
    if (Process.pointerSize == 4) {
        cm_code = cm_include + "#define __work_around_b_24465209__ 1" + cm_code;
    } else {
        cm_code = cm_include + "#define __LP64__ 1" + cm_code;
    }
    cm = new CModule(cm_code, {});
    tell_init_info = new NativeFunction(cm.tell_init_info, "void", ["pointer", "pointer"]);
}
 
function get_addr_info(addr) {
    let mm = new ModuleMap();
    let info = mm.find(addr);
    if (info == null) return "null";
    return `[${info.name} + ${addr.sub(info.base)}]`;
}
 
function hook_call_constructors() {
    let get_soname = null;
    let call_constructors_addr = null;
    let hook_call_constructors_addr = true;
 
    let linker = null;
    if (Process.pointerSize == 4) {
        linker = Process.findModuleByName("linker");
    } else {
        linker = Process.findModuleByName("linker64");
    }
 
    let symbols = linker.enumerateSymbols();
    for (let index = 0; index < symbols.length; index++) {
        let symbol = symbols[index];
        if (symbol.name == "__dl__ZN6soinfo17call_constructorsEv") {
            call_constructors_addr = symbol.address;
        } else if (symbol.name == "__dl__ZNK6soinfo10get_sonameEv") {
            get_soname = new NativeFunction(symbol.address, "pointer", ["pointer"]);
        }
    }
    if (hook_call_constructors_addr && call_constructors_addr && get_soname) {
        Interceptor.attach(call_constructors_addr,{
            onEnter: function(args){
                let soinfo = args[0];
                let soname = get_soname(soinfo).readCString();
                tell_init_info(soinfo, new NativeCallback((count, init_array_ptr, init_func) => {
                    console.log(`[call_constructors] ${soname} count:${count}`);
                    console.log(`[call_constructors] init_array_ptr:${init_array_ptr}`);
                    console.log(`[call_constructors] init_func:${init_func} -> ${get_addr_info(init_func)}`);
                    for (let index = 0; index < count; index++) {
                        let init_array_func = init_array_ptr.add(Process.pointerSize * index).readPointer();
                        let func_info = get_addr_info(init_array_func);
                        console.log(`[call_constructors] init_array:${index} ${init_array_func} -> ${func_info}`);
                    }
                }, "void", ["int", "pointer", "pointer"]));
            }
        });
    }
}
 
function main(){
    setup_cmodule();
    hook_call_constructors();
}
 
setImmediate(main);
 
// frida -U -f pkg_name -l hook.js -o hook.log

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 12
支持
分享
最新回复 (11)
雪    币: 2399
活跃值: (2852)
能力值: ( LV5,RANK:61 )
在线值:
发帖
回帖
粉丝
2
感谢大佬的分享~~~
2024-1-8 00:59
0
雪    币: 10
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
感谢分享yyds
2024-1-8 09:11
0
雪    币: 1490
活跃值: (9913)
能力值: ( LV9,RANK:240 )
在线值:
发帖
回帖
粉丝
4
再来个样本就好了
2024-1-8 11:47
0
雪    币: 1229
活跃值: (1760)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
tql
2024-1-8 13:30
0
雪    币: 3004
活跃值: (30866)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
感谢分享
2024-1-8 13:51
1
雪    币: 562
活跃值: (4325)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
7
感谢分享-frida hook init_array自吐新解.
2024-1-8 17:11
0
雪    币: 507
活跃值: (1742)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
misskings [em_13]再来个样本就好了
随便拿个有init_array测就可以啦,默认是打印所有加载库的。
2024-1-8 17:11
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
9
强大
2024-1-9 10:50
0
雪    币: 120
活跃值: (1597)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
感谢分享-frida hook init_array自吐新解
2024-4-12 15:14
0
雪    币: 76
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
11
strong
2024-4-12 15:42
0
雪    币: 47
活跃值: (110)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
qig
12

强大,我这里有一个apk ,init_array 里面有个thread_create的方法,经过测试,的确可以解析出来.

上传的附件:
2024-5-18 14:54
0
游客
登录 | 注册 方可回帖
返回
//