打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
安卓 dex 通用脱壳技术研究(二)
安卓 dex 通用脱壳技术研究(二)
2015-09-26 22:52 2262人阅读 (0)
分类:
Android(10)
http://my.oschina.net/cve2015/blog/508605
摘要 本文剖析安卓 Dalvik 解释器 Portable 的原理与实现,并通过修改 Dalvik 虚拟机实现 dex 文件的通用脱壳方案;本方法同样适应于 ART 虚拟机;
目录[-]
0x03 DexHunter代码分析
0x03 DexHunter代码分析
DexHunter 实现中,只需要修改一处文件:dalvik\vm\native\dalvik_system_DexFile.cpp
下面是BeyondCompare比对:
首先看一下DexHunter的设计原理:
APP 启动时,通过freature string定位dex在内存中位置,并读取classdef块之前的内存为part1,读取classdef之后的内存为data。遍历class_def_item结构,生成文件classdef,并通过code_item_off判断具体的类方法是否在dex范围内,若不在,则写extra文件。
描述几个问题:
从哪里dump出dex文件
dex文件打开时
类加载时
类初始化时
类方法调用时
DexHunter中,我们关注,ClassLoader.loadClass->Dalvik_dalvik_system_DexFile_defineClassNative这个函数,它实现了类的加载,实现过程如下:
选择脱壳的时机应是在APP的第一个类加载的时候,为什么呢?
类加载之前,类的内容是在内存当中的
当类初始化时,该内存的内容可能会被动态修改
在一个类方法被调用前,code_item或指令肯定是可用的
那如何做呢?
我们要主动加载并初始化所有的类;
因此,我们代码的注入点,应该是Dalvik_dalvik_system_DexFile_defineClassNative()函数的clazz = dvmDefineClass(pDvmDex, descriptor, loader);语句之前;即在APP加载第一个类之前完成;通过dvmDefineClass主动遍历class_def_item加载每个类,并调用dvmIsClassInitialized和dvmInitClass函数初始化之。
初始化完成之后,内存中的就是将执行的代码,像梆梆加固针对每个方法进行的加密,会在运行时解密、运行完成后清理内存并再次加密,通过这种方法就可以过掉;因为我们模拟了这样一次调用过程;
下面是我加入注释的代码:
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
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
//------------------------added begin----------------------//
#include <asm/siginfo.h>
#include "libdex/DexClass.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
static char dexname[100]={0};   //feature string
static char dumppath[100]={0};  //dump的文件路径
static bool readable=true;
static pthread_mutex_t read_mutex;
static bool flag=true;
static pthread_mutex_t mutex;
static bool timer_flag=true;
static timer_t timerId;
struct arg{
DvmDex* pDvmDex;
Object * loader;
}param;
void timer_thread(sigval_t)
{
timer_flag=false;
timer_delete(timerId);
ALOGI("GOT IT time up");
}
void* ReadThread(void *arg){
FILE *fp = NULL;
while (dexname[0]==0||dumppath[0]==0) {
fp=fopen("/data/dexname", "r");
if (fp==NULL) {
sleep(1);
continue;
}
fgets(dexname,99,fp);   //读feature string
dexname[strlen(dexname)-1]=0;
fgets(dumppath,99,fp);
dumppath[strlen(dumppath)-1]=0;//取dump路径
fclose(fp);
fp=NULL;
}
struct sigevent sev;
sev.sigev_notify=SIGEV_THREAD;
sev.sigev_value.sival_ptr=&timerId;
sev.sigev_notify_function=timer_thread;
sev.sigev_notify_attributes = NULL;
timer_create(CLOCK_REALTIME,&sev,&timerId);
struct itimerspec ts;
ts.it_value.tv_sec=5;
ts.it_value.tv_nsec=0;
ts.it_interval.tv_sec=0;
ts.it_interval.tv_nsec=0;
timer_settime(timerId,0,&ts,NULL);
return NULL;
}
/*
这里是class_data_item的前4项,称为ClassDataHeader
Dex File->class_defs->class_def_item(class_data_offset)->class_data_item->ClassDataHeader
*/
void ReadClassDataHeader(const uint8_t** pData, DexClassDataHeader *pHeader)
{
pHeader->staticFieldsSize = readUnsignedLeb128(pData);
pHeader->instanceFieldsSize = readUnsignedLeb128(pData);
pHeader->directMethodsSize = readUnsignedLeb128(pData);
pHeader->virtualMethodsSize = readUnsignedLeb128(pData);
}
/*
下面两个函数,分别读class_data_item Header下的内容,分Field和Method
*/
void ReadClassDataField(const uint8_t** pData, DexField* pField)
{
pField->fieldIdx = readUnsignedLeb128(pData);
pField->accessFlags = readUnsignedLeb128(pData);
}
void ReadClassDataMethod(const uint8_t** pData, DexMethod* pMethod)
{
pMethod->methodIdx = readUnsignedLeb128(pData);
pMethod->accessFlags = readUnsignedLeb128(pData);
pMethod->codeOff = readUnsignedLeb128(pData);
}
/*
解析class_data_item结构,使用到上面3个函数,分别解析,Header、Field和Method部分
*/
DexClassData* ReadClassData(const uint8_t** pData)
{
DexClassDataHeader header;
if (*pData == NULL) {
return NULL;
}
//读取 class_data_item的Header
ReadClassDataHeader(pData, &header);
size_t resultSize = sizeof(DexClassData) + (header.staticFieldsSize * sizeof(DexField)) + (header.instanceFieldsSize * sizeof(DexField)) + (header.directMethodsSize * sizeof(DexMethod)) + (header.virtualMethodsSize * sizeof(DexMethod));
DexClassData* result = (DexClassData*) malloc(resultSize); //result指向class_data_item并返回
if (result == NULL) {
return NULL;
}
uint8_t* ptr = ((uint8_t*) result) + sizeof(DexClassData);  //指向class_data_item的staic_fields偏移
result->header = header;
//以下依次读class_data_item的staticFields,instanceFields,directMethods和virtualMethods域大小————————begain
if (header.staticFieldsSize != 0) {
result->staticFields = (DexField*) ptr;
ptr += header.staticFieldsSize * sizeof(DexField);
} else {
result->staticFields = NULL;
}
if (header.instanceFieldsSize != 0) {
result->instanceFields = (DexField*) ptr;
ptr += header.instanceFieldsSize * sizeof(DexField);
} else {
result->instanceFields = NULL;
}
if (header.directMethodsSize != 0) {
result->directMethods = (DexMethod*) ptr;
ptr += header.directMethodsSize * sizeof(DexMethod);
} else {
result->directMethods = NULL;
}
if (header.virtualMethodsSize != 0) {
result->virtualMethods = (DexMethod*) ptr;
} else {
result->virtualMethods = NULL;
}
//以下依次读class_data_item的staticFields,instanceFields,directMethods和virtualMethods域大小————————end
//以下依次读staticFields,instanceFields,directMethods,virtualMethods域内容————————begain
for (uint32_t i = 0; i < header.staticFieldsSize; i++) {
ReadClassDataField(pData, &result->staticFields[i]);
}
for (uint32_t i = 0; i < header.instanceFieldsSize; i++) {
ReadClassDataField(pData, &result->instanceFields[i]);
}
for (uint32_t i = 0; i < header.directMethodsSize; i++) {
ReadClassDataMethod(pData, &result->directMethods[i]);
}
for (uint32_t i = 0; i < header.virtualMethodsSize; i++) {
ReadClassDataMethod(pData, &result->virtualMethods[i]);
}
//以下依次读staticFields,instanceFields,directMethods,virtualMethods域内容————————end
return result;
}
/*
class_data_item中的一些域是用LEB128算法编码的
*/
void writeLeb128(uint8_t ** ptr, uint32_t data)
{
while (true) {
uint8_t out = data & 0x7f;
if (out != data) {
*(*ptr)++ = out | 0x80;
data >>= 7;
} else {
*(*ptr)++ = out;
break;
}
}
}
/*
此函数读取class_data_item,并将内容用writeLeb128转码后返回
*/
uint8_t* EncodeClassData(DexClassData *pData, int& len)
{
len=0;
len+=unsignedLeb128Size(pData->header.staticFieldsSize);
len+=unsignedLeb128Size(pData->header.instanceFieldsSize);
len+=unsignedLeb128Size(pData->header.directMethodsSize);
len+=unsignedLeb128Size(pData->header.virtualMethodsSize);
if (pData->staticFields) {
for (uint32_t i = 0; i < pData->header.staticFieldsSize; i++) {
len+=unsignedLeb128Size(pData->staticFields[i].fieldIdx);
len+=unsignedLeb128Size(pData->staticFields[i].accessFlags);
}
}
if (pData->instanceFields) {
for (uint32_t i = 0; i < pData->header.instanceFieldsSize; i++) {
len+=unsignedLeb128Size(pData->instanceFields[i].fieldIdx);
len+=unsignedLeb128Size(pData->instanceFields[i].accessFlags);
}
}
if (pData->directMethods) {
for (uint32_t i=0; i<pData->header.directMethodsSize; i++) {
len+=unsignedLeb128Size(pData->directMethods[i].methodIdx);
len+=unsignedLeb128Size(pData->directMethods[i].accessFlags);
len+=unsignedLeb128Size(pData->directMethods[i].codeOff);
}
}
if (pData->virtualMethods) {
for (uint32_t i=0; i<pData->header.virtualMethodsSize; i++) {
len+=unsignedLeb128Size(pData->virtualMethods[i].methodIdx);
len+=unsignedLeb128Size(pData->virtualMethods[i].accessFlags);
len+=unsignedLeb128Size(pData->virtualMethods[i].codeOff);
}
}
uint8_t * store = (uint8_t *) malloc(len);
if (!store) {
return NULL;
}
uint8_t * result=store;
writeLeb128(&store,pData->header.staticFieldsSize);
writeLeb128(&store,pData->header.instanceFieldsSize);
writeLeb128(&store,pData->header.directMethodsSize);
writeLeb128(&store,pData->header.virtualMethodsSize);
if (pData->staticFields) {
for (uint32_t i = 0; i < pData->header.staticFieldsSize; i++) {
writeLeb128(&store,pData->staticFields[i].fieldIdx);
writeLeb128(&store,pData->staticFields[i].accessFlags);
}
}
if (pData->instanceFields) {
for (uint32_t i = 0; i < pData->header.instanceFieldsSize; i++) {
writeLeb128(&store,pData->instanceFields[i].fieldIdx);
writeLeb128(&store,pData->instanceFields[i].accessFlags);
}
}
if (pData->directMethods) {
for (uint32_t i=0; i<pData->header.directMethodsSize; i++) {
writeLeb128(&store,pData->directMethods[i].methodIdx);
writeLeb128(&store,pData->directMethods[i].accessFlags);
writeLeb128(&store,pData->directMethods[i].codeOff);
}
}
if (pData->virtualMethods) {
for (uint32_t i=0; i<pData->header.virtualMethodsSize; i++) {
writeLeb128(&store,pData->virtualMethods[i].methodIdx);
writeLeb128(&store,pData->virtualMethods[i].accessFlags);
writeLeb128(&store,pData->virtualMethods[i].codeOff);
}
}
free(pData);
return result;
}
uint8_t* codeitem_end(const u1** pData)
{
uint32_t num_of_list = readUnsignedLeb128(pData);
for (;num_of_list>0;num_of_list--) {
int32_t num_of_handlers=readSignedLeb128(pData);
int num=num_of_handlers;
if (num_of_handlers<=0) {
num=-num_of_handlers;
}
for (; num > 0; num--) {
readUnsignedLeb128(pData);
readUnsignedLeb128(pData);
}
if (num_of_handlers<=0) {
readUnsignedLeb128(pData);
}
}
return (uint8_t*)(*pData);
}
代码未完,下一篇继续;
0
0
上一篇安卓 dex 通用脱壳技术研究(一)
下一篇安卓 dex 通用脱壳技术研究(三)
我的同类文章
Android(10)
·安卓 dex 通用脱壳技术研究(四)2015-09-26阅读1768
·安卓 dex 通用脱壳技术研究(一)2015-09-26阅读3265
·开源多语言公历农历转换2015-01-19阅读2239
·android ProgressDialog 模态2014-01-04阅读1526
·搭建cocos2d-x-android环境 Windows XP3 + Eclipse + NDKR7+COCOS2DX(没有用到cygwin和minigw)2012-02-28阅读1988
·安卓 dex 通用脱壳技术研究(三)2015-09-26阅读1810
·Android dex文件通用自动脱壳器2015-09-26阅读1502
·Android 中的 Service 全面总结2014-05-28阅读1187
·android BitmapFactory.decodeFile out of memory 崩溃2013-12-22阅读1274
·Android 24点游戏 程序 源码2012-02-28阅读1422
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Intel平台下Linux中ELF文件动态链接的加载、解析及实例分析(一): 加载
C语言难点分析整理
android上用C语言读取fb0实现截屏,并保存为rgb565的bmp
经典程序100例(71-80)
bmp转tiff
共享内存实用研究(一)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服