百度网盘已收集,需要回顾在文件夹【CTF题库收集】查看即可
刚开始先运行一下
这是一道crackme类型题目,是一道看雪CTF上的竞赛题,用OD进行分析一下。
刚开始用的是IDA分析,分析了半天也没有看出来什么,然后就在网上搜,还真搜出来了,直接上flag,解决了我的燃眉之急,哈哈,事后又看了看wp,才知道了真正的解法,还是应该总结的,毕竟有的题目是搜不到的......
问题:为什么用OD,不用IDA呢?
OD可以动态跟踪变量变化过程。OD反汇编代码可以着色,比较醒目。Crackme类题目
→动调首选
IDA可以看到数据结构乃至反汇编至C代码,有利于把握整体结构。
→静调首选
在OD中运行程序,发现在地址00401494处运行函数后出来messagebox,可知这是关键函数,F2下断点,F7跟进
在跟进这个函数的过程中,会发生Windows GUI -- 消息循环与消息,可以参考这篇文章
Windows GUI -- 消息循环与消息_gui 消息循环_我家有一口鱼塘的博客-CSDN博客
好像是必须得输入东西才能跳出这个循环,然后下断点,F9运行并输入字符跳出循环
在哪里下断点呢?如果在这里下断点,下图,
运行完后,就会直接报错了因为汇编指令retn用来结束当前过程返回到上一调用过程
所以最早得在这条汇编指令的下一条指令下断点
成功在断点处运行下来了,接下来就是反汇编的关键代码了:
CPU Disasm
地址 十六进制数据 指令 注释 标签
00401225 . 83F8 04 CMP EAX,4
00401228 . 59 POP ECX
00401229 . 0F85 A0000000 JNE 004012CF strlen()函数
0040122F . 6A 30 PUSH 30
00401231 . 59 POP ECX
00401232 . 384D E4 CMP BYTE PTR SS:[EBP-1C],CL 判断key第1个字符是否为“0”
00401235 . 0F84 94000000 JE 004012CF
0040123B . 384D E5 CMP BYTE PTR SS:[EBP-1B],CL 判断key第2个字符是否为“0”
0040123E . 0F84 8B000000 JE 004012CF
00401244 . 384D E6 CMP BYTE PTR SS:[EBP-1A],CL 判断key第3个字符是否为“0”
00401247 . 0F84 82000000 JE 004012CF
0040124D . 384D E7 CMP BYTE PTR SS:[EBP-19],CL 判断key第4个字符是否为“0”
00401250 . 74 7D JE SHORT 004012CF
00401252 . 807D E4 31 CMP BYTE PTR SS:[EBP-1C],31 判断key第1个字符是否等于“1”,不等于则直接跳转弹出“error”
00401256 . 75 77 JNE SHORT 004012CF
00401258 . 807D E5 35 CMP BYTE PTR SS:[EBP-1B],35 判断key第2个字符是否等于“5”,不等于则直接跳转弹出“error”
0040125C . 75 71 JNE SHORT 004012CF
0040125E . 74 03 JE SHORT 00401263 花指令
00401260 . 75 01 JNE SHORT 00401263
00401262 E8 DB E8 CHAR 'è'
00401263 > 66:B8 0800 MOV AX,8
00401267 . 66:35 0700 XOR AX,0007
0040126B . 0FBE45 E6 MOVSX EAX,BYTE PTR SS:[EBP-1A] 取输入key的第3位数
0040126F . 2BC1 SUB EAX,ECX 减去0x30,得到a
00401271 . 8945 FC MOV DWORD PTR SS:[EBP-4],EAX 把得到的值保存在[ebp-0x4]中
00401274 . 0FBE45 E4 MOVSX EAX,BYTE PTR SS:[EBP-1C] 取输入key的第1位值“1”
00401278 . DB45 FC FILD DWORD PTR SS:[EBP-4] 把[ebp-0x4]中保存的值压入到ST(0)中
0040127B . 2BC1 SUB EAX,ECX 0x31减去0x30,则为1
0040127D . 8945 FC MOV DWORD PTR SS:[EBP-4],EAX 把得到的值1保存在[ebp-0x4]中
00401280 . 0FBE45 E5 MOVSX EAX,BYTE PTR SS:[EBP-1B] 取输入key的第2位值“5”
00401284 . DB45 FC FILD DWORD PTR SS:[EBP-4] 把[ebp-0x4]中保存的值1压入到ST(0)中
00401287 . 2BC1 SUB EAX,ECX 0x35减去0x30,则为5
00401289 . 8945 FC MOV DWORD PTR SS:[EBP-4],EAX 把得到的值5保存在[ebp-0x4]中
0040128C . DA75 FC FIDIV DWORD PTR SS:[EBP-4] st(0)中的值1除以[ebp-0x4]中的值5,得到0.2保存到st(0)中
0040128F . 0FBE45 E7 MOVSX EAX,BYTE PTR SS:[EBP-19] 取输入key的第4位值
00401293 . 2BC1 SUB EAX,ECX 减去0x30,得到b
00401295 . 8945 FC MOV DWORD PTR SS:[EBP-4],EAX 把得到的值b保存在[ebp-0x4]中
00401298 . DEE9 FSUBP ST(1),ST st(1)-st并保存在st(0)中,即(a-0.2)
0040129A . DA4D FC FIMUL DWORD PTR SS:[EBP-4] st(0)乘以[ebp-0x4] 中保存的值b,结果保存在st(0)中
0040129D . D80D 1C714000 FMUL DWORD PTR DS:[40711C] 数据段ds:[0x40711C]值为16,这里则是st(0)乘以16
004012A3 . D95D FC FSTP DWORD PTR SS:[EBP-4] 把上面得到值保存在[ebp-0x4]中
004012A6 . 74 03 JE SHORT 004012AB
004012A8 . 75 01 JNE SHORT 004012AB
004012AA E8 DB E8 CHAR 'è'
004012AB /> 66:B8 0800 MOV AX,8
004012AF |. 66:35 0700 XOR AX,0007
004012B3 |. D945 FC FLD DWORD PTR SS:[EBP-4] 取出[ebp-0x4]中保存的值
004012B6 |. D81D 18714000 FCOMP DWORD PTR DS:[407118] 得出的值与384比较是否相等
004012BC |. 6A 00 PUSH 0
004012BE |. 68 78804000 PUSH OFFSET 00408078 ASCII "CrackMe 2017 CTF"
004012C3 |. DFE0 FSTSW AX
004012C5 |. 9E SAHF
004012C6 |. 75 0E JNE SHORT 004012D6
004012C8 |. 68 5C804000 PUSH OFFSET 0040805C ASCII "Registration successful !"
004012CD \. EB 0C JMP SHORT 004012DB
004012CF /> 6A 00 PUSH 0
004012D1 |. 68 48804000 PUSH OFFSET 00408048 ASCII "CrackMe 2017 CTF v2"
004012D6 |> 68 40804000 PUSH OFFSET 00408040 ASCII "error !"
0x01 判断输入值的长度
可以查看到我们输入后传入值的部分,并通过 strlen 来获取其长度是否为 4 ,不为 4 则直接跳转到 004012CF
现在可以确定key的长度为4
0x02 验证key前2位的值
这里验证key的值是否都为字符串“0”,如果4位的key又一个为“0”,则直接跳转到“error”弹出框
然后接着就是继续验证key前2位字符串的值,即给出字符串的前2位为“15”
如果 key 的前 2 位的值不为 “15” ,则直接跳转到 “error” 弹出框
这里得到前2为key的值为“15”
0x03 分析算法
这里运作流程:
1、取key中第3位的十六进制值,然后减去0x30,这里则假定值为a
2、取key中第1位值为“1”的十六进制值即0x31,然后减去0x30,0x31-0x30 =1
3、取key中第2位值为“5”的十六进制值即0x35,然后减去0x30,0x31-0x30 =5 ,接着就是1除以5得出浮点数0.2
4、取key中第4位的十六进制值,然后减去0x30,这里则假定值为b
5、接着就是(a-0.2)*b乘以16得出的结果为c
6、判断c与384是否相等,相等则Registration successful !,不相同则“error”
公式: (a-0.2)*b*16 = 384 求解 a 和 b
0x04 编写算法脚本
这里根据上面分析,写了个简单的脚本,跑出了 2 个结果 “151N” 和 "1555"
for i in range(126):
for j in range(126):
if(((i-48)-0.2)*(j-48) == 24):
print(i)
print(j)
print("15"+"%s"%(chr(i))+"%s"%(chr(j)))
print("------")