zoukankan      html  css  js  c++  java
  • 看雪CTF 2016_第八题分析

    用exeinfo查看发现是x64程序,所以用平常的OD调试器是调试不到的,需要用x64的调试器

     

    我这里是用x64dbug 这个调试器来进行调试分析

    经过一步一步调试,发现程序调用RtlMoveMemory 这个api来进行获取我们输入的注册码

     

    Rax的内存地址即为我们输入的假码

     

    我们先不要一步一步分析下去,直接来到提示注册码不正确那里。

    我们来到上图的地方,走到000000013F5018E1 | E8 4E 8D 00 00 | call crackme.13F50A634 | 这里提示注册码不正确

    然后上面有个跳转,为了验证是否为关键跳转,我们修改zf标志位使跳转成立,看看是不是提示成功,经过证实是提示成功,所以这个就是关键跳转。

    然后我们看看它是使什么条件成立才跳转的呢。

    000000013F5018A7 | 48 63 C6 | movsxd rax,esi |

    000000013F5018AA | 49 63 D6 | movsxd rdx,r14d |

    000000013F5018AD | 48 8D 0C 90 | lea rcx,qword ptr ds:[rax+rdx*4] |

    000000013F5018B1 | 48 03 D1 | add rdx,rcx |

    000000013F5018B4 | 48 8D 05 05 44 02 00 | lea rax,qword ptr ds:[13F525CC0] |

    000000013F5018BB | 8B 0D 63 44 02 00 | mov ecx,dword ptr ds:[13F525D24] |

    000000013F5018C1 | 0F AF CF | imul ecx,edi |

    000000013F5018C4 | 03 0C 90 | add ecx,dword ptr ds:[rax+rdx*4] |

    000000013F5018C7 | 8D 04 7F | lea eax,dword ptr ds:[rdi+rdi*2] |

    000000013F5018CA | 3B C8 | cmp ecx,eax |

    000000013F5018CC | 48 8D 0D A5 06 02 00 | lea rcx,qword ptr ds:[13F521F78] |

    000000013F5018D3 | 74 07 | je crackme.13F5018DC |

    这段汇编是对比ecx是否等于eax,如果等于就是为正确的注册码。

    那么ecx的值和eax的值是怎么来的。

    我们来分析一下:

    movsxd rax,esi // esi=2

    movsxd rdx,r14d //r14d=2

    lea rcx,qword ptr ds:[rax+rdx*4] // [rax+rdx*4] 2+2*4=A

    add rdx,rcx // rdx=A+2=C

    lea rax,qword ptr ds:[13F525CC0] // [13F5B5CC0] =134

    mov ecx,dword ptr ds:[13F525D24] // [13F5B5D24] =2=ecx

    imul ecx,edi //这里的edi是个变量 我输入的假码是123456 所以这里edi=A678 ecx=2*A678=14cf0

    add ecx,dword ptr ds:[rax+rdx*4] // dword [rax+rdx*4]=00000134 ecx=14cf0+134=14E24

    lea eax,dword ptr ds:[rdi+rdi*2] // eax= [rdi+rdi*2]=A678+A678*2=1F368

    所以很明显ecx = eax

    上面的值除了变量之外,其余的都是固定的,你可以其他假码进行测试,我这里就不再举例了。

    所以由上面得出:

    edi X

    2X+134=3X

    X=134

    所以只要变量等于134,就是正确的注册码,然而134是怎么计算出来的,即上面的edi=A678是怎么来的。

    经过向上分析,我们得出edi的结果是下面这个call计算出来的

    000000013F2D197B | E8 80 F9 FF FF | call crackme.13F2D1300 |

    000000013F2D1980 | 85 C0 | test eax,eax |

    000000013F2D1982 | 75 2B | jne crackme.13F2D19AF |

    000000013F2D1984 | 48 8D 0D 8D 06 02 00 | lea rcx,qword ptr ds:[13F2F2018] |

    我们进入这个call分析

    000000013F921300 | 45 33 C9 | xor r9d,r9d |

    000000013F921303 | 44 8B D9 | mov r11d,ecx |

    000000013F921306 | 41 B8 01 00 00 00 | mov r8d,1 |

    000000013F92130C | 45 8B D1 | mov r10d,r9d |

    000000013F92130F | 81 F9 6A 03 00 00 | cmp ecx,36A | 和注册码对比 ecx为注册码

    000000013F921315 | 75 04 | jne crackme.13F92131B |

    000000013F921317 | 83 C8 FF | or eax,FFFFFFFF |

    000000013F92131A | C3 | ret |

    当前ecx=1E240 十进制是123456 是我刚才出入的假码 它和36A对比 36A十进制是874

    这里不是很清楚为什么注册码不能为874,因为我这样分析在前面丢失了很多细节,不过没所谓,我们继续分析下去。

    000000013F92131B | 81 F9 B1 68 DE 3A | cmp ecx,3ADE68B1 | 注册码和3ADE68B1 对比 十进制为987654321 即注册码不能是987654321

    000000013F921321 | 74 F4 | je crackme.13F921317 |

    000000013F921323 | 85 C9 | test ecx,ecx |

    000000013F921325 | 75 09 | jne crackme.13F921330 |

    000000013F921327 | 45 8B D0 | mov r10d,r8d |

    000000013F92132A | EB 21 | jmp crackme.13F92134D |

    下面这段是检测注册码长度是否少于1

    000000013F921330 | B8 67 66 66 66 | mov eax,66666667 |

    000000013F921335 | 41 FF C2 | inc r10d |

    000000013F921338 | F7 E9 | imul ecx |

    000000013F92133A | 8B CA | mov ecx,edx |

    000000013F92133C | C1 F9 02 | sar ecx,2 |

    000000013F92133F | 8B C1 | mov eax,ecx |

    000000013F921341 | C1 E8 1F | shr eax,1F |

    000000013F921344 | 03 C8 | add ecx,eax |

    000000013F921346 | 75 E8 | jne crackme.13F921330 |

    000000013F921348 | 45 3B D0 | cmp r10d,r8d | 检测注册码长度要大于1

    000000013F92134B | 7C 13 | jl crackme.13F921360 |

    循环计算出r8的值 后面用来进行运算 这里r8=F4240 十进制是 1000000

    000000013F92134D | 41 8B C2 | mov eax,r10d | 输入的长度

    000000013F921350 | 47 8D 04 80 | lea r8d,dword ptr ds:[r8+r8*4] |

    000000013F921354 | 45 03 C0 | add r8d,r8d |

    000000013F921357 | 48 83 E8 01 | sub rax,1 |

    000000013F92135B | 75 F3 | jne crackme.13F921350 |

    --------------------------------------------------------------------------------------------------------------------------------------------------------------------

    000000013F921360 | 41 FF C1 | inc r9d |

    000000013F921363 | 41 8B C1 | mov eax,r9d |

    000000013F921366 | 41 0F AF C1 | imul eax,r9d |

    000000013F92136A | 99 | cdq |

    000000013F92136B | 41 F7 F8 | idiv r8d |

    000000013F92136E | 41 3B D3 | cmp edx,r11d | r11d等于输入的假码

    000000013F921371 | 75 ED | jne crackme.13F921360 |

    000000013F921373 | 41 8B C1 | mov eax,r9d |

    000000013F921376 | C3 | ret |

    这里就是计算出上面edi=A678 值的地方

    用易语言是这么实现的

     
     

    所以我们上面说到X=134就能得出正确的注册码,注意这里的134是十六进制,转换10进制是等于308

    所以r9d=308时,eax=eax*eax 就是正确的注册码,计算得出注册码为:94864

    文档和CM下载地址:http://www.vdisk.cn/down/index/19775196

  • 相关阅读:
    BZOJ2140: 稳定婚姻(tarjan解决稳定婚姻问题)
    BZOJ2124: 等差子序列(树状数组&hash -> bitset 求是否存在长度为3的等差数列)
    HDU 1217 Arbitrage(Bellman-Ford判断负环+Floyd)
    HDU 2112 Today(Dijkstra+map)
    HDU 2066 一个人的旅行(dijkstra水题+判重边)
    POJ 1511 Invitation Cards(Dijkstra(优先队列)+SPFA(邻接表优化))
    HDU 2544 最短路(floyd+bellman-ford+spfa+dijkstra队列优化)
    POJ 2431 Expedition (贪心 + 优先队列)
    POJ 3253 Fence Repair(哈夫曼编码)
    优先队列的使用(转)
  • 原文地址:https://www.cnblogs.com/Sendige/p/9601045.html
Copyright © 2011-2022 走看看