360手机助手中软件更新

0x01:分析过程

使用wireshark抓包分析更新时请求的是一个配置文件,请求url:update.api.sj.360.cn/mintf/getAppsByPackNames  后面是参数,请求方式为POST,内容如下:

可以看到其中包含了几个关键的参数down_url,apk_md5,signature_md5,size,其中比较关键的一个校验是signature_md5,其他都可以轻松替换,所以我们的重点就是对signature_md5,校验的破解,去分析他对signature_md5加密的方式,以及如何模拟算法,

0x02:知识补充

关于安卓apk数字签名校验的知识补充,安卓apk数字校验使用的是rsa非对称加密算法也就是我们常说的公钥私钥加密,这个算法

指数运算谁都懂,不必说了,先说说模运算。模运算是整数运算,有一个整数m,以n为模做模运算,即m mod n。怎样做呢?让m去被n整除,只取所得的余数作为结果,就叫做模运算。例如,10 mod 3=1;26 mod 6=2;28 mod 2 =0等等。 
模指数运算就是先做指数运算,取其结果再做模运算。如
好,现在开始正式讲解RSA加密算法。
算法描述:
(1)选择一对不同的、足够大的素数p,q。
(2)计算n=pq。
(3)计算f(n)=(p-1)(q-1),同时对p, q严加保密,不让任何人知道。
(4)找一个与f(n)互质的数e,且1<e<f(n)。
(5)计算d,使得de≡1 mod f(n)。这个公式也可以表达为d ≡e-1 mod f(n)
这里要解释一下,≡是数论中表示同余的符号。公式中,≡符号的左边必须和符号右边同余,也就是两边模运算结果相同。显而易见,不管f(n)取什么值,符号 右边1 mod f(n)的结果都等于1;符号的左边d与e的乘积做模运算后的结果也必须等于1。这就需要计算出d的值,让这个同余等式能够成立。
(6)公钥KU=(e,n),私钥KR=(d,n)。
(7)加密时,先将明文变换成0至n-1的一个整数M。若明文较长,可先分割成适当的组,然后再进行交换。设密文为C,则加密过程为:
(8)解密过程为:

Android的签名机制,通过分析signapk.jar这个可执行包可以知晓签名APK的整个过程

1.程序遍历整个apk文件包中的所有文件(entry),对非文件夹非签名文件的文件,逐个生成SHA1的数字签名信息,再用Base64进行编码,之后将生成的签名写入MANFEST.MF文件

2.对前一步生成的Manifest,使用SHA1-RSA算法,用私钥进行签名,生成CERT.SF文件

3.生成MANIFEST.MF没有使用密钥信息,生成CERT.SF文件使用了私钥文件。那么我们可以很容易猜测到,CERT.RSA文件的生成肯定和公钥相关CERT.RSA文件中保存了公钥、所采用的加密算法等信息

知晓了加密流程,我们可以认识到

1、 Android签名机制其实是对APK包完整性和发布机构唯一性的一种校验机制。
    2、 Android签名机制不能阻止APK包被修改,但修改后的再签名无法与原先的签名保持一致。(拥有私钥的情况除外)。
    3、 APK包加密的公钥就打包在APK包内,且不同的私钥对应不同的公钥。换句话言之,不同的私钥签名的APK公钥也必不相同。所以我们可以根据公钥的对比,来判断私钥是否一致。

也就是说360手机助手也不可能知道需要升级软件数字签名的私钥,所以可以猜测它进行的是对公钥的加密,那么接下来要验证这个观点

0x03逆向分析

这里我们使用一个强大的安卓反编译软件ApkIDE.exe,然后把360手机助手逆向分析一下:

1.搜索signature_md5我们发现了另一个量sign_md5_default_value,那么我们来定位一下:在Apk改之理中搜索sign_md5_default_value 我们分析出现的位置

分析中在d.smali文件中有一段很关键

method private static b(Landroid/content/Context;Lcom/qihoo/appstore/resource/app/App;)V

.locals 3 //  private static void b(Context paramContext, App paramApp)

invoke-virtual {p1}, Lcom/qihoo/appstore/resource/app/App;->Z()Ljava/lang/String;

