某些apk为了防止重打包,使用了签名校验。所以在破解的时候我们需要破解签名校验。在定位签名校验位置时常用的关键词有sign,signature,checkSign,signCheck,getPackageManager,getPackageInfo,verify,same等。
  java层签名校验代码示例:
 //原签名信息
private static final String SIGNATURE = "478yYkKAQF+KST8y4ATKvHkYibo=";
private static final int VALID = 0;
private static final int INVALID = 1; public static int checkAppSignature(Context context) {
try {
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(),PackageManager.GET_SIGNATURES); for (Signature signature : packageInfo.signatures) {
byte[] signatureBytes = signature.toByteArray();
MessageDigest md = MessageDigest.getInstance("SHA");
md.update(signature.toByteArray()); final String currentSignature = Base64.encodeToString(md.digest(), Base64.DEFAULT); Log.d("REMOVE_ME", "Include this string as a value for SIGNATURE:" + currentSignature); //compare signatures
if (SIGNATURE.equals(currentSignature)){
return VALID;
};
}
} catch (Exception e) {
//assumes an issue in checking signature., but we let the caller decide on what to do. }
return INVALID;
}

    最近遇到一个进行了签名校验的apk,它是在客户端获取签名信息然后在服务器端进行签名比对的,而且签名的获取是在native代码中实现的。这种签名校验的破解思路一般是在sd卡中保存一个原apk包,修改apk路径,让程序获取原apk的签名信息。修改办法一般有三种,下面一一介绍。

(一)在java层修改context进行破解

  首先安装apk,启动DDMS查看log信息:
 
 
 
 
 
根据这个“verifyHashByC”这个字符串猜测跟签名校验有关系,于是在java层搜索verifyHashByC,没有找到对应的log打印处,只发现同名的native函数调用:
 
 
 
 
 
 
猜测此log打印信息是在so中,于是找到该native函数对应的so加载处,发现加载的是libAppVerify.so这个动态库:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
用ida打开libAppVerify.so,搜索verifyHashByC,在VerifyHash_BySha函数中发现了log日志打印的代码:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
光看函数名称VerifyHash_BySha就知道是通过sha算法验证Hash,但是这是不是用于签名校验的呢,利用ida的交叉引用查看函数调用关系,发现这个函数在VerifyHash(_JNIEnv *, char *, char const*, int)函数中被调用。而VerifyHash则是由前面提到的native函数verifyHashByC来调用的。
 
 
 
 
 
VerifyHash函数先获取应用包名,然后调用GetApkMFData函数:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
在该函数中获取应用路径,然后解压应用安装包,读取里面的MANIFEST.MF文件内容,然后再进行签名比对:
 
 
 
 
 
 
 
  获取apk路径的示例代码如下:
 private static String getApkPath(String pkgName) {
PackageManager pm = mContext.getPackageManager();
ApplicationInfo pi = null;
try {
pi = pm.getApplicationInfo(pkgName,PackageManager.GET_UNINSTALLED_PACKAGES);
if(pi != null)
return pi.sourceDir;
else
return null;
} catch (NameNotFoundException e) {
e.printStackTrace();
return null;
}
}

sourceDir保存了apk的完整路径:

 
 
 
接下来,解压apk,读取MANIFEST.MF文件:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
下图为MF文件中的内容,与上图中内存单元的内容一致:
 
 
 
 
 
 
 
 
 
 
 
 
 
  分析了这么多,如何破解呢?通过前面的分析可知在so中获取apk包的路径的流程是:
 
 
 
 
传入context,通过ApplicationInfo的sourceDir获取到apk路径,如果我们修改sourceDir让它始终指向原apk,那么我们的目的就达到了。
通过反编译java代码,找到调用libAppVerify.so的地方,如图所示,context就是从这里传入的:
 
 
 
 
 
 
 
 
 
 
 
 
我们要做的就是修改这个context,使它最后指向的sourceDir为原apk路径。
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  根据上图原理,我们自己实现一个ApkApplicationInfo类指定sourceDir为原apk(SD卡中apk)路径,ApkApplicationInfo在getApplicationInfo函数中实例化,由于getApplicationInfo函数为PackageManager类的成员函数,所以需要自己实现一个ApkPackageManager类(继承自PackageManager类)来调用getApplicationInfo函数。ApkPackageManager类需要在getPackageManager函数中得到实例化,getPackageManager函数为Context的成员函数,所以还需要自己实现一个继承自Context的类ApkContext。
  于是,创建一个Android工程,创建ApkApplicationInfo、ApkPackageManager和ApkContext这三个类,设置sourceDir为“/sdcard/myapk.apk”。编译后,将生成的apk反编译,得到这的三个类的smali代码文件,如下图所示:
 
 
 
 
 
