首页
社区
课程
招聘
[原创] 看雪CTF2017第三题爱情海CrackMe的writeup(虽然没解出来,但也写写过程)
2017-6-6 23:07 4219

[原创] 看雪CTF2017第三题爱情海CrackMe的writeup(虽然没解出来,但也写写过程)

2017-6-6 23:07
4219

1. 一个小坑


将cm拖进OD就直接弹出异常,第一反应是加壳,反调试了!

用PEid一看是vc的程序,但是ida看导入表一对vb的函数,什么鬼!

还有就算加壳,一般也是运行中才会反跳试,这是加载程序就出问题了!

在ida中看到eop居然是400000,这.不是PE头吗,直接运行又是可以的,这究竟是怎么回事!

换一个调试器windbg,可以加载运行成功,然后去确认是不是直接eop的400000

执行eop的代码位置如下(xpsp3,每次重启地址不一样):

kernel32!GetModuleFileNameW+0xc:
75e53c32 90              nop
kernel32!BaseThreadInitThunk:
75e53c33 8bff            mov     edi,edi
75e53c35 55              push    ebp
75e53c36 8bec            mov     ebp,esp
75e53c38 85c9            test    ecx,ecx
75e53c3a 0f8586000000    jne     kernel32!BaseThreadInitThunk+0x93 (75e53cc6)
75e53c40 ff7508          push    dword ptr [ebp+8]
75e53c43 ffd2            call    edx //eop 400000

下断方式:

0:000> u kernel32!BaseThreadInitThunk
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Windows\system32\kernel32.dll - 
kernel32!BaseThreadInitThunk:
76d43c33 8bff            mov     edi,edi
76d43c35 55              push    ebp
76d43c36 8bec            mov     ebp,esp
76d43c38 85c9            test    ecx,ecx
76d43c3a 0f8586000000    jne     kernel32!BaseThreadInitThunk+0x93 (76d43cc6)
76d43c40 ff7508          push    dword ptr [ebp+8]
76d43c43 ffd2            call    edx //这个地址下断
76d43c45 50              push    eax
0:000> bp 76d43c43

运行

76d43c43 ffd2            call    edx {image00400000 (00400000)}

还真的是入口在这,可是这个段不是只读的吗?

0:000> t
eax=76d43c33 ebx=7ffdf000 ecx=00000000 edx=00400000 esi=00000000 edi=00000000
eip=00400000 esp=0012ff8c ebp=0012ff94 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
image00400000:
00400000 4d              dec     ebp

可以确认是只读的,但是确实已经执行了(OD无法加载,可能跟加载机制有关,没有细究,大神请指点,爱情海挖的坑!)

Usage:                  Image
Allocation Base:        00400000
Base Address:           00400000
End Address:            00401000
Region Size:            00001000
Type:                   01000000	MEM_IMAGE
State:                  00001000	MEM_COMMIT
Protect:                00000002	PAGE_READONLY //只读

这里确认是从400000执行的,这地址究竟是怎么回事呢?

HEADER:00400000 4D                                      dec     ebp //M
HEADER:00400001 5A                                      pop     edx //Z
HEADER:00400002 52                                      push    edx
HEADER:00400003 45                                      inc     ebp
HEADER:00400004 68 90 10 40 00                          push    401090h
HEADER:00400009 C3                                      retn

PE头MZ被解析成了dec ebp, pop edx,这里为了平衡堆栈,加入了push edx, inc ebp,然后就是挑战到401090,真正的入口

这里用PE工具将入口偏移修改为1090,就可以用OD调试了。

.text:00401088                         ; ---------------------------------------------------------------------------
.text:00401088 FF 25 24 10 40 00                       jmp     ds:ThunRTMain
.text:00401088                         ; ---------------------------------------------------------------------------
.text:00401090                         loc_401090:                             ; CODE XREF: __ImageBase+9j
.text:00401090 68 90 75 40 00                          push    offset dword_407590
.text:00401095 E8 66 7D 00 00                          call    sub_408E00
.text:0040109A 00 00                                   dw 0

