嗯嗯手机支付宝怎样进行支付宝智能加密是什么

扫描下载MIUI论坛APP
经验17374 米
在线时间2327 小时
版本4.3.14
机型小米手机1/1S
签到次数41
MIUI版本4.3.14
本帖最后由 今夜好梦 于
13:41 编辑
& && &&&小米手机的MIUI系统,功能全面,个性十足,今天推荐一个《隐藏应用功能 》,现在的手机占用的时间越来越长,与之而来的就是隐私的问题。 & &&&
& && & 相信小米粉们,开始担心手机里的应用,轻松别人打开,例如QQ,会有很多记录;支付宝,涉及到财产安全;陌陌,涉及到你的性趣爱好哟!诸如此类的敏感私密的软件,不想别人打开或者看到,今天发布两个教程帮你实现隐藏软件:
第一个、小米系统自带《安全与隐私》帮你实现。
& &&& 操作步骤:设置--安全与隐私--隐私保护--访问限制--设定你的图像密码---选择你需要的加密的软件---设定完成以后,重新点击加密的软件,会出现输入密码,即可完成加密哟!
11.png (138.14 KB, 下载次数: 1)
12.png (76.28 KB, 下载次数: 1)
13.png (83.25 KB, 下载次数: 0)
14.png (75.85 KB, 下载次数: 0)
15.png (55.61 KB, 下载次数: 1)
16.png (116.4 KB, 下载次数: 0)
190.png (52.69 KB, 下载次数: 0)
第二种、推荐你小米桌面(最新版)
第一步、下载安装,《小米桌面》安装以后,然后把小米桌面设置为默认桌面。
第二步、 设置小米桌面为默认桌面以后,桌面双指上滑--然后会进入---隐藏桌面应用--根据提示设定密码---根据图示选择需要隐藏app。
第三步、你会看到桌面上,会有空白的地方,就是隐藏的应用。
第四步、如果你想打开隐藏应用---桌面双指上滑--会提示你输入密码--就可以看到隐藏应用了,是不是很好玩!赶紧尝鲜哟!
1.png (153.42 KB, 下载次数: 0)
2.png (55.99 KB, 下载次数: 1)
3.png (125.15 KB, 下载次数: 1)
4.png (111.92 KB, 下载次数: 1)
5.png (198.82 KB, 下载次数: 0)
6.png (141.64 KB, 下载次数: 1)
7.png (267.28 KB, 下载次数: 0)
8.png (111.87 KB, 下载次数: 1)
10.png (138.24 KB, 下载次数: 0)
小米桌面下载:
(7.09 MB, 下载次数: 4915)
23:40 上传
点击文件名下载附件
下载积分: 经验 -1 米
最后:感谢原创作者@Cx暗夜皇族 和 @黄米弟 因为小米,所以分享给更多的朋友,谢谢各位的支持!
分享到微信朋友圈
打开微信,点击底部的“发现”,使用 “扫一扫” 即可将网页分享到我的朋友圈。
MIUI系统的就不需要下载小米桌面了&
已有&18&人评分
屌丝逆袭活动继续 /QXfV7d..
miui4.x.14反正是最新版的。双指向上毫无反.
小米桌面比系统桌面功能多了一些.
米3双指上滑毫无反应
骗子,米3双指上滑半天都没进不去,根本就.
MIUI 因你更精彩!
good idea!
MIUI 因你更精彩!
MIUI 因你更精彩!
MIUI系统貌似没这功能啊?
只求MIUI添加隐藏图标功能
MIUI 因你更精彩!
感谢分享^_^
MIUI 因你更精彩!
MIUI 因你更精彩!
感谢分享^_^
精品文章^_^
助人为乐^_^
经验17230 米
在线时间1460 小时
版本6.6.30
MIUI日历同步要等到何年何月?
机型小米手机2/2S
签到次数146
MIUI版本6.6.30
经验1110 米
在线时间17 小时
版本ICS25.0
头像被屏蔽
积分 734, 距离下一级还需 1266 积分
积分 734, 距离下一级还需 1266 积分
机型小米手机2A
签到次数132
MIUI版本ICS25.0
通过手机发布
提示: 该帖被管理员或版主屏蔽
经验86355 米
威望387 米
在线时间3711 小时
版本6.10.20
机型小米平板1
签到次数176
MIUI版本6.10.20
学习了,谢谢分享
已有&2&人评分
大神还需要学习?
感谢分享^_^
经验5653 米
在线时间284 小时
头像被屏蔽
机型小米手机2/2S
签到次数21
MIUI版本4.8.8
提示: 作者被禁止或删除 内容自动屏蔽
经验1527 米
在线时间52 小时
版本5.11.26
积分 1654, 距离下一级还需 346 积分
积分 1654, 距离下一级还需 346 积分
机型小米手机3 TD版
签到次数81
MIUI版本5.11.26
隐藏或者加密手机桌面APP(保护隐私软件支付宝、QQ)
经验557 米
在线时间306 小时
版本6.5.27
积分 1129, 距离下一级还需 871 积分
积分 1129, 距离下一级还需 871 积分
机型夏新N828
MIUI版本6.5.27
看看怎么来
经验1551 米
在线时间21 小时
版本4.9.26
积分 1790, 距离下一级还需 210 积分
积分 1790, 距离下一级还需 210 积分
机型小米手机3/4 WCDMA版
签到次数37
MIUI版本4.9.26
来学习一下
经验3943 米
在线时间421 小时
版本V8.0.3.0.MXECNDG
积分 5175, 距离下一级还需 14825 积分
积分 5175, 距离下一级还需 14825 积分
机型小米Note 移动4G/联通4G
签到次数85
MIUI版本V8.0.3.0.MXECNDG
通过手机发布
经验1866 米
在线时间18 小时
版本6.9.22
积分 1854, 距离下一级还需 146 积分
积分 1854, 距离下一级还需 146 积分
机型小米手机3/4 WCDMA版
签到次数192
MIUI版本6.9.22
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
MIUI 300周
MIUI 300周更新纪念勋章
MIUI 3000万
MIUI 3000万发烧友纪念勋章
MIUI 2000万
MIUI 2000万发烧友纪念勋章
MIUI 7纪念勋章
MIUI五周年
MIUI五周年纪念勋章
MIUI三周年
MIUI三周年纪念勋章
已关注极客秀微信
已关注微信
关注腾讯微博
已关注腾讯微博
关注新浪微博
已关注新浪微博
MIUI 100周
100周发布纪念勋章
MIUI六周年
MIUI六周年纪念勋章
1000万用户纪念勋章
MIUI1000万用户纪念勋章
百万壁纸评审纪念勋章
发烧友俱乐部
发烧友俱乐部
小米平板首发纪念勋章
小米平板首发纪念勋章
Copyright (C) 2016 MIUI
京ICP备号 | 京公网安备34号 | 京ICP证110507号3728人阅读
android 安全(13)
作者:非虫
随着电子商务在国内的迅猛发展,网上购物也成为了时下流行的消费方式。就我个人来说,每年在淘宝上也会购物上百起。这足不出户的购物方式的确给我们的生活带来了不少实惠与方便,但同时,购物安全也成为了广大网购消费者担心的一个问题。每年在新闻中爆光的网银被盗、被骗的事件也屡见不鲜。
长期使用网络客户端软件的朋友都有一个习惯,为了避免每次使用时输入帐号名和密码,都习惯使用软件的自动保存密码功能来记住登录密码,这样下次直接点击登录按钮就可以登录软件了(有些软件直接跳过了登录确认的界面),这样,一个安全问题就出来了,软件为我们保存的密码是明文存储的吗?如果加密了,加密强度怎样?外部用户可以直接破解吗?试想一下,像支付宝这类敏感的网银软件,如果本地存储的密码被人直接破解,那后果是很难预料的!而随着我对支付宝程序的逆向分析,也证明了这个安全问题确实存在。在此申明:以下文章涉及的代码与分析内容仅供安卓系统安全学习交流,任何个人或组织不得使用文中提到的技术做违法犯罪活动,否则由此引发的任何后果与法律责任本人概不负责。
一台安装有支付宝的安卓手机,并且能获得ROOT权限。
支付宝的版本为3.4.0.0229。
程序运行后使用了自动保存密码功能。为了测试更详细,我分别保存了支付宝与淘宝的帐号密码。
医生给病人看病步骤讲究的是望闻问切,通过查看病人的面貌体态来对病情做初步判断,我们今天的分析也一改以往的埋头分析,采用类似的方法,先看看软件运行后的“症状”。打开支付宝软件,点击右上角的登录按钮,分别使用淘宝与支付宝帐号登录,勾选上自动保存密码,如图1所示:
退出软件,然后重新登录,发现软件的确记住了保存的密码,而且密码框显示“星星”的位数与我实际的密码位数一样,看到这里我立马来劲了!这说明密码肯定是保存在本地的某个文件中,而且程序启动时读取密码,然后设置到密码框中。
下面,请出DDMS,进入支付宝数据目录“/data/data/com.eg.android.AlipayGphone/”,里面的文件结构如图2所示:
在DateBases目录里有个RecentDB文件,初步判断它是使用的Sqlite3保存的数据库,将该文件导出到D盘根目录,进行命令行,使用AndroidSDK里面的Sqlite3.exe打开该数据库并分别执行“.tables”、“.schema RecentTable2”、“select * from RecentTable2;”命令,执行后结果如图3所示:
这不看不知道,一看真吓一跳,原来帐号名与密码直接保存在了这个数据库中!只是密码被加过密,看后面的“==”还以为是Base64,可测试后发现不是,退出支付宝程序将它卸载并重新安装。重新运行软件一次后退出,将刚才导出的“RecentDB”文件导入,再次运行支付宝后发现软件登录框中帐号名与密码都记住了!接下来为手机换一张电话号码卡,重新进入程序发现密码框为空了。同样,在其它安卓手机上安装支付宝后导入RecentDB文件,密码框也为空,看来,支付宝对使用者手机与电话号码有所判断。
使用ApkTool将支付宝APK安装文件解包,打开“AndroidManifest.xml”文件,将“android:name”一栏的android:debuggable=&false&改成android:debuggable=&true&,然后重新编译签名并安装,打开DDMS,在LogCat中新建一栏,设置“Filter Name”与“By Application Name”为“com.eg.android.AlipayGphone”,如图4所示:
启动程序,这时就可以在DDMS中查看支付宝的Log输出了,运行程序后点击登录按钮进入到登录界面,在界面随意处点击几下,发现拦截到的消息如图5所示:
由Log输出信息得知程序所在的Activity为“com.alipay.android.client.Login”,在反编译出的Smali文件夹中找到“Login.smali”文件并查看OnCreate()方法。代码太长,只帖关键部分:
.method public onCreate(Landroid/os/B)V
&&& .locals 6
&&& const/4 v5, 0x1
&&& const/4 v4, 0x0
&&& invoke-super {p0, p1},Lcom/alipay/android/client/RootA-&onCreate(Landroid/os/B)V
&&& invoke-static {p0},Lcom/alipay/android/appHall/h;-&a(Landroid/app/A)Z
&&& new-instance v0,Lcom/alipay/platform/a/b;
&&& ............&&&
&&&&&&& const-string v1, &logintype&
&&& invoke-virtual {v0, v1},Lcom/alipay/android/client/a/o;-&a(Ljava/lang/S)Ljava/lang/S
&&& move-result-object v0
&&& const-string v1,&taobao&& #判断登录类型
&&& invoke-virtual {v0, v1},Ljava/lang/S-&equals(Ljava/lang/O)Z
&&& move-result v0
&&& if-eqz v0, :cond_3
&&& iput-boolean v5, p0, Lcom/alipay/android/client/L-&k:Z
&&& iput-boolean v4, p0,Lcom/alipay/android/client/L-&l:Z
&&& iget-object v0, p0,Lcom/alipay/android/client/L-&K:Landroid/widget/B
&&& invoke-virtual {v0, v4},Landroid/widget/B-&setSelected(Z)V
&&& iget-object v0, p0,Lcom/alipay/android/client/L-&L:Landroid/widget/B
&&& invoke-virtual {v0, v5},Landroid/widget/B-&setSelected(Z)V
&&& iget-object v0, p0,Lcom/alipay/android/client/L-&v:Landroid/widget/AutoCompleteTextV
&&& const v1, 0x7f0a0010
&&& invoke-virtual {v0, v1},Landroid/widget/AutoCompleteTextV-&setHint(I)V #设置输入框的提示
&&& :goto_0
&&& invoke-direct {p0},Lcom/alipay/android/client/L-&d()V #?关键方法
&&& iget-object v0, p0,Lcom/alipay/android/client/L-&D:Landroid/widget/CheckB
&&& new-instance v1,Lcom/alipay/android/client/
&&& invoke-direct {v1, p0},Lcom/alipay/android/client/-&&init&(Lcom/alipay/android/client/L)V
&&& invoke-virtual {v0, v1},Landroid/widget/CheckB-&setOnClickListener(Landroid/view/View$OnClickL)V
&&& return-void
&&& :cond_3
&&& iput-boolean v4, p0,Lcom/alipay/android/client/L-&k:Z
&&& iput-boolean v5, p0,Lcom/alipay/android/client/L-&l:Z
&&& iget-object v0, p0,Lcom/alipay/android/client/L-&K:Landroid/widget/B
&&& invoke-virtual {v0, v5},Landroid/widget/B-&setSelected(Z)V
&&& iget-object v0, p0,Lcom/alipay/android/client/L-&L:Landroid/widget/B
&&& invoke-virtual {v0, v4},Landroid/widget/B-&setSelected(Z)V
&&& iget-object v0, p0,Lcom/alipay/android/client/L-&v:Landroid/widget/AutoCompleteTextV
&&& const v1, 0x7f0a0011
&&& invoke-virtual {v0, v1},Landroid/widget/AutoCompleteTextV-&setHint(I)V #设置输入框的提示
&&& goto :goto_0
.end method
在OnCreate()方法中,设置了控件的显示、提示及监听器,而后判断登录类型并设置“支付宝会员”或“淘宝会员”按钮的选择状态,在这期间调用了d()方法,该方法过后,帐号名与密码就被显示了出来,d()方法代码如下:
.method private d()V
&&& .locals 5
&&& const/16 v2, 0x8& #设置为View.GONE
&&& const/4 v4, 0x0& #设置不选中或View.VISIBLE
&&& iget-boolean v0, p0,Lcom/alipay/android/client/L-&k:Z
&&& if-nez v0, :cond_5 #检查用户类型
&&& const-string v0,&alipay&
&&& iget-object v1, p0,Lcom/alipay/android/client/L-&J:Landroid/widget/B
&&& invoke-virtual {v1, v4},Landroid/widget/B-&setVisibility(I)V&#设置为View.VISIBLE
&&& iget-object v1, p0,Lcom/alipay/android/client/L-&H:Landroid/widget/TextV
&&& invoke-virtual {v1, v4},Landroid/widget/TextV-&setVisibility(I)V&#设置为View.VISIBLE
&&& iget-boolean v1, p0,Lcom/alipay/android/client/L-&P:Z
&&& if-nez v1, :cond_3
&&& iget-object v1, p0,Lcom/alipay/android/client/L-&d:Landroid/widget/RelativeL
&&& invoke-virtual {v1, v2},Landroid/widget/RelativeL-&setVisibility(I)V #设置为View.GONE
&&& :goto_0
&&& iget-object v1, p0,Lcom/alipay/android/client/L-&j:Lcom/alipay/android/client/a/l; #获取j对象
&&& #?调用j.a(String)方法获得ho对象,传入的参数为代表用户类型的“alipay”或“taobao”?
&&& invoke-virtual {v1, v0},Lcom/alipay/android/client/a/l;-&a(Ljava/lang/S)Lcom/alipay/android/client/
&&& move-result-object v0
&&& if-nez v0, :cond_0 #?检查有没有“alipay”类型登录的用户?,没有下面就new个空的ho对象
&&& new-instance v0,Lcom/alipay/android/client/& #new一个ho对象
&&& invoke-direct {v0},Lcom/alipay/android/client/-&&init&()V
&&& :cond_0
&&& iget-object v1, p0,Lcom/alipay/android/client/L-&v:Landroid/widget/AutoCompleteTextV
&&& const-string v2,&&
&&& invoke-virtual {v1, v2},Landroid/widget/AutoCompleteTextV-&setText(Ljava/lang/CharS)V
&&& #将用户名输入框清空
&&& iget-object v1, p0,Lcom/alipay/android/client/L-&x:Landroid/widget/EditT
&&& const-string v2,&&
&&& #将密码输入框清空
&&& invoke-virtual {v1, v2},Landroid/widget/EditT-&setText(Ljava/lang/CharS)V
&&& iget-object v1, p0,Lcom/alipay/android/client/L-&D:Landroid/widget/CheckB
&&& invoke-virtual {v1, v4},Landroid/widget/CheckB-&setChecked(Z)V #设置“记住登录密码”选择状态
&&& iget-object v1, p0,Lcom/alipay/android/client/L-&v:Landroid/widget/AutoCompleteTextV
&&& const/16 v2, 0x64
&&& invoke-virtual {v1, v2},Landroid/widget/AutoCompleteTextV-&setThreshold(I)V
&&& iget-object v1, p0,Lcom/alipay/android/client/L-&v:Landroid/widget/AutoCompleteTextV
&&& iget-object v2, v0,Lcom/alipay/android/client/-&a:Ljava/lang/S # ho.a 为用户名
&&& # ?将ho.a中的用户名设置到用户名输入框?
&&& invoke-virtual {v1, v2},Landroid/widget/AutoCompleteTextV-&setText(Ljava/lang/CharS)V
&&& iget-object v1, p0,Lcom/alipay/android/client/L-&v:Landroid/widget/AutoCompleteTextV
&&& const/4 v2, 0x0
&&& invoke-static {v1, v2},Lcom/alipay/android/client/a/o;-&a(Landroid/widget/EditTLandroid/text/method/PasswordTransformationM)V
&&& const-string v1,&&
&&& :try_start_0
&&& iget-object v2, v0,Lcom/alipay/android/client/-&b:Ljava/lang/S #ho.b为加密过的密码
&&& const-string v3,&&
&&& invoke-virtual {v2, v3},Ljava/lang/S-&equals(Ljava/lang/O)Z #?判断密码是否为空?
&&& move-result v2
&&& if-nez v2, :cond_8
&&& iget-object v0, v0,Lcom/alipay/android/client/-&b:Ljava/lang/S #?需要解密的密码?
&&& sget-object v1,Lcom/alipay/android/client/d/b;-&I:Ljava/lang/S&& #?解密密钥?
&&& #调用com.google.zxing.c.a.b.b(String)方法解密ho.b中加密过的密码
&&& invoke-static {v0, v1},Lcom/google/zxing/c/a/b;-&b(Ljava/lang/SLjava/lang/S)Ljava/lang/S
&&& move-result-object v0
&&& if-eqz v0, :cond_1 #解密出的密码是否为空,为空就跳过设置密码框
&&& iget-object v1, p0,Lcom/alipay/android/client/L-&x:Landroid/widget/EditT #密码框
&&& invoke-virtual {v1, v0},Landroid/widget/EditT-&setText(Ljava/lang/CharS)V #?设置密码?
&&& :cond_1
&&& :goto_1
&&& if-eqz v0, :cond_2
&&& iget-object v1, p0,Lcom/alipay/android/client/L-&D:Landroid/widget/CheckB
&&& invoke-virtual {v0},Ljava/lang/S-&length()I
&&& move-result v0
&&& if-lez v0, :cond_9
&&& const/4 v0, 0x1
&&& :goto_2
&&& invoke-virtual {v1, v0},Landroid/widget/CheckB-&setChecked(Z)V #取消“记住登录密码”选中状态
&&& :try_end_0
&&& .catchLjava/lang/E {:try_start_0 .. :try_end_0} :catch_0
&&& :cond_2
&&& :goto_3
&&& return-void& #返回
&&& :cond_3
&&& iget-object v1, p0,Lcom/alipay/android/client/L-&d:Landroid/widget/RelativeL
&&& invoke-virtual {v1, v4},Landroid/widget/RelativeL-&setVisibility(I)V #设置为View.VISIBLE
&&& iget-object v1, p0,Lcom/alipay/android/client/L-&h:Landroid/graphics/B
&&& if-eqz v1, :cond_4
&&& iget-object v1, p0,Lcom/alipay/android/client/L-&h:Landroid/graphics/B
&&& invoke-direct {p0, v1},Lcom/alipay/android/client/L-&a(Landroid/graphics/B)V
&&& :cond_4
&&& iget-object v1, p0,Lcom/alipay/android/client/L-&e:Landroid/widget/EditT
&&& const-string v2,&&
&&& invoke-virtual {v1, v2},Landroid/widget/EditT-&setText(Ljava/lang/CharS)V
&&& goto :goto_0
&&& :cond_5
&&& const-string v0,&taobao&& #?等待查询&taobao& 类型的用户登录记录?
&&& iget-object v1, p0,Lcom/alipay/android/client/L-&J:Landroid/widget/B
&&& invoke-virtual {v1, v2},Landroid/widget/B-&setVisibility(I)V
&&& iget-object v1, p0,Lcom/alipay/android/client/L-&H:Landroid/widget/TextV
&&& invoke-virtual {v1, v2},Landroid/widget/TextV-&setVisibility(I)V
&&& iget-boolean v1, p0,Lcom/alipay/android/client/L-&M:Z
&&& if-nez v1, :cond_6
&&& iget-object v1, p0,Lcom/alipay/android/client/L-&d:Landroid/widget/RelativeL
&&& invoke-virtual {v1, v2},Landroid/widget/RelativeL-&setVisibility(I)V
&&& goto/16 :goto_0
&&& :cond_6
&&& iget-object v1, p0,Lcom/alipay/android/client/L-&d:Landroid/widget/RelativeL
&&& invoke-virtual {v1, v4},Landroid/widget/RelativeL-&setVisibility(I)V #设置为View.VISIBLE
&&& iget-object v1, p0,Lcom/alipay/android/client/L-&g:Landroid/graphics/B
&&& if-eqz v1, :cond_7
&&& iget-object v1, p0,Lcom/alipay/android/client/L-&g:Landroid/graphics/B
&&& invoke-direct {p0, v1},Lcom/alipay/android/client/L-&a(Landroid/graphics/B)V
&&& :cond_7
&&& iget-object v1, p0,Lcom/alipay/android/client/L-&e:Landroid/widget/EditT
&&& const-string v2,&&
&&& invoke-virtual {v1, v2},Landroid/widget/EditT-&setText(Ljava/lang/CharS)V #清空
&&& goto/16 :goto_0
&&& :cond_8 #跳到这里说明密码为空,则直接设置密码框内容为空
&&& :try_start_1
&&& iget-object v2, p0,Lcom/alipay/android/client/L-&x:Landroid/widget/EditT #密码框
&&& iget-object v0, v0,Lcom/alipay/android/client/-&b:Ljava/lang/S #密码
&&& invoke-virtual {v2, v0},Landroid/widget/EditT-&setText(Ljava/lang/CharS)V#设置密码框
&&& :try_end_1
&&& .catchLjava/lang/E {:try_start_1 .. :try_end_1} :catch_0
&&& move-object v0, v1
&&& goto :goto_1
&&& :cond_9
&&& move v0, v4
&&& goto :goto_2
&&& :catch_0
&&& move-exception v0
&&& invoke-virtual {v0},Ljava/lang/E-&printStackTrace()V
&&& goto :goto_3
.end method
在整个Login类中,有三个变量是需要注意的,它们分别是“EditText e”、“AutoCompleteTextView v”、“EditText x”。因为只有它们才可能是用户名或密码输入框,经过分析发现“AutoCompleteTextView v”为用户名输入框,而“EditText x”为密码输入框。在d()方法中,代码首先设置用户名输入框内容为ho.a,如果ho.b不为空就先其解密,然后设置到密码框,这样,用户名与密码就设置好了,由于我们的主题是分析密码存储机制,所以,其它代码就不着重分析了。
为了验证上面的分析,这里使用一个小技巧来查看上面ho.a与ho.b以及解密后的值,很多人可能立即想到了使用Toast弹出信息提示,不过个人觉得使用LogCat输出显示更方便,一方面是加入代码量少,使用的寄存器少,另一方面是输出的结果可以随时查看。在d()方法中加入两处Log.v的代码,修改后的代码如图6所示:
在插入代码时需要注意不要随意使用寄存器,而破坏了原程序的状态。接下来保存“Login.Smali”文件后对整个APK进行重新编译与签名,再次安装后导入上面保存的RecentDB文件,启动程序进入登录界面,会发现LogCat会显示如图7所示的信息:
这个时候神奇的发现,被加密的密码、密钥以及解密后的密码都输出到了LogCat中!ho对象何时获取的密码信息?而密钥又是如何生成的?这重重的疑问更增加了我的好奇心!我们这个时候可以采取顺藤摸瓜的方式来追根溯源了。在d()方法中有如下一段代码:
iget-object v1, p0,Lcom/alipay/android/client/L-&j:Lcom/alipay/android/client/a/l;
invoke-virtual {v1, v0},Lcom/alipay/android/client/a/l;-&a(Ljava/lang/S)Lcom/alipay/android/client/
move-result-object v0
if-nez v0, :cond_0
new-instance v0, Lcom/alipay/android/client/& #如果j.a()返回为0,就new一个ho对象
ho对象是通过this.j.a()方法生成的,j是一个l对象,代码位于“com\alipay\android\client\a\l.smali”文件中,找到相应的l.a(String)方法,代码如下:
.method public final a(Ljava/lang/S)Lcom/alipay/android/client/
&&& .locals 12
&&& const/4 v10, 0x3
&&& const/4 v7, 0x2
&&& const/4 v8, 0x1
&&& const/4 v9, 0x0
&&& const/4 v3, 0x0
&&& if-nez p1, :cond_0 #p1为String类型的参数,不为空就跳走,为空下面就查询所有用户登录的记录
&&& iget-object v0, p0,Lcom/alipay/android/client/a/l;-&a:Landroid/database/sqlite/SQLiteD
&&& const-string v1,&RecentTable2& #需要查询的表
&&& const/4 v2, 0x6
&&& new-array v2, v2,[Ljava/lang/S
&&& const-string v4,&ID& #ID
&&& aput-object v4, v2, v9
&&& const-string v4,&NAME& #用户名
&&& aput-object v4, v2, v8
&&& const-string v4,&PASSWORD& #加密过的密码
&&& aput-object v4, v2, v7
&&& const-string v4,&TYPE& #用户类型
&&& aput-object v4, v2, v10
&&& const/4 v4, 0x4
&&& const-string v5,&LOGINTIME& #最后登录的时间
&&& aput-object v5, v2, v4
&&& const/4 v4, 0x5
&&& const-string v5, &USERID&
&&& aput-object v5, v2, v4
&&& const-string v7,&LOGINTIME desc& #构造SQL语句
&&& move-object v4, v3
&&& move-object v5, v3
&&& move-object v6, v3
&&& invoke-virtual/range {v0.. v7}, Landroid/database/sqlite/SQLiteD-&query(Ljava/lang/S[Ljava/lang/SLjava/lang/S[Ljava/lang/SLjava/lang/SLjava/lang/SLjava/lang/S)Landroid/database/C
&&& move-result-object v0 #?执行查询并返回结果?
&&& :goto_0
&&& invoke-interface {v0},Landroid/database/C-&moveToFirst()Z #转到第一条记录
&&& move-result v1
&&& if-eqz v1, :cond_2 #如果记录为空就跳走关闭数据库并返回
&&& new-instance v1,Lcom/alipay/android/client/ #?new一个ho对象?
&&& invoke-direct {v1},Lcom/alipay/android/client/-&&init&()V
&&& const-string v2,&NAME&
&&& invoke-interface {v0, v2},Landroid/database/C-&getColumnIndex(Ljava/lang/S)I
&&& move-result v2
&&& invoke-interface {v0, v2},Landroid/database/C-&getString(I)Ljava/lang/S #?查询结果的用户名
&&& move-result-object v2
&&& iput-object v2, v1,Lcom/alipay/android/client/-&a:Ljava/lang/S #?用户名赋值给ho.a?
&&& const-string v2,&PASSWORD&
&&& invoke-interface {v0, v2},Landroid/database/C-&getColumnIndex(Ljava/lang/S)I
&&& move-result v2
&&& invoke-interface {v0, v2},Landroid/database/C-&getString(I)Ljava/lang/S#?查询结果的密码
&&& move-result-object v2
&&& iput-object v2, v1,Lcom/alipay/android/client/-&b:Ljava/lang/S#?密码赋值给ho.b?
&&& if-nez p1, :cond_1
&&& const-string v2,&TYPE&
&&& invoke-interface {v0, v2},Landroid/database/C-&getColumnIndex(Ljava/lang/S)I
&&& move-result v2
&&& invoke-interface {v0, v2},Landroid/database/C-&getString(I)Ljava/lang/S#查询结果的用户类型
&&& move-result-object v2
&&& iput-object v2, v1,Lcom/alipay/android/client/-&c:Ljava/lang/S?用户类型赋值给ho.c?
&&& :goto_1
&&& const-string v2,&USERID&
&&& invoke-interface {v0, v2},Landroid/database/C-&getColumnIndex(Ljava/lang/S)I
&&& move-result v2
&&& invoke-interface {v0, v2},Landroid/database/C-&getString(I)Ljava/lang/S
&&& move-result-object v2
&&& iput-object v2, v1,Lcom/alipay/android/client/-&e:Ljava/lang/S?用户ID赋值给ho.e?
&&& :goto_2
&&& invoke-interface {v0},Landroid/database/C-&close()V #关闭Cursor
&&& return-object v1 #返回ho对象
&&& :cond_0 #?跳到这里查询特定“TYPE”的用户登录记录?
&&& iget-object v4, p0,Lcom/alipay/android/client/a/l;-&a:Landroid/database/sqlite/SQLiteD
&&& const-string v5,&RecentTable2& #要查询的数据表
&&& const/4 v0, 0x5
&&& new-array v6, v0,[Ljava/lang/S
&&& const-string v0,&ID&
&&& aput-object v0, v6, v9
&&& const-string v0,&NAME&
&&& aput-object v0, v6, v8
&&& const-string v0,&PASSWORD&
&&& aput-object v0, v6, v7
&&& const-string v0,&LOGINTIME&
&&& aput-object v0, v6, v10
&&& const/4 v0, 0x4
&&& const-string v1,&USERID&
&&& aput-object v1, v6, v0
&&& const-string v7,&TYPE = ?&
&&& new-array v8, v8,[Ljava/lang/S
&&& aput-object p1, v8, v9
&&&&&&& const-string v11, &LOGINTIMEdesc&
#上面在构造SQL语句,整个语句类似于:
#select ID, NAME, PASSWORD, LOGINTIME, USERID from RecentTable2
# where TYPE=&alipay& order by LOGINTIME
&&& move-object v9, v3
&&& move-object v10, v3
&&& invoke-virtual/range {v4.. v11},Landroid/database/sqlite/SQLiteD-&query(Ljava/lang/S[Ljava/lang/SLjava/lang/S[Ljava/lang/SLjava/lang/SLjava/lang/SLjava/lang/S)Landroid/database/C#执行SQL查询语句
&&& move-result-object v0
&&& goto :goto_0&& #跳转去赋值
&&& :cond_1
&&& iput-object p1, v1,Lcom/alipay/android/client/-&c:Ljava/lang/S #保存用户类型到ho.c
&&& goto :goto_1
&&& :cond_2
&&& move-object v1, v3
&&& goto :goto_2
.end method
这段代码我注释的很清楚,而且功能也很简单,就是查询SQL语句,然后对ho对象的相应字段赋值。
用户名与加密密码的获取弄清楚后,来看看密钥是如何生成的。从上面密码解密部分的分析得知它是通过“com.alipay.android.client.d.b”对象的I成员传递进来的,而它是在哪里被赋的值呢?经过分析,发现是在Login类的“b(com.alipay.platform.core.b)”方法中调用了“com.alipay.android.client.a.m.b(Context)”方法,而后者又调用了“com.alipay.android.client.a.o”类的“a(Context)”方法,“a(Context)”方法代码如下:
.method public static a(Landroid/content/C)Ljava/lang/S
&&& .locals 3
& invoke-static {p0},Lcom/alipay/android/client/a/j;-&a(Landroid/content/C)Lcom/alipay/android/client/a/j;
&&& move-result-object v0
&&& invoke-virtual {v0},Lcom/alipay/android/client/a/j;-&e()Ljava/lang/S
&&& move-result-object v0
&&& const/4 v1, 0x0
&&& const/16 v2, 0x8
&&& invoke-virtual {v0, v1,v2}, Ljava/lang/S-&substring(II)Ljava/lang/S
&&& move-result-object v0
&&& return-object v0
.end method
转换成JAVA代码只只执行如下一行:
return com.alipay.android.client.a.j.a(Context).e().substring(0, 8);
取e()方法返回字符串的前8位,“e()”方法代码如下:
.method public final e()Ljava/lang/S
&&& .locals 2
&&& iget-object v0, p0,Lcom/alipay/android/client/a/j;-&b:Ljava/lang/S #j.b是否为空字符串
&&& if-nez v0, :cond_0
&&& iget-object v0, p0,Lcom/alipay/android/client/a/j;-&a:Ljava/lang/S#j.a是否为空字符串
&&& if-nez v0, :cond_0
&&& const-string v0,&000& #调用b()方法构造一个全0字符串
&&& invoke-direct {p0, v0},Lcom/alipay/android/client/a/j;-&b(Ljava/lang/S)Ljava/lang/S
&&& move-result-object v0
&&& :goto_0
&&& const-string v1,&[[a-z][A-Z][0-9]]{15}\\|[[a-z][A-Z][0-9]]{15}&
&&& invoke-virtual {v0, v1},Ljava/lang/S-&matches(Ljava/lang/S)Z # #字符串是否适合要求
&&& move-result v1
&&& if-eqz v1, :cond_3 #字符串构造失败跳走
&&& :goto_1
&&& return-object v0 #返回
&&& :cond_0
&&& iget-object v0, p0,Lcom/alipay/android/client/a/j;-&b:Ljava/lang/S #取j.b字符串
&&& if-nez v0, :cond_1 #不为空就跳走
&&& new-instance v0,Ljava/lang/StringB
&&& invoke-direct {v0},Ljava/lang/StringB-&&init&()V
&&& iget-object v1, p0,Lcom/alipay/android/client/a/j;-&a:Ljava/lang/S #取j.a字符串
&&& invoke-virtual {v0, v1},Ljava/lang/StringB-&append(Ljava/lang/S)Ljava/lang/StringB
&&& move-result-object v0
&&& const-string v1,&|& #添加‘|’
&&& invoke-virtual {v0, v1},Ljava/lang/StringB-&append(Ljava/lang/S)Ljava/lang/StringB
&&& move-result-object v0
&&& const-string v1,&000& #添加全0
&&& invoke-virtual {v0, v1},Ljava/lang/StringB-&append(Ljava/lang/S)Ljava/lang/StringB
&&& move-result-object v0
&&& invoke-virtual {v0},Ljava/lang/StringB-&toString()Ljava/lang/S #转换为字符串
&&& move-result-object v0
&&& goto :goto_0 #返回
&&& :cond_1
&&& iget-object v0, p0,Lcom/alipay/android/client/a/j;-&a:Ljava/lang/S #取j.a字符串
&&& if-nez v0, :cond_2
&&& iget-object v0, p0,Lcom/alipay/android/client/a/j;-&b:Ljava/lang/S #取j.b字符串
&&& invoke-direct {p0, v0},Lcom/alipay/android/client/a/j;-&b(Ljava/lang/S)Ljava/lang/S
&&& move-result-object v0
&&& goto :goto_0
&&& :cond_2
&&& new-instance v0, Ljava/lang/StringB
&&& invoke-direct {v0},Ljava/lang/StringB-&&init&()V
&&& iget-object v1, p0,Lcom/alipay/android/client/a/j;-&a:Ljava/lang/S
&&& invoke-virtual {v0, v1},Ljava/lang/StringB-&append(Ljava/lang/S)Ljava/lang/StringB
&&& move-result-object v0
&&& const-string v1,&|&
&&& invoke-virtual {v0, v1},Ljava/lang/StringB-&append(Ljava/lang/S)Ljava/lang/StringB
&&& move-result-object v0
&&& iget-object v1, p0,Lcom/alipay/android/client/a/j;-&b:Ljava/lang/S
&&& invoke-virtual {v0, v1},Ljava/lang/StringB-&append(Ljava/lang/S)Ljava/lang/StringB
&&& move-result-object v0
&&& invoke-virtual {v0},Ljava/lang/StringB-&toString()Ljava/lang/S
&&& move-result-object v0
&&& goto :goto_0
&&& :cond_3
&&& const-string v0,&000&
&&& invoke-direct {p0, v0},Lcom/alipay/android/client/a/j;-&b(Ljava/lang/S)Ljava/lang/S
&&& move-result-object v0
&&& goto :goto_1
.end method
这段代码通过判断j.a与j.b两个字符串并根据情况返回相应的字符串,而j.a与j.b是在j对象的构造函数中赋值的,j.b由getDeviceId()来设置,j.a由getSubscriberId()来设置,具体的代码由于篇幅我就不贴了,由于我手机获取这两个值都不为空,所以,这里返回的字符串为我的SubscriberId,经过SubString(0, 8)后最后得到的密钥为我手机SubscriberId的前8位。到这里,加密密码读取与密钥计算都明白了,还剩下加密与解密方法没有分析。
密码的加密与解密分别调用了“com.google.zxing.c.a.b.a(String, String)”与“com.google.zxing.c.a.b.b(String,String)”方法,两个参数中第一个为需要加密或解密的字符串,第二个为密钥,最终两个方法都调用了“com.google.zxing.c.a.b.a(int , String, String)”方法,转换成JAVA代码如下:
& private static String a(intparamInt, String paramString1, String paramString2)
& &&&&byte[] arrayOfByte =paramString2.getBytes();
&&&&& SecretKeySpeclocalSecretKeySpec = new SecretKeySpec(arrayOfByte, &DES&); //初始化SecretKey
&&&&& Cipher localCipher =Cipher.getInstance(&DES&);
&&&&&localCipher.init(paramInt, localSecretKeySpec); #paramInt为1就加密,为2就解密
&&&&& byte[] localO
&&&&& if (paramInt == 2) {
&&&&&&& localObject =a.a(paramString1); //调用a.a(String)进行一轮运算,返回处理后的字符数组
&&&&&&& localObject =localCipher.doFinal(localObject);&& //进行DES解密
&&&&&&& return newString(localObject );
&&&&& } else {
&&&&&&& localObject =paramString1.getBytes(&UTF-8&); //将需要加密的字符串转成字符数组
&&&&&&& localObject =localCipher.doFinal(localObject);&& //进行DES加密
&&&&&&& returna.a(localObject); //调用a.a(byte[])进行一轮运算,返回最终处理后的字符串
&&& catch (Exception localException)
&&&&&&&localException.printStackTrace();
代码最终进行了DES加密与解密操作,只是其中多了一道“a.a(byte[])”与“a.a(String)&的加密与解密工序,
有过二维码扫描程序编写经验的朋友一定会发现“com.google.zxing”包是一个开源的一维、二维码扫描项目,到GoogleCode上下载该项目的源码,可以发现,上面的代码是经过支付宝修改过的“ReedSolomonEncoder.java”文件,源码位于“zxing-2.0\core\src\com\google\zxing\common\reedsolomon”目录,但没有这个“a.a(byte[])”与“a.a(String)&方法,显示是支付宝手动添加的,而修改过的b类(未混淆则为ReedSolomonEncoder类)的a方法是调用了“com.alipay.android.c.a.a方法”进行字符编码运算,代码位于“com.alipay.android.c”目录中,这个c类提供了四个方法,其中两个为字符处理的判断方法,另外两个分别是加密与解密的代码,限于本人算法能力有限,无法对算法代码进行分析讲解。大家可以参看相关文件来了解它的具体实现,到这里支付宝登录密码的加密与解密也算搞清楚了。
仔细的观察“com.alipay.android.c.a”类,会发现它是一个功能独立的算法类,与支付宝程序的其它逻辑部分无任何耦合,因此,代码编写时我使用了一个取巧的方法,将“a.smali”文件转换成dex文件,然后使用dex2jar转换成jar文件拿到安卓项目中调用,程序的代码如下:
public&void&onCreate(BundlesavedInstanceState) {
&&&&&&&&super.onCreate(savedInstanceState);
&&&&&&& setContentView(R.layout.main);
&&&&&&&&setTitle(&支付宝本地密码查看测试程序&);
&&&&&&&&tv&= (TextView)findViewById(R.id.text_passwords);
&&&&&&&&if&(!RootUtils.hasRootPermission()){
&&&&&&&&&&& Toast.makeText(AlipaypwdActivity.this,&&程序只能在ROOT过的手机上运行&,
&&&&&&&&&&&&&&&&&&& Toast.LENGTH_LONG).show();
&&&&&&&&&&& AlipaypwdActivity.this.finish();
&&&&&&&&if&(!RootUtils.hasInstalledApp(AlipaypwdActivity.this,&&com.eg.android.AlipayGphone&))
&&&&&&&&&&& Toast.makeText(AlipaypwdActivity.this,&&检测到手机上未安装的支付宝软件&,
&&&&&&&&&&&&&&&&&&& Toast.LENGTH_LONG).show();
&&&&&&&&&&&&return;
&&&&&&&&//改权限以便下面进行数据库访问
&&&&&&& RootUtils.RootCommand(&chmod 666 /data/data/com.eg.android.AlipayGphone/databases/RecentDB&);
&&&&&&&&try&{
&&&&&&&&&&& Context context =createPackageContext(&com.eg.android.AlipayGphone&,
&&&&&&&&&&&&&&&&&&& Context.CONTEXT_IGNORE_SECURITY);
&&&&&&&&&&& SQLiteDatabase db=context.openOrCreateDatabase(&RecentDB&, 0,&null);
&&&&&&&&&&& Cursor cursor = db.rawQuery(&select NAME,PASSWORD, TYPE from RecentTable2&,&null);
&&&&&&&&&&& TelephonyManager tm =(TelephonyManager)getSystemService(&phone&);
&&&&&&&&&&& String str =tm.getSubscriberId();&&&&//支付宝用这个ID的前8位做加密密钥&&&
&&&&&&&&&&& Log.v(TAG, str);
&&&&&&&&&&& String subStr = str.substring(0,8);&&&&//只取前8位
&&&&&&&&&&&&byte[] keys =subStr.getBytes();
&&&&&&&&&&& StringBuffer sb =&new&StringBuffer();
&&&&&&&&&&& sb.append(&\n以下为本地保存的支付宝密码解密:\n&);
&&&&&&& &&&&while&(cursor.moveToNext())
&&&&&&&&&&& {
&&&&&&&&&&&&&&& sb.append(&帐号类型:&&+ cursor.getString(2) +&'\n');
&&&&&&&&&&&&&&& sb.append(&用&&户& 名:& + cursor.getString(0) +&'\n');
&&&&&&&&&&&&&&& sb.append(&加密密码:&&+ cursor.getString(1) +&'\n');
&&&&&&&&&&& &&&&sb.append(&解密密码:&&+decryptPassword(cursor.getString(1), keys) +&'\n');&&&&&&&&&&&&&&& sb.append(&----------------------------------------------------\n&);
&&&&&&&&&&& }
&&&&&&&&&&& sb.append(&\n\n以下为测试支付宝密码加密:\n&);
&&&&&&&&&&& sb.append(&原&&密& 码:& +&&&&+&'\n');
&&&&&&&&&&& sb.append(&加密密码:&&+ encryptPassword(&&, keys) +&'\n');
&&&&&&&&&&& sb.append(&----------------------------------------------------\n&);
&&&&&&&&&&& sb.append(&原&&密& 码:& +&&&&+&'\n');
&&&&&&&&&&& sb.append(&加密密码:&&+ encryptPassword(&&, keys) +&'\n');
&&&&&&&&&&& sb.append(&----------------------------------------------------\n&);
&&&&&&&&&&&&tv.setText(sb.toString());
&&&&&&&&&&& db.close();
&&&&&&& }&catch&(NameNotFoundException e1){
&&&&&&&&&&& e1.printStackTrace();
&&&&&&& }&&&&&&&
加密与解密部分代码如下:
&&&&private&StringdecryptPassword(String encryptedPass,&byte[] keys) {
&&&&&&&&try&{
&&&&&&&&&&& SecretKeySpec localSecretKeySpec =&new&SecretKeySpec(keys,&&DES&);
&&&&&&&&&&& Cipher localCipher = Cipher.getInstance(&DES&);
&&&&&&&&&&& localCipher.init(Cipher.DECRYPT_MODE, localSecretKeySpec);
&&&&&&&&&&&&byte[] bytes =com.alipay.android.c.a.a(encryptedPass);//调用支付宝的解密接口对密码进行解密
&&&&&&&&&&& bytes = localCipher.doFinal(bytes);//DES解密
&&&&&&&&&&& String password =&new&String(bytes);
&&&&&&&&&&& Log.v(TAG, password);
&&&&&&&&&&&&return&&&&&&&&&&&&
&&&&&&& }&catch&(Exception e) {
&&&&&&&&&&& e.printStackTrace();
&&&&&&&&&&&&return&null;
&&&&private&StringencryptPassword(String pass,&byte[] keys) {
&&&&&&&&try&{
&&&&&&&&&&& SecretKeySpec localSecretKeySpec =&new&SecretKeySpec(keys,&&DES&);
&&&&&&&&&&& Cipher localCipher = Cipher.getInstance(&DES&);
&&&&&&&&&&& localCipher.init(Cipher.ENCRYPT_MODE, localSecretKeySpec);
&&&&&&&&&&&&byte[] passBytes =pass.getBytes(&UTF-8&);
&&&&&&&&&&&&byte[] bytes =localCipher.doFinal(passBytes);&&&&&&//DES加密
&&&&&&&&&&& String password =com.alipay.android.c.a.a(bytes);&&//调用支付宝的加密接口对密码进行加密
&&&&&&&&&&& Log.v(TAG, password);
&&&&&&&&&&&&return&&&&&&&&&&&&
&&&&&&& }&catch&(Exception e) {
&&&&&&&&&&& e.printStackTrace();
&&&&&&&&&&&&return&null;
最后,程序运行后效果如图8所示:
被混淆过的APK,在分析的时候无疑是十分困难的,尤其是对安卓编程不太熟悉的朋友。因此,这次没有从程序运行流程开始分析,而是采用“症状”式的猜测进行打Log分析,这一方面可以节省分析成本,另一方面也可以真实看到程序运行到某处的结果,为我们的下一步分析提供有效的数据支持。
通过本文以及前几篇安卓程序的分析文章,大家可以发现,对于“ROOT”过的手机,是没有安全可言的,最后,提醒大家要妥善地使用自己的手机,不要随意安装非正规的软件,不到万不得已不要“ROOT”掉手机。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:668113次
积分:8487
积分:8487
排名:第1648名
原创:52篇
转载:814篇
译文:10篇
评论:97条
(1)(5)(14)(7)(1)(7)(4)(2)(3)(5)(1)(4)(3)(6)(7)(2)(5)(5)(5)(2)(5)(2)(4)(8)(2)(11)(6)(9)(11)(14)(17)(35)(82)(13)(9)(56)(44)(71)(55)(142)(118)(16)(22)(35)

我要回帖

更多关于 如何给手机支付宝加密 的文章

 

随机推荐