- 东南的平台又放了新题,这次决定都做一下试试,在这里记录解题过程,因为是平时练习,我会尽可能多的把思路和解法写全,鉴于东南平台的wp不是很多,也方便下一届萌新的自主练习.平台地址:http://sus.njnet6.edu.cn
helloworld
- 逆向签到题,直接f5看到内部if条件即可
- 抛开f5,分析一下汇编,首先是函数头部连续mov到栈中的数据,也就是flagenc
1 2 3 4 5 6 7 |
mov dword ptr [ebp+flag], 0C881E8F1h mov dword ptr [ebp+flag+4], 0CECF81D2h mov dword ptr [ebp+flag+8], 81C081D5h mov dword ptr [ebp+flag+0Ch], 0C8D5C0D3h mov dword ptr [ebp+flag+10h], 0CDC0CFCEh mov dword ptr [ebp+flag+14h], 0CCD4CF81h mov dword ptr [ebp+flag+18h], 8FD3C4C3h |
- 之后程序%d读入数字,随后cmp比较
1 2 3 4 |
add esp, 10h mov eax, [ebp+n] cmp eax, 12B9B0A1h jnz short loc_804852D |
- 随后进入字符串解密的过程,lea将偏移地址给了edx,然后吧eax偏移取了以后,将*eax的值给到eax,如果eax不为0,那么进入一个汇编块中
1 2 3 4 5 6 7 8 9 10 11 12 |
lea edx, [ebp+flag] mov eax, [ebp+i] add eax, edx movzx edx, byte ptr [eax] mov eax, [ebp+n] mov ecx, edx xor ecx, eax lea edx, [ebp+flag] mov eax, [ebp+i] add eax, edx mov [eax], cl add [ebp+i], 1 |
- 我们可以看出来,首先按照i获取偏移,然后将值传给edx,接着是将刚才输入的n的值的一byte传给eax,随后进行一个异或然后从新把值赋会到flag[i],然后进行i++.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
from struct import pack def p32(i): return pack("<I", i) a = [0xC881E8F1, 0xCECF81D2, 0x81C081D5, 0xC8D5C0D3, 0xCDC0CFCE, 0xCCD4CF81, 0x8FD3C4C3] t = "" for i in a: t += p32(i) flag = "" for i in range(len(t)): flag += chr(ord(t[i])^0xa1) print flag |
simple-rev
- 先说正常做法:ida定位main函数,f5,发现读入后进行一个循环遍历,非空或者回车的,每位加上1,最后一个字符串比较,逆向过程即为每位字符串减一
- 汇编的话,函数头fgets读入z字符串,给栈空间的i赋值为0,将数组的首地址给到edx后继续取偏移,值为为0时跳出到strcmp所在代码块中,否则进入一个循环
- 循环内还有两个判断,一个是为0xa跳到的循环,一个是非0xa的循环,内部汇编比较清晰,获取偏移随后add加一
1 2 3 4 5 |
a = [ord(i) - 1 for i in "UIJT.JT.ZPVS.GMBH"] flag = "" for i in a: flag += chr(i) print flag |
bitx
- 很像asi3的题,简直是一样的,没有那个题复杂,但是主要算法就是一行
- 另一个题目经常被拿来用于做符号执行的讲解,这里说一下符号执行,因为命令行符号执行默认参数范围的问题,会从0开始输入,然而这样会截断我们的输入,所以我们要加上一些限制,脚本如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
import angr import claripy p = angr.Project("./bitx",auto_load_libs=False) arg1 = claripy.BVS('arg1', 50*8) args = [p.filename,arg1] s = p.factory.entry_state(args=args) for byte in arg1.chop(8): s.add_constraints(byte != '\x00') s.add_constraints(byte >= ' ') s.add_constraints(byte <= '~') simgr = p.factory.simgr(s) simgr.explore(find = 0x8048508,avoid = 0x804851A) print simgr.found[0].solver.eval(args[1], cast_to=str) |
mozhucy@ubuntu:~/Desktop/mac/Home/Desktop$ python 1.py
WARNING | 2018-09-08 18:17:26,007 | angr.analyses.disassembly_utils | Your version of capstone does not support MIPS instruction groups.
FLAG{Swap two bits is easy 0xaa with 0x55} @
unpackme
- 这个题居然到了400分..题目名字是unpackme,众所周知,CTF中对于逆向的考察中,壳的考察是比较少的,这个题目名很明显是加了壳,查壳发现居然不是自写壳,而是upx壳,直接上脱壳机,脱壳后进行算法逆向,定位到关键算法,可以看到函数先对输入进行hash运算,然后进行hash的一个循环比较,我们可以提取出这些hash,发现正好为32位,somd5反查一下,发现解密后的字符串是”how[空格]do[空格]you[空格]turn[空格]this”,很神奇,随后是函数的解密过程,经过化简后可以得到算法 flag[i] = flag[0] ^ md5flag[i/2] ^ key[i],其中已知两个参数,这里选择爆破flag的第一字节,脚本如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import string import binascii flag = "" flagenc = [0x1 |