可是这里看到sub_408e00内部一大堆东西,不知道做了什么,我是直接忽略的,因为我记得vb入口会调用ThunRTMain,所以我对401088下断,断下后

0012FF84   0040109A  返回到 cm3_eop3.0040109A 来自 cm3_eop3.00408E00

调用401090时,可以看到返回地址是40109A,其实就是在call sub_408e00内部转了一圈然后调用了ThunRTMain

这里可以直接修改为call 401088,这样就是一个标准的vb程序开始了。

00401088  - FF25 24104000   jmp dword ptr ds:[<&MSVBVM60.#100>]      ; msvbvm60.ThunRTMain
0040108E    0000            add byte ptr ds:[eax],al
00401090 >  68 90754000     push cm3_eop3.00407590                   ; ASCII "VB5!#vb6chs.dll"
00401095    E8 EEFFFFFF     call <jmp.&MSVBVM60.#100> //call 401088


2. 分析算法


由于很少分析vb,各种工具翻来覆去用vb parser,wktvbdebug, vb decompiler。

wktvbdebug调试字体太小了(难受),vb decomplier真不错,反编译器基本还原了算法(在Check_Click_40864c中), Form_Load_408040初始化了几个全局变量(算法中会使用)

Private Sub Form_Load() '408040
  'Data Table: 407BB0
  loc_408025: global_76 = CDbl(&H6606D1F5)
  loc_40802E: global_100 = "373414231.362502"
  loc_408038: global_104 = "874402299.931726"
  loc_40803C: Exit Sub
End Sub

算法部分

Private Sub Check_Click() '40864C
  'Data Table: 407BB0
  Dim var_C0 As String
  Dim var_94 As Double
  Dim var_8C As Double
  loc_408258: On Error Resume Next
  loc_40826A:  = (var_9C).Text
  loc_408280: var_C0 = CStr(Trim(CVar(var_9C)))
  loc_40828E: (var_C0).Text = 
  loc_4082B3:  = (var_9C).Text
  loc_4082D2: (Len(var_9C) = &H10) = var_C6(var_C0).Text
  loc_4082DA: Call Proc_0_2_4081F0(var_C0)
  loc_4082F4: If ( And (var_C6 = &HFF)) Then
  loc_408306:    = (var_9C).Text
  loc_408336:   global_84 = Val(CStr("&H" & Left(CVar(var_9C), 8)))
  loc_408357:    = global_84(var_9C).Text
  loc_408387:   global_92 = Val(CStr("&H" & Right(CVar(var_9C), 8)))
  loc_4083BE:   If (((global_84 > CDbl(0)) And (global_92 > CDbl(0))) And (global_84 > global_92)) Then
  loc_4083D7:     var_94 = ((global_84 + global_92) / CDbl(&HF4240))
  loc_4084CA:     var_94 = ((0.5 * ((((((((CDbl(2) * ((global_76 + global_52) ^ CDbl(2))) * ((global_84 - global_52) ^ CDbl(2))) + ((global_92 + global_52) ^ (CDbl(4) + global_68))) + ((global_76 - global_60) ^ (CDbl(4) + global_52))) + ((CDbl(2) * (global_76 ^ CDbl(2))) * ((global_92 + global_68) ^ CDbl(2)))) + ((CDbl(2) * (global_84 ^ CDbl(2))) * (global_92 ^ CDbl(2)))) + (global_84 ^ (CDbl(4) - global_52))) ^ 0.5)) / (((((global_76 + global_68) + global_84) - global_60) + global_92) + global_52))
  loc_40857A:     var_8C = (((global_76 * (global_84 - global_52)) * global_92) / ((((((((global_76 + global_84) + global_92) - global_60) * ((((global_76 + global_68) + global_84) - global_92) + global_68)) * (((global_76 + global_92) - global_84) - global_52)) * (((global_52 + global_84) + global_92) - global_76)) + global_60) ^ (0.5 + global_68)))
  loc_4085FC:     If CBool(1 And (Format(var_94, "0.000000") = CVar(global_104))) Then
  loc_40860D:       1(0).Enabled = (Format(var_8C, "0.000000") = CVar(global_100))
  loc_408623:       1(0).Enabled = True
  loc_408639:       var_8C(&HFF).Visible = var_94
  loc_408641:     End If
  loc_408643:   End If
  loc_408645: End If
  loc_408649: Exit Sub
End Sub

其中global_52, global_60, global_68这几个不知道值,就通过调试去确认了一下,方法如下:

将vb decompiler切换到反汇编窗口,找到访问global_52的代码,然后用OD对4083F1下内存断点,go

loc_4083F1: MemLdFPR8 global_52

断下后,执行如下代码(vb虚拟机中了,补了cyclotron大大的vb系列),此时esi地址是4083F1

72A41F8D    8A06            mov al,byte ptr ds:[esi]
72A41F8F    46              inc esi
72A41F90    FF2485 5CD4A372 jmp dword ptr ds:[eax*4+0x72A3D45C]

继续跟入jmp地址,执行到72A4193E,就是加载global_52的值了,ds:[0025C0AC]=0.0,是0.0

72A41938    8B7D B4         mov edi,dword ptr ss:[ebp-0x4C]
72A4193B    0FB706          movzx eax,word ptr ds:[esi]
72A4193E    DD0438          fld qword ptr ds:[eax+edi]

同样的其他2两个变量也同样方式,确认是0.0

那么算法的表达式就可以搞了,看到那么多括号,^,肯定被吓着了,整理一下,其实是这样的:

k = global_76 =CDbl(&H6606D1F5) = 1711722997.000000
a 是输入key的前8字节按16进制转为double值
b 是输入key的后8字节按16进制转为double值
R1 = global_100 = "373414231.362502"
R2 = global_104 = "874402299.931726"
k*a*b/((k+a+b)*(kb)*(ka)*(ak))^0.5 = R1 //这里显示不正确
0.5*((2*k^2*a^2 + b^4+k^4+2*k^2*b^2+ 2*a^2*b^2 + a^4)^0.5) / (k+a+b) = R2

//上面显示错误的是(k*a*b/((k+a+b)*(kb)*(ka)*(ak))^0.5 = R1)

通过化解得到

k*a*b/((4a^2b^2-(a^2+b^2-k^2)^2)^0.5) = R1 (1)
a^2+b^2+k^2 = 2*R2*(k+a+b) (2)

这样基本是可以带入各类科学计算工具计算了的,我用的python 的sympy,不知道是不是有4次的原因,非常慢算不出来

然后只得将(1)转为下面的式子

(4-k^2/R1^2)*a^2*b^2 = (a^2+b^2-k^2)^2 (1)

可是tmd,4-k^2/R1^2 < 0,小于0....这...怎么办?!

是不是^0.5平方时候有什么问题(大神求教?)

然后尝试了下面的式子求解

(4+k^2/R1^2)*a^2*b^2 = (a^2+b^2-k^2)^2 (1)

得到解如下

43988495.1121868, 1824689156.30927=》 029f360f 0x6cc28c0
6cc28c04029f360f 029f360f6cc28c04

可惜不对,(1)中会出现负数,看来(1)化解真有问题


搞了很久了,有点怀疑人生了,没解出来,只有看其他大神的帖子了,自己记录一下,表示努力过!





[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

收藏
点赞1
打赏
分享
最新回复 (2)
雪    币: 1355
活跃值: (329)
能力值: ( LV13,RANK:920 )
在线值:
发帖
回帖
粉丝
爱琴海 13 2017-6-8 07:25
2
0
查看作者文档,脱离地球坑
雪    币: 598
活跃值: (282)
能力值: ( LV13,RANK:330 )
在线值:
发帖
回帖
粉丝
Fpc 4 2017-6-8 08:53
3
0
掉坑里了
游客
登录 | 注册 方可回帖
返回