avatar

CTF-JarvisOJ-Re-CTF_100_0

文件下载点击下载

进行分析
接下来我将在 WinXP的虚拟机下进行调试
1、先进行查壳

Not packed 表示无壳,那么我们直接进行调试了。
2、导入OD

3、由于没有加壳 所以可以直接搜索字符串,猜测flag的位置

4、由于习惯问题,mfc程序的代码一般位于 基址偏移+0x10000 开始
所以直接往上拉 即可

5、注意到上面有flag 我们猜测下面几个地址是主要的代码位置,flag很可能会在这里出现,但是很明显的是,flag被隐藏了。很可能是被拆成了非 unicode的字符或者直接用ascii的十六进制 进行保存,使字符无法被搜索到

6、我们双击进入你赢了,毕竟这个比较显眼,一般都是通过 MessageBoxA 来告诉你一些信息

7、将代码拉到头部

很明显这里是一个call的内部。具体为什么这里不方便阐述。

8、我们在这里下cc断点,然后运行程序看看 看看会不会被断下,如果断下,说明这个按钮的事件中必然运行到了此call,那么我们就可以大致的确定flag的位置了

由结果证明,按钮的事件确实和这个call有关联
9、接下来就要单步分析了,因为一步一步分析较慢,繁琐,请允许我在一定的代码上写上注释,且不对无关代码进行分析

看到mov eax,005779F8 时,我们就要警惕了,因为这很可能要进行比较或者将假码进行变换,于是我们单步到该地址。
Eax表示指针已经指向假码了,
Add esp,0xC 对分析无用。
然后看到
00401C0D |. 8D50 02 lea edx,dword ptr ds:[eax+0x2]
00401C10 |> 66:8B08 /mov cx,word ptr ds:[eax] ; 将假码依次放入cx
00401C13 |. 83C0 02 |add eax,0x2 ; 偏移 一个位置 指向下一位字符
00401C16 |. 66:85C9 |test cx,cx
其实就是等效于 你输入的假码是否为空 及判断
If(假码 == “”)
对于实际当前代码中,没有什么用途
但是它对下面的代码有很大影响

Eax和edx的改变 是的 它们之间的差值再右移一位,恰好是0xE
我一开始也是猜测这个很可能是和位数有关,发现eax的最终结果 始终等于你输入的文本的长度,我们当前是12341234,所以下面的 cmp就无法通过了
于是我尝试14位假码时,恰好 长度等于0xE(其实就是假码长度要等于十进制的14)
实际上由于jg的跳转条件的原因,只要小于14位都可通过,大于14位直接跳转
【至于为什么会这样会等于长度,我可能要用数学算一下哦】

10、接下来是对flag的分析了

首先它把我们的文本转化为ascii码
且注意!!!!!!!! Flag本身只有14位 而且前面的假码要求我们就是14位,说明我们输入的假码要参与运算,只有符合条件的时候才能得出正确的数据。【推测,还未证实】
然后WideCharToMultiByte函数,将文本存入了00D69F00。此时我已经重新输入了16位假码


但是我们看到是乱码
实际上是因为 将假码转化为ascii后,我们通过unicode查看就会乱码,转化为ascii就好

注意!!!!
00401C53 |. B9 F8775700 mov ecx,005777F8 ; UNICODE “在此输入口令:”
00401C58 |. 8BC3 mov eax,ebx ; eax = 假码
00401C5A |. 2BCB sub ecx,ebx
00401C5C |. 8D6424 00 lea esp,dword ptr ss:[esp]
00401C60 |> 8A1401 /mov dl,byte ptr ds:[ecx+eax] ; 将[ecx+eax]的值传入 dl
00401C63 |. 3010 |xor byte ptr ds:[eax],dl
00401C65 |. 40 |inc eax
00401C66 |. 4E |dec esi
00401C67 |.^ 75 F7 \jnz short 00401C60 ; 判断 假码是否等于 在此输入口令:

这几条汇编我们要好好分析一下
00401C5C |. 8D6424 00 lea esp,dword ptr ss:[esp] 是栈处理 我们无需理会,对分析无作用
首先它将UNICODE “在此输入口令:” 的指针传到了005777F8,且此时 ebx为假码的指针,然后它将假码的指针传给了 eax,根据个人经验,他们肯定要进行转化或者比较了。

然后它竟然 把 ecx 减去了ebx 即 ecx = ecx – ebx; 哇绝望啊 因为它是负数 注意mov eax,ebx 很明显 eax = ebx的
所以后面的[ecx+eax]= [005777F8 -ebx + eax] = [005777F8] 坑爹啊 根本没变
然后将 005777F8 的单个二进制数值 和 [eax] 假码 进行 xor操作
因为已经到该call结尾了,后面也有flag的字符串,所以我们很有必要怀疑 这里就是flag的隐藏点

结论:简单说 就是 把 “在此输入口令:” 和 假码转化为 ascii 然后进行xor (异或操作)

00401C69 |> \813B 1B1C1746 cmp dword ptr ds:[ebx],0x46171C1B
00401C6F 0F85 E7000000 jnz 00401D5C
00401C75 |. 817B 04 F4FD2>cmp dword ptr ds:[ebx+0x4],0x3020FDF4
00401C7C 0F85 DA000000 jnz 00401D5C
00401C82 |. 817B 08 B70C8>cmp dword ptr ds:[ebx+0x8],0x7E8E0CB7
00401C89 0F85 CD000000 jnz 00401D5C
00401C8F |. 807B 0C 78 cmp byte ptr ds:[ebx+0xC],0x78
00401C93 0F85 C3000000 jnz 00401D5C
00401C99 |. 807B 0D DE cmp byte ptr ds:[ebx+0xD],0xDE

上一步中 ebx=eax 且 ebx是假码的指针,然后他要判断假码的 的数据是不是
1B 1C 17 46 F4 FD 20 30 B7 0C 8E 7E 78 DE

对此我们可以确定 上一步中 假设我们输入正确的 假码 应该是 1B 1C 17 46 F4 FD 20 30 B7 0C 8E 7E 78 DE 的数据
所以我们可以用c++直接 进行运算,代码如下

28 57 64 6B 93 8F 65 51 E3 53 E4 4E 1A FF 00 00 在此输入口令:
1B 1C 17 46 F4 FD 20 30 B7 0C 8E 7E 78 DE F酏 0?巭x?.
进行异或运算

得出 Flag{3Ks-grEaT_j0b!}
大总结:这个程序对于汇编的前后联系有较高要求,要求对指针有较强的敏感,对函数的各个参数有仔细观察。整体来说 难度不高,只要一步一步分析正确,最终发现flag的关键汇编代码,便可得出flag

文章作者: 咲夜南梦
文章链接: http://yoursite.com/2018/11/17/CTF-JarvisOJ-Re-CTF-100-0/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 咲夜南梦's 博客
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论