ISCTF2022
我复现所看的Wp来自:
https://www.cnblogs.com/Only-xiaoxiao/p/16859493.html
如果想看Wp 请看上面这篇文章,写得很好,我只是将它的方法记录下来,并且我也有很多地方都没有能够成功的找出flag。看我的只会浪费你的时间。【真的】
5121-babyre
这个题,我分析不来…看了Wp后:
一个5251的编码:
flag{1594826307}
babyopcode
这个是一个VM的题。Wp说很简单,但是我觉得一点都不简单。
首先我们来分析伪汇编的内容。
sub_4111BD
:
fun1
:是一个模仿mov 操作的函数
fun2
:
是一个模仿xor的函数
fun3
:
是一个读取文件的操作。
然后我们来看循环读取指令的操作
就是一直读取,然后遇到F4就结束。
最后看flag的判断的函数
就是执行完上面的“加密”[循环的操作后]flag要和byte_41A000取反后的值相同。
然后就是用脚本来模拟出这些操作:将他弄成伪代码
首先我们找到要执行的代码来进行匹配的数据:
因为我们知道一直到F4就会停止。所以我们就提取数据一直到F4.
借用了下面的大佬写的代码:
https://www.cnblogs.com/Only-xiaoxiao/p/16859493.html
1 | opcode = [0xF5, 0xF1, 0xE1, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, |
1 | read flag |
对于上面的flag[32]不要大惊小怪:
说白了就是先用的flag[0]的数据然后存储到了flag[32]的位置
从比较的地方也能看出来是对flag[32+i]地址上的值来比较
但是我们不知道a1[1]的值是多少哇。因为我们看上面的代码容易知道ebx的值是没用进行变化的。所以我们动态调试的看一下其中的值是多少。
首先看是dw类型的
最后写exp:
1 | enc = [0xBB, 0x80, 0xB2, 0x9E, 0x82, 0xDC, 0x9E, 0xB2, 0xDE, 0x8C, |
或者在线:
easyopcode
和babyopcode基本一样:
1 | opcode = [0xF5, 0xF1, 0xE1, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, |
1 | C:\Users\ASUS\Desktop\ppp\Scripts\python.exe C:\Users\ASUS\Desktop\1.py |
base64
base64换标
1 | import base64 |
Block
不会
easyVM
进来首先是定义了opcode
然后就是一个为while循环来遍历opcode 然后执行代码:
+=
-=
^
主力逻辑不算难,因为大概能猜。主要就是opcde坑人,需要你在动调调试的时候去弄。它和那个不是一一对应的。
1 | opcode = [0x04, 0x0f, 0x31, 0x05, 0x03, 0x95, 0x04, 0x02, 0x59, 0x05, 0x16, 0xf5, 0x01, 0x15, 0x22, 0x01, |
最后借用了一点点网上的Wp 然后写了代码:
输出:
1 | flag[ 15 ]-= 49 |
最后flag进行比较
所以我们逆向:
需要倒叙,+变成- ;-变成+
ezbase
最后是Str1和Str2比较
我们这里动态调试得到Str2的值
1 | flag = [0x5A, 0x6D, 0x78, 0x68, 0x5A, 0x33, 0x73, 0x7A, 0x4E, 0x48, |
base64解码:
final
混淆,可以先看看:
https://firmianay.gitbooks.io/ctf-all-in-one/content/doc/3.2.6_instruction_confusion.html
这个题,进来就是一直跳跳跳,并且还不是jmp的跳转,是ret的跳转,我晕。
他这种调过来跳过去的不影响程序的运行但是妨碍了我们逆向来看,就是代码混淆。
这里简单的看看:
他每跳一下就进行一点点操作。【在我看来】
因为上面的网址说了
1 | jmp {label} |
可以变成
1 | push {label} |
这里我们尝试将跳转该回去用jmp
1 | JMP 的 3 种类型 |
尝试着用:最后EA可以
所以我们使用EA
代码混淆的都在easy里面
然后都是68 ????C3 ==>EA ????00
这里以至于为什么是使用00 而不是90 【nop】。我也不清楚
我们用IDApython来实现【因为太多了】
1 | import idaapi |
然后就能F5了
OK算法对我来说也好难…
SigninReverse
用IDA打开就是flag
simple_flower
进来main函数
报红
跟进push指令、
看到一堆的push pop 没有啥用,就不管了
然后下面有一个call $+5
这句话啥意思不懂。我们就chat一下:
可以理解到’$’的意思就是获取当前指令在内存中的位置。
对于call 指令我的理解就是call 一个地址
。然后就去调用这个地址上的函数。
所以我们就能得到对应的call指令还会讲call指令的下一条指令的地址push到堆栈里面,以至于可以pop 出来返回到主函数。
然后我们在来看:题目中是call $+5。但是对于call指令来说,它本身就是要占用5个字节的。所以这里的call $ + 5 我感觉意义不大,其实就是去执行后面的句子。没有进行跳转,但是它又会push一个地址到堆栈中,在后面的ret的时候又会返回来
但是这个时候我们去看call 和 ret 指令中间代码:
有点点豁然开朗的感觉,感觉中间的代码基本都没有任何意义。
所以我们就把中间的全部给Nop掉
1 | import idaapi |
选中整个区域重新分析一下然后打包成函数:
如何选中这么大一篇的范围呢?
首先找到你要重新分析开始的位置:“ALT+L”
然后用鼠标点击你选中的位置的末尾就可以了
得到一个这样的F5后的。
因为之前知道有很多push pop 都是没有什么作用的,所以我们尝试将他也全部nop掉
我去nop掉后发现好像没啥变化,不知道是我的问题还是本身就不会发生变化。。。
1 | import idaapi |
虽然我上面这个代码第一段的nop掉4个但看有点点问题,因为它本身是实现了一个mov eax ,ecx。但是它交换了偶数次就不影响了。
但是我反编译出来的东西还是非常的难懂。。
可能是我弄错了吧。
这里就用大佬的IDC脚本吧
1 |
|
最后就呈现出来的函数:
看起来就好了很多。
这里我们重新来看看它去除冗余指令
好吧最后我屈服了,不想看了:
1 | veryEasy:004094C4 51 push ecx |
最后放上大佬分析的内容。以上的内容都是没有作用的全部NOP掉就好了。
。。真的会又程序这么多的没有用的代码吗》。