[【通过】] 深入解析Android系统屏幕锁

[复制链接]
胡椒和盐 发表于 2017-3-15 09:15:32 | 显示全部楼层 |阅读模式

正式成员|主题 |帖子 |积分 6

Android系统的屏幕锁有9宫格、PIN锁和密码锁3种方式。在9宫格方式下,图案中的每个联通的点的坐标会组成一个字符串,通过计算这个字符串的MD5值,并将其与/data/system/gesture.key中存储的值进行比较,来确定输入是否合法(参考资料1)。对于其他两种模式,参考资料不多。本文将通过分析相关的Android源代码来剖析其他两种屏幕锁的运行机制和安全性。分析基于Android -19,其他版本在功能上大致相同,需要注意的不同之处会在文中给出说明。
密码文件
9宫格模式使用的密码文件是/data/system/gesture.key,文件内容为9宫格图案中点坐标MD5值的16进制字符串形式,文件长32字节。在该目录下,还有一个password.key文件,长72字节,存放的就是PIN锁和密码锁使用的key。虽然这两种锁模式的表现方式不同,但是他们的处理方式在内部是一样的。尽管这个文件里也是存放的Hash值,但是文件长度表示,它使用的应该是扩展的Hash函数。
计算Hash值得函数在源文件LockPatternUtils.java中,
public byte[] passwordToHash(String password) {
.......
            byte[] saltedPassword = (password + getSalt()).getBytes();
            byte[] sha1 = MessageDigest.getInstance(algo = "SHA-1").digest(saltedPassword);
            byte[] md5 = MessageDigest.getInstance(algo = "MD5").digest(saltedPassword);
            hashed = (toHex(sha1) + toHex(md5)).getBytes();
......
        return hashed;    }
从这段代码中可以看到,使用的Hash函数形式为,
                sha1(salted-password)|md5(salted-password)
也就是说,这里使用了SHA1和MD5两个Hash函数,他们的结果加起来,才是我们需要的新的Hash值。
组合使用Hash函数的方式在应用密码学中非常普遍。区别于标准的MD5和SHA1,这种“非标准”的函数形式,通常情况下其安全性要高于单独使用的、“标准的”Hash函数。例如,对于上面的计算函数,即使找到了一个字符串,其MD5值和后32个字节相匹配;因为其SHA1值未必同前40个字节相匹配,所以最后的计算结果也未必能匹配,这进一步提升了Hash函数的安全性。
加盐的密码
从函数passwordToHash中可以看到,用户输入的字符串并不直接用在计算Hash值上。
byte[] saltedPassword = (password + getSalt()).getBytes();
用户输入的字符串在末尾加上了getSalt()函数的返回值,构成一个新字符串。这个操作就是密码学中所谓的加盐:在计算Hash值之前,在明文字符串的指定位置加上一些特定的字符串。
这里的关键是获取salt的getSalt(),
private String getSalt(){
long salt=getLong(LOCK_PASSWORD_SALT_KEY, 0);
...
return Long.toHexString(salt);}
这个函数也可以在文件LockPatternUtils.java中找到。其中,
public final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
也就是说,getSalt函数通过调用getLong函数获得一个64位Long型数值,并将其转换成16进制字符串附加在用户输入的字符串末尾,从而得到新的密码字符串。
getLong函数为,
private long getLong(String secureSettingKey, long defaultValue) {
        ...
return getLockSettings(). getLong ( secureSettingKey ,  defaultValue ,
                    getCurrentOrCallingUserId ( ) ) ;
        ...
从上面的代码可以看出,它最终会调用LockSettingsService的getLong函数来实现其功能。在LockSettingsService.java中可以找到getLong的实现,
public long getLong(String key, long defaultValue, int userId) throws RemoteException{
...
String value=readFromDb(key, userId);
return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);}
也就是说,getLong返回的salt是从数据库中读取的一个值。通过检查readFromDb函数,可以发现,程序从数据库locksettings.db中读取表locksettings中name列为lockscreen.password_salt的记录,其value列就是我们要找的salt值。
文件位置
我的测试机为联想S899T,版本为Android 4.0.3.在尝试读取文件/data/system/locksettings.db时,发现找不到这个文件。通过分析Android 4.0.3的源代码发现,数据库文件是/data/data/com.android.providers.settings/databases/settings.db,表名为secure。

破解
通过上面的分析可以看出,在PIN模式密码下,用户输入为4位数字,暴力破解可以很简单的解决问题。在密码模式下,用户输入为4~16位数字、字符,密码只要设置得当,破解是非常费时间的。下面是破解步骤,
1.        导出/data/system/password.key文件.
2.        导出/data/system/locksettings.db文件。
3.        读取locksettings.db中locksettings表name列为lockscreen.password_salt的记录的value。
4.        根据步骤3的结果构造密码password,计算key=sha1(password)+md5(password)。
5.        比较key和步骤1获得的password.key,相同,key就是要找的密码;否则转步骤4继续构造新密码.
参考资料
《Android图形锁破解》,《黑客防线》,2013年第4期。

评分

参与人数 1酒票 +5 收起 理由
管理05 + 5 欢迎加入90!

查看全部评分

快速回复 返回顶部 返回列表