然后,将原apk反编译,把上述三个文件放入反编译后的apk smali文件夹中,在Lcom/rytong/emp/security/AppVerify类的verifyHash函数中插入下述代码,如图所示:
 
 
 
 
 
 
 
重打包,安装运行,成功!

(二)使用hook技术

  我们知道进行签名校验是在libAppVerify.so中,所以我们只需hook这个so中的函数,更改传入的apk路径就行了。通过分析可知,该so是使用MINIZIP进行apk文件解压缩,然后获取签名信息的。
  使用MINIZIP进行apk文件解压缩的示例代码如下:
 void uncrypt_test()
{
//采用MINIZIP进行文件解压缩
unzFile uf=NULL;
unzFile data[1200];
unz_global_info64 gi;
unz_file_info64 FileInfo; //打开zip文件
uf = unzOpen64("D:\\myfile.zip");
int result=unzGetGlobalInfo64(uf, &gi);
if (result != UNZ_OK)
throw "文件错误"; //循环解压缩文件
for(int i=0;i<gi.number_entry;++i)
{
if (unzGetCurrentFileInfo64(uf, &FileInfo, 0, 0,NULL,0,NULL,0)!= UNZ_OK)
throw "文件错误"; if(!(FileInfo.external_fa & FILE_ATTRIBUTE_DIRECTORY)) //文件,否则为目录
//打开文件
//result=unzOpenCurrentFile(uf);/* 无密码 */
result=unzOpenCurrentFilePassword(uf,"123"); /* 有密码 */ //读取内容
int size= unzReadCurrentFile(uf,data,sizeof(data)); //关闭当前文件
unzCloseCurrentFile(uf); //出错
if(i < gi.number_entry - 1 && unzGoToNextFile(uf) != UNZ_OK)
throw "error";
} //关闭流
unzClose(uf);
}

  从上述代码可知,解压过程中,apk路径以参数形式传入unzOpen64函数。所以我们需要hook这个函数。但是如何知道libAppVerify.so何时被加载呢?我们知道系统通过dvmLoadNativeCode函数从指定的路径加载so,如果对系统函数dvmLoadNativeCode进行hook,当它加载libAppVerify.so的时候,再hook unzOpen64函数,修改apk路径,不就行了?

  dvmLoadNativeCode函数原型:  

bool dvmLoadNativeCode(constchar* pathName, Object* classLoader, char** detail)

  这里我们使用cydia substrate这个hook框架,关键代码如下:

 
将编译生成的so文件放到原apk lib目录下。再通过java层进行加载,加载代码如下:
     const-string/jumbo v0, "substrate"
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
const-string/jumbo v0, "substrate-dvm"
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
const-string/jumbo v0, "HookVerify.cy"
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V

由于需要在签名校验代码运行之前加载这些so,所以我们在Lcom/cgbchina/xpt/EMPView类的构造函数中添加上述代码,如下图所示:

重打包签名,安装运行成功!

(3)直接修改so文件

由于签名验证验证的是MANIFEST.MF文件,我们将原apk中MANIFEST.MF文件改名为SIGNFILE.MF放到修改了的apk META-INF文件夹下,然后将so中验证的文件名改为SIGNFILE.MF,如图所示:
保存,替换原so,重打包安装,运行成功!

