android 如何生成签名gensigature 生成的签名是根据手机来的吗

360手机助手关于签名校验的分析 - 剑残雪飘 - 博客园
愿我的的剑芒永远闪耀!
360手机助手中软件更新
0x01:分析过程
&&&&&&&使用抓包分析更新时请求的是一个配置文件,请求:后面是参数,请求方式为,内容如下:
可以看到其中包含了几个关键的参数,,,,其中比较关键的一个校验是signature_md5,其他都可以轻松替换,所以我们的重点就是对ignature_md5,校验的破解,去分析他对加密的方式,以及如何模拟算法,
0x02:知识补充
关于安卓数字签名校验的知识补充,安卓数字校验使用的是非对称加密算法也就是我们常说的公钥私钥加密,这个算法
指数运算谁都懂,不必说了,先说说模运算。模运算是整数运算,有一个整数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公钥也必不相同。所以我们可以根据公钥的对比,来判断私钥是否一致。
也就是说手机助手也不可能知道需要升级软件数字签名的私钥,所以可以猜测它进行的是对公钥的加密,那么接下来要验证这个观点
0x03逆向分析
&&这里我们使用一个强大的安卓反编译软件,然后把手机助手逆向分析一下:
1.搜索我们发现了另一个量,那么我们来定位一下:在改之理中搜索我们分析出现的位置
分析中在文件中有一段很关键
method&private&static&b(Landroid/content/CLcom/qihoo/appstore/resource/app/A)V
&&&&.locals&3&//&&private&static&void&b(Context&paramContext,&App&paramApp)
&&&&invoke-virtual&{p1},&Lcom/qihoo/appstore/resource/app/A-&Z()Ljava/lang/S
&&&&move-result-object&v0
&&&&invoke-static&{v0},&Lcom/qihoo/appstore/j/d;-&c(Ljava/lang/S)Z
&&&&move-result&v0
&&&&if-eqz&v0,&:cond_0
&&&&sget-object&v0,&Lcom/qihoo/appstore/j/d;-&a:Landroid/content/C
&&&&invoke-virtual&{p1},&Lcom/qihoo/appstore/resource/app/A-&Z()Ljava/lang/S
&&&&move-result-object&v1
&&&&invoke-static&{v0,&v1},&Lcom/qihoo/appstore/utils/-&f(Landroid/content/CLjava/lang/S)Ljava/lang/S
&&&&move-result-object&v0
&&&&invoke-virtual&{p1},&Lcom/qihoo/appstore/resource/app/A-&bL()Ljava/lang/S
&&&&move-result-object&v1
&&&&const-string&v2,&"sign_md5_default_value"
&&&&invoke-virtual&{v2,&v1},&Ljava/lang/S-&equals(Ljava/lang/O)Z
&&&&move-result&v2
&&&&if-nez&v2,&:cond_1
&&&&const-string&v2,&""
&&&&invoke-virtual&{v1,&v2},&Ljava/lang/S-&equals(Ljava/lang/O)Z
&&&&move-result&v2
&&&&if-nez&v2,&:cond_1
&&&&sget-object&v2,&Lcom/qihoo/appstore/j/d;-&a:Landroid/content/C
&&&&invoke-static&{v2,&v0,&v1},&Lcom/qihoo/appstore/utils/-&a(Landroid/content/CLjava/lang/SLjava/lang/S)Z
&&&&move-result&v0
&&&&if-nez&v0,&:cond_1
&&&&const/4&v0,&0x1
&&&&invoke-virtual&{p1,&v0},&Lcom/qihoo/appstore/resource/app/A-&r(Z)V
&&&&:cond_0
&&&&:goto_0
&&&&return-void
&&&&:cond_1
&&&&const/4&v0,&0x0
&&&&invoke-virtual&{p1,&v0},&Lcom/qihoo/appstore/resource/app/A-&r(Z)V
&&&&goto&:goto_0
.end&method
前面那几句大概意思就是用一个方法判断成员的方法也就是说那个是不是一个,换句话我们可以大胆猜测这里是判断有没有获取到程序的,
所以定位到这一句关键的代码
其中使用了的&方法对,&参数进行处理&我们可以猜测这里的代表的就是我们的:
.method&public&static&f(Landroid/content/CLjava/lang/S)Ljava/lang/S
&&&&.locals&2
&&&&:try_start_0
&&&&invoke-virtual&{p0},&Landroid/content/C-&getPackageManager()Landroid/content/pm/PackageM
&&&&move-result-object&v0
&&&&const/16&v1,&0x40
&&&&invoke-virtual&{v0,&p1,&v1},&Landroid/content/pm/PackageM-&getPackageInfo(Ljava/lang/SI)Landroid/content/pm/PackageI
&&&&move-result-object&v0
&&&&iget-object&v0,&v0,&Landroid/content/pm/PackageI-&signatures:[Landroid/content/pm/S
&&&&const/4&v1,&0x0
&&&&aget-object&v0,&v0,&v1
&&&&invoke-virtual&{v0},&Landroid/content/pm/S-&toByteArray()[B
&&&&move-result-object&v0
&&&&invoke-static&{v0},&Ljava/util/A-&toString([B)Ljava/lang/S
&&&&move-result-object&v0
&&&&invoke-static&{v0},&Lcom/qihoo/appstore/utils/-&e(Ljava/lang/S)Ljava/lang/S
&&&&move-result-object&v0
&&&&invoke-virtual&{v0},&Ljava/lang/S-&toLowerCase()Ljava/lang/S
&&&&:try_end_0
&&&&.catch&Ljava/lang/E&{: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/E-&printStackTrace()V
&&&&:cond_0
&&&&const/4&v0,&0x0
&&&&goto&:goto_0
.end&method
首先调用系统的然后返回一个对象然后再调用类的方法
.method&public&static&e(Ljava/lang/S)Ljava/lang/S
&&&&.locals&2
&&&&:try_start_0
&&&&const-string&v0,&"MD5"
&&&&invoke-static&{v0},&Ljava/security/MessageD-&getInstance(Ljava/lang/S)Ljava/security/MessageD
&&&&move-result-object&v0
&&&&invoke-virtual&{p0},&Ljava/lang/S-&getBytes()[B
&&&&move-result-object&v1
&&&&invoke-virtual&{v0,&v1},&Ljava/security/MessageD-&update([B)V
&&&&invoke-virtual&{v0},&Ljava/security/MessageD-&digest()[B
&&&&move-result-object&v0
&&&&invoke-static&{v0},&Lcom/qihoo/appstore/utils/-&a([B)Ljava/lang/S
&&&&:try_end_0
&&&&.catch&Ljava/security/NoSuchAlgorithmE&{: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/NoSuchAlgorithmE-&printStackTrace()V
&&&&goto&:goto_0
.end&method
这段话就是对进行一次运算然后调用方法,其中我们看到的是调用的的参数的方法
method&public&static&a([B)Ljava/lang/S
&&&&.locals&4
&&&&new-instance&v1,&Ljava/lang/StringB
&&&&array-length&v0,&p0
&&&&mul-int/lit8&v0,&v0,&0x2
&&&&invoke-direct&{v1,&v0},&Ljava/lang/StringB-&&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/-&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/StringB-&append(C)Ljava/lang/StringB
&&&&sget-object&v2,&Lcom/qihoo/appstore/utils/-&f:[C
&&&&aget-byte&v3,&p0,&v0
&&&&and-int/lit8&v3,&v3,&0xf
&&&&aget-char&v2,&v2,&v3
&&&&invoke-virtual&{v1,&v2},&Ljava/lang/StringB-&append(C)Ljava/lang/StringB
&&&&add-int/lit8&v0,&v0,&0x1
&&&&goto&:goto_0
&&&&:cond_0
&&&&invoke-virtual&{v1},&Ljava/lang/StringB-&toString()Ljava/lang/S
&&&&move-result-object&v0
&&&&return-object&v0
.end&method
这段代码的作用就是对一个数组进行格式化处理返回一个对象
那么现在可以猜测手机助手是对软件公钥的数字签名放到一个数组中,然后取它的第个成员sinagture[0]进行加密,下面我们来验证猜想
0x04&验证猜想
首先搭建好环境&然后我们来写一个安卓程序来模拟手机助手加密的过程,这里我们用自带的进行操作
其中代码如下:
import&java.lang.reflect.A
import&java.security.MessageD
import&java.security.NoSuchAlgorithmE
import&java.util.A
import&android.app.A
import&android.content.pm.PackageI
import&android.content.pm.PackageM
import&android.content.pm.PackageManager.NameNotFoundE
import&android.content.pm.S
import&android.os.B
import&android.text.TextU
import&android.view.M
import&android.view.V
import&android.widget.EditT
import&android.widget.TextV
import&android.widget.T
public&class&MainActivity&extends&Activity&{
private&EditText&et_
private&TextView&tv_
private&PackageManager&
private&PackageInfo&packageI
private&Signature[]&
private&StringBuilder&
private&String&
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,&"应用程序的包名不能为空!
/**&通过包管理器获得指定包名包含签名的包信息&
packageInfo&=&manager.getPackageInfo(pkgname,&PackageManager.GET_SIGNATURES);
/*******&通过返回的包信息获得签名数组&
signs&=&packageInfo.
/*******&循环遍历签名数组拼接应用签名&
/**************&得到应用签名&
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)
&&&&&&MessageDigest&localMessageDigest&=&MessageDigest.getInstance("MD5");
&&&&&&localMessageDigest.update(paramString.getBytes());
&&&&&&String&str&=&a(localMessageDigest.digest());
&&&&&&return&
&&&&catch&(NoSuchAlgorithmException&localNoSuchAlgorithmException)
&&&&&&localNoSuchAlgorithmException.printStackTrace();
&&&&return&paramS
&&public&static&String&a(byte[]&paramArrayOfByte)
&&&&StringBuilder&localStringBuilder&=&new&StringBuilder(2&*&paramArrayOfByte.length);
&&&&for&(int&i1&=&0;&i1&&&paramArrayOfByte.&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);
我们要在onCreate()函数调用我们的方法也就是我们构造出来的计算的&的方法
localStringBuilder.append(f[((0xF0&&&paramArrayOfByte[i1])&&&&&4)]);
localStringBuilder.append(f[(0xF&&&paramArrayOfByte[i1])]);
这两句代码是模拟手机助手的格式化的方法取前四位放到然后取后四位放到中。。
然后我们来用安卓模拟器进行模拟计算新浪微博的算法,获得新浪包名,下查看就行了:
运行我们写好的安卓程序来计算我们的签名:
我们来查看与360计算的结果是否相同:
在后面的入侵测试中,由于本地签名保存,会导致提示签名非法
从图中我们可以猜测360手机助手是在本地保存了原有的数字签名公钥,然后会对比公钥是否一致,而在实际的代码分析中的确是有读取到一个数组中然后保存到了本地,虽然这次入侵结果是失败了,不过过程很迷人,结论就是:安卓公钥私钥的数字签名校验确保了安卓软件的安全性。16178人阅读
Android开发(46)
首先说一下 我弄这个微信 有一个问题纠结了差不多5个月(下面再说) 现在把个人的总结写下来:
1.给你的应用签名:右键点击你的项目 -Android Tools-》Export signed application package填写相关信息一直到底 最后你会得到apk以及签名文件(会自动生成,以后打包就用这& 个已有的文件签名)
2.在ShareSDK或者微信官网下载签名的工具GenSignature.apk安装打开,输入你的应用包名,就会得到签名
3.在微信开发者官网()注册你的应用:(我只列出重要的几个地方)
&&& a.填写你的应用名称(注意一定要与你的应用名称一致,我由于把一个字母大小写写错害得我为这个问题纠结了5个月,大家一定要注意)
&&&& b.在应用签名上填写在步骤1中得到的签名
&&&& c.包名一定要与你的应用包名完全一致
&&&& d.信息填写完整 提交审核 其实这个时候你已经得到你的AppID把这个加入到你的项目中去 就可以了
4.等待微信审核通过。你就可以调试你的应用了
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:535261次
积分:3591
积分:3591
排名:第9550名
原创:48篇
评论:115条
(1)(1)(1)(2)(1)(1)(2)(1)(3)(1)(20)(14)
(window.slotbydup = window.slotbydup || []).push({
id: '4740881',
container: s,
size: '200,200',
display: 'inlay-fix'}

我要回帖

更多关于 mac 生成android 签名 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信