获取百度钱包app的dex
- apk中无原始dex,只有加载器,真正的dex在资源中加密
- 在启动过程中存在反java层和c层调试,检测调试器(包括android_server),运行后则无
- 考虑app启动时调用加载dex的api和每次搜索java类时解析DexFile的api ,编写cydia插件拦截dexFileParse得到4个文件dex,其中7M的为我们需要的dex,反编译失败;再次尝试dexFindClass获取内存dex,反编译失败
- 研究dex结构发现内存dex的头部被擦除,另外类实现的字节码指针由局部偏移修改成超大地址,可知字节码被另外分配空间,需要还原内存dex
- 遍历每个类结构,得到另外分配的地址范围,将这段数据dump出来,附加到原dex文件尾,修改偏移即可
- 反编译dex,最后得到50M的smali
dexFindClass
if __name__=='__main__':
pDexFile=0x75741828
pOptHeader=Dword(pDexFile+0)
pHeader=Dword(pDexFile+4)
pStringIds=Dword(pDexFile+8)
pTypeIds=Dword(pDexFile+12)
pFieldIds=Dword(pDexFile+16)
pMethodIds=Dword(pDexFile+20)
pProtoIds=Dword(pDexFile+24)
pClassDefs=Dword(pDexFile+28)
pLinkData=Dword(pDexFile+32)
pClassLookup=Dword(pDexFile+36)
DexBase=Dword(pDexFile+44)
print "DexBase=%08x ClassDefBase=%08x classDefsSize=%d"%(DexBase,pClassDefs,classDefsSize)
classDefsSize=Dword(pHeader+0x60)
minaddr=0xffffffff
maxaddr=0
for i in range(0,classDefsSize):
off=pClassDefs+32*i
classIdx=Dword(off)
classDataOff=(Dword(off+24)+DexBase)&0xFFFFFFFF;
if(classDataOff!=0x75f40028):
if(classDataOff < minaddr):
minaddr=classDataOff
if(classDataOff > maxaddr):
maxaddr=classDataOff
print "%08x"%classDataOff
#datastr=""
#for j in range(0,16):
# datastr += "%02x"%(Byte(classDataOff+j))
#print "classIdx=%04d,classDataOff=%08x,sig:%s"%(classIdx,classDataOff,datastr)
print "min=%08x,max=%08x"%(minaddr,maxaddr)
#include <jni.h>
#include "substrate.h"
#include <android/log.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <sys/stat.h>
#define TAG "HOOKTEST"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
struct DexOptHeader
{
char magic[8];
u_int32_t dexOffset;
u_int32_t dexLength;
u_int32_t depsOffset;
u_int32_t depsLength;
u_int32_t optOffset;
u_int32_t optLength;
u_int32_t flags;
u_int32_t checksum;
};
struct DexHeader
{
char magic[8];
u_int32_t checksum;
char signature[20];
u_int32_t fileSize;
u_int32_t headerSize;
u_int32_t endianTag;
u_int32_t linkSize;
u_int32_t linkOff;
u_int32_t mapOff;
u_int32_t stringIdsSize;
u_int32_t stringIdsOff;
u_int32_t typeIdsSize;
u_int32_t typeIdsOff;
u_int32_t protoIdsSize;
u_int32_t protoIdsOff;
u_int32_t fieldIdsSize;
u_int32_t fieldIdsOff;
u_int32_t methodIdsSize;
u_int32_t methodIdsOff;
u_int32_t classDefsSize;
u_int32_t classDefsOff;
u_int32_t dataSize;
u_int32_t dataOff;
};
struct DexFile
{
struct DexOptHeader* pOptHeader;
struct DexHeader* pHeader;
};
MSConfig(MSFilterLibrary, "libdvm.so"); // 要hook的so库,后缀名即可。
static int num=0;
void* new_dexFileParse(const unsigned char* data, size_t length, int flags);
void* (*old_dexFileParse)(const unsigned char* data, size_t length, int flags);
void* new_dexFindClass(DexFile* pDexFile, const char* descriptor);
void* (*old_dexFindClass)(DexFile* pDexFile, const char* descriptor);
int (*old_execve)(char* name, char* argv, char* envp);
int new_execve(char* name, char* argv, char* envp);
bool getProcPackage(int pid, char* buf) {
char filename[256];
sprintf(filename,"/proc/%d/cmdline",pid);
FILE *f = fopen(filename,"r");
if (f)
{
fread(buf,256,1,f);
fclose(f);
}
}
char* whitelist[]=
{
"meizu",
"miui",
"xiaomi",
"android",
"app_process",
"system_server",
"zygote",
};
#define arraysize(x) (sizeof(x)/sizeof(x[0]))
void* new_dexFileParse(const unsigned char* data, size_t length, int flags)
{
LOGI("Enter dexFileParse!!!");
char filename[256];
char name[256];
getProcPackage(getpid(),name);
bool isinlist = false;
if(name[0] == '\0')
isinlist = true;
for(int i=0;i<arraysize(whitelist) && !isinlist;i++)
{
if(strstr(name, whitelist[i]))
isinlist = true;
}
if(!isinlist)
{
int len=strlen(name);
for(int i=0;i<len;i++)
{
if (name[i] >= 'a' && name[i] <= 'z' || name[i] >= '0' && name[i] <= '9' ||
name[i] >= 'A' && name[i] <= 'Z' || name[i] == '.') {
}
else {
name[i] = '_';
}
}
sprintf(filename, "/data/local/tmp/unpatch-%s-%d-%d.odex", name, getpid(), num++);
LOGI("patch %s",filename);
FILE *fp = fopen(filename, "wb");
if (!fp)
LOGI("fopen failed!");
else {
fwrite((void *) data, length, 1, fp);
fclose(fp);
}
}
return old_dexFileParse(data, length, flags);
}
int count=0;
void* new_dexFindClass(DexFile* pDexFile, const char* descriptor)
{
char name[128];
getProcPackage(getpid(),name);
void* pdata = old_dexFindClass(pDexFile, descriptor);
if(0 != strstr(name, "com.baidu.wallet") && pdata && strstr(descriptor, "Lcom/baidu/wallet"))
{
LOGI("--------%s-%s-%x-%s-%x-------",name,descriptor,pdata,pDexFile->pOptHeader->magic,pDexFile);
if(pdata && count < 2)
{
char buf[32];
sprintf(buf,"/data/local/tmp/wallet-%s%d.odex",name,count++);
if(0!=access(buf, F_OK))
{
FILE* fp = fopen(buf, "wb");
if(fp != 0)
{
fwrite(pDexFile->pOptHeader, pDexFile->pOptHeader->optOffset + pDexFile->pOptHeader->optLength, 1, fp);
LOGI("----------Dumped %s---------",buf);
fclose(fp);
}
}
}
}
return pdata;
}
int new_execve(char* name, char* argv, char* envp)
{//从execve拦kill
int ret = old_execve(name, argv, envp);
LOGI("evec:%s %s",name,argv);
return ret;
}
//Substrate entry point
MSInitialize{
LOGI("Substrate initialized.");
MSImageRef image;
//image = MSGetImageByName("/system/lib/libdvm.so"); // 此处要绝对路径
image = MSGetImageByName("/system/lib/libc.so"); // 此处要绝对路径
if (image != NULL)
{
LOGI("dvm image: 0x%08X", (void*)image);
//void * dvmload = MSFindSymbol(image, "_Z12dexFileParsePKhji");
//void * dvmload = MSFindSymbol(image, "_Z12dexFindClassPK7DexFilePKc");
void * dvmload = MSFindSymbol(image, "execve");
if(dvmload == NULL)
{
//LOGI("error find dexFindClass.");
LOGI("error find execve");
}
else
{
//MSHookFunction(dvmload,(void*)&new_dexFileParse,(void **)&old_dexFileParse);
// MSHookFunction(dvmload,(void*)&new_dexFindClass, (void **)&old_dexFindClass);
// LOGI("hook dexFindClasas sucess.");
MSHookFunction(dvmload,(void*)&new_execve, (void **)&old_execve);
LOGI("success hook execve");
}
}
else{
LOGI("can not find libdvm.");
}
}