SICTF r3 closeme
第一部分
打开题目,先找main函数,点进第一个函数中(此时只有几十行代码)发现有不少地方爆红(看网上一些大佬的wp没有讲到这一个,应该是简单没有提),在爆红的地方按TAB进入反汇编窗口,用d + c小连招解决爆红,然后发现代码有400行(QAQ),那只能慢慢分析了。
第二部分
发现下面的代码,在大约360行附近的if ( v45 == “combase.dll” )语句处有一个突兀的异或,分析一下发现这是一个hint,解出来:
1 | data = [0x23, 0x11, 0x0D, 0x1B, 0x13, 0x4B, 0x18, 0x04, 0x03, 0x0A, 0x50, 0x08, 0x1D, 0x06, 0x54, 0x16, 0x1A, 0x18, 0x0B, 0x1C, 0x5A, 0x0F, 0x14, 0x18, 0x5E, 0x12, 0xE5, 0xF2, 0xF1, 0xE2, 0xE3, 0xE0, 0xE4, 0xE8, 0xF0, 0xA9, 0xE8, 0xF2, 0xAC, 0xEE, 0xE2, 0xE6, 0xF3, 0xFA, 0xB2, 0xF3, 0xCD, 0xF0, 0xE5, 0xF7, 0xB8, 0xF6, 0xE8, 0xBB, 0xFC, 0xD3, 0xF1, 0xFF, 0x8C, 0x81, 0xCB, 0xD7, 0x84, 0xD2, 0xCF, 0xCB, 0xC4, 0x89, 0xC8, 0xCE, 0x8C, 0xDE, 0xDA, 0xC0, 0xC2, 0xD4, 0xD6, 0x9D, 0x94, 0xFF, 0xC3, 0xC4, 0xCC, 0x99, 0xD9, 0xD3, 0xD3, 0xD2, 0xCD, 0xDA, 0xE0, 0x98, 0xA7, 0xB0, 0xEB, 0x8B, 0xA9, 0xEF, 0xF9, 0xE6, 0xFA, 0xE2, 0xEC, 0xA4, 0xA0, 0xEF, 0xB1, 0xF1, 0xB1, 0xB6, 0xA6, 0xA1, 0xB7, 0xBE, 0xB6, 0xF9, 0xB5, 0xA9, 0xB8, 0xB8, 0xAC, 0xFF, 0x97, 0x89, 0x8B, 0x80, 0x8C, 0xC5, 0x8F, 0x94, 0xC8, 0x9D, 0x82, 0x8E, 0xCC, 0x8B, 0x82, 0x8E, 0x97, 0xDD, 0xD2, 0x80, 0x81, 0x96, 0x9E, 0xD7, 0x99, 0x8A, 0xDA, 0xCB, 0xCD, 0xCD, 0xCE, 0xCE, 0x31, 0x31, 0x32, 0x2D, 0x24, 0x55, 0x6A, 0x62, 0x69, 0x7A, 0x6F, 0x2B, 0x7F, 0x78, 0x6C, 0x62, 0x79, 0x65, 0x32, 0x75, 0x78, 0x74, 0x71, 0x37, 0x6F, 0x71, 0x73, 0x78, 0x74, 0x3D, 0x6A, 0x77, 0x45, 0x01, 0x44, 0x4C, 0x56, 0x48, 0x47, 0x53, 0x08, 0x45, 0x43, 0x40, 0x49, 0x0D, 0x4E, 0x7C, 0x79, 0x72, 0x66, 0x75, 0x4F, 0x05, 0x07, 0x07, 0x08, 0x08, 0x0B, 0x0B, 0x0C, 0x40, 0x5E] |
根据提示我们发现,这是一个根据我们点击是或否来进行加密的,结合hint我们再分析一下代码,在180行代码附近有两个if的嵌套判断,查官网MessageBoxw函数的介绍,我们知道它的返回值6和7是点击是和点击否,所以我们可以判断出我们点击是时为1,点击否时为0,且我们需要点击16次是/否,大致如下。
1 | v23 = MessageBoxW(0i64, p10, lpCaption[1], 4u); |
第三部分
在根据题目给我们动态调试的提示,我们开始通过动态调试来找到更多的线索。在205处下断点,我们可以调试发现(要点击完16下是否),196行代码处v63存储着我们输入的1/0记录(注意要按几下d键修正地址偏移)
1 | if ( v64 == v62 ) |
1 | debug050:000002EAF2CDD660 unk_2EAF2CDD660 db 1 ; DATA XREF: Stack[0000058C]:000000FED7FEF988↑o |
我们再在269行代码处下断点,可以明显发现LABEL_4下的十几行代码都是记录我们输入1/0的顺序,并将它们存放在p0~p15中,这里我们可以发现p0最先被输入却在个位,而p15最后被输入却在最高位,所以我们可以发现这里将我们的输入的1/0顺序给倒序了一下(重点)。
1 | result = p0 |
而且这里是在将我们输入的01转换成一个十进制的数。
第四部分(个人能力问题,这部分猜的占比很大)
在350行LABEL_3上面有一个if判断:
1 | if ( (v44 & 0xFFFF0000) != -1443823616 ) |
这里我们可以根据上面的p0~p15如果输入不正确就会跳转这里猜出这里应该是最终我们要比较的地方,
1 | v44 = 0xA9F10000(-1443823616) |
然后我们看一下v44的二进制形式
1 | 1010 1001 1111 0001 |
然后我们就可以进行下一轮的调试(在上面哪个v44的if语句处下断点),输入:
1 | 输入 v44 二进制输出 |
然后我们开始找规律:看第一组数据,我们发现加密部分应该是有一个倒序(我们上面分析的哪个),看第二个像是倒序后将末尾两位移到最前面,即:
1 | 输入 倒序 移位 |
如果是这样那么我们第一个就不只是倒序应该是:
1 | 1111 1111 0000 0000 ->(0000 0000) 1111 1111 -> (0000 0000) 1111 1111(此时末尾的11移到了最前面,但是先移位了,在补零) |
我们可以在输入几个验证一下:
1 | 输入 倒序 移位 |
完美匹配,所以我们找到了加密的方法,就可以对v44逆向找出flag了:
1 | v44 = 0xA9F1 (1010 1001 1111 0001) |
所以flag就是:
1 | SICTF{0110001111100101} |
第五部分(大佬的做法)
1 | imlzh1‘Blog: https://imlzh1.github.io/posts/SICTF-Round-3-WriteUps_by_AhiSec/ |
直接读代码,写脚本(膜拜一下QWQ)