Android SO文件保护加固——混淆篇(一)
来源:互联网 发布:大连理工大学知乎 编辑:程序博客网 时间:2024/06/09 19:34
继上次基于源码级别和二进制级别的SO文件的核心函数保护后,没看的网友可以点击:点击打开链接;这篇是针对我们在JNI开发过程中利用javah生成本地层对应的函数名类似于java_com_XX这种形式,很容易被逆向者在逆向so的时候在IDA的Exports列表中找到这样一个问题,我们的目的就是让IDA在反汇编过程显示不出来,以及就算找到函数实现也是乱码的形式接下来开始搞;有问题欢迎大家批评指正和讨论。
问题篇:
比如拿上一篇中的例子来说,我们在破解分析的时候,在Java层看到调用libegg.so文件,我们用IDA打开,很容易的看到:
造成的结果会使得破解者很容易的切入主题,因此我们接下来就要解决这个问题。
原理篇:
我们知道JNI就是在java层与本地层之间起着一个桥梁的作用,因为java层是运行在Dalvik虚拟机中,而本地层则不会,因此这里在进入主题前很有必要理解一些几个问题:
1.java层虚拟机需要使用到哪些的本地层的lib库?
2.java层与本地层是怎么建立起一个对应的映射关系?
这时候我们不得不分析Android源码:
首先我们知道对于第一个问题,在JNI开发的过程中我们会在java层编写这种形式:
第一:告诉虚拟机去加载用static里面的libegg.so的动态链接库;
第二:告诉虚拟机用native声明的getStringFromNative的方法是在本地层实现的;
对于第二个问题,当虚拟机加载这个libegg.so这个库的时候,从java层进入本地层首先会执行JNI_Onload这个函数,所以可以在JNI_OnLoad函数中完成一些native层组件的初始化工作,同时更加重要的是,通常在JNI_jint JNI_OnLoad(JavaVM* vm, void* reserved)函数中会注册java层的native方法,提到注册就不得不提到一个很重要的一个静态函数registerNativeMethods:
传统java Jni方式:1.编写带有native方法的Java类;--->2.使用javah命令生成.h头文件;--->3.编写代码实现头文件中的方法,这样的“官方” 流程,是我们认识到这样会带来java_com_xxxx这样很容易被逆向者发现的弊端;
通用方式:RegisterNatives方法能帮助你把c/c++中的方法隐射到Java中的native方法,而无需遵循特定的方法命名格式。应用层级的Java类别透过VM而呼叫到本地函数。一般是仰赖VM去寻找*.so里的本地函数。如果需要连续呼叫很多次,每次都需要寻找一遍,会多花许多时间。此时,组件开发者可以自行将本地函数向VM进行登记。
VM调registerNativeMethods()函数的用途有二:
(1)更有效率去找到函数。
(2)可在执行期间进行抽换。
由于gMethods[]是一个<名称,函数指针>对照表,在程序执行时,可多次呼叫registerNativeMethods()函数来更换本地函数之指针,而达到弹性抽换本地函数之目的。这就引出了本文解决以上问题所采用的办法:
第一步:自定义JNI_Onload,来自定义JNI函数的函数名,通过registerNativeMethods()函数来更换本地函数指针并加入头文件;
第二步:所更换的本地函数所对应的函数的实现。
第三步:隐藏符号表,在Android.mk文件里面添加一句LOCAL_CFLAGS := -fvisibility=hidden
实现篇:
第一步:自定义JNI_Onload,来自定义JNI函数的函数名,通过registerNativeMethods()函数来更换本地函数指针并加入头文件;我们在上一个工程的基础上来改:
这里我们要注意一点:
JNINativemethod中结构体的定义:
第一个变量name是Java中函数的名字。
第二个变量signature,用字符串是描述了Java中函数的参数和返回值
第三个变量fnPtr是函数指针,指向native函数。前面都要接 (void *)
第一个变量与第三个变量是对应的,一个是java层方法名,对应着第三个参数的native方法名字:就像在本文中
第三步:隐藏符号表,在Android.mk文件里面添加一句LOCAL_CFLAGS := -fvisibility=hidden
第一个和第三个好理解:对于第二个:
括号里面表示参数的类型,括号后面表示返回值。我们要参照一个表格:
第二步:所更换的本地函数所对应的函数的实现:
这里的关键是,在函数前加上attribute((section (“.mytext”))),这样的话,编译的时候就会把这个函数编译到自定义的名叫”.mytext“的section里面,由于我们在java层没有定义这个函数因此要写到一个自定义的section里面。
第三步:隐藏符号表,在Android.mk文件里面添加一句LOCAL_CFLAGS := -fvisibility=hidden
注意的是在android studio中在build.gradle中
第一:defaultConfig{}中增加ndk设置:
第二:因为要手动ndk-build,需要在android{}中增加jni和jniLibs路径说明:
第三:在/src/main/jni中进行ndk-build手动编译生成对应的.so文件。
程序跑起来跟之前一样,我们用IDA打开对应的.so文件可以看出:
总结篇:
优点:
1.源码改动少,只需要添加JNI_Onload函数;
2.无需加解密so,就可以实现混淆so中的JNI函数(使得IDA分析紊乱);
3.可以加上前面说到的基于源码的函数的加解密,从而增加破解者的难度;
步骤:
第一步:自定义JNI_Onload,来自定义JNI函数的函数名,并加入头文件;
第二步:Java层函数所对应的函数的实现。
第三步:隐藏符号表,在Android.mk文件里面添加一句LOCAL_CFLAGS := -fvisibility=hidden
原理本质:
当java层调用System.loadLibrary函数时,函数会找到对应的so库,然后试着去找“JNI_Onload函数”;JNI_OnLoad可以和JNIEnv的registerNatives函数结合起来,实现动态的函数替换,再加上getStringc函数符号表的隐藏,就可以起到保护的作用。
附件:源码下载处:点击打开链接
- Android SO文件保护加固——混淆篇(一)
- Android SO文件保护加固——混淆篇(一)
- Android SO文件保护OLLVM混淆加固——混淆篇(二)
- Android SO文件保护OLLVM混淆加固——混淆篇(二)
- Android SO文件保护加固——加密篇(一)
- Android SO文件保护加固——加密篇(一)
- Android SO文件保护加固——加密篇(二)
- Android SO文件保护加固——加密篇(二)
- 学徒浅析Android开发——SO文件的混淆
- 学徒浅析Android开发——SO文件的混淆
- Android so文件保护——使用upx加壳
- android加固系列—1.如何检验so文件是否加壳成功
- apkprotect(免费android代码混淆、加密保护工具) Android中的Apk的加固(加壳)原理解析和实现
- android加固系列—3.加固前先学会破解,静态修改so
- Android So简单加固
- Android So简单加固
- Android混淆带有so文件的工程
- Android中对Apk加固(加壳)续篇之---对Native层(so文件)进行加固
- SSL 1715_计算面积_计算几何
- 【数据结构】栈的链表实现
- 指针与常量
- 电话本管理系统(数组版)
- Xcode打包ipa的基本步骤
- Android SO文件保护加固——混淆篇(一)
- java 线程中断机制
- CentOS下设置IP地址
- rhel6下yum源配置
- 按下enter键让提交页面的某个方法
- 员工管理系统(数组版)
- 线程池
- abstract class和interface的区别
- poj 1830 开关问题(高斯消元法)