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)化解真有问题
搞了很久了,有点怀疑人生了,没解出来,只有看其他大神的帖子了,自己记录一下,表示努力过!
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法