标签:
记录下两个逆向的writeup,第二个还是有点费事的。
题目比较简单,算法也很简单,求用户名为ctfking的注册码。
注册码需要满足条件:
1. 全是数字 2. 长度10的倍数 3. 由serial经过算法生成的serial_gen和由用户名ctfking生成的name_gen相等
如下图:
下面简单分析下算法:
Serial_gen 由 输入的serial的每一个字节模上一个从9开始依次递加的值。由于用户名已经固定,即ctfking。所以调试后,可以直接发现name_gen为0x8c,进而直接写了几行脚本爆破一下,秒出结果。
直接定位到关键位置
在handle函数内,inputstring必须满足xxxxxxxx-xxxxxxxx的格式,并将前8个字节和后8个字节转为两个整数存在v8和v7当中。
举个例子,如果输入格式为12ab34cd-ab345678,那么v8=0x12ab34cd,
v7=0x12ab34cd ^ 0xab345678。
在judge函数内判断这两个整数是否满足条件,如果满足条件,那么注册成功。
重点在judge函数内。
算法比较简明,所以我的重点就是如何求出一个符合条件的num1和num2。暴力搜索的话,搜索空间太大,我们可以对算法分析来减少搜索的范围。
v4形成的字符串String1需要满足等于String2,而v7就是机器码,都已知。
如图中所示,*v4++ = num1 ^ ( v7 – num2 ),记lsb(i)取i的最低位,根据此,我们可以知道,Lsb(*v4++) = lsb(num1) ^ lsb(v7) ^ lsb(num2),那么我们就能知道lsb(num1) ^ lsb(num2)。那么经过32轮循环后,我们可以知道了 num1 ^ num2的值。
记byte0(i)为整数i的低8位,byte1(i)为整数i的[8,16]位,byte3(i)为整数i的[16,24]位,byte4(i)为整数i的最高8位。
如果仔细琢磨的话,会发现,每当循环移位8次后,就会运算到num1和num2的byte0、byte1、byte2、byte3中的一个。
也就是说, String2[0] = byte0(num1) ^ (String1[0] – byte0[num2]),即,String2[0] ^ byte0(num1) ^ byte0(num2) = byte0(num2) ^ (String1[0] – byte0[num2])。而num1 ^ num2我们已经得到,所以byte0(num1) ^ byte0(num2)也已经知道,byte0[num2]总共256中情况,遍历这256种情况也就可以确定byte0[num2]可以取哪些值。
同理,可以确定byte1[num2]、byte2[num2]、byte3[num2],从而确定num2可以取的范围,因此,大大缩小了搜索空间。
根据上述的思想,写出下列脚本,几秒出注册码。
标签:
原文地址:http://www.cnblogs.com/wangaohui/p/4970278.html