Apk去签名校验详解的更多相关文章

  1. iOS 证书与签名 解惑详解

    iOS 证书与签名 解惑详解 分类: iPhone2012-06-06 19:57 9426人阅读 评论(1) 收藏 举报 iosxcodecryptographyappleiphone测试   目录 ...

  2. Renix签名字段详解——网络测试仪实操

    一.签名字段简介 在添加/修改流量时,会有一个签名字段选项 (1)勾选以后,RENIX软件在发流时,会把每个报文的Payload(净荷)的最后18字节修改为特殊的值,用来统计流的时延.丢包等内容 (2 ...

  3. Android APK反编译easy 详解

    在学习Android开发的过程你,你往往会去借鉴别人的应用是怎么开发的,那些漂亮的动画和精致的布局可能会让你爱不释手,作为一个开发者,你可能会很想知道这些效果界面是怎么去实现的,这时,你便可以对改应用 ...

  4. Android签名机制之---签名过程详解

    http://www.2cto.com/kf/201512/455388.html 一.前言 又是过了好长时间,没写文章的双手都有点难受了.今天是圣诞节,还是得上班.因为前几天有一个之前的同事,在申请 ...

  5. IONIC 开发的Android应用程序签名(或重新签名)详解

    完全通过DOS命令来完成apk签名 给apk签名一共要用到3个工具,或者说3个命令,分别是:keytool.jarsigner和zipalign,下面是对这3个工具的简单介绍:            ...

  6. Android Studio Gradle 多渠道自动打包,动态修改HostUrl,签名apk,混淆配置详解

    文/ skay csdn博客:http://blog.csdn.net/sk719887916/article/details/40541163 最近遇到项目从Eclispe迁移到Android st ...

  7. 补习系列(4)-springboot 参数校验详解

    目录 目标 一.PathVariable 校验 二.方法参数校验 三.表单对象校验 四.RequestBody 校验 五.自定义校验规则 六.异常拦截器 参考文档 目标 对于几种常见的入参方式,了解如 ...

  8. Android签名打包详解

    一.      Android签名有什么作用? 应用程序升级:如果你希望用户无缝升级到新的版本,那么你必须用同一个证书进行签名.这是由于只有以同一个证书签名,系统才会允许安装升级的应用程序.如果你采用 ...

  9. ValidForm5.3.2 忽略表单项校验详解

    ValidForm 官方文档 项目的需求是这样的:一个checkbox,一个input,选中checkbox的时候,需要校验input,取消选中的时候,不要校验input. <input typ ...

随机推荐

  1. [jQuery学习系列六]6-jQuery实际操作小案例

    前言最后在这里po上jQuery的几个小案例. Jquery例子1_占位符使用需求: 点击第一个按钮后 自动去check 后面是否有按钮没有选中, 如有则提示错误消息. <html> &l ...

  2. atitit.条形码的原理与生成总结java Barcode4j barcode o5

    atitit.条形码的原理与生成总结java Barcode4j barcode o5 条形码类库使用报告Barcode4j, ZXing 1 使用成果图片 1 条形码标准code 128和code  ...

  3. iOS开发——高级技术&签名机制

    签名机制 最近看了objc.io上第17期中的文章 <Inside Code Signing> 对应的中文翻译版 <代码签名探析> ,受益颇深,对iOS代码签名机制有了进一步的 ...

  4. JSP取得绝对路径

    在JavaWeb开发中,常使用绝对路径的方式来引入JavaScript和CSS文件,这样可以避免因为目录变动导致引入文件找不到的情况,常用的做法如下: 一.使用${pageContext.reques ...

  5. 生成读取相关连接的物理地址的lib(动态导入库)和dll(动态链接库)

    一.导出相关dll库 将原先的CmdInfoToPipe.h class后加入关键字 __declspec(dllexport) #ifndef NETINFO_CMDINFOTOPIPE_H_ #d ...

  6. Leetcode 202 Happy Number 弗洛伊德判环解循环

    今天先谈下弗洛伊德判环,弗洛伊德判环原来是在一个圈内有两人跑步,同时起跑,一人的速度是另一人的两倍,则那个人能在下一圈追上另一个人,弗洛伊德判环能解数字会循环出现的题,比如说判断一个链表是不是循环链表 ...

  7. Bootstrap3.0入门学习系列规划[持续更新]

    详情请看http://aehyok.com/Blog/Detail/5.html 个人网站地址:aehyok.com QQ 技术群号:206058845,验证码为:aehyok 本文文章链接:http ...

  8. MRBS, meeting room manager system,会议预定管理系统

    MRBS,会议管理软件,新增权限控制,周期性例会管理等. 下载地址 http://www.dotnetcms.org/mrbs/mrbs.rar

  9. PIC24FJ64GB002 with bluetooth USB dongle

    PIC24FJ64GB002 with bluetooth USB dongle I will explain my project (how to control a bluetooth USB d ...

  10. 【VerySky原创】怎样查找到CDHDR、CDPOS表中的OBJECTCLAS字段

    可以通过pooled table TCDOB - Objects for change document creation 找到对应的表的对象值: se38 run:  RSSCD1TS object ...