安卓 dex 通用脱壳技术研究(三)
/*
此为DexHunter实现的主要功能,进行内存dump,将class_def_items中dump出classdef和extra部分
*/
void* DumpClass(void *parament)
{
while (timer_flag) {
sleep(5);
} DvmDex* pDvmDex=((struct arg*)parament)->pDvmDex; //pDvmDex代表一个dex文件
Object *loader=((struct arg*)parament)->loader;
DexFile* pDexFile=pDvmDex->pDexFile;
MemMapping * mem=&pDvmDex->memMap; u4 time=dvmGetRelativeTimeMsec();
ALOGI("GOT IT begin: %d ms",time); char *path = new char[100];
strcpy(path,dumppath);
strcat(path,"classdef"); //构造classdef文件路径
FILE *fp = fopen(path, "wb+"); strcpy(path,dumppath);
strcat(path,"extra"); //构造extra文件路径
FILE *fp1 = fopen(path,"wb+"); uint32_t mask=0x3ffff;
char padding=0;
const char* header="Landroid";
unsigned int num_class_defs=pDexFile->pHeader->classDefsSize; //dex文件的Header域,class_defs_size,标示了class_def域有几个class_def_item
uint32_t total_pointer = mem->length-uint32_t(pDexFile->baseAddr-(const u1*)mem->addr);
uint32_t rec=total_pointer; while (total_pointer&3) {
total_pointer++;
} int inc=total_pointer-rec;
uint32_t start = pDexFile->pHeader->classDefsOff+sizeof(DexClassDef)*num_class_defs;
uint32_t end = (uint32_t)((const u1*)mem->addr+mem->length-pDexFile->baseAddr); for (size_t i=0;i<num_class_defs;i++) //遍历所有class_def_item
{
bool need_extra=false;
ClassObject * clazz=NULL;
const u1* data=NULL;
DexClassData* pData = NULL;
bool pass=false;
const DexClassDef *pClassDef = dexGetClassDef(pDvmDex->pDexFile, i);
const char *descriptor = dexGetClassDescriptor(pDvmDex->pDexFile,pClassDef); if(!strncmp(header,descriptor,8)||!pClassDef->classDataOff)
{
pass=true;
goto classdef;
} clazz = dvmDefineClass(pDvmDex, descriptor, loader); //First Step:class加载 if (!clazz) {
continue;
} ALOGI("GOT IT class: %s",descriptor); if (!dvmIsClassInitialized(clazz)) { //Second Step:class初始化,遍历所有类进行初始化
if(dvmInitClass(clazz)){ //与dvmIsClassInitialized()函数共同完成初始化
ALOGI("GOT IT init: %s",descriptor);
}
}
if(pClassDef->classDataOff<start || pClassDef->classDataOff>end)
{
need_extra=true; //是不是需要extra这一块,当存在class_data_off不在dex范围内时,就需要
} data=dexGetClassData(pDexFile, pClassDef);
pData = ReadClassData(&data); if (!pData) {
continue;
} if (pData->directMethods) {
for (uint32_t i=0; i<pData->header.directMethodsSize; i++) {
Method *method = &(clazz->directMethods[i]);
uint32_t ac = (method->accessFlags) & mask; ALOGI("GOT IT direct method name %s.%s",descriptor,method->name); if (!method->insns||ac&ACC_NATIVE) {
if (pData->directMethods[i].codeOff) {
need_extra = true;
pData->directMethods[i].accessFlags=ac;
pData->directMethods[i].codeOff=0;
}
continue;
} u4 codeitem_off = u4((const u1*)method->insns-16-pDexFile->baseAddr); if (ac != pData->directMethods[i].accessFlags)
{
ALOGI("GOT IT method ac");
need_extra=true;
pData->directMethods[i].accessFlags=ac;
} if (codeitem_off!=pData->directMethods[i].codeOff&&((codeitem_off>=start&&codeitem_off<=end)||codeitem_off==0)) {
ALOGI("GOT IT method code");
need_extra=true;
pData->directMethods[i].codeOff=codeitem_off;
} if ((codeitem_off<start || codeitem_off>end) && codeitem_off!=0) {
//如果code_item_off不在dex文件范围内,则写入extra; fp1为extra的句柄
//这里使用的是slider.pptx,中的第二种方案,见p42
need_extra=true;
pData->directMethods[i].codeOff = total_pointer;
DexCode *code = (DexCode*)((const u1*)method->insns-16);
uint8_t *item=(uint8_t *) code;
int code_item_len = 0;
if (code->triesSize) {
const u1 * handler_data = dexGetCatchHandlerData(code);
const u1** phandler=(const u1**)&handler_data;
uint8_t * tail=codeitem_end(phandler);
code_item_len = (int)(tail-item);
}else{
code_item_len = 16+code->insnsSize*2;
} ALOGI("GOT IT method code changed"); fwrite(item,1,code_item_len,fp1);
fflush(fp1);
total_pointer+=code_item_len;
while (total_pointer&3) {
fwrite(&padding,1,1,fp1);
fflush(fp1);
total_pointer++;
}
}
}
} if (pData->virtualMethods) {
for (uint32_t i=0; i<pData->header.virtualMethodsSize; i++) {
Method *method = &(clazz->virtualMethods[i]);
uint32_t ac = (method->accessFlags) & mask; ALOGI("GOT IT virtual method name %s.%s",descriptor,method->name); if (!method->insns||ac&ACC_NATIVE) {
if (pData->virtualMethods[i].codeOff) {
need_extra = true;
pData->virtualMethods[i].accessFlags=ac;
pData->virtualMethods[i].codeOff=0;
}
continue;
} u4 codeitem_off = u4((const u1 *)method->insns - 16 - pDexFile->baseAddr); if (ac != pData->virtualMethods[i].accessFlags)
{
ALOGI("GOT IT method ac");
need_extra=true;
pData->virtualMethods[i].accessFlags=ac;
} if (codeitem_off!=pData->virtualMethods[i].codeOff&&((codeitem_off>=start&&codeitem_off<=end)||codeitem_off==0)) {
ALOGI("GOT IT method code");
need_extra=true;
pData->virtualMethods[i].codeOff=codeitem_off;
} if ((codeitem_off<start || codeitem_off>end)&&codeitem_off!=0) {
need_extra=true;
pData->virtualMethods[i].codeOff = total_pointer;
DexCode *code = (DexCode*)((const u1*)method->insns-16);
uint8_t *item=(uint8_t *) code;
int code_item_len = 0;
if (code->triesSize) {
const u1 *handler_data = dexGetCatchHandlerData(code);
const u1** phandler=(const u1**)&handler_data;
uint8_t * tail=codeitem_end(phandler);
code_item_len = (int)(tail-item);
}else{
code_item_len = 16+code->insnsSize*2;
} ALOGI("GOT IT method code changed"); fwrite(item,1,code_item_len,fp1);
fflush(fp1);
total_pointer+=code_item_len;
while (total_pointer&3) {
fwrite(&padding,1,1,fp1);
fflush(fp1);
total_pointer++;
}
}
}
} classdef:
DexClassDef temp=*pClassDef;
uint8_t *p = (uint8_t *)&temp; if (need_extra) {
ALOGI("GOT IT classdata before");
int class_data_len = 0;
uint8_t *out = EncodeClassData(pData,class_data_len);
if (!out) {
continue;
}
temp.classDataOff = total_pointer;
fwrite(out,1,class_data_len,fp1);
fflush(fp1);
total_pointer+=class_data_len;
while (total_pointer&3) {
fwrite(&padding,1,1,fp1);
fflush(fp1);
total_pointer++;
}
free(out);
ALOGI("GOT IT classdata written");
}else{
if (pData) {
free(pData);
}
} if (pass) {
temp.classDataOff=0;
temp.annotationsOff=0;
} ALOGI("GOT IT classdef");
fwrite(p, sizeof(DexClassDef), 1, fp);
fflush(fp);
} fclose(fp1);
fclose(fp);
//目前已经准备好了part1,classdef,data和extra 4部分文件
strcpy(path,dumppath);
strcat(path,"whole.dex"); //组合4部分,并写入whole.dex
fp = fopen(path,"wb+");
rewind(fp); int fd=-1;
int r=-1;
int len=0;
char *addr=NULL;
struct stat st; strcpy(path,dumppath);
strcat(path,"part1"); fd=open(path,O_RDONLY,0666);
if (fd==-1) {
return NULL;
} r=fstat(fd,&st);
if(r==-1){
close(fd);
return NULL;
} len=st.st_size;
addr=(char*)mmap(NULL,len,PROT_READ,MAP_PRIVATE,fd,0);
fwrite(addr,1,len,fp);
fflush(fp);
munmap(addr,len);
close(fd); strcpy(path,dumppath);
strcat(path,"classdef"); fd=open(path,O_RDONLY,0666);
if (fd==-1) {
return NULL;
} r=fstat(fd,&st);
if(r==-1){
close(fd);
return NULL;
} len=st.st_size;
addr=(char*)mmap(NULL,len,PROT_READ,MAP_PRIVATE,fd,0);
fwrite(addr,1,len,fp);
fflush(fp);
munmap(addr,len);
close(fd); strcpy(path,dumppath);
strcat(path,"data"); fd=open(path,O_RDONLY,0666);
if (fd==-1) {
return NULL;
} r=fstat(fd,&st);
if(r==-1){
close(fd);
return NULL;
} len=st.st_size;
addr=(char*)mmap(NULL,len,PROT_READ,MAP_PRIVATE,fd,0);
fwrite(addr,1,len,fp);
fflush(fp);
munmap(addr,len);
close(fd); while (inc>0) {
fwrite(&padding,1,1,fp);
fflush(fp);
inc--;
} strcpy(path,dumppath);
strcat(path,"extra"); fd=open(path,O_RDONLY,0666);
if (fd==-1) {
return NULL;
} r=fstat(fd,&st);
if(r==-1){
close(fd);
return NULL;
} len=st.st_size;
addr=(char*)mmap(NULL,len,PROT_READ,MAP_PRIVATE,fd,0);
fwrite(addr,1,len,fp);
fflush(fp);
munmap(addr,len);
close(fd); fclose(fp);
delete path; time=dvmGetRelativeTimeMsec();
ALOGI("GOT IT end: %d ms",time); return NULL;
}
//------------------------added end----------------------//
安卓 dex 通用脱壳技术研究(三)的更多相关文章
- 安卓 dex 通用脱壳技术研究(一)
注:以下4篇博文中,部分图片引用自DexHunter作者zyqqyz在slide.pptx中的图片,版本归原作者所有: 0x01 背景介绍 安卓 APP 的保护一般分为下列几个方面: JAVA/C代码 ...
- 安卓 dex 通用脱壳技术研究(二)
0x03 DexHunter代码分析 DexHunter 实现中,只需要修改一处文件:dalvik\vm\native\dalvik_system_DexFile.cpp 下面是BeyondCompa ...
- 安卓 dex 通用脱壳技术研究(四)
/* 当第一个类执行到此函数时,我们在dvmDefineClass执行之前,也就是第一个类加载之前 注入我们的dump代码:即DumpClass()函数 */ static void ...
- 基于.net的分布式系统限流组件 C# DataGridView绑定List对象时,利用BindingList来实现增删查改 .net中ThreadPool与Task的认识总结 C# 排序技术研究与对比 基于.net的通用内存缓存模型组件 Scala学习笔记:重要语法特性
基于.net的分布式系统限流组件 在互联网应用中,流量洪峰是常有的事情.在应对流量洪峰时,通用的处理模式一般有排队.限流,这样可以非常直接有效的保护系统,防止系统被打爆.另外,通过限流技术手段,可 ...
- 20145307陈俊达_安卓逆向分析_Xposed的hook技术研究
20145307陈俊达_安卓逆向分析_Xposed的hook技术研究 引言 其实这份我早就想写了,xposed这个东西我在安卓SDK 4.4.4的时候就在玩了,root后安装架构,起初是为了实现一些屌 ...
- 【转】手把手教你读取Android版微信和手Q的聊天记录(仅作技术研究学习)
1.引言 特别说明:本文内容仅用于即时通讯技术研究和学习之用,请勿用于非法用途.如本文内容有不妥之处,请联系JackJiang进行处理! 我司有关部门为了获取黑产群的动态,有同事潜伏在大量的黑产群 ...
- 手把手教你读取Android版微信和手Q的聊天记录(仅作技术研究学习)
1.引言 特别说明:本文内容仅用于即时通讯技术研究和学习之用,请勿用于非法用途.如本文内容有不妥之处,请联系JackJiang进行处理! 我司有关部门为了获取黑产群的动态,有同事潜伏在大量的黑产群 ...
- Ngnix技术研究系列2-基于Redis实现动态路由
上篇博文我们写了个引子: Ngnix技术研究系列1-通过应用场景看Nginx的反向代理 发现了新大陆,OpenResty OpenResty 是一个基于 Nginx 与 Lua 的高性能 Web 平台 ...
- Nginx技术研究系列2-基于Redis实现动态路由
上篇博文我们写了个引子: Ngnix技术研究系列1-通过应用场景看Nginx的反向代理 发现了新大陆,OpenResty OpenResty 是一个基于 Nginx 与 Lua 的高性能 Web 平台 ...
随机推荐
- CSS3透明背景+渐变样式
CSS3透明背景+渐变样式 转载自博文:<CSS3透明背景+渐变样式> http://blog.csdn.net/netbug_nb/article/details/44343809 效果 ...
- 关于ORA-06508 , ORA-04068异常的详细说明
参考:程序包调用报ORA-06508: PL/SQL: 无法找到正在调用的程序单元 出现这种情况的原因是因为,对于全局变量,每一个session会生成一个本地copy,如果程序重新编译的话,就会因程序 ...
- spring cloud服务发现注解之@EnableDiscoveryClient与@EnableEurekaClient区别
在使用服务发现的时候有两种注解, 一种为@EnableDiscoveryClient, 一种为@EnableEurekaClient, 用法上基本一致,下文是从stackoverflow上面找到的对这 ...
- 水题系列二:PhoneNumbers
问题描述: Phonenumbers 企业喜欢用容易被记住的电话号码.让电话号码容易被记住的一个办法是将它写成一 个容易记 住的 单词或 者短语 .例如 ,你 需要给 滑铁卢 大学打 电话时 ,可 以 ...
- GNU和GPL的区别/关系
GUN:GNU's Not UNIX的缩写,是一项运动.是1983年Richard Stallman针对UNIX走向毕源和和收费后发起的运动,旨在打造出一套完全开源免费的操作系统. 为了更好地实施GN ...
- Windows服务手动关闭教程
Windows上关闭软件自启动,经常使用360等软件的开机加速功能去优化. 但有时候有些服务开机是启动的但在360中并没有找到那如何手动关闭这些服务的自启动呢? 下边以Autodesk Applica ...
- Java Web(十一) 文件上传与下载
文件上传 上传的准备工作 表单method必须为post 提供file组件 设置form标签的enctype属性为multipart/form-data,如果没有设置enctype属性,浏览器是无法将 ...
- 【基础】selenium中元素定位的常用方法(三)
一.Selenium中元素定位共有八种 id name className tagName linkText partialLinkText xpath cssSelector 其中前六种都比较简单, ...
- linux command useradd
Linux command useradd [Purpose] Learning linux command useradd to create a new user or update ...
- 【资料收集】QT 环境安装配置
(很详细,极力推荐) [OpenCV] -- win7下配置OpenCV的Qt开发环境 - 代码人生 - 博客频道 - CSDN.NET http://blog.csdn.net/qiurisuix ...