也许每个人出生的时候都以为这世界都是为他一个人而存在的,当他发现自己错的时候,他便开始长大

少走了弯路,也就错过了风景,无论如何,感谢经历


本篇文章遇到排版混乱的地方,可点击文末阅读原文或前往该地址:https://orangey.blog.csdn.net/article/details/126219765

更多关于Android安全的知识,可前往:https://blog.csdn.net/ananasorangey/category11955914.html

android密钥保护(Android加密算法浅析)(1)

android密钥保护(Android加密算法浅析)(2)

0x01 前言

车机渗透,博主感觉大致可分为:软件层、系统层、硬件层

例如,我们测试软件层以及系统层的时候,会关注一些加密算法以及该密码或敏感数据是否加密或加密后又如何解析,它们又存放在哪个位置等等。

例如,Android设备(也可以是手机,也可以是智能大屏等)解锁屏幕时输入的密码,那么这个密码存放在哪里?是否为明文存储?如果是加密存储,那么加密算法是什么?

例如,连接一些车机WI-FI时,为了安全考虑会要求输入PIN码才能连接成功,那么此时我们要考虑该PIN码输入的密码,那么这个密码存放在哪里?是否为明文存储?如果是加密存储,那么加密算法是什么?

0x02 Android加密算法浅析

这里以Android 里面的锁屏为例,来对加密算法了解,以点盖面

Android 设备中常见的锁屏密码主要有两种:一种是手势密码(九宫格密码图);一种是输入密码,分为PIN密码和复杂字符密码,而PIN密码就是数字密码,比较简单;还有一种是指纹密码

我们这里主要关注PIN码来说说,通过工具获取当前PIN输入界面的View类,然后定位到一个锁屏密码工具类:lockPatternUtils.java

此处,大家可以思考一个小问题:假如有一台智能后视镜,智能电视机等硬件设备, 本身开启热点,但需要输入PIN码才能接入,但当前设备可root接入,你会怎么办呢?是拆卸机器从串口进行攻击?还是adb进入系统?

这里以5.1版本的源码进行分析,至于真机或模拟器,当前按照自身条件来。

2.1 源码编译(此处可跳过)

mkdir ~/bin PATH=~/bin:$PATH curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo chmod a x ~/bin/repo

编辑 ~/bin/repo,把 REPO_URL 一行替换成下面的:

REPO_URL = 'https://gerrit-googlesource.lug.ustc.edu.cn/git-repo'

android密钥保护(Android加密算法浅析)(3)

然后repo sync 一下同步

android密钥保护(Android加密算法浅析)(4)

后续步骤省略,,自行查找。网上容易出现问题的是源地址错误等问题。

Windows 下载Android源码教程链接

模拟器博主用的是夜神模拟器(夜神默认手机机型是三星,大家可切换一下机型方便测试):

android密钥保护(Android加密算法浅析)(5)

探测一下试试是否能成功连接夜神模拟器:

adb connect 127.0.0.1:62001 adb devices adb shell

博主,编译老是出错,最后直接下载现有的好了,地址如下(Android 5.1.1):Android 5.1.1源码

2.2 Android 锁屏源码浅析

源码下载好后,开始正式进入正题,定位到锁屏的java代码,了解锁屏界面输入密码的规则,此处我们使用Android-SDK 3.0.1 (这里你也可以使用最新版的,都是一样的)中的uiautomatorviewer.bat(该工具默认是安装在C盘当前用户的/AppData/local/Android/Sdk/tools/bin目录下)工具分析获取当前的锁屏View类LockPattern,一步步追踪,最终会跟到一个包名为com.android.internal.widget锁屏密码工类:LockPatternUtils.java,如下图:

下载地址:https://developer.android.com/studio/archive?hl=zh-cn

锁屏代码的目录路径:frameworks/base/core/java/com/android/internal/widget/LockPatternView.java

如果是,下载的Github的源码的话在文件的android\internal\widget目录下

checkPasswordHistory的方法,这个方法就是来对比密码是否一致的,能否成功解锁手机的

android密钥保护(Android加密算法浅析)(6)

passwordToHash方法就是输入密码的算法,继续跟踪(passwordToHash()方法):

android密钥保护(Android加密算法浅析)(7)

从上面代码的注释中已经告诉我们,这个View是用于绘制九宫格和手势密码的地方。passwordToHash 方法中的参数为用户输入的密码和当前用户对应的id,一般设备不会有多个用户,所以这里的userId是默认值0。再往下看就是加密算法了:原文密码 设备的salt值,然后分别进行SHA-1和Md5加密,将数据复制到一个数组中后转换成Hex编码进行拼接,得到的就是最终保存到本地的加密密码内容。而这里最重要的是如何获取设备对应的salt值,这可以跟踪代码(getsalt()方法):

android密钥保护(Android加密算法浅析)(8)

查看getsalt方法(如何获取到设备对应的salt值),long salt = getLong(LOCK_PASSWORD_SALT_KEY, 0, userId);,首先根据字段key为lockscreen.password_salt从某个地方获取salt值,通过if判断该值为0的话,就调用SecureRandom.getInstance("Sha1PRNG").nextLong()随机生成一个,然后将其保存到key为LOCK_PASSWORD_SALT_KEY的那个方法,最后将salt值转换为Hex值即可,继续跟踪代码(getLong()方法):

android密钥保护(Android加密算法浅析)(9)

