在日常的APP开发过程中我们都会遇到安全相关的问题,针对不同的安全需求会有不同的解决方案。那么我们今天来看看与Android动态库相关的安全问题。
今天我们以AndroidSO工程为基础,通过实际的例子来解决一些常见的安全需求。
动态库被第三方APP非法使用
我们辛辛苦苦开发了一个动态库,最终却被非授权的第三方APP用了,那么不是很尴尬嘛。
那么如何防止我们的动态库被第三方非法使用呢?客官往下看~
非授权使用的问题本质上是因为我们的动态库没有做验签功能,接下来就带大家实现对SO调用的签名验证功能。
敏感字符串信息可见
native-lib-static.cpp的JNI函数代码如下。
JNIEXPORT jstring JNICALL
Java_com_demon_so_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from static register jni function";
return env->NewStringUTF(hello.c_str());
}
上面这个图片是我通过IDA(逆向分析工具)打开static-dynamic-so工程生成的libnative-lib.so
后截图的信息。
我们可以很容易看到字符串的信息。与我们代码中的字符串一模一样,很完整被解析出来。
是不是突然感觉很没有安全感,这么随意。。。
我们这个字符串没有什么价值,但是如果我们存放了敏感的字符串信息又如何是好呢?
简单的解决办法有如下两种:
001 定义char数组
字符串信息以数组的方式初始化,比如以下写法:
JNIEXPORT jstring JNICALL
Java_com_demon_so_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
char* hello = ((char[]){'H','e','l','l','o',' ','f','r','o','m',' ','s','t','a','t','i','c',' ','r','e','g','i','s','t','e','r',' ','j','n','i',' ','f','u','n','c','t','i','o','n'});
return env->NewStringUTF(hello);
}
看到这么一长串的代码是不是要疯了,我擦,一个完整的字符串居然被凌乱掉了。这么写代码要疯掉了。
办法总是有的嘛......
用一个python脚本就可以解决问题了
content = "Hello from static register jni function"
length = len(content)
str = "((char[]){"
for i in range(length):
str = str+'\''+content[i]+'\''
if i !=(length-1):
str=str+','
str = str+"})"
print str
最终输出内容如下:
((char[]){'H','e','l','l','o',' ','f','r','o','m',' ','s','t','a','t','i','c',' ','r','e','g','i','s','t','e','r',' ','j','n','i',' ','f','u','n','c','t','i','o','n'});
注意这种写法只能用在函数内部
002 敏感字符串信息加密
加密分为对称加密和非对称加密,常见的对称加密包括DES
、AES
等,非对称加密包括RSA
、背包算法
等。
非对称加密的缺点是加密和解密花费时间长、速度慢,只适合对少量数据进行加密。
对称加密算法的优点是算法公开、计算量小、加密速度快、加密效率高。
在项目针对可以采用DES
进行对称加密即可。
JNI函数信息可见
每一个动态库都会包含符号表信息,通过objdump工具在命令行中可以查看到动态库最终包含的符号表。
采用静态方式注册JNI函数会最终会包含在符号表中,那么我们就可以从符号表中看到以Java_
开头的所有JNI函数。那么别人就会通过JNI函数来最终分析APK中相应Class
对应的动态库文件,进而分析整个APK以及动态库的调用逻辑。
针对AndroidSO工程中的static-dynamic-so工程,我们可以分别设置CMakeLists.txt中DYNAMIC_FLAG
的取值。
DYNAMIC_FLAG
是一个布尔值,为true的时候动态库最终包含native-lib-dynamic.cpp,相反包含native-lib-static.cpp。
native-lib-dynamic.cpp采用动态注册JNI的方式,而native-lib-static.cpp采用静态注册JNI的方式。
执行objdump -D libnative-lib.so | grep Java_*
可以查看以Java_
开头的符号表信息。
native-lib-static.cpp静态注册输出结果如下:
4118: 52 00 00 ea b #328 <Java_com_demon_so_MainActivity_stringFromJNI+0x28>
native-lib-dynamic.cpp动态注册JNI函数输出结果如下:
_ZN7_JavaVM6GetEnvEPPvi:
对比上边的输出结果我们可以很容易看出动态注册的JNI函数就无法看到我们定义的JNI函数了。
采用动态注册的方式即可解决JNI函数可见的问题。
objdump的用法点击直达
Reference:
网友评论