本帖最后由 solly 于 2019-6-28 23:23 编辑
160 个 CrackMe 之 086 zerocool.2 是一个 VB 6.0 编译的 p-code 代码程序,所以算法追踪相对麻烦一点,我前面分析过的VB p-cdoe程序一样,使用三大工具配合,可以方便的跟踪 p-code 代码。
具体的过程和方法就不説了, 可以参考以前的贴子: https://www.52pojie.cn/thread-943702-1-1.html , 有详细的说明。
CrackMe 启动后如下图,需要输入用户名和注册码进行验证:
我们先通过 VB Explorer 确定事件的p-code地址,如下图所示:
这里可以确定按钮事件的开始地址(p-code 中的 esi 值)。
然后我们再通地 WKTVBDebugger 来确定上面按钮事件第一条指令的解析 Handler Proc,事件处理的第一条指令如下:
[Asm] 纯文本查看 复制代码 :0042D5D4 0474FF FLdRfVar ;Push LOCAL_008C;
这条指令的指令码为“04”,操作数的偏移量是“74FF",表示变量的相对基址的偏移是 0xFF74,也就是通过[ebp+0xFF74]就可取到变量的值,0xFF74是负数,转换一下就是[ebp-0x008C],这条指令翻译过来就是 Push LOCAL_008C。
有了指令,我们就可以到 WKTVBDebugger 中查到这条指令在 MSVBVM60.DLL 中的解释子程序了,如下图所示:
可以从 Opcodes Control Dialog 面板中,查到 "04" 指令的 Handler Proc 的入口地址为 0x660FD1DE。
最后我们切到 OD,载入 CrackMe 后,直接 Ctrl + G ,跳转到我们前面查到的 Handler Proc。
跳转到相应解释子程序后,我们就可以以esi 指令地址值,下一个条件指令:
下完断点,直接 F9 运行 CrackMe,如下图所示:
输入用户名和注册码假码,再点“Check"按钮,就会在前面下的断点停下,可以进一步跟踪其算法了。
VB p-code 代码中,其局部变量都是以 EBP 的值为基址,加上指令中的偏移量,就可以访问其值,我们在 OD 也可通过[EBP+偏移量]查看变量值,如下所示:
具体的注册码算法代码如下,包括算法分析在内:
[Visual Basic] 纯文本查看 复制代码
:0042D5D4 0474FF FLdRfVar ;Push LOCAL_008C;字符串变量
:0042D5D7 21 FLdPrThis ;[SR]=[stack2]
:0042D5D8 0F0C03 VCallAd ;Return the control index 05
:0042D5DB 1978FF FStAdFunc ;
:0042D5DE 0878FF FLdPr ;[SR]=[LOCAL_0088]
***********Reference To:[propget]TextBox.Text
|
:0042D5E1 0DA0000000 VCallHresult ;Call ptr_0042BDB8; 从界面读取用户名
:0042D5E6 6C74FF ILdRf ;Push DWORD [LOCAL_008C]; 字符串变量,保存的用户名
******Possible String Ref To->""
|
:0042D5E9 1B0100 LitStr ;Push ptr_0042BDB4
:0042D5EC FB30 EqStr ;将用户名字符串与空串比较
:0042D5EE 2F74FF FFree1Str ;SysFreeString [LOCAL_008C]; [LOCAL_008C]=0
:0042D5F1 1A78FF FFree1Ad ;Push [LOCAL_0088]; Call [[[LOCAL_0088]]+8]; [[LOCAL_0088]]=0
:0042D5F4 1C5700 BranchF ;If Pop=0 then ESI=0042D62B; 如果不为空则跳转
'
' if TextBox.Text = "" then
'
:0042D5F7 27F4FE LitVar ;PushVar LOCAL_010C
:0042D5FA 2714FF LitVar ;PushVar LOCAL_00EC
******Possible String Ref To->"Name required!"
|
:0042D5FD 3A44FF0200 LitVarStr ;PushVarString ptr_0042BE08
:0042D602 4E34FF FStVarCopyObj ;[LOCAL_00CC]=vbaVarDup(Pop)
:0042D605 0434FF FLdRfVar ;Push LOCAL_00CC
:0042D608 F530000000 LitI4 ;Push 00000030
******Possible String Ref To->"Entering a name would help!"
|
:0042D60D 3A64FF0300 LitVarStr ;PushVarString ptr_0042BDCC
:0042D612 4E54FF FStVarCopyObj ;[LOCAL_00AC]=vbaVarDup(Pop)
:0042D615 0454FF FLdRfVar ;Push LOCAL_00AC
**********Reference To->msvbvm60.rtcMsgBox
|
:0042D618 0A04001400 ImpAdCallFPR4 ;Call ptr_00401040; 提示输入用户名!!!
:0042D61D 36080054FF34FF14 FFreeVar ;Free 0008/2 variants
:0042D628 1E4102 Branch ;ESI=0042D815; 跳转到函数结束代码
' MsgBox "Entering a name would help!", vbOKOnly, "Name required!"
' Exit Sub
'
' end if
'
' 如果用户名不为空就跳转到这里,进行注册码校验
'
:0042D62B 2824FF0100 LitVarI2 ;PushVarInteger 0001; 在堆栈压入立即数 0x0001, 循环开始值
:0042D630 04E4FE FLdRfVar ;Push LOCAL_011C; 循环变量
:0042D633 0474FF FLdRfVar ;Push LOCAL_008C; 字符串变量
:0042D636 21 FLdPrThis ;[SR]=[stack2]
:0042D637 0F0C03 VCallAd ;Return the control index 05
:0042D63A 1978FF FStAdFunc ;
:0042D63D 0878FF FLdPr ;[SR]=[LOCAL_0088]
***********Reference To:[propget]TextBox.Text
|
:0042D640 0DA0000000 VCallHresult ;Call ptr_0042BDB8; 从界面读取用户名
:0042D645 6C74FF ILdRf ;Push DWORD [LOCAL_008C]; 字符串变量,保存的用户名
:0042D648 4A FnLenStr ;vbaLenBstr; 取得用户名的长度
:0042D649 FD6944FF CVarI4 ;将长度值转换成 Long 类型的 Variable,并入栈,循环结束值
:0042D64D 2F74FF FFree1Str ;SysFreeString [LOCAL_008C]; [LOCAL_008C]=0
:0042D650 1A78FF FFree1Ad ;Push [LOCAL_0088]; Call [[[LOCAL_0088]]+8]; [[LOCAL_0088]]=0
:0042D653 FE68C4FEE100 ForVar ;循环体开始
'
' 生成一个 For 循环
' for i=1 to len(username) step 1
'
:0042D659 0474FF FLdRfVar ;Push LOCAL_008C; 字符串变量,用来保存用户名
:0042D65C 21 FLdPrThis ;[SR]=[stack2]
:0042D65D 0F0C03 VCallAd ;Return the control index 05
:0042D660 1978FF FStAdFunc ;
:0042D663 0878FF FLdPr ;[SR]=[LOCAL_0088]
***********Reference To:[propget]TextBox.Text
|
:0042D666 0DA0000000 VCallHresult ;Call ptr_0042BDB8; 从界面读取用户名
:0042D66B 04B4FE FLdRfVar ;Push LOCAL_014C; 保存结果的变量 sum
:0042D66E 2834FF0100 LitVarI2 ;PushVarInteger 0001; Mid()函数的长度参数
:0042D673 04E4FE FLdRfVar ;Push LOCAL_011C; 循环变量,Mid()函数的开始位置参数
:0042D676 FC22 CI4Var ;vbaI4Var; 位置参数
:0042D678 3E74FF FLdZeroAd ;Push DWORD [LOCAL_008C]; [LOCAL_008C]=0; 载入 sum = 0
:0042D67B 4654FF CVarStr ; 字符串,用户名
:0042D67E 0414FF FLdRfVar ;Push LOCAL_00EC; 保存字符的变量
**********Reference To->msvbvm60.rtcMidCharVar
|
:0042D681 0A05001000 ImpAdCallFPR4 ;Call ptr_00401046; 读取字符,Mid(username, i, 1)
:0042D686 0414FF FLdRfVar ;Push LOCAL_00EC; 用户名串中的字符
:0042D689 FDFEB0FE CStrVarVal ;
**********Reference To->msvbvm60.rtcAnsiValueBstr
|
:0042D68D 0B06000400 ImpAdCallI2 ;Call ptr_0040104C; 取得字符的 ASCII 码值
:0042D692 4444FF CVarI2 ;
:0042D695 FB94F4FE AddVar ; 求和 sum = sum + ASCII码值
:0042D699 FCF6B4FE FStVar ; 保存 sum
'
' sum = sum + Asc(Mid(TextBox.Text, i, 1))
'
:0042D69D 2FB0FE FFree1Str ;SysFreeString [LOCAL_0150]; [LOCAL_0150]=0
:0042D6A0 1A78FF FFree1Ad ;Push [LOCAL_0088]; Call [[[LOCAL_0088]]+8]; [[LOCAL_0088]]=0
:0042D6A3 36060054FF34FF14 FFreeVar ;Free 0006/2 variants
:0042D6AC 04E4FE FLdRfVar ;Push LOCAL_011C; 循环变量
:0042D6AF FE7EC4FE8500 NextStepVar ;循环体结束
'
' 循环结束
' Next i
'
:0042D6B5 04B4FE FLdRfVar ;Push LOCAL_014C; 保存运算结果的变量 s
:0042D6B8 0474FF FLdRfVar ;Push LOCAL_008C; 压入 sum
:0042D6BB 21 FLdPrThis ;[SR]=[stack2]
:0042D6BC 0F0C03 VCallAd ;Return the control index 05
:0042D6BF 1978FF FStAdFunc ;
:0042D6C2 0878FF FLdPr ;[SR]=[LOCAL_0088]
***********Reference To:[propget]TextBox.Text
|
:0042D6C5 0DA0000000 VCallHresult ;Call ptr_0042BDB8; 从界面读取用户名
:0042D6CA 6C74FF ILdRf ;Push DWORD [LOCAL_008C]; 用户名
:0042D6CD 4A FnLenStr ;vbaLenBstr; 取得用户长度 n = len(username)
:0042D6CE FD6964FF CVarI4 ;
:0042D6D2 FBEF54FF ConcatVar ; 字符串连接 s = sum & n, 是将两个数字转换成字符串后连接起来
:0042D6D6 FCF6B4FE FStVar ;
:0042D6DA 2F74FF FFree1Str ;SysFreeString [LOCAL_008C]; [LOCAL_008C]=0
:0042D6DD 1A78FF FFree1Ad ;Push [LOCAL_0088]; Call [[[LOCAL_0088]]+8]; [[LOCAL_0088]]=0
:0042D6E0 04B4FE FLdRfVar ;Push LOCAL_014C; 压入 s
:0042D6E3 FEC464FF33333333 LitVarR8 ; cd1 = 1.7
:0042D6EF FBB454FF MulVar ; id0 = s * 1.7
:0042D6F3 FACDCCCCCCCCCC00 LitDate ; cd2 = 2.1
:0042D6FC FAB81E85EB51B80A LitDate ; cd3 = 3.34
:0042D705 FA9A999999999905 LitDate ; cd4 = 2.7
:0042D70E FBCF PwrR8R8 ; cd3^cd4
:0042D710 B3 MulR8 ; id1 = (cd3 ^ cd4) * cd2
:0042D711 FD6B44FF CVarR8 ;
:0042D715 FBAC34FF IDvVar ; div1 = id0/id1
:0042D719 FCF6A0FE FStVar ; 保存 div1
:0042D71D 04B4FE FLdRfVar ;Push LOCAL_014C; s
:0042D720 04A0FE FLdRfVar ;Push LOCAL_0160; div1
:0042D723 FEC464FFF2D24D62 LitVarR8 ; cd5 = 2.918
:0042D72F FBB454FF MulVar ; cd5 * div1
:0042D733 FB9434FF AddVar ; d0 = (cd5 * div1) + s
:0042D737 FCF690FE FStVar ; 保存d0
:0042D73B 04B4FE FLdRfVar ;Push LOCAL_014C; s
:0042D73E 04A0FE FLdRfVar ;Push LOCAL_0160; div1
:0042D741 FB9454FF AddVar ; div1 + s
:0042D745 0490FE FLdRfVar ;Push LOCAL_0170; d0
:0042D748 FB9434FF AddVar ; d1 = d0 + (div1 + s)
:0042D74C FCF680FE FStVar ; 保存 d1
:0042D750 3554FF FFree1Var ;Free LOCAL_00AC
:0042D753 04B4FE FLdRfVar ;Push LOCAL_014C; s
:0042D756 04A0FE FLdRfVar ;Push LOCAL_0160; div1
:0042D759 FB9454FF AddVar ; d2 = div1 + s
:0042D75D 0490FE FLdRfVar ;Push LOCAL_0170; d0
:0042D760 FEC464FF9CC420B0 LitVarR8 ; cd6 = 1.213
:0042D76C FBAC34FF IDvVar ; i0 = d0 / cd6
:0042D770 FB9414FF AddVar ; i1 = i0 + d2
:0042D774 FCF670FE FStVar ; 保存 i1
:0042D778 3554FF FFree1Var ;Free LOCAL_00AC
:0042D77B 04B4FE FLdRfVar ;Push LOCAL_014C; s
:0042D77E 04A0FE FLdRfVar ;Push LOCAL_0160; div1
:0042D781 FB9454FF AddVar ; i2 = s + div1
:0042D785 0490FE FLdRfVar ;Push LOCAL_0170; d0
:0042D788 FB9434FF AddVar ; d3 = i2 + d0
:0042D78C 0480FE FLdRfVar ;Push LOCAL_0180; d1
:0042D78F 0470FE FLdRfVar ;Push LOCAL_0190; i1
:0042D792 FBB414FF MulVar ; d4 = i1 * d1
:0042D796 FB94F4FE AddVar ; d5 = d4 + d3
******Possible String Ref To->"]qcc["
|
:0042D79A 3A64FF0700 LitVarStr ;PushVarString ptr_0042BE2C; 字符串常量"]qcc["
:0042D79F FBEF60FE ConcatVar ; 连接字符串 sn = d5 & "]qcc["
:0042D7A3 FCF6B4FE FStVar ; 将 sn 存入 LOCAL_014C
:0042D7A7 36060054FF34FFF4 FFreeVar ;Free 0006/2 variants
'
' sn 计算完毕,下面是比较注册码是否正确
'
:0042D7B0 0474FF FLdRfVar ;Push LOCAL_008C; 保存输入的注册码的变量
:0042D7B3 21 FLdPrThis ;[SR]=[stack2]
:0042D7B4 0F0803 VCallAd ;Return the control index 04
:0042D7B7 1978FF FStAdFunc ;
:0042D7BA 0878FF FLdPr ;[SR]=[LOCAL_0088]
***********Reference To:[propget]TextBox.Text
|
:0042D7BD 0DA0000000 VCallHresult ;Call ptr_0042BDB8; 读取界面输入的注册码
:0042D7C2 3E74FF FLdZeroAd ;Push DWORD [LOCAL_008C]; [LOCAL_008C]=0; 读入的注册码
:0042D7C5 4654FF CVarStr ;
:0042D7C8 5D HardType ;
:0042D7C9 04B4FE FLdRfVar ;Push LOCAL_014C 计算出来的注册码
:0042D7CC FB40 NeVarBool ;比较两个注册码,是否不相等(Ne, Not Equal),相等为 False,不相等为 True
:0042D7CE 1A78FF FFree1Ad ;Push [LOCAL_0088]; Call [[[LOCAL_0088]]+8]; [[LOCAL_0088]]=0
:0042D7D1 3554FF FFree1Var ;Free LOCAL_00AC
:0042D7D4 1C2E02 BranchF ;If Pop=0 then ESI=0042D802; 注册码相等则跳转
'
' if sn != snTextBox.Text then
'
:0042D7D7 2744FF LitVar ;PushVar LOCAL_00BC
:0042D7DA 25 PopAdLdVar ;
:0042D7DB 2764FF LitVar ;PushVar LOCAL_009C
:0042D7DE 25 PopAdLdVar ;
:0042D7DF 050800 ImpAdLdRf ;Push ptr
:0042D7E2 240900 NewIfNullPr ;[Pop] [SR]
:0042D7E5 0DB0020A00 VCallHresult ;Call ptr_0042BE38; 显示注册码错误的信息
******Possible String Ref To->""
|
:0042D7EA 1B0100 LitStr ;Push ptr_0042BDB4; 空字符串
:0042D7ED 21 FLdPrThis ;[SR]=[stack2]
:0042D7EE 0F0803 VCallAd ;Return the control index 04
:0042D7F1 1978FF FStAdFunc ;
:0042D7F4 0878FF FLdPr ;[SR]=[LOCAL_0088]
***********Reference To:[propput]TextBox.Text
|
:0042D7F7 0DA4000000 VCallHresult ;Call ptr_0042BDB8; 将注册码输入框中的错误注册码清空
:0042D7FC 1A78FF FFree1Ad ;Push [LOCAL_0088]; Call [[[LOCAL_0088]]+8]; [[LOCAL_0088]]=0
:0042D7FF 1E4102 Branch ;ESI=0042D815
'
' else
'
' 注册码正确来到这里
'
:0042D802 2744FF LitVar ;PushVar LOCAL_00BC
:0042D805 25 PopAdLdVar ;
:0042D806 2764FF LitVar ;PushVar LOCAL_009C
:0042D809 25 PopAdLdVar ;
:0042D80A 050B00 ImpAdLdRf ;Push ptr
:0042D80D 240C00 NewIfNullPr ;[Pop] [SR]
:0042D810 0DB0020D00 VCallHresult ;Call ptr_0042BEB0; 显示注册码正确的信息
'
' end if
'
' 退出
'
:0042D815 13 ExitProcHresult ;
:0042D816 0000 LargeBos ;IDE beginning of line with 00 byte codes
如果输入的注册码不正确,则会提示:
如果输入的注册码是正确的,则提示:
既然是 VB 程序,我们可以使用Excel+VBA来做注册机,界面如下:
上面包含了计算好的注册码,VBA代码如下:
具体代码如下:
[Visual Basic] 纯文本查看 复制代码 '
' 注册机源码
'
Sub getSN()
Dim i As Long, n As Long, sum As Long
Dim username As String, s As String, sn As String
username = Sheet1.Cells(4, 4)
If username = "" Then
MsgBox "Entering a name would help!", vbOKOnly, "Name required!"
Exit Sub
End If
n = Len(username) 'solly88
sum = 0
For i = 1 To n Step 1
sum = sum + Asc(Mid(username, i, 1))
Next i
s = sum & n ' "6757"
Dim cd1 As Double, cd2 As Double, cd3 As Double
Dim cd4 As Double, cd5 As Double, cd6 As Double
Dim id0 As Double, id1 As Double, id2 As Double
Dim i0 As Long, i1 As Long, i2 As Long, div1 As Long
Dim d0 As Double, d1 As Double, d2 As Double
Dim d3 As Double, d4 As Double, d5 As Double
cd1 = 1.7
cd2 = 2.1
cd3 = 3.34
cd4 = 2.7
cd5 = 2.918
cd6 = 1.213
id0 = s * cd1
id1 = (cd3 ^ cd4) * cd2
div1 = Int(CLng(id0) / CLng(id1)) '212
d0 = (div1 * cd5) + s '618.616 + 6757 = 7375.616
d1 = div1 + s + d0 ' 212 + 6757 + 7375.616 = 14344.616
d2 = div1 + s '212 + 6757 = 6969
i0 = CLng(d0) / CLng(cd6) '7376
i1 = CLng(i0 + d2) ' 14345
i2 = s + div1 '6969
d3 = i2 + d0 '14344.616
d4 = i1 * d1 '205773515.52
d5 = d4 + d3 '205787861.136
sn = d5 & "]qcc["
Sheet1.Cells(5, 4) = sn
Range("D5").Select
Selection.Copy
End Sub
分析完毕!!! |