Android JNI接口混淆方案
来源:互联网 发布:淘宝店铺起名字大全 编辑:程序博客网 时间:2024/06/03 03:50
一. 背景
由于项目有一些比较敏感的判断函数放在了native层,比如是否被改包,是否被Hook,是否被监听,是否有代理,是否运行了一些敏感程序等等,这种接口在编写的时候为了方便一般会写成isModifyPkg,isHook,isListening等等这样的函数,由于是JNI方法,因此也不能混淆,所以很容易被居心不良者直接hook住Java层或者反编译后通过关键字查找到函数调用,从而改变判断逻辑。因此需要对这些接口进行一层混淆,增加被Hook或者被发现的难度。
二. 未混淆的JNI接口
我们可以先看看未被混淆的JNI接口有多容易被Hook或者被识别。我模拟了一个类
package cn.zarathustra.obscure;public class NotObscureJNI { public static native boolean isModifyPkg(); public static native boolean isHook(); public static native boolean isListening(); public static native boolean hasSensitiveProcess();}
这就是我们一般声明的JNI方法,因为JNI方法不能被混淆,所以这样调用的意图很容易被人识破,反编译成smali之后就是这样的代码
.line 19invoke-static {}, Lcn/zarathustra/obscure/NotObscureJNI;->isHook()Z.line 20invoke-static {}, Lcn/zarathustra/obscure/NotObscureJNI;->hasSensitiveProcess()Z.line 21invoke-static {}, Lcn/zarathustra/obscure/NotObscureJNI;->isListening()Z.line 22invoke-static {}, Lcn/zarathustra/obscure/NotObscureJNI;->isModifyPkg()Z
甚至都不用hook native层都可以轻易的识破代码逻辑,再利用idap看看so
也很浅显易懂
三. 混淆JNI接口的方案
问题来了,怎么样能达到混淆的效果呢?
3.1 java层使用一个调用接口,利用opcode区分不同功能
由于Java的JNI方法和类是不能混淆的,因此需要让类的方法名尽可能的不好读,可以把类声明成A或者B这样,方法同理。如果每个功能使用一个接口,首先是会让代码更加难度,其次容易让别人逐个函数去hook来猜测用途,如果将所有需要的方法都写在一个函数里面,通过一个标识变量来区分具体的调用的功能,并且在Native层再进行区分,这样就能加大别破解的难度。
public static native boolean a(String opcode);
3.2 opcode进行加密,让意图不容易猜测
接下来就是Opcode怎么样去定义,首先不可能让其直接用”isListening”这样意图明显的字符串去定义,其次要保证opcode不会冲突,Hash算法就是一个不错的方案,比如OPCODE1代表isModifyPkg这个方法,利用Hash算法算出字符串“OPCODE1”的值,Hash算法我这里用了MD5(当然SHA256,SM3等更佳)。
//isModifyPkgpublic static String OPCODE1 = "805af30bbb66cb65accdea8b37890ec3";//isHookpublic static String OPCODE2 = "8727fd99374b1989fe854785b48f8dc6";//isListeningpublic static String OPCODE3 = "a2a5ef0cc5017e0c4da97a8e61705196";//hasSensitiveProcesspublic static String OPCODE4 = "dc2ad8b00cac1e98f15e67fd7f9248ab";
在Native层只要相应的用MD5去Hash出相应Opcode的值即可,如下:
//isModifyPkg#define OPCODE1 "OPCODE1"//isHook#define OPCODE2 "OPCODE2"//isListening#define OPCODE3 "OPCODE3"//hasSensitiveProcess#define OPCODE4 "OPCODE4"bool result = false;if (opcodeStr == MD5(OPCODE1)) { result = true;} else if (opcodeStr == MD5(OPCODE2)) { result = true;} else if (opcodeStr == MD5(OPCODE3)) { result = true;} else if (opcodeStr == MD5(OPCODE4)) { result = true;}
调用的方式变为:
ObscureJNI.a(ObscureJNI.OPCODE1);ObscureJNI.a(ObscureJNI.OPCODE2);ObscureJNI.a(ObscureJNI.OPCODE3);ObscureJNI.a(ObscureJNI.OPCODE4);
四. 总结
在进行了上面的混淆方式之后,可以看到反编译到Smali之后已经不能很清楚的看到函数意图,增加了篡改代码逻辑的难度
.line 25sget-object v0, Lcn/zarathustra/obscure/ObscureJNI;->OPCODE1:Ljava/lang/String;invoke-static {v0}, Lcn/zarathustra/obscure/ObscureJNI;->a(Ljava/lang/String;)Z.line 26sget-object v0, Lcn/zarathustra/obscure/ObscureJNI;->OPCODE2:Ljava/lang/String;invoke-static {v0}, Lcn/zarathustra/obscure/ObscureJNI;->a(Ljava/lang/String;)Z.line 27sget-object v0, Lcn/zarathustra/obscure/ObscureJNI;->OPCODE3:Ljava/lang/String;invoke-static {v0}, Lcn/zarathustra/obscure/ObscureJNI;->a(Ljava/lang/String;)Z.line 28sget-object v0, Lcn/zarathustra/obscure/ObscureJNI;->OPCODE4:Ljava/lang/String;invoke-static {v0}, Lcn/zarathustra/obscure/ObscureJNI;->a(Ljava/lang/String;)Z
native层也只有一个入口函数,内部的逻辑也没有之前那么好修改,当然要花心思还是能动的,但是如果配合一些so加壳,vmp,乱序插花,压缩之类的操作,这些逻辑就会变得坚不可摧了。
最后附上demo的代码:
github
csdn 文件共享
- Android JNI接口混淆方案
- Android 混淆打包方案
- Android资源混淆打包方案
- android jni接口函数
- Android JNI 接口总结
- android - Jni 接口函数表
- android - JNI接口函数 (1)
- android - JNI接口函数 (2)
- android - JNI接口函数 (3)
- android - JNI接口函数 (2)
- android - JNI接口函数 (1)
- Android 代码混淆can’t find referenced class问题解决方案
- Android 热修复 HotFix 混淆apk生成patch包方案
- android 热修复 HotFix 混淆apk生成patch包方案
- Android-项目中采用的混淆加固多渠道打包方案
- android JNI学习-接口-函数-JNI签名类型定义
- Android本地接口JNI的使用分析
- Android NDK JNI接口的声明
- css 父元宽度有子元素撑开
- 修改注册表屏蔽或替换键盘上的某个按键
- 中介者模式
- Linux系统下编译sqlite有关.c文件,显示fatal error: sqlite3.h: No such file or directory错误
- java集合一
- Android JNI接口混淆方案
- LeetCode 59.Spiral Matrix || (Medium)
- eclipse的Ctrl+Alt+方向键在英特尔显示器上会切换屏幕方向
- 获取ip地址的方法
- Python 2.6 升级到3.6
- CSS笔记:简析margin,padding,border
- grafana 页面报错被重定向次数过多,后台报 Failed to start session%!(EXTRA *os.PathError=open /var/lib/grafana/session
- 基数排序
- Collection容器初探之LinkedList