看雪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