首先,关于Android 如何防止 so库文件被未知应用盗用这个话题并不是我擅长的,只是在开发中遇到了这个问题,因此在这里总结一下。

故事回到几个月之前,当时公司和第三方音乐平台合作了一款内置于手表系统的音乐APP应用,合作过程中需要第三方提供so库文件来进行相关操作。当时提供so库文件的时候,第三方公司要求我们提供一个我们音乐APP应用的签名文件(这个签名文件称呼为V1)中的MD5码,然后再给我们提供了so库文件用于开发。

经过几个月的开发,我们的音乐APP要正式发布的时候,公司要求换一个应用签名文件,即之前的V1签名不用了,改用新的应用签名文件(这个签名文件称呼为V2)。

这个要求并不过分,因此我就立马换了签名文件为V2。可是当我把换了应用签名V2版本的APP运行的时候,直接crash了,crash log 打印为 so库文件找不到,应用无限crash然后无限自动重启,要泪奔了。

一开始以为是新版本的签名文件V2出问题了,但是其他同事使用的也是V2签名文件,并没有什么异常。然后只能将apk解压,对so库文件进行分析。

使用Beyond Compare工具打开该so库文件,可以更加清晰的看到十六进制的文件内容,如下图所示

通过分析so库文件,发现加密后的so库文件中 有 “Signature”以及“MD5”的字样,这个时候我脑海中突然回想起来几个月之前第三方平台提供给我们so库文件的时候,要求我们提供我们的应用签名文件V1的MD5码,是不是就是因为第三方平台提供的so库文件用MD5码进行了签名校验呢???

速度联系第三方平台,经过咨询之后确定是第三方平台提供的so库文件用MD5码进行了签名校验,然后我提供了V2签名文件的MD5给他们,之后第三方平台使用新的MD5码对so文件重新进行签名之后重新发给我们。接着使用新的MD5码签名过的so文件替换之前的老版本的so文件之后,使用V2版本的应用签名的APP正常运行了。

下图是分别使用V1版本的MD5码签名的so库文件使用V2版本的MD5码签名的so库文件 的对比图

附,有读者eziowayne看完之后弄不明白为什么同事的可以而我的不可以?

这里具体介绍下原因:

因为公司对于小型app都是单人独立开发,其他同事开发的是其他的apk,仅仅是将V1版本签名换成V2版本的签名用于打包apk而已,并没有使用V1或者V2签名对so进行签名等任何操作。

而我的apk用到的第三方音乐平台提供的so开发的音乐播放器,而这个so之前使用的是V1版本签名文件中的MD5码等属性做了加密,而V2版本签名文件的MD5码和V1版本签名中的MD5码不同,所以导致换签名文件之后,程序运行加载so的时候校验程序合法性的时候crash了。


上面内容是我自己遇到so库文件使用签名加密等防止未知应用盗用so库所遇到的问题,由以上的操作可以发现,我们可以通过在so库里面验证App的签名的方式来防止未知应用盗用so文件。

至于具体so库文件的源代码 cpp 里面是如何检验签名如何加密的,可以参考下面的文章了解大概的流程。

文章链接: http://blog.csdn.net/xx753277/article/details/37567951

下面是一段验证APP前面的示例代码,如下所示:

#include <jni.h>
#include <string.h>
#include <stdio.h>
#include <com_android_jni_JNI.h>
/**
* http api 授权 key ,由服务端提供
*/
const char* AUTH_KEY = "0CC175B9C0F1B6A831C399E269772661"; /**
* 发布的app 签名,只有和本签名一致的app 才会返回合法的 授权 key
*/
const char* RELEASE_SIGN ="3082030d308201f5a0030201020204163677d7300d06092a864886f70d01010b05003037310b30090603550406130255533110300e060355040a1307416e64726f6964311630140603550403130d416e64726f6964204465627567301e170d3134303131343035333835315a170d3434303130373035333835315a3037310b30090603550406130255533110300e060355040a1307416e64726f6964311630140603550403130d416e64726f696420446562756730820122300d06092a864886f70d01010105000382010f003082010a02820101008f02a948189bfa0134bdb17155061a4b62956c08881eac87b39f0a0acf1c808596100b09a16600f5567e5504f035f1deadc1dcc93fa93b930f78ac9a55ee961283458d66d3775e612e4eb5f5076bf06aeabb6e285400e89dd6e1327a52b4739a91d04d7288bc64c336b7776efe0b6341913d655943ffc9da4b8ba157a52f7790a815bf0cc693dd684209a07290b9c8d4220c8f56c00c25bee78500231213adba58b3c2c9e95951308dfab9edc4f9744fe6c99b3311b54971210db4c2e8a5d518def97535a69170827d6c14bd8a822a0d1b179a3633178db16376a9596df91c595b8cb3d3a916b0f10d029a0aad3b345a7ad54e85f2547686f612b62a010d7dd90203010001a321301f301d0603551d0e04160414f7c342dca7f916bb77312bb517105732c5e96328300d06092a864886f70d01010b0500038201010010b1bb9c29118a7eb15193ef15d40bafd4338526b200511f0e348e5c93eb9cbdf9330163cba183022572513dc7dac14cbd384c116bfc2c3d5efc9f545c3972ec8ce32908eb4e54a6940774ac569d682c188388380d60ed1904ecca4f4bf6bdcacd8be71557f1133c2fd5bcc2577fde19adef54cb91e02e635b47e6a6bfb1f46a5956259a10c61727e70cd8595fd632d4ed6c588dcb089967f164090aa89050911fd70eb1f7ccacd4d7b75c0b5ecd2bb84709b16176b9ac21f8bb25a970f65105af7939057cbf616abf5e9617f1ef87e39d16e458b278cbdc4f9ccb5d8e0c69719a5fae55bdd786b7b59c4a37a205972de1b0f3d4e8877267bad8f28ab09800f2"; /**
* 拿到传入的app 的 签名信息,对比合法的app 签名,防止so文件被未知应用盗用
*/
static jclass contextClass;
static jclass signatureClass;
static jclass packageNameClass;
static jclass packageInfoClass;
JNIEXPORT jstring JNICALL Java_com_android_jni_JNI_getAuthKey(
JNIEnv * env, jobject obj, jobject contextObject) { jmethodID getPackageManagerId = (env)->GetMethodID(contextClass, "getPackageManager","()Landroid/content/pm/PackageManager;");
jmethodID getPackageNameId = (env)->GetMethodID(contextClass, "getPackageName","()Ljava/lang/String;");
jmethodID signToStringId = (env)->GetMethodID(signatureClass, "toCharsString","()Ljava/lang/String;");
jmethodID getPackageInfoId = (env)->GetMethodID(packageNameClass, "getPackageInfo","(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
jobject packageManagerObject = (env)->CallObjectMethod(contextObject, getPackageManagerId);
jstring packNameString = (jstring)(env)->CallObjectMethod(contextObject, getPackageNameId);
jobject packageInfoObject = (env)->CallObjectMethod(packageManagerObject, getPackageInfoId,packNameString, 64);
jfieldID signaturefieldID =(env)->GetFieldID(packageInfoClass,"signatures", "[Landroid/content/pm/Signature;");
jobjectArray signatureArray = (jobjectArray)(env)->GetObjectField(packageInfoObject, signaturefieldID);
jobject signatureObject = (env)->GetObjectArrayElement(signatureArray,0); const char* signStrng = (env)->GetStringUTFChars((jstring)(env)->CallObjectMethod(signatureObject, signToStringId),0);
if(strcmp(signStrng,RELEASE_SIGN)==0)//签名一致 返回合法的 api key,否则返回错误
{
return (env)->NewStringUTF(AUTH_KEY);
}else
{
return (env)->NewStringUTF("error");
} } JNIEXPORT jint JNICALL JNI_OnLoad (JavaVM* vm,void* reserved){ JNIEnv* env = NULL;
jint result=-1;
if(vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK)
return result; contextClass = (jclass)env->NewGlobalRef((env)->FindClass("android/content/Context"));
signatureClass = (jclass)env->NewGlobalRef((env)->FindClass("android/content/pm/Signature"));
packageNameClass = (jclass)env->NewGlobalRef((env)->FindClass("android/content/pm/PackageManager"));
packageInfoClass = (jclass)env->NewGlobalRef((env)->FindClass("android/content/pm/PackageInfo")); return JNI_VERSION_1_4;
}

更多关于Android安全与逆向分析的知识可以参考一下几个链接:

  1. 移动安全与逆向http://blog.csdn.net/column/details/13287.html

  2. 手把手教你逆向分析 Android 程序

    (https://segmentfault.com/a/1190000005133219)


作者:欧阳鹏 欢迎转载,与人分享是进步的源泉!

转载请保留原文地址: http://blog.csdn.net/ouyang_peng/article/details/65938698

【我的Android进阶之旅】Android 如何防止 so库文件被未知应用盗用?的更多相关文章

  1. 我的Android进阶之旅------>Android颜色值(#AARRGGBB)透明度百分比和十六进制对应关系以及计算方法

    我的Android进阶之旅-->Android颜色值(RGB)所支持的四种常见形式 透明度百分比和十六进制对应关系表格 透明度 十六进制 100% FF 99% FC 98% FA 97% F7 ...

  2. 我的Android进阶之旅------>Android中查看应用签名信息

    一.查看自己的证书签名信息 如上一篇文章<我的Android进阶之旅------>Android中制作和查看自定义的Debug版本Android签名证书>地址:http://blog ...

  3. 我的Android进阶之旅------>Android利用温度传感器实现带动画效果的电子温度计

    要想实现带动画效果的电子温度计,需要以下几个知识点: 1.温度传感器相关知识. 2.ScaleAnimation动画相关知识,来进行水印刻度的缩放效果. 3.android:layout_weight ...

  4. 我的Android进阶之旅------>Android实现用Android手机控制PC端的关机和重启的功能(三)Android客户端功能实现

    我的Android进阶之旅------>Android实现用Android手机控制PC端的关机和重启的功能(一)PC服务器端(地址:http://blog.csdn.net/ouyang_pen ...

  5. 我的Android进阶之旅------> Android为TextView组件中显示的文本添加背景色

    通过上一篇文章 我的Android进阶之旅------> Android在TextView中显示图片方法 (地址:http://blog.csdn.net/ouyang_peng/article ...

  6. 我的Android进阶之旅------> Android在TextView中显示图片方法

    面试题:请说出Android SDK支持哪些方式显示富文本信息(不同颜色.大小.并包含图像的文本信息),并简要说明实现方法. 答案:Android SDK支持如下显示富文本信息的方式. 1.使用Tex ...

  7. 我的Android进阶之旅------>Android疯狂连连看游戏的实现之实现游戏逻辑(五)

    在上一篇<我的Android进阶之旅------>Android疯狂连连看游戏的实现之加载界面图片和实现游戏Activity(四)>中提到的两个类: GameConf:负责管理游戏的 ...

  8. 我的Android进阶之旅------>Android疯狂连连看游戏的实现之加载界面图片和实现游戏Activity(四)

    正如在<我的Android进阶之旅------>Android疯狂连连看游戏的实现之状态数据模型(三)>一文中看到的,在AbstractBoard的代码中,当程序需要创建N个Piec ...

  9. 我的Android进阶之旅------>Android疯狂连连看游戏的实现之状态数据模型(三)

    对于游戏玩家而言,游戏界面上看到的"元素"千变万化:但是对于游戏开发者而言,游戏界面上的元素在底层都是一些数据,不同数据所绘制的图片有所差异而已.因此建立游戏的状态数据模型是实现游 ...

  10. 我的Android进阶之旅------>Android疯狂连连看游戏的实现之开发游戏界面(二)

    连连看的游戏界面十分简单,大致可以分为两个区域: 游戏主界面区 控制按钮和数据显示区 1.开发界面布局 本程序使用一个RelativeLayout作为整体的界面布局元素,界面布局上面是一个自定义组件, ...

随机推荐

  1. xmapp+netbeans调试

    1.netbeans的设置 2.修改php.ini 如下: [XDebug]zend_extension = "D:\dev\xampp\php\ext\php_xdebug.dll&quo ...

  2. Spring的AOP简单理解

    最近在研究spring的AOP,翻译出来的意思是面向切面. 总结如下: 所谓AOP就是将分散在各个方法处的公共代码提取到一处, 并通过类似拦截器的机制实现代码的动态整合.可以简单地想象成, 在某个方法 ...

  3. 已知问题汇总 (2013-11-30) - QQ空间, EXTJS

    目前发现两个已知问题暂时无法得到解决: 1. QQ空间问题. 打开页面 http://user.qzone.qq.com/822994792/311, 点击 "xxx人赞" 这个链 ...

  4. CSS(二):选择器

    一.基本选择器 1.标签选择器 HTML标签作为标签选择器的名称,例如<h1>~<h6>.<p>等. 语法: p{font-size: 16px;} p:标签选择器 ...

  5. 解决request.getRemoteAddr()获取的值为0:0:0:0:0:0:0:1这个小问题

    症状: Windows操作系统,eclipse开发环境下,在本机上使用http://localhost:8080/...访问本机上的页面,使用tomcat作为服务器 在Servlet或者Action中 ...

  6. Sublime Text 模版插件: SublimeTmpl

    开发者的插件介绍页面:http://www.fantxi.com/blog/archives/sublime-template-engine-sublimetmpl/ 写了个sublime的模版插件, ...

  7. sublime text 2自定义代码片段

    本文引用   http://www.blogjava.net/Hafeyang/archive/2012/08/17/how_to_create_code_snippet_in_subline_tex ...

  8. ThinkPHP整合cropper剪裁图片上传功能

    1.先下载核心文件:https://github.com/fengyuanchen/cropper 2. 3.对于index.html文件 4.对于main.js文件 5.对于crop.php文件 & ...

  9. url 模式录制脚本web_concurrent_start和web_concurrent_end

    LoadRunner函数中文翻译系列之三--Concurrent Groupweb_concurrent_start 语法: int web_concurrent_start ( [char * Co ...

  10. LoadRunner中winsocket协议学习

    首先让我们先看一下loadrunner- winsock 函数 一览表:        lrs_accept_connection 接受侦听套接字连接 lrs_close_socket 关闭打开的套接 ...