最近在研究逆向工程,做了一些ctf题,今天遇到的这个问题卡了我很长时间才拿到flag。事后分析这道题暴露出我的一个思维短板:形象思维总是盖过逻辑思维,太相信直觉,于是总也拿不到正确结果。
核心算法如下:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
TextList = [?,?,?,?,?,?,?]#列表长度是7,元素内容未知
dw=0x02
v38 = [0x62,0x39,0x62,0x37,0x64,0x64,0x31]
v39 = [0x79,0x65,0x6e,0x6f,0x6d,0x6f,0x6e]
for i in range(7):
TextList[6-i] ^= v38[i] ^ dw ^ v39[i]
dw = TextList[6-i]
print "CipherList is:",
------------------------------------------------------
已知密文是:
CipherList = [0x51,0x3c,0x0f,0x67,0x5c,0x2c,0x41]#密文
已知密文CipherList,让反推出明文,属于很常见的逆向题目。
这个算法有几方面增加了过程的复杂度和迷惑性,1)对列表元素的处理是逆序处理的;2)^=操作;3)dw的值每个循环都在变化。这些处理过程成功迷惑了我,使得我认为逆运算就是这个算法本身!因为我把关注点都放在了TextList[6-i] ^= v38[i] ^ dw ^ v39[i]这行代码,我认为名文就是"密文 xor v38 xor v39 xor dw",而忽略了dw值是否正确。
实际上,为了得到正确的明文,你必须获取到正向运算中的dw值,但是按照我最开始的想法“逆运算就是它本身”,得到的dw值根本就不是正向运算中的值。因为忽略了这一点,所以永远也不会得到正确答案。
其实现在看来我最开始的想法是很低级错误的,根本原因是对逆运算的分析错误,再根本的原因是对逆向的理解不正确。我原来更多将逆向的关注点放在算术操作上,也就是那些异或操作。实际上,为了得到正确的逆向结果,不仅操作要正确,过程中的数据也要正确。
而且,为了降低代码的迷惑性,也可以把那一行异或操作展开,改为"TextList[6-i] = v38[i] ^ dw ^ v39[i] ^ TextList[6-i]"。
下面附上正确的逆运算代码:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import random
dwlist = [0x02,0x41,0x2c,0x5c,0x67,0x0f,0x3c]
PlainTextList = [0,0,0,0,0,0,0]
CipherText = [0x51,0x3c,0x0f,0x67,0x5c,0x2c,0x41]#密文
v38 = [0x62,0x39,0x62,0x37,0x64,0x64,0x31]
v39 = [0x79,0x65,0x6e,0x6f,0x6d,0x6f,0x6e]
l1 = []
l2 = []
for i in range(7):
PlainTextList[6-i] = v38[i] ^ dwlist[i] ^ v39[i] ^ CipherText[6-i]
resStr = ""
for j in PlainTextList:
resStr += chr(j)
print resStr#key is:28ac|1X
#username is:nsfocus