- 无,看文章就可以了解大致了
(当然你要是想编译下dumpDex项目,需要如下工具)
- Android Studio
- sdk ndk
入口
所有的程序执行的时候都是有个入口的,dumpDex工程也不例外。 由于是个xposed插件,所以我们先看com.wrbug.dumpdex.XposedInit
类。
public class XposedInit implements IXposedHookLoadPackage {
//--------略---------
@Override
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) {
PackerInfo.Type type = PackerInfo.find(lpparam);
if (type == null) {
return;
}
final String packageName = lpparam.packageName;
//这里主要是各个app只管解析各个app自己的进程的程序
if (lpparam.packageName.equals(packageName)) {
//首先在当前app的指定目录,创建好目录,以便于一会儿脱壳存放dex文件
String path = “/data/data/” + packageName + “/dump”;
File parent = new File(path);
if (!parent.exists() || !parent.isDirectory()) {
parent.mkdirs();
}
log(“sdk version:” + Build.VERSION.SDK_INT);
if (DeviceUtils.isOreo()) {
//api为27或27版本的执行下面一行,进行脱壳
OreoDump.init(lpparam);
} else {
//低版本api执行下面一行进行脱壳
LowSdkDump.init(lpparam,type);
}
}
}
}
已经加好注释,值得注意的就是,此处程序有分叉了,分别是 OreoDump.init()和LowSdkDump.init() 我们先看OreoDump.init方法
public class OreoDump {
//--------略---------
public static void init(final XC_LoadPackage.LoadPackageParam lpparam) {
Native.dump(lpparam.packageName);
}
}
跟着进入Native.dump(),
- 注:不会android ndk也没关系,可以继续往下看
Native hook
以下可以先粗略的说一下,主要就是进入了ndk层进行hook,然后进行dump 进入native.cpp
文件里面找到JNICALL Java_com_wrbug_dumpdex_Native_dump
方法。
由于切换到了c语言,所以我会帮大家删除一些代码的细枝末节,只看主干。
再次声明下,以下方法实在当android版本为26或27的时候,会默认进行Native层脱壳
JNIEXPORT void JNICALL Java_com_wrbug_dumpdex_Native_dump
(JNIEnv *env, jclass obj, jstring packageName) {
//在这里作者考虑到了防止每次app启动的时候都会dump,因此保存了一个变量is_hook来记录,如果hook过了的话就会退出程序
static bool is_hook = false;
char *p = (char *) env->GetStringUTFChars(packageName, 0);
if (is_hook) {
__android_log_print(ANDROID_LOG_INFO, TAG, “hooked ignore”);
return;
}
init_package_name§;
env->ReleaseStringChars(packageName, (const jchar *) p);
//这里由于使用了第三方库,所以先执行第三方库的初始化操作,具体第三方库,见下文
ndk_init(env);
//下面就是重点了,首先以RTLD_NOW模式打开动态库libart.so,拿到句柄
void *handle = ndk_dlopen(“libart.so”, RTLD_NOW);
if (handle == NULL) {
__android_log_print(ANDROID_LOG_ERROR, TAG, “Error: unable to find the SO : libart.so”);
return;
}
//根据不同的版本,拿到不同的对应的加载的符号
void *open_common_addr = ndk_dlsym(handle, get_open_function_flag());
//--------略---------
//略掉很多分支,单独说一个,见下文
if (registerInlineHook((uint32_t) open_common_addr, (uint32_t) get_new_open_function_addr(),
(uint32_t **) get_old_open_function_addr()) != ELE7EN_OK) {
__android_log_print(ANDROID_LOG_ERROR, TAG, “register1 hook failed!”);
return;
} else {
__android_log_print(ANDROID_LOG_ERROR, TAG, “register1 hook success!”);
}
//设置hook标记为true
is_hook = true;
}
registerInlineHook(
(uint32_t) open_common_addr, (uint32_t) get_new_open_function_addr(),
(uint32_t **) get_old_open_function_addr())
已经定位到函数的地址,接下来就是Hook替换以前的函数,替换成我们自己定义的函数,例如下面的函数
static void *new_arm64_open_common(uint8_t *base, size_t size, void *location,
uint32_t location_checksum, void *oat_dex_file,
bool verify,
bool verify_checksum,
void *error_meessage, void *verify_result) {
//--------略---------
//首先在程序运行时,保存dex,完成脱壳
save_dex_file(base, size);
//调用以前的函数,保证程序正确执行,
void *result = old_arm64_open_common(base, size, location, location_checksum,
oat_dex_file, verify, verify_checksum,
error_meessage,
verify_result);
return result;
}
NDK层hook完毕
到此为止NDK层hook分析完毕,分别用了第三方库hook了android指定版本的加载dex函数的方法,然后在hook的新函数里面添加到保存到dump目录的函数,达到脱壳 的目的。
ndk hook主要用到的库
SDK层hook
回到入口的那个章节,还记得吗,还有一个LowSdkDump.init
这个是低版本的时候的逻辑
写在最后
本次我的分享也接近尾声了,感谢你们在百忙中花上一下午来这里聆听我的宣讲,希望在接下来的日子,我们共同成长,一起进步!!!
最后放上一个大概的Android学习方向及思路(详细的内容太多了~),提供给大家:
对于程序员来说,要学习的知识内容、技术有太多太多,这里就先放上一部分,其他的内容有机会在后面的文章向大家呈现出来,不过我自己所有的学习资料都整理成了一个文档,一直在不断学习,希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!
为什么某些人会一直比你优秀,是因为他本身就很优秀还一直在持续努力变得更优秀,而你是不是还在满足于现状内心在窃喜!希望读到这的您能点个小赞和关注下我,以后还会更新技术干货,谢谢您的支持!
Android架构师之路很漫长,一起共勉吧!
如果你觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言,一定会认真查询,修正不足,谢谢。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
。**
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!