首先,这道题在《加密与解密》中有完整的分析,那我为什么要再写一遍? 因为这题的脑洞你不自己做过是感受不到的。
文章位于《加密与解密》的5.5 KeyFile保护
文件:http://pan.baidu.com/s/1c1QBKWw 密码:vweu
界面:
首先,上面的那个编辑框不是给你输入用的,所以考虑是从注册表,ini或是其他类型文件读入。
观察程序的api调用,
发现有ReadFile,双击过去下断,上面发现CreateFileA,发现是从一个叫做KwazyWeb.bit
的文件读入。
这里我没有书上那么好的水平,我用ida分析。(以下代码已经重命名过)
- 在call 0x4012CF中有如下一段:
从而得知,注册文件由三部分组成,一字节的len_name,len_name字节的name,18字节的key。
- 以下为calc_name()中的代码:
得知,name_calc为name每一位所对应的ascii数相加以后与0xFF做&(与)运算。
- 以下为sub_4010C9check函数的代码:
这里的string1和string2都是一串很长的字符串,这里我把他dump出来:
1 | ****************C*......*...****.*.****...*....*.*..**********.*..*....*...*...**.****.*.*...****.*....*.*******..*.***..*.....*.*..***.**.***.*...****....*X..***************** |
后面call sub_40101D,我把代码也粘上:
代码很好懂,用name_calc对key每一位异或加密。
来看下面的循环,首先i = 0
,后面有++i != 18
,大循环一共18次;然后对i累加的条件是j = 0
,而j = 8
,j -= 2
,所以小循环是4次,一共循环18*4 = 72次。
(key[i] >> j) & 3
是传入key的每2bits。传入的数据只有0,1,2,3四种可能。
- 再看show_msg()函数:
根据传入的choice,pt_long_str的值会±1,±16。如果指针指向的字符为’*‘,直接失败;如果指针指向的字符为’X’,则成功。后面两句赋值无关紧要。
代码逆向分析完了,
首先我们根据show_msg函数的判断逆出异或后的key_enc,然后根据自己输入的name算出name_calc,然后得到key = name_calc ^ key_enc。然后按照格式创建注册信息文件。
难就难在如何逆出key_enc。一开始我的思路断了。后来在思考为什么是±1和±16的时候恍然大悟,我们只要将之前那一长串字符串按照16位一组然后回车换行,我们就会得到:
1 | **************** |
这就是一个迷宫游戏,从c走到x。1就是向右走,-1就是向左走,16就是向下,-16就是向上。
再根据判断条件编码一下,得到顺序:
1 | move=[2,2,2,1,2,2,2,3,2,2,1,1,0,1,0,0,1,1,1,0,0,3,3,3,0,3,0,0,1,1,1,1,1,2,1,1,0,1,1,2,1,1,1,2,2,3,3,2,3,3,0,3,3,2,2,2,3,2,2,1,1,1,0,0,1,1,1,1,2,2,3,3] |
剩下的就轻松多了,直接上python脚本:
1 | def calc_name(name_str): |
破解成功!
这次逆向最开脑洞的地方就是如何把数据隐藏起来不被轻松dump,之前我做到题都是用算法来隐藏,而这题的思路非常创新,值得我学习。