请注意,本文编写于 1706 天前,最后修改于 1704 天前,其中某些信息可能已经过时。
主要是之前看了《加密与解密》的那本书,对动态调试产生了浓厚的兴趣。并且在完成了一道很简单的crackme的动态调试后,猛然间想起曾经好像还见过一道crackme在BUUCTF上。于是就翻出来看了看,然后啊,然后就是三天结束了。说来也怪我,但是我还是想打出题人。由于这道题的防止动态调试的方法,不是阻止OD运行,而是在你使用调试器的时候,偷偷的改你的算法,让你使用OD出来的东西和你静态分析出来的东西不一样。好巧不巧的是,这次我刚拿到题目,就自己暗暗发誓,我要通过动态调试完成这道题目。emmmmm所以我死得有多惨我觉得也不用我多说了吧。题目涉及考点:
首先我们先打开OD,很容易我们就能找到主体函数,这里的主体函数指的不是主体的加密函数,而是大体的流程。
然我们看一看这些call,有一些call我们可以步过,观察一下变化,我们可以很容易分辨出print函数等,为这些函数打上标签,下次看见就不用再分析了。总体上,看完上部函数,连蒙带猜的应该是是否合规的函数。我们继续往下看,像加密函数的我们就步入看一看。由于习惯,我还是稍微的静态分析了一下,但是着实没有注意居然还有反调试。当时只是看了一下字符串,但是发现字符串中没有判断成功与失败时候弹出的字符串。可能他不太想让你一下就能定位到算法吧。动态调试的时候就看见了这个有趣的CAll。
这里将内存里面的东西经过了一些列不重要我也不想知道的算法,就把字符串给造出来了。这里我分析到一半时看见栈内出现了“con”我就没有一步一步地看了,直接拉下去就完成了这个函数的分析。
之后就是一个拆分的过程,将我们的输入进行了拆分,我当时就在想,应该是建立了一张奇怪的表。
然后我们去找最关键的判断函数,就在这里,我们让条件满足的话,就会输出正确。就是让一个栈(应该是之前处理过的东西被压倒栈中的)与0xab9进行了比较。
然后我们顺着往上寻找,就发现关键的加密函数。
既然是关键的加密函数,我们就应该一句一句的读下去,发现整个算法是在以用户名建立的表为基础的一个异或运算。本身这道题导致里应该结束了。但是算出来的东西不对,这让我纠结了好久。
这是实在没有办法了,觉得自己应该是哪里理解有问题。于是参考了一下题解,静态分析才发现了这道题目的最大的坑。那就是动态调试的时候会执行不同的if代码分支。
这就意味着动态调试中去到的内存并不是真正的正确内存。这里有两种方法,一种就是强型静态分析,完成题目的算法加密。第二种就是在汇编代码处找到反调试的汇编代码,把他nop掉。
这里也就不再演示了。
a="dbappsec"
c=[]
b="welcomebeijing"
d=[0x2a,0xd7,0x92,0xe9,0x53,0xe2,0xc4,0xCD]
for i in range(0,8):
c.append(ord(a[i])^ord(b[i]))
print(c)
for i in range(0,8):
d[i]=hex(d[i]^ord(a[i])).replace("0x",'')
print(d[i],end='')
#flag{d2be2981b84f2a905669995873d6a36c}
这道题虽然因为被坑了一下,导致题目还是看着题解摸索摸出来的。但是整个动态分析我可是一点都没有偷懒,这次我仔细阅读了汇编代码,感觉自己的阅读汇编代码的能力又提升了呢。总体经过这几次的动态调试发现,动态调试虽然没有F5给我们用,虽然看上去汇编代码十分的恐怖,但是一旦自己认真的去阅读之后会发现逻辑比静态分析要清楚很多。并且由于是在程序运行的情况下分析,所以可以随时查看内存中的数据是否被修改。总的来说大概明白了为啥好多程序选择使用反动态调试的方法,阻止逆向手进行程序的动态分析。果然计算机就是语言就是抽象语言的圣经!
全部评论 (暂无评论)
info 还没有任何评论,你来说两句呐!