Rev④
声明:本篇的主要作者 Fish(CCSR小组重要成员之一)
一道中等难度的Reverse题,由蓝鲸安全平台提供。
题目:标准的用户名–密码类型。地址:https://pan.baidu.com/s/12FfpVJ81hxaM71fk1qV0zA
知识点:IDA动态调试
目录
题目解析
直接运行程序,要求输入用户名和密码:

使用IDA反编译该程序的main函数,结果如下图:

- 第一部分为默认自动输出;
- 第二、四部分为干扰程序执行的sleep函数,可以利用IDA动态调试,在循环开始前下断点,然后在循环结束处set IP的方式跳过;
- 第三部分获得输入的Username和Password;
- 第五部分为破解程序的主要关注点。
函数sub_400C9A
该函数通过for循环获得Username的长度,并将长度赋值给i(如果长度大于等于50,则i=50),执行sub_400C41函数。

函数sub_400C41
该函数传入的参数为之前输入的Username的长度,如果不符合4个if判别式的要求,则会输出invalid username or password并退出。

可以通过编写C程序来判断什么数满足该条件(测试了0~99):

python脚本:可知Username的长度必须为8或12。
1 | for i in range(100): |
此外,也可以直接分析该判别式:
- 第四个条件可知a1长度不能超过4位,在1000~1111之间;
- 第一个条件可知a1后两位为00,a1位双数,且是4的倍数;
- 第二个条件可知a1的前两位不能全为0,a1起码大于3;
- 第三个条件可知a1的最高位为1;
- 所以,a1只能为1000或1100,也即Username的长度必须为8或12。
函数sub_400CDD

通过动态调试的方法,可以看出:
- 当Username为8位时,v4对应其高4位,v3对应其低4位,v2为0;
- 当Username为12位时,v4对应其高4位,v3对应其中4位,v2为其低4位;
- 其原因是已经按照每4位进行了赋值。

然后通过列方程的方式解出v4、v3、v2的值:
v4-v3+v2=1550207830v3+3*(v2+v4)=12465522610v2*v3=3651346623716053780
②-3*①即可得到v3的值,带入③得到v2的值,代回①得到v4:
V4=1635017059,即0x61746163,对应ascii码为atac
V3=1953724780,即0x7473796C,对应ascii码为tsyl
V2=1868915551,即0x6F65635F,对应ascii码为oec_
因为是小端序,所以Username为catalyst_ceo。
函数sub_4008F7
这个函数比较简单:如果Username出现了既非_,又非小写英文字母的字符,则报错并停止运行。实际上,如果上个函数已经求出了Username,这个函数就起不到限制效果。

函数sub_400977
这个函数比较长,但后面部分只是简单的重复,所以这里只分析前面部分:

通过计算for循环的限制条件,可知password每位的ascii码必须位于
(47,57]或(64,90]或(96,122],查ascii码表可知password为数字或大小写字母;Srand()函数生成随机数种子,通过分析可知,随机种子是根据Username生成的;Rand()函数生成一个随机数,但由于之前srand()函数已指定了随机数种子,所以每次执行时,生成的随机数是一样的,可以通过IDA动态调试的方法得到十个随机数的值,从而算出v2~v11(v2到v11从高到低各对应password的4位),得到password;
右上角的RAX保存的即是rand()得到的随机数
0x684749,与后面比较时用到的0x55EB052A相加,就得到了password的前四个字母0x56534C73,也即VSLs(因为小端序,所以password开头四个字母实际为sLSV)。后面部分原理与此相同(相加结果如果溢出,移除最高位即可),最终得到password为:
sLSVpQ4vK3cGWyW86AiZhggwLHBjmx9CRspVGggj。
1 | #username |
函数sub_400876

该函数用于输出最后的flag。输入正确的Username和password后,即可得到flag。

总结
这道题整体分析下来并不难,只是看着复杂些而已,在调试过程中需要绕过一些sleep()函数,其他的就是需要耐心调试了。
小组成员Fish,第一次写writeup,大家多多鼓励。