move-result-object v0

invoke-static {v0}, Lcom/qihoo/appstore/j/d;->c(Ljava/lang/String;)Z

move-result v0

if-eqz v0, :cond_0

sget-object v0, Lcom/qihoo/appstore/j/d;->a:Landroid/content/Context;

invoke-virtual {p1}, Lcom/qihoo/appstore/resource/app/App;->Z()Ljava/lang/String;

move-result-object v1

invoke-static {v0, v1}, Lcom/qihoo/appstore/utils/de;->f(Landroid/content/Context;Ljava/lang/String;)Ljava/lang/String;

move-result-object v0

invoke-virtual {p1}, Lcom/qihoo/appstore/resource/app/App;->bL()Ljava/lang/String;

move-result-object v1

const-string v2, "sign_md5_default_value"

invoke-virtual {v2, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

move-result v2

if-nez v2, :cond_1

const-string v2, ""

invoke-virtual {v1, v2}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

move-result v2

if-nez v2, :cond_1

sget-object v2, Lcom/qihoo/appstore/j/d;->a:Landroid/content/Context;

invoke-static {v2, v0, v1}, Lcom/qihoo/appstore/utils/de;->a(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)Z

move-result v0

if-nez v0, :cond_1

const/4 v0, 0x1

invoke-virtual {p1, v0}, Lcom/qihoo/appstore/resource/app/App;->r(Z)V

:cond_0

:goto_0

return-void

:cond_1

const/4 v0, 0x0

invoke-virtual {p1, v0}, Lcom/qihoo/appstore/resource/app/App;->r(Z)V

goto :goto_0

.end method

前面那几句大概意思就是用一个boolean方法判断App成员的Z()方法也就是说那个是不是一个String,换句话我们可以大胆猜测这里是判断有没有获取到程序的MD5,

所以定位到这一句关键的代码Lcom/qihoo/appstore/utils/de;->f(Landroid/content/Context;Ljava/lang/String;)Ljava/lang/String;

其中使用了de的 f() 方法对Context, String 参数进行处理 我们可以猜测这里的String代表的就是我们的MD5:

.method public static f(Landroid/content/Context;Ljava/lang/String;)Ljava/lang/String;

.locals 2

:try_start_0

invoke-virtual {p0}, Landroid/content/Context;->getPackageManager()Landroid/content/pm/PackageManager;

move-result-object v0

const/16 v1, 0x40

invoke-virtual {v0, p1, v1}, Landroid/content/pm/PackageManager;->getPackageInfo(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;

move-result-object v0

iget-object v0, v0, Landroid/content/pm/PackageInfo;->signatures:[Landroid/content/pm/Signature;

const/4 v1, 0x0

aget-object v0, v0, v1

invoke-virtual {v0}, Landroid/content/pm/Signature;->toByteArray()[B

move-result-object v0

invoke-static {v0}, Ljava/util/Arrays;->toString([B)Ljava/lang/String;

move-result-object v0

invoke-static {v0}, Lcom/qihoo/appstore/utils/de;->e(Ljava/lang/String;)Ljava/lang/String;

move-result-object v0

invoke-virtual {v0}, Ljava/lang/String;->toLowerCase()Ljava/lang/String;

:try_end_0

.catch Ljava/lang/Exception; {:try_start_0 .. :try_end_0} :catch_0

move-result-object v0

:goto_0

return-object v0

:catch_0

move-exception v0

sget-boolean v1, Lcom/qihoo360/mobilesafe/a/a;->a:Z

if-eqz v1, :cond_0

invoke-virtual {v0}, Ljava/lang/Exception;->printStackTrace()V

:cond_0

const/4 v0, 0x0

goto :goto_0

.end method

首先调用系统的Context.getPackageManager().getPackageInfo(String,256/4).signature[0].toByteArray() 然后返回一个String对象然后再调用de类的e方法

.method public static e(Ljava/lang/String;)Ljava/lang/String;

.locals 2

:try_start_0

const-string v0, "MD5"

invoke-static {v0}, Ljava/security/MessageDigest;->getInstance(Ljava/lang/String;)Ljava/security/MessageDigest;

move-result-object v0

invoke-virtual {p0}, Ljava/lang/String;->getBytes()[B

move-result-object v1

invoke-virtual {v0, v1}, Ljava/security/MessageDigest;->update([B)V

invoke-virtual {v0}, Ljava/security/MessageDigest;->digest()[B

move-result-object v0

invoke-static {v0}, Lcom/qihoo/appstore/utils/de;->a([B)Ljava/lang/String;

:try_end_0

.catch Ljava/security/NoSuchAlgorithmException; {:try_start_0 .. :try_end_0} :catch_0

move-result-object p0

:goto_0

return-object p0

:catch_0

move-exception v0

invoke-virtual {v0}, Ljava/security/NoSuchAlgorithmException;->printStackTrace()V

goto :goto_0

.end method

这段话就是对String进行一次MD5运算然后调用a方法,其中我们看到的是调用的a的byte[]参数的方法

method public static a([B)Ljava/lang/String;

.locals 4

new-instance v1, Ljava/lang/StringBuilder;

array-length v0, p0

mul-int/lit8 v0, v0, 0x2

invoke-direct {v1, v0}, Ljava/lang/StringBuilder;-><init>(I)V

const/4 v0, 0x0

:goto_0

array-length v2, p0

if-ge v0, v2, :cond_0

sget-object v2, Lcom/qihoo/appstore/utils/de;->f:[C

aget-byte v3, p0, v0

and-int/lit16 v3, v3, 0xf0

ushr-int/lit8 v3, v3, 0x4

aget-char v2, v2, v3

invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(C)Ljava/lang/StringBuilder;

sget-object v2, Lcom/qihoo/appstore/utils/de;->f:[C

aget-byte v3, p0, v0

and-int/lit8 v3, v3, 0xf

aget-char v2, v2, v3

invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(C)Ljava/lang/StringBuilder;

add-int/lit8 v0, v0, 0x1

goto :goto_0

:cond_0

invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

move-result-object v0

return-object v0

.end method

这段代码的作用就是对一个Byte[]数组进行格式化处理返回一个String对象

那么现在可以猜测360手机助手是对软件公钥的数字签名放到一个数组中,然后取它的第1个成员sinagture[0]进行MD5加密,下面我们来验证猜想

0x04 验证猜想

首先搭建好google sdk 环境 然后我们来写一个安卓程序来模拟360手机助手加密的过程,这里我们用google skd自带的Eclipse进行操作

其中代码如下:

import java.lang.reflect.Array;

import java.security.MessageDigest;

import java.security.NoSuchAlgorithmException;

import java.util.Arrays;

import android.app.Activity;

import android.content.pm.PackageInfo;

import android.content.pm.PackageManager;

import android.content.pm.PackageManager.NameNotFoundException;

import android.content.pm.Signature;

import android.os.Bundle;

import android.text.TextUtils;

import android.view.Menu;

import android.view.View;

import android.widget.EditText;

import android.widget.TextView;

import android.widget.Toast;

public class MainActivity extends Activity {

private EditText et_pkgname;

private TextView tv_signature;

private PackageManager manager;

private PackageInfo packageInfo;

private Signature[] signs;

private StringBuilder builder;

private String signature;

private static final char[] f = new char[] { 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70 };

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

et_pkgname = (EditText) findViewById(R.id.et_pkgname);

tv_signature = (TextView) findViewById(R.id.tv_signature);

manager = getPackageManager();

builder = new StringBuilder();

}

public void getSignature(View view) {

String pkgname = et_pkgname.getText().toString();

boolean isEmpty = TextUtils.isEmpty(pkgname);

if (isEmpty) {

Toast.makeText(this, "应用程序的包名不能为空!", Toast.LENGTH_SHORT);

} else {

try {

/** 通过包管理器获得指定包名包含签名的包信息 **/

packageInfo = manager.getPackageInfo(pkgname, PackageManager.GET_SIGNATURES);

/******* 通过返回的包信息获得签名数组 *******/

signs = packageInfo.signatures;

/******* 循环遍历签名数组拼接应用签名 *******/

/************** 得到应用签名 **************/

String str = e(Arrays.toString(packageInfo.signatures[0].toByteArray()).toLowerCase());

builder.append(str);

signature = builder.toString();

tv_signature.setText(signature);

} catch (NameNotFoundException e) {

e.printStackTrace();

}

}

}

public static String e(String paramString)

{

try

{

MessageDigest localMessageDigest = MessageDigest.getInstance("MD5");

localMessageDigest.update(paramString.getBytes());

String str = a(localMessageDigest.digest());

return str;

}

catch (NoSuchAlgorithmException localNoSuchAlgorithmException)

{

localNoSuchAlgorithmException.printStackTrace();

}

return paramString;

}

public static String a(byte[] paramArrayOfByte)

{

StringBuilder localStringBuilder = new StringBuilder(2 * paramArrayOfByte.length);

for (int i1 = 0; i1 < paramArrayOfByte.length; i1++)

{

localStringBuilder.append(f[((0xF0 & paramArrayOfByte[i1]) >>> 4)]);

localStringBuilder.append(f[(0xF & paramArrayOfByte[i1])]);

}

return localStringBuilder.toString();

}

public boolean onCreateOptionsMenu(Menu menu) {

getMenuInflater().inflate(R.menu.activity_main, menu);

return true;

}

}

我们要在onCreate()函数调用我们的方法也就是我们构造出来的计算signature[]的 MD5的方法

其中

localStringBuilder.append(f[((0xF0 & paramArrayOfByte[i1]) >>> 4)]);

localStringBuilder.append(f[(0xF & paramArrayOfByte[i1])]);

这两句代码是模拟360手机助手的格式化MD5的方法取前四位放到StringBuilder然后取后四位放到StringBuilder中。。

然后我们来用安卓模拟器进行模拟计算新浪微博的md5算法,获得新浪包名,adb shell下查看就行了:adb shell  , cd  data,cd   app, ls,

包名是:com.sina.weibo

运行我们写好的安卓程序来计算我们的签名:

我们来查看与360计算的结果是否相同:

0x05 后记

在后面的入侵测试中,由于本地签名保存,会导致360提示签名非法

从图中我们可以猜测360手机助手是在本地保存了原有的数字签名公钥,然后会对比公钥是否一致,而在实际的代码分析中360的确是有读取sigaature到一个数组中然后保存到了本地,虽然这次入侵结果是失败了,不过过程很迷人,结论就是:安卓公钥私钥的数字签名校验确保了安卓软件的安全性。

转载于:https://www.cnblogs.com/jiancanxuepiao/p/4103414.html

360手机助手关于签名校验的分析相关推荐

  1. 应用商店调研-360手机助手

    360手机助手 背景 国内360手机助手广告主信息的抓取 分析 分类分析 在360中将应用分成了软件(工具类)和游戏(游戏类) 游戏中分为角色扮演101587.休闲益智19.动作冒险20.网络游戏10 ...

  2. 360 android 应用市场,360手机助手在安卓应用市场占大份额

    日前,奇虎360发布了2014财年第三季度未经审计财报.据报告显示,奇虎360第三季度营收为3.764亿美元,比去年同期的1.879亿美元增长100.3%.奇虎董事长周鸿祎在电话会议中表示,我们还在继 ...

  3. Python爬取360手机助手评论——以百度地图为例

    想做竞品分析,打算先从应用市场爬一些应用的用户用户评论作为素材:这次爬取的是360手机助手网站,结尾附爬取完的百度地图和高德地图的用户评论文件~ 网页链接:http://zhushou.360.cn/ ...

  4. 360手机助手显示手机型号错误

    今天客户反馈,在使用360手机助手的时候,显示的手机型号有时候错误,比如你用的华为的手机,而显示的是THC的手机型号,需要我们修改,我先分析了一下,根本不可能啊,因为我认为显示的型号应该是读系统的属性 ...

  5. 360安卓_数据 | TalkingData:360手机助手份额32.27%居第一

    2015年春节刚过,各大手机应用市场都没闲着,360手机助手在春节期间发出2亿现金红包,腾讯应用宝也开启扫码抢红包活动,百度手机助手则亮相江苏卫视.据独立的移动互联网数据服务商TalkingData的 ...

  6. 玻璃心?App Store下架PP助手与360手机助手,做aso会被苹果下架吗

    柚鸥ASO 在别人的场子混,码头得拜,高香得烧,可即便如此,毕竟是人在屋檐下,纵然低了头,弯了腰,也免不了东家将你扫地出门,为哪般?业务有冲突嘛,在利益面前,哪怕租客背景强大,也照下架不误,谁叫你抢我 ...

  7. 360手机助手2016年度嗨APP全民榜入围名单

    如果说评选2016年最火热的APP,那么一定不能不提直播类APP.近期在360手机助手"2016年度嗨APP全民榜"入围榜单中,映客.花椒.斗鱼等多款直播类都名列前茅.那么哪些年龄 ...

  8. 360手机助手又开启“全民分发”时代

    360手机助手又开启"全民分发"时代  2015-04-23 10:44   生活杂记   标签:360 科技   883    发表评论 2015年的移动应用分发市场正在走向&q ...

  9. 应用发布——发布应用程序到360手机助手

    360手机助手发布android app 1.首先登录360移动开放平台 http://dev.360.cn/ 注册开发者账号 a)首先注册360账号 用手机号,设置密码,验证码验证就OK了 b)注册 ...

  10. 360手机助手游戏怎么实名认证 360手机助手下载的游戏怎么关了悬浮窗

    360手机助手除了我们日常的传输文件,分享资源之外,上面还是有海量的游戏资源供我们下载的,而且平台还提供360币可以进行充值,不过很多小伙伴在下载游戏之后不知道在哪实名认证,哪里可以改实名认证?下面一 ...

最新文章

  1. 内存分配的原理__进程分配内存有两种方式,分别由两个系统调用完成:brk和mmap(不考虑共享内存)
  2. 【转】(原創) 如何使用ModelSim-Altera對Nios II仿真? (SOC) (Nios II) (SOPC Builder) (ModelSim) (DE2)...
  3. 如何利用1%推广费用提高50%的用户增长
  4. 【学生信息管理系统】——优化篇(一)
  5. 【牛客 - 280A】勘测(fib数列,思维,打表)
  6. 数组中的键值对去重_javascript利用对象键值对中键的唯一性实现数组去重
  7. VS2012 UPDATE 2 发布了离线包
  8. 《西点军校的经典法则》序 -- 責任(せきにん)、栄誉(えいよ)、国家(こっか)
  9. 1062. 洪水填充
  10. 【外挂编程】外挂编程技术揭秘(一)
  11. 胡昊—第6次作业—static关键字、对象
  12. 趋势预测方法(五)Holt-Winters模型_时序递推预测
  13. python分支机构_基于Python爬取天眼查网站的企业信息!Python无所不能!
  14. Word 注重页面细节才专业(添加页眉页脚,调整页边距,消灭孤行) | 职场人就应该这样用 Word
  15. 客户端+调用+matlab,基于web的android图像处理示范(Win7+Apache+PHP+Matlab+Android)
  16. 第一篇Mac上fluter开发环境配置
  17. python 解压缩文件中文名字乱码解决
  18. Cython配置安装(ubuntu)
  19. 猿辅导python辅导老师_猿辅导哪些老师比较好?
  20. 有趣好玩的带音乐24H全自动在线要饭系统源码

热门文章

  1. python语音识别终极指南_Python语音识别终极指南
  2. 将微信表情包保存为图片
  3. 爱加密和梆梆加固的破解方法
  4. 普通话水平测试用朗读作品60篇-(练习版)
  5. JDK动态代理和CGLIB动态代理介绍
  6. redis MySQL 脏读_redis多线程情况下避免读脏数据的悲观锁解决方案
  7. springmvc/ssm框架详细图文解说流程图及运行原理_附源码
  8. 华为服务器培训文档,华为机架服务器渠道培训.ppt
  9. 华硕bios更改固态硬盘启动_华硕主板BIOS设置固态硬盘启动顺序为第一启动硬盘教程...
  10. charles安卓抓包步骤详解