论坛中某锁机软件破解及注册码计算过程
起因
最开始是今天下午在论坛病毒样本区发现了这个锁机软件,出于学习与助人的目的对该锁机软件进行了逆向分析。并编写了注册机注册代码。原帖的地址贴在下面。
https://www.52pojie.cn/thread-1757174-1-1.html
直入主题
该锁机软件,共需要解锁三次。每次注册码的计算都大体上相同,但是有细微的区别。
这里先给出注册码计算代码
# "❥" - 0
# "★" - 1
# "♬" - 2
# "♁" - 3
# "✄" - 4
# "啊" - 5
# "௵" - 6
# "✿" - 7
# "ぇ" - 8
# "◎" - 9
import hashlib
import re
def MD5(s):
s += "23543dfggeelysdafaqj23ou89ZXcj@#$@#$#@KJdjklj;D../dSF.,"
md5 = hashlib.md5()
md5.update(s.encode('utf-8'))
return md5.hexdigest().upper()
def SHA1(s):
sha1 = hashlib.sha1()
sha1.update(s[:-1].encode('utf-8'))
return sha1.hexdigest().upper()
register = "1422165"
res = re.sub(r'\D+', '', SHA1(MD5(register)))[:9]
# "6D91290A4382B010643970816C4548D6" 290
# "E48DAFD477C1AE9A01D5555585938D86" 100
# "A7BDC7CED8416DB0E2C6ADA4FEE8007C" 800
print("Your password1 is :", "290" + res)
print("Your password2 is :", "100" + res)
print("Your password3 is :", "800" + res)
对于第一个锁机页面,其布局如图,我们需要点击大概60+次右下角的需要解锁加群按钮,然后蓝色按钮上方就会出现输入框。对于注册码的计算。我们需要先将识别码按上方代码中的注释对照表。按照图标-数字 一一对应,转化为注册码填入输入框中,之后点击蓝色按钮,可以通过第一层锁机界面来到第二层。如图中的★✄♬♬★௵啊
,将其转换成与之对应的注册码为1422165
。我们将该转换得到的数字填入上方代码中,运行脚本。紧跟输出Your password1 is :
之后的就是第一层锁机的注册码。
原谅我对图片打这么多码,因为我知道不打这么厚的码,图片是无法过审核的。同时该锁机软件在运行时还会发出令人社会性死亡的声音。并且自动将你手机音量开至最大无法关闭。
那么对于图片中的识别码,我们可以计算出来第一层密码为 290304753532
来到锁机第二层,界面变得比上层友好了一些,但仍旧伴有令人羞耻的声音。计算方法同上,将字符识别码转化为数字,填入python脚本中,紧跟着输出Your password2 is :
之后的就是你的第二层锁机密码。
这里我们的解锁密码为100841573560
最后一层计算同理,这里我们的解锁密码为800948640024
全部解锁完毕后,声音依旧不会消失。这时把软件卸载即可。声音与锁机界面再也不会出现。
软件分析
正如原帖子中提到的。这个锁机机软件对smali代码进行了混淆。这里的混淆实际上比较简单,做的就是在调用类的方法时,将其转换为一个函数调用的过程。几乎所有java中的方法都进行了这样的转换。其主要表现形式如下方的代码,并且对于java中的变量名使用了一些unicode字符作为变量名。这些unicode 字符不仅长得相似还难以区分。如下方这个代码中,你调用bb这个函数,实际上就是在执行一个判断两个字符串是否相等的方法而已。当这样的混淆很多,并且结合unicode变量名的时候。代码看起来就很混乱。
public static boolean bb(String arg2, Object arg3) {
return arg2.equals(arg3);
}
对于如何反混淆这个问题,经过一番搜索后,我搜索到一个android通用反混淆工具 simplify。不过我在使用之后,发现它对于这个样本中的混淆并不能很好的去除,反混淆得到的dex文件,在jeb中看与原dex基本没有区别。所有这里我还是选择通过JEB去调试与分析apk中的注册码的计算过程。在逆向过程中我也考虑过是否可以使用frida框架来hook获取某些函数的返回值。但最后并没有使用,第一点是我本身对于frida并不是很熟悉,第二点则是这里java中的关键部分类名都是unicode字符,几乎复制不出来。如果编写frida hook脚本我不知道能不能正常hook。
对于smali中的变量名混淆,我选择的是使用JEB的变量重命名功能来批量对自己所关心的变量进行重命名。而将方法转换为函数调用的混淆。我则是去硬阅读代码与结合调试分析。毕竟将方法与函数进行一一映射这个逻辑还是比较容易去理解。同时也可以通过对函数一些名称进行重命名,这样看见函数名就可以知道它调用的是什么方法。
下面给出一些我逆向过程中的关键分析。
所有逆向中最关键的是在 com.mycompany.myapp7.chengnan 这个类,这个里实现的加盐的md5算法,与去掉最后一个字符进行sha1哈希计算的算法。
在chengnan这个类中
对于md5 我们的盐是储存在类的一开始。进行md5计算时会将盐一起附在需要计算的字符串后面。
通过函数中的一些字符串信息,我们可以去猜测这里使用的是md5加密算法。并且调试去验证这里是一个标准的md5加密算法。且返回结果为大写的md5结果。
sha1 加密算法也可以从图中找到。这里需要注意的是。红框中的这个函数调用做的一件事是将传入的字符串,截掉最后一位然后返回。所以其实v1 的值是 arg7[:-1] 这样的字符串。
然后是我们需要关心的第一个锁机界面的,验证密码的类。它原本的名字是一个unicode字符,如红框中。在这里我将他重命名了一下,箭头指向的。
这个类的特征是一开始有这样一个数组的定义
对于第一个锁机页面我们需要关心的代码如下。
首先第一个红框是获取我们的输入,也就是密码。并判断它的长度。
第二个红框里的小框就是获取我们的识别码,在这里它是每一次都会随机生成的一个随机数。
然后大红框里所做的事就是对转换成数字的识别码先进行加盐的md5加密,然后进行截断掉最后一位的sha1加密。sha1之后得到的结果我们还要通过正则匹配将其中的所有非数字字符替换为空。只保留下数字字符。并且最后得到的纯数字字符串,它的长度要大于9。
下面的if 条件判断就是在判断我们输入的密码经过加密后与识别码计算得到的结果是否相同。计算过程如下。
首先将我们上方通过识别码得到的纯数字字符串。将其截取前9位并凭借在"6D91290A4382B010643970816C4548D6"
字符串后得到我们的字符串一。
而我们的输入的密码进行了哪些计算呢。我们输入的密码被分隔成了两份,前三个字节作为第一份。后面作为第二份。前3个字节先进行sha1计算再进行md5计算。后面的部分直接与三个字节计算得到的结果拼接起来得到字符串二。
这个时候我们就发现了,"6D91290A4382B010643970816C4548D6"
字符串实际上是与我们md5哈希计算后得到的结果长度是相同的,所以我们输入的密码的前三个数字一定是固定不变的。并且由于是先进行的sha1计算再计算md5。这个样本的sha1计算会截断最后一位。所以我们只需要爆破前两个字节即可得到前三个数字是什么数字。爆破代码如下
def MD5(s):
s += "23543dfggeelysdafaqj23ou89ZXcj@#$@#$#@KJdjklj;D../dSF.,"
md5 = hashlib.md5()
md5.update(s.encode('utf-8'))
return md5.hexdigest().upper()
def SHA1(s):
sha1 = hashlib.sha1()
sha1.update(s[:-1].encode('utf-8'))
return sha1.hexdigest().upper()
l = [chr(i) for i in range(0x21, 0x7f)]
for c1 in l:
for c2 in l:
for c3 in ["0"]:
if MD5(SHA1(c1 + c2 + c3)) == "6D91290A4382B010643970816C4548D6":
print(c1 + c2 + c3)
# 290
所以对于第一层锁机密码的前三个数字我们已经得到。而后面9个数字实际上就是通过识别码计算得到的了。计算方法在上面已经解释了。先md5再sha1。去除掉非数字字符,截取前9位就是我们的最后9个数字。拼接在一起就是我们第一层锁机的密码。
第2 3层锁机密码计算过程相同,只不过对于前3个数字的加密结果做了更改。分别为"E48DAFD477C1AE9A01D5555585938D86"
与 "A7BDC7CED8416DB0E2C6ADA4FEE8007C"
我们同样可以用上方代码进行爆破。
得到结果如下
# "6D91290A4382B010643970816C4548D6" 290
# "E48DAFD477C1AE9A01D5555585938D86" 100
# "A7BDC7CED8416DB0E2C6ADA4FEE8007C" 800
这也就是我们上方计算密码的python脚本中的注释。
结束语
至此这个锁机软件已经分析完毕。作为潜水论坛多年的底层人员,这次也终于对论坛有了贡献,如文章中有不足之处,也希望各位大佬能够指出并包涵我的错误。同时最后也要提醒大家对于不明软件不要乱安装,同时不要乱给权限即可保证安全。下面我还会打包一份我修改过的锁机样本。将其中令人会社会性死亡的音频给替换掉了以供大家学习。不然在你分析锁机软件时,手机一直发出奇怪的声音,那么也不能安心分析软件了。
压缩包的解压密码为 52pojie
链接:https://pan.baidu.com/s/1ZMGPGf2PM8F3FOcCdqpdXw?pwd=541r
提取码:541r