CTF Re Mo writeup

2017看雪秋季CTF--第二题分析笔记

2017-11-10  本文已影响46人  SueLyon

首先拿到题目打开,


crackme

程序要求输入注册码,失败输出Bad register-code
按常规思路,想直接丢IDA里F5大法,找到字符串,尝试F5失败
只能逐行看汇编


main

发现 41B034为0,则输出“You get it!\n”;
而变量41B034初始值为2,但是紧跟着三个调用401050 401090 4010E0
则初步判断函数在这三个调用里对输入的注册码进行校验和处理的

双击进去看看,401090 4010E0里发现有运算,F5分析


0x401090 0x4010e0

两个if得出4个等式

5  * (v1 - v0) + v1   =  0x8F503A42     (等式1)
13 * (v1 - v0) + v0   =  0xEF503A42
17 * (v1 - v0) + v1   =  0xF3A94883     (等式2)
7  * (v1 - v0) + v0   =  0x33A94883

if语句通过的话刚好把变量41B034的值减到0,就可以通过验证了
本以为这题就结束了
但是
仔细看等式2-等式1 等式是永远无法成立的,需要换个思路

IDA继续往下看

发现一大堆数据


有点奇怪但不知道问题在哪
只能从已知的内容下手,返回刚才的401050
401050
发现了该函数在栈中分配了一块12字节大小的局部空间
(var_C = dwrod ptr -0Ch)
该空间提供给scanf做输入缓冲区
F5,我们看到v1(缓冲区)大小为12

而且发现序列号没有限制输入位数,这里就考虑到scanf的栈溢出

简单验证一下
OD载入,在输入前下段,查看堆栈情况

堆栈
输入123测试,看堆栈
scanf 123.png
scanf存储输入的缓冲区是地址为12FF6C,这样以来,如果输入的字符长度大于8,则会将堆栈中的数据覆盖掉。
当前程序控制权在0x401050,也就是说我们想从当前溢出,就必须输入13位以上字符去覆盖0x401050的返回地址,才能在调用结束后溢出到我们想要的位置。 我们当然想要程序直接溢出到输出“You get it!\n”(0x0040102F)的位置,这样我们的任务就完成了。

但这样与题不符,如果输入13个字符,将1C改成2F,由于scanf会在读取字符的末尾加上0x00(结束符)会将0x10改成00,也就是将地址改成了40002F,这样肯定不对。那么只能输入15位了。因为恰好40102F的最高字节也是00,不怕被00覆盖。这样就可构造出序列号成功溢出了,但是这样有与题不符,无法保证序列号唯一性(前12位)并且不符合题目所给序列号要求(大小写字母和数字)

问题又来了,我们到底溢出到哪呢
继续从IDA里面找
想起来之前IDA里看到的一大堆数据
仔细看前面的数据,很多7开头的,查手册


jxx.png

都是跳转啊!很明显的程序加花指令,明显是作者不想让我们看些到什么
而地址为00413131, 又考虑到0x14 0x31都符合要求(注册码要求的值的ascii),构造溢出点11A(00413131)


溢出

可以看到已经溢出到我们想要的位置

dd.png

OD进去发现也是一堆数据,但是程序竟然在数据上跳转,立马反应过来这段并不是数据而是代码,可能是程序加花

参考看雪的《加密与解密》,抵御静态分析主要从汇编代码可读性入手,对反汇编来说其中一个关键的问题就是数据与代码的区分
大量花指令,汇编指令长度和多种多样间接跳转,导致反汇编工具把代码段当作数据段来处理

输入12345678901211A,OD跟进,处理数据 右键->分析->下次分析时视为commands 这时汇编指令已经出来了
//或者IDA选中代码块,右键->分析选中代码->force->yes

汇编.png

程序加花指令后汇编的可读性很差,但还要一步步调,

我想偷个懒
在程序 push验证失败信息 0x40103F 处下段
尝试 查看->RUN跟踪 打开跟踪窗口 调试->跟踪步入



只截了一部分图
最后程序停在了 “验证失败”的信息处 证明程序验证我们输入的字符串,再看EAX=34333231,存入了我们输入的前4个值并进行验证,也就是说我们猜测的溢出点正确

OD记录了经过的所有汇编指令,去除花指令(各种跳)后记录分析
发现
最后 sub eax, 0xEAF917E2 (记录为校验1)之后验证就结束了,跳到验证失败

fail.png

尝试在 sub eax, 0xEAF917E2 下段并修改eax的值,使sub运算结束eax为0,继续执行验证。
再次RUN跟踪(记为校验2) 这次在 sub eax,0xE8F508C8 跳出
再次重复操作 使sub后为0 再次跟踪(记为校验3)
至此我们已经完整记录了三次(12字符)的计算流程
然后化简出公式算出三次校验的正确输入值

如下

sub esp,10
xor eax,eax
mov dword_41B034, eax
pop eax
mov ecx,eax
pop eax
mov ebx,eax
pop eax
mov edx,eax

;校验1    地址:4131B9
mov eax,ecx        
sub eax,ebx             ecx-ebx 
shl eax,2              (ecx-ebx)*4 
add eax,ecx            (ecx-ebx)*2+ecx
add eax,edx            (ecx-ebx)*2+ecx+edx
sub eax, 0xEAF917E2    (ecx-ebx)*2+ecx+edx-0xEAF917E2 == 0  eax清0
 
;校验2   地址:413455     
add eax,ecx   ecx
sub eax,ebx   eax-ebx 
mov ebx,eax   
shl eax,1              (ecx-ebx)*2 
add eax,ebx            (ecx-ebx)*2 +(ecx-ebx) 
add eax,ecx            (ecx-ebx)*2 +(ecx-ebx) + ecx 
mov ecx, eax           //这一行校验3后面用
add eax,edx            (ecx-ebx)*2 +(ecx-ebx) + ecx +edx 
sub eax,0xE8F508C8     (ecx-ebx)*2 +(ecx-ebx) + ecx +edx -0xE8F508C8 == 0  eax清0
 
;校验3   
mov eax,ecx          (ecx-ebx)*2 +(ecx-ebx) + ecx  
sub eax,edx          (ecx-ebx)*2 +(ecx-ebx) + ecx -edx  
sub  eax, 0xC0A3C68  (ecx-ebx)*2 +(ecx-ebx) + ecx -edx - 0xC0A3C68 == 0     

换算
4 * (v0-v1)+v0+v2 == 0xEAF917E2
2 * (v0-v1)+(v0-v1)+v0+v2 == 0xE8F508C8
2 * (v0-v1)+(v0-v1)+v0-v2 == 0xC0A3C68

可直接百度在线计算

v0=0x7473754A
v1=0x726F6630
v2=0x6E756630
放进十六进制编辑器 key.png

注册码:Just0for0fun11A

注意小端,加上溢出点尝试验证

成功

上一篇下一篇

猜你喜欢

热点阅读