标题要牛逼点,才有人看吧!
apk加载方案相关文章不少,但是要么是一代(不落地)加载方案,要么二代方案做的不完善,Android高版本支持不了,或者不支持多dex等,反正就是存在各种小问题,离可以使用还有这一点点距离。按理说现在加固方案都到第四代了,没道理二代的完善方案还没人开源吧,仔细想想可能是现在方案更先进了,当年的方案问题没人关注了,二来加固工具使用起来也方便,没必要自己搞一个。
为了让后来人有个学习参考吧,这里把自己鼓捣的结果写出来,大家共同学习共同进步吧!
------------------------------------ 废话分割线 -------------------------------------------
8.0及以后有系统提供的内存加载dex接口,所以难点主要集中在8.0以前。
8.0以前实现原理是加载虚dex然后替换成真实的cookie返回。这里如何替换是个难点,好在网上大神已经开源了方案,只是一番尝试下来只能在5.0和5.1上使用,并且也不支持多dex。网上查找相关资料,没有找到有用的结果,可能是搜索姿势不对。
那么就只能自己来了,首先查看6.0及以上部分的源码,需要hook的函数OpenMemory与5.1相比,返回发生了变化
std::unique_ptr<const DexFile> DexFile::OpenMemory(const std::string& location,
uint32_t location_checksum,
MemMap* mem_map,
std::string* error_msg)这个好处理,我改改不就行了吗,修改后在6.0上ok了,难道就这么搞定了。拿着代码去7.1上跑跑,报dex的错误。
A/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
A/DEBUG: Build fingerprint: 'qcom/msm8909/msm8909:7.1.2/N2G47H/54:user/release-keys'
A/DEBUG: Revision: '0'
A/DEBUG: ABI: 'arm'
A/DEBUG: pid: 13210, tid: 13210, name: m.frezrik.jiagu >>> com.frezrik.jiagu <<<
A/DEBUG: signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
A/DEBUG: Abort message: 'art/runtime/class_linker.cc:3225] Check failed: dex_cache_length > 0u (dex_cache_length=0, 0u=0) '
A/DEBUG: r0 00000000 r1 0000339a r2 00000006 r3 00000008
A/DEBUG: r4 ae5ca584 r5 00000006 r6 ae5ca52c r7 0000010c
A/DEBUG: r8 ab02f3df r9 9f3e63c0 sl 0000000a fp ab084400
A/DEBUG: ip 00000000 sp be61e3d8 lr ab5215a7 pc ab523e28 cpsr 200f0010
A/DEBUG: backtrace:
A/DEBUG: #00 pc 00049e28 /system/lib/libc.so (tgkill+12)
A/DEBUG: #01 pc 000475a3 /system/lib/libc.so (pthread_kill+34)
A/DEBUG: #02 pc 0001d7f5 /system/lib/libc.so (raise+10)
A/DEBUG: #03 pc 00019331 /system/lib/libc.so (__libc_android_abort+34)
A/DEBUG: #04 pc 000172e8 /system/lib/libc.so (abort+4)
A/DEBUG: #05 pc 000b7f89 /system/lib/libart.so (offset 0x258000)一番源码看下来,发现在7.0上加了dex check的代码,难道在7.0上真的没办法了,不死心的我突然想到8.0不是已经实现了内存加载dex吗,看看他们怎么做的呗。阅读了相关代码后,也没发现什么特殊的地方,能算上可疑点的是给内存的dex location命名(只记得这个解决问题的可疑点了,笑)
static const DexFile* CreateDexFile(JNIEnv* env, std::unique_ptr<MemMap> dex_mem_map) {
std::string location = StringPrintf("Anonymous-DexFile@%p-%p",
dex_mem_map->Begin(),
dex_mem_map->End());
std::string error_message;
std::unique_ptr<const DexFile> dex_file(DexFile::Open(location,
0,
std::move(dex_mem_map),
/* verify */ true,
/* verify_location */ true,
&error_message));死马当活马医,先加了试试
std::unique_ptr<const void *> load23(void *artHandle, const char *base, size_t size) {
std::string location = "Anonymous-DexFile"; //解决问题的关键就是这里
std::string err_msg;
std::unique_ptr<const void *> value;
const auto *dex_header = reinterpret_cast<const Header *>(base);
auto func23 = (org_artDexFileOpenMemory23) ndk_dlsym(artHandle, OpenMemory23);
value = func23((const unsigned char *) base,
size,
location,
dex_header->checksum_,
nullptr,
nullptr,
&err_msg);
if (!value) {
LOGE("[-]call load23 failed");
return nullptr;
}
return value;
}跑一把,成功了,此时的我流下了激动的泪水。
就这样终于搞定了6.0、7.0、7.1,后续也搞定了多dex的支持,整个项目完成度可以说达到了100%,下载后可直接使用。懒得贴相关代码了,大家直接去看吧
上干货: GitHub - Frezrik/Jiagu: Android apk jiagu
https://github.com/Frezrik/Jiagu
这里也不要积分下载了,大家如果觉得又有,打个星呗!
APK加固
- 支持Android5.0及其以上版本(已在5.1、7.1、8.1、10.0、11.0真机测试)
- 支持多dex加固
- 采用不落地加载dex方案
一.模块说明
工具开发调试使用
- app: 需要加固的源程序代码
- jiagu: 用于生成壳dex
- pack: java执行程序,用于打包加固app
Release工具
- JigguTool: 加固工具打包,如果只需要使用加固功能,直接用这个目录的工具即可
二.脚本说明
工具开发调试使用
- Jiagu_app.bat:编译打包app,打包出来的应用用于加固测试
- Jiagu_build.bat:编译生成加固工具
- Jiagu_input.bat:对input目录下的apk进行加固
Release工具
- Jiagu_update.bat:将Jiagu_build编译出来的工具更新到JiaguTool目录
三.使用说明
方法一(工具开发调试使用):
- 1.执行脚本Jiagu_build.bat生成加固工具
- 2.将要加固的应用放到input文件夹,执行脚本Jiagu_input.bat进行加固,加固后的应用将输出到output文件夹
方法二(Release工具):
- 加固环境会打包到JiaguTool,可以直接使用jiaguTool进行应用加固
- 如果修改了加固工具代码,可执行Jiagu_updata.bat重新打包加固工具
四.加固原理
1.加固工具处理
- 获取app的application名
- 修改app的AndroidManifest.xml的Application为dex壳的Application
- 壳dex和源dex拼接成一个dex,格式如下:
- 壳dex + (1字节application名长度 + app的application名 + 4字节源dex大小 + 源dex) + 4字节源dex2大小 + [源dex2] + 4字节源dex3大小 + [源dex3] + ... + 4字节壳dex大小
- 小括号的数据前512字节进行AES加密
- 中括号的数据的dex头(也就是前112位进行异或)
- 打包签名app
2.壳dex处理
- 解密出app的application名和dex
- 加载app的dex
- Android8.0以下版本采用call libart的OpenMemory函数实现内存加载dex
- Android8.0及以上采用系统提供的InMemoryDexClassLoader实现内存加载dex
- 壳application替换为app的application
巨人的肩膀:
https://bbs.pediy.com/thread-225303.htm