谁知道这种网络验证叫什么名字!修改安卓apk的名字网络验证

矿大人论坛
后使用快捷导航没有帐号?
只需一步,快速开始
现在就登录 - 矿大人论坛 手机版
立即使用手机访问,获得极速移动体验
/forum.php
您可以通过手机快速访问论坛版块及管理收藏夹,随时随地访问自己最爱的内容
看帖及回帖更快速
通过手机版,可以快速的访问您需要阅读的主题,并可以快速的发布新帖及回复
站内短信实时收发,与短信另一端的朋友进行单人或多人聊天
节省流量与获得优质手机体验并存
Powered byAndroid单元测试(1):什么是单元测试 - 安卓 - 伯乐在线
& Android单元测试(1):什么是单元测试
这是一系列安卓单元测试的文章,目测主要会cover以下的主题:
什么是单元测试
为什么要做单元测试
Robolectric
一个具体的app例子实践
神秘的bonus
什么是单元测试
首先需要介绍一下什么是单元测试。很多人像我一样,本科并不是计算机专业出身的,如果在职的公司不要求做单元测试的话,可能对这个词并没有一个确切的概念。而即使是计算机专业出身,如果毕业以后写的不多的话,可能对这个词的含义也不是很清楚。从名字上看,单元测试是为了测试某一个代码单元而写的测试代码。但是什么叫“一个代码单元”呢?是一个模块、还是一个类、还是一个方法(函数)呢?不同的人、不同的语言,都有不同的理解。一般的定义,尤其是是在OOP领域,是一个类的一个方法。在此,我们也这样理解:单元测试,是为了测试某一个类的某一个方法能否正常工作,而写的测试代码。
我们举一个例子说明一下,假如你有一个类,定义如下:
public class Calculator {
public int add(int one, int another) {
//为了简单起见,暂不考虑溢出等情况。
return one +
public class Calculator {&&&&public int add(int one, int another) {&&&&&&&&//为了简单起见,暂不考虑溢出等情况。&&&&&&&&return one + another;&&&&}}
那么为了测试这个Calculator类的add()方法,我们可以写如下的单元测试代码:
public class CalculatorTest {
public void testAdd() throws Exception {
Calculator calculator = new Calculator();
int sum = calculator.add(1, 2);
Assert.assertEquals(3, sum);
public class CalculatorTest {&&&&public void testAdd() throws Exception {&&&&&&&&Calculator calculator = new Calculator();&&&&&&&&int sum = calculator.add(1, 2);&&&&&&&&Assert.assertEquals(3, sum);&&&&}}
这里的CalculatorTest是Calculator对应的测试类。而这里的testAdd()就是add()这个方法对应的测试方法。所以,写单元测试,就是给你的每个类的每个public方法写对于的测试方法。非public方法我们一般是不测试的,虽然可以通过反射等手段去做,但是一般看来,非public方法是这个类的实现细节,我们并不关心,我们只关心某一个public方法的输入、输出。
一般来说,一个方法对应的测试方法主要分为3部分,以上面的测试方法为例:
setup。一般是new出你要测试的那个类,以及其他一些前提条件的设置:Calculator calculator = new Calculator();
执行操作。一般是调用你要测试的那个方法,获得运行结果:int sum = calculator.add(1, 2);
验证结果。验证得到的结果跟预期中是一样的:Assert.assertEquals(3, sum);
一般来说,我们写单元测试,会用到一些单元测试框架。常见的Java单元测试框架有、等等。在这个系列的文章中,我采用JUnit 4,这也是用的最多的一个测试框架。上面的第三部,Assert.assertEquals(3, sum); 用的就是JUnit里面的验证结果的方法,最常见的就是调用Assert类的一些assert方法。除了上面用到的assertEquals,还有assertTrue, assertNotNull等等。关于JUnit,我会在后面的系列文章中专门介绍。
如何在一个android project里面运行单元测试
我们知道,在一个android gradle project中,源代码默认是放在src/main/java下面的。而对应的单元测试代码则是放在src/test/java下面的,如下图所示:
其中的package name可以随意定,很多人喜欢跟src package name保持一致,我个人习惯在最后加上.test后缀,因为AndroidStudio太智能了,经常我需要重命名单元测试的package的时候,AndroidStudio会把src的package也给重命名了。
打开CalculatorTest,用鼠标右键点击testAdd()方法,选择Run testAdd(), 如下图所示:
从图中你可以看出,你可以按快捷键Ctrl+Shift+R快速运行,当然,这要求你的光标当前焦点是在这个方法内部的。如果你的焦点是在类内部,而不在某一个测试方法内部,那么Ctrl+Shift+R将运行这个测试类的所有测试方法。当然,你也可以通过右键点击测试类名来运行这个测试类里面的所有测试方法。
运行结束以后,你会在底部的“Run”这个tab看到运行的结果,如下图所示:
除了在AndroidStudio里面运行,你还可以在命令行通过gradle testDebugUnitTest,或者是gradle testReleaseUnitTest,分别运行debug和release版本的unit testing,这种方式可以一次性运行所有测试类的所有测试方法。 这种方式的运行结果如下图所示:
每个test case的报告可以在project_root/app/build/reports/tests/debug/index.html 这个xml里面看到。大致如下图:
这篇文章的代码在上,感兴趣的可以clone下来自己试试。
单元测试不是集成测试
这里需要强调一个观念,那就是单元测试只是测试一个方法单元,它不是测试一整个流程。举个例子来说,一个Login页面,上面有两个输入框和一个button。两个输入框分别用于输入用户名和密码。点击button以后,有一个UserManager会去执行performlogin操作,然后将结果返回,更新页面。
那么我们给这个东西做单元测试的时候,不是测这一整个login流程。这种整个流程的测试:给两个输入框设置正确的用户名和密码,点击login button, 最后页面得到更新。叫做集成测试,而不是单元测试。当然,集成测试也是有他的必要性的,然而这不是我们每个程序员应该花多少精力所在的地方。在这方面,有一个理论叫做,如下图所示:
Test Pyramid理论基本大意是,单元测试是基础,是我们应该花绝大多数时间去写的部分,而集成测试等应该是冰山上面能看见的那一小部分。
为什么是这样呢?因为集成测试设置起来很麻烦,运行起来很慢,发现的bug少,在保证代码质量、改善代码设计方面更起不到任何作用,因此它的重要程度并不是那么高,也无法将它纳入我们正常的工作流程中。
而单元测试则刚好相反,它运行速度超快,能发现的bug更多,在开发时能引导更好的代码设计,在重构时能保证重构的正确性,因此它能保证我们的代码在一个比较高的质量水平上。同时因为运行速度快,我们很容易把它纳入到我们正常的开发流程中。
至于为什么集成测试发现的bug少,而单元测试发现的bug多,这里也稍作解释,因为集成测试不能测试到其中每个环节的每个方面,某一个集成测试运行正确了,不代表另一个集成测试也能运行正确。而单元测试会比较完整的测试每个单元的各种不同的状况、临界条件等等。一般来说,如果每一个环节是对的,那么在很大的概率上,整个流程就是对的。虽然不能保证整个流程100%一定是对的。所以,集成测试需要有,但应该是少量,单元测试是我们应该花重点去做的事情。
那对于这个例子,单元测试是怎么样的呢?这个请看下一小节。
两种函数(方法),两种不同的测试方式
一个类的方法可以分为两种,一种是有返回值的,另一种是没有返回值的。对于有返回值的方法,我们要测起来比较容易,就跟上面的Calculator例子那样,输入相应的参数,得到相应的返回值,然后验证得到的返回值跟我们预期的值一样,就好了。
但是没有返回值的方法,要怎么测试呢?比如说刚刚login的例子,点击那个按钮,会执行Activity的login()方法,它的定义如下:
public void login() {
String username = ...//get username from username EditText
String password = ...//get password from password EditText
//do other operation like validation, etc
mUserManager.performlogin(username, password);
public void login() {&&&&String username = ...//get username from username EditText&&&&String password = ...//get password from password EditText&&&&//do other operation like validation, etc&&&&...&&&&&mUserManager.performlogin(username, password);}
这个方法是void的,那么怎么验证这个方法是正确的呢?其实仔细想想,这个方法也是有输出的,它的输出就是,调用了mUserManager的performLogin方法,同时传给他两个参数。所以只要验证mUserManager的performLogin方法得到了调用,同时传给他的参数是正确的,就说明这个方法是能正常工作的。
那怎么样验证这个Activity的login()方法,会调用mUserManager的performLogin方法呢?这里涉及到的概念,在后面的文章关于的使用的时候,会介绍到,这里简单解释下,那就是在测试环境下,我们会使用一套mock framework(Mockito),生成一个mock的UserManager然后赋值给mUserManager,因为这个mUserManager是通过mock framework生成的,所以这个mock framework可以验证它的什么方法被调用了,参数是什么,等等。
上面讲述了单元测试的定义,以及与集成测试的区别,一般来说,单元测试不会接触到数据库,不会接触到网络,不会接触到一些复杂的外部环境,如果有的话,那可能是你测试的方式有误,测试的粒度不够“单元”,希望这篇文章能将这两者的区别解释清楚。
如果文中有任何的错误或疑问欢迎留言。
打赏支持我写出更多好文章,谢谢!
打赏支持我写出更多好文章,谢谢!
关于作者:
可能感兴趣的话题
关于安卓频道
安卓频道分享Android开发文章,精选工具和安卓相关的行业动态。
新浪微博:
推荐微信号
(加好友请注明来意)
– 好的话题、有启发的回复、值得信赖的圈子
– 分享和发现有价值的内容与观点
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 翻译传播优秀的外文文章
– 国内外的精选文章
– UI,网页,交互和用户体验
– 专注iOS技术分享
– 专注Android技术分享
– JavaScript, HTML5, CSS
– 专注Java技术分享
– 专注Python技术分享
& 2017 伯乐在线深圳市艾秀信息技术有限公司
All Rights Reserved
&粤网文[号 &【网络验证】_网络验证工具_大全 - 淘宝网
河北 石家庄
香港 香港岛
黑龙江 鸡西
江苏 连云港
淘宝全球购为您提供最新最全面的包括美国、日本、澳洲等海外网络验证代购,网络验证洋货直邮,网络验证海外品牌等全球购商品
您是不是想找:Apk去签名校验详解 - 推酷
Apk去签名校验详解
某些apk为了防止重打包,使用了签名校验。所以在破解的时候我们需要破解签名校验。在定位签名校验位置时常用的关键词有sign,signature,checkSign,signCheck,getPackageManager,getPackageInfo,verify,same等。
java层签名校验代码示例:
1 //原签名信息
2 private static final String SIGNATURE = &478yYkKAQF+KST8y4ATKvHkYibo=&;
3 private static final int VALID = 0;
4 private static final int INVALID = 1;
6 public static int checkAppSignature(Context context) {
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路径的示例代码如下:
1 private static String getApkPath(String pkgName) {
PackageManager pm = mContext.getPackageManager();
ApplicationInfo pi = null;
pi = pm.getApplicationInfo(pkgName,PackageManager.GET_UNINSTALLED_PACKAGES);
if(pi != null)
return pi.sourceDir;
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文件解压缩的示例代码如下:
1 void uncrypt_test()
//采用MINIZIP进行文件解压缩
unzFile uf=NULL;
unzFile data[1200];
unz_global_info64
unz_file_info64 FileI
//打开zip文件
uf = unzOpen64(&D:\\myfile.zip&);
int result=unzGetGlobalInfo64(uf, &gi);
if (result != UNZ_OK)
throw &文件错误&;
//循环解压缩文件
for(int i=0;i&gi.number_++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/S-&loadLibrary(Ljava/lang/S)V
const-string/jumbo v0, &substrate-dvm&
invoke-static {v0}, Ljava/lang/S-&loadLibrary(Ljava/lang/S)V
const-string/jumbo v0, &HookVerify.cy&
invoke-static {v0}, Ljava/lang/S-&loadLibrary(Ljava/lang/S)V
由于需要在签名校验代码运行之前加载这些so,所以我们在Lcom/cgbchina/xpt/EMPView类的构造函数中添加上述代码,如下图所示:
重打包签名,安装运行成功!
(3)直接修改so文件
由于签名验证验证的是MANIFEST.MF文件,我们将原apk中MANIFEST.MF文件改名为SIGNFILE.MF放到修改了的apk META-INF文件夹下,然后将so中验证的文件名改为SIGNFILE.MF,如图所示:
保存,替换原so,重打包安装,运行成功!
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致

我要回帖

更多关于 apk签名验证失败 的文章

 

随机推荐