应该是把密码保存起来了,继续跟踪代码(getLockSettings()方法):

android密钥保护(Android加密算法浅析)(10)

通过getLong()方法发现这个地方用了AIDL类型,通过在ServiceManager中获取一个服务来进行操作,那么它应该是有相应的Service类,这里是在包名为com.android.server.locksettings下的LockSettingsService.java类,找到这个类,查看它的getLong方法

frameworks/base/services/core/java/com /android/server /LockSettingsService.java

如果是,下载的Github的源码的话在文件的com\android\server目录下

android密钥保护(Android加密算法浅析)(11)

到此,我们已经可以确定该Service类是保存在数据库中的了,而且在LockSettingsService构造方法中存在SQLiteDatabase的字眼

PS:SQLiteDatabase代表一个数据库对象,提供了操作数据库的一些方法

android密钥保护(Android加密算法浅析)(12)

android密钥保护(Android加密算法浅析)(13)

这里调用了mStorage方法,继续跟踪代码

android密钥保护(Android加密算法浅析)(14)

从上图中的mStorage = new LockSettingsStorage(context, new LockSettingsStorage.Callback() 可以看到,将输入的密码存放到了数据库中,继续跟踪代码:

到LockSettingsStorage方法中去看一下

android密钥保护(Android加密算法浅析)(15)

android密钥保护(Android加密算法浅析)(16)

数据库名字叫做:locksettings.db,那么它保存在哪里呢?

android密钥保护(Android加密算法浅析)(17)

两个key文件,那么这个就是用来保存加密之后的手势密码和输入密码的信息到本地,下次开机解锁就需要读取这个文件内容进行密码比对了,查看具体的存在路径:

find -name / locksettings.db

android密钥保护(Android加密算法浅析)(18)

SQLite Expert Professional 是一个专用高级可靠的工具,旨在帮助大家同时管理多个数据库,并且执行各种数据库语法。由于所有菜单功能集成到一个简约易懂的窗口中,刚入门的人员和专业人员都能很好的掌握该工具。在主窗口中,用户可以直接明了的查看所有已连接的数据库,并使用相关的语法进行操作。左侧区域为可用表,能够进行字段重组、外键、触发器等功能,并且不会丢失任何数据库信息。如果需要连接或者打开新的数据库,则可以通过菜单中的文件选项进行操作,并为文件名或者新数据库重新命名。除此之外,该工具还能轻松处理并纠正故障,保证数据库不会受到外界的干扰和影响。

首先设置锁屏密码(模拟器中设置锁屏密码):

android密钥保护(Android加密算法浅析)(19)

PS:

/data/data/com.android.providers.settings/databases/databasessettings.db(Android 4.0及以前) /data/system/locksettings.db(Android4.1及以后)

单独拷贝locksettings.db 是没数据的,如下:

android密钥保护(Android加密算法浅析)(20)

应该将locksettings.db-shm、locksettings.db-wal 一起拷贝出来

adb pull /data/system/locksettings.db adb pull /data/system/locksettings.db-shm adb pull /data/system/locksettings.db-wal

android密钥保护(Android加密算法浅析)(21)

salt值:-2428488924405522123

还有一个加密密码Key文件

adb pull /data/system/password.key .

E03FF03CA6C923FC3D7BE13ECA1AD9E159917CD7F901431E8569A3F7F815E570E758EBD5

最终的值应该是类似这样的(MD5(输入明文密码 设备的salt).Hex SHA1(输入明文密码 设备的salt).Hex就是最终的加密内容)拼接起来就是密码:

android密钥保护(Android加密算法浅析)(22)

android密钥保护(Android加密算法浅析)(23)

但我这里借出来跟原生程序不太一样,发现是模拟器用的是三星的系统,这个系统对锁屏做过修改,没有用原生程序,网上有代码说是做了1024次Sha1运算,此处可以使用hashcat 爆破,三星做了1024次Sha1运算代码如下:

public byte[] passwordToHash(String paramString) { if (paramString == null) return null; String str = null; byte[] arrayOfByte1 = null; try { byte[] arrayOfByte2 = (paramString getSalt()).getBytes(); byte[] arrayOfByte3 = null; str = "SHA-1"; MessageDigest localMessageDigest = MessageDigest.getInstance(str); long l1 = System.currentTimeMillis(); for (int i = 0; i < 1024; i ) { arrayOfByte1 = null; if (arrayOfByte3 != null) localMessageDigest.update(arrayOfByte3); localMessageDigest.update(("" i).getBytes()); localMessageDigest.update(arrayOfByte2); arrayOfByte3 = localMessageDigest.digest(); } arrayOfByte1 = toHex(arrayOfByte3).getBytes(); long l2 = System.currentTimeMillis(); Log.w("LockPatternUtils", "passwordToHash time = " (l2 - l1) "ms"); return arrayOfByte1; } catch (NoSuchAlgorithmException localNoSuchAlgorithmException) { Log.w("LockPatternUtils", "Failed to encode string because of missing algorithm: " str); } return arrayOfByte1; }

PIN或复杂密码,因为salt 值是随机的,且输入密码加salt后再sha1 md5拼接复杂的多,所以安全性相对九宫格密码要安全一些

参考链接:

http://blog.md5.red/?p=456

http://www.520monkey.com/archives/1022


你以为你有很多路可以选择,其实你只有一条路可以走


,