> 前言
最近从朋友那里拿到了一个加密狗授权的软件安装包,秉承着LCG的精神,开启了逆向之路,经过查壳和综合分析确定是VB6编写的程序(这年头使用VB6开发商业程序的还真少见),作为一名C# Winform的业余程序员,靠着C#的知识勉强分析个大概.
> 授权简介
软件共分三种授权模式:
1.账号密码模式:免费,但功能有限制
2.硬盘绑定模式:收费,绑定电脑硬盘ID
3.加密狗模式:插着加密狗就可以使用
经过对程序代码分析,软件是在编译前通过更改内部变量标志位实现不同授权模式,并且编译后只能识别对应的授权模式
所需工具
这里是引用
1.VB Decompiler 11 (爱盘里面下载)
2.文本批量查找工具
源程序
aHR0cHM6Ly93d3cuMTIzcGFuLmNvbS9zL1FMaVJWdi00WHZoaA==
分析过程[由浅入深,正向推进]
分析软件结构
1.安装软件,并打开安装目录
通过编译时间和经验筛选,除软件主程序外,只有
FT_ET299_API.dll
FD181.dll
RCGrandDogW32.dll
三种加密狗的库,具体用的是哪一种,后文会有分析过程
设置VB Decompiler参数
1.这个软件不能在WIN10系统上运行,解析不出来code段代码,我用的是WIN7的虚拟机.
2.打开VB Decompiler,按F11(或者菜单栏工具→选项),设置完成后保存,重启软件
逆向分析1 验证窗口的来源(正向推进)
1.打开软件,弹出登录界面/验证界面(因为我获得了加密狗版的安装包,所以知道不同的软件界面,这个是后话)
2.记住这个登录界面,我们打开VB Decompiler,导入软件的主程序,并反编译.
3.在树形分支窗口中在forms里面找到刚才的界面(frmlogin)
4.CTRL+S(菜单栏文件→保存反编译的项目),将反编译的内容保存在单独的文件夹里面.
5.使用文本批量查找工具,在刚刚保存的目录下查找"frmlogin"
通过查找定位可找到frmmain.frm和frmzc.frm两个调用了这个登录界面.
6.通过具体跟进代码,发现在frmmain的Form_Load窗体加载事件中调用了这个窗体的显示
NewIfNullPr frmlogin 'Ignore this
frmlogin.Show var_C8, var_D8
通过上下文代码内容得知:
var_98 = "软件启动检测"var_F6 = 1If (var_F6 = 1) Thenvar_88 = "NET"ElseIf (var_F6 = 2) Thenvar_88 = "HDD"ElseIf (var_F6 = 3) Thenvar_88 = "DOG"End IfEnd IfEnd If
通过对var_F6的赋值来决定模式,但是经过上下文跟进和实际测试这个只会影响软件各窗口标题内容
7.继续对上下文代码分析复制代码 隐藏代码loc_66AB02: var_98 = "软件验证"loc_66AB0B: Call Proc_42_11_585008(var_B0)var_98 = "软件验证"Call Proc_42_11_585008(var_B0)MemVar_6AF114 = CStr(var_B0)var_B0 = "" 'Ignore thisIf &HFF Then //这个值是那里来的,望VB的程序员帮忙解答一下,这个直接决定软件授权验证窗口的类型(授权模式)var_D8 = CVar(Me) 'AddressPopAdLdVar 'Ignore thisvar_C8 = 1PopAdLdVar 'Ignore thisNewIfNullPr frmlogin 'Ignore thisfrmlogin.Show var_C8, var_D8 //免费版网络验证窗口ElseIf 0 ThenProc_30_2_56F550(var_B0)Proc_30_4_56DE7C(var_B0)var_B0 = "" 'Ignore thisIf (MemVar_6AFF20 = vbNullString) ThenNewIfNullPr Me 'Ignore thisvar_9C = Me.Global.Appvar_B4 = "" 'Ignore thisvar_9C = vbNull 'Ignore thisvar_B0 = "" 'Ignore thisIf (Dir(CVar(App.Path & "\sn.bmp"), 0) <> vbNullString) ThenPopAdLdVar 'Ignore thisPopAdLdVar 'Ignore thisPopAdLdVar 'Ignore thisPopAdLdVar 'Ignore thisNewIfNullPr Me 'Ignore thisvar_9C = Me.Global.AppPopAdLdVar 'Ignore thisNewIfNullPr Me 'Ignore thisMe.Global.LoadPicture CVar(App.Path & "\sn.bmp"), var_C8, var_D8, var_164, var_184Me.picSn.Picture = var_188var_B4 = "" 'Ignore thisvar_9C = "": var_18C = "" 'Ignore thisvar_B0 = "" 'Ignore thisMemVar_6AFF34 = Call Proc_60_5_57F48C(Proc_59_1_58D9AC(Me.picSn), "F1DD7CDB1328DB1E") //modRij对称加密程序处理部分var_B4 = "" 'Ignore thisvar_9C = vbNull 'Ignore thisvar_B4 = "" 'Ignore thisvar_B0 = "" 'Ignore thisMemVar_6AFF20 = Split(MemVar_6AFF34 & "||||||||||||||||||||||||||||||||||||||||||||||||", "|", -1, 0)(0)End IfEnd IfIf (Proc_30_12_5968F0(MemVar_6AFF34) = 0) Then //盲猜应该是硬盘绑定授权模式的验证PopAdLdVar 'Ignore thisPopAdLdVar 'Ignore thisNewIfNullPr frmzc 'Ignore thisfrmzc.Show 1, CVar(Me)End IfIf 0 ThenIf (Proc_30_1_5A0AA4(var_188) = 0) ThenIf (Proc_30_1_5A0AA4(MemVar_6AF114) = 0) Then //经过跟进分析应该是加密狗授权模式的验证PopAdLdVar 'Ignore thisPopAdLdVar 'Ignore thisNewIfNullPr frmzc 'Ignore thisfrmzc.Show 1, CVar(Me)End IfEnd IfSet var_9C = Me.picsqMe.picsq(0).Picture = Me(2).Picturevar_9C = "": var_188 = "": var_190 = "": var_19C = "" 'Ignore thisElseIf (Proc_30_1_5A0AA4("Times New Roman") = 0) ThenPopAdLdVar 'Ignore thisPopAdLdVar 'Ignore thisNewIfNullPr frmzc 'Ignore thisfrmzc.Show 1, CVar(Me)End IfSet var_9C = Me.picsqMe.picsq(0).Picture = Me(1).Picturevar_9C = "": var_188 = "": var_190 = "": var_19C = "" 'Ignore thisEnd IfEnd IfEnd If
经过以上的分析,没有获得什么有价值的线索,忽略
逆向分析2 通过机器码文本跟进(正向推进) 在账号密码验证模式下左下角有一个机器码文本,点进去之后可以生成机器码. 1.我们在VB Decompiler 的forms分支找到frmlogin,查看这个文本的空间名(Lable1),然后到code分支找到Lable1.Click事件的代码
2.代码内容:
NewIfNullPr frmGetZCHao 'Ignore thisfrmGetZCHao.Show 1, CVar(Me)
这样我们就知道生成机器码的窗口是frmGetZCHao[Get注册号]
3.继续在forms分支找到这个窗口 得知下拉框控件名Combo1,文本框Text1 跳转到Code分支的frmGetZCHao代码段 在Form_Load加载事件中
For var_A8 = 0 To 3: var_86 = var_A8 'IntegerNewIfNullPr clsdno 'Ignore thisvar_8C.CurrentDrive = CByte(var_86) //获取硬盘名NewIfNullPr clsdno 'Ignore thisvar_94 = var_8C.GetSerialNumber() //获取硬盘序列号If (var_94 <> vbNullString) ThenPopAdLdVar 'Ignore thisNewIfNullPr clsdno 'Ignore thisMe.Combo1.AddItem var_8C.GetModelNumber(), var_A4 //将硬盘模块号添加到下拉列表中var_94 = "" 'Ignore thisvar_90 = vbNull 'Ignore thisElsePopAdLdVar 'Ignore thisMe.Combo1.AddItem Call Proc_42_6_57E0AC("Msg_DiskUnAble"), var_A4var_94 = "" 'Ignore thisvar_90 = vbNull 'Ignore thisEnd IfNext var_A8 'Integer
在Combo1_Click点击事件方法中复制代码 隐藏代码If CBool((Left(var_88, 3) <> "ERR") And (Len(var_88) = &H10)) Thenvar_B4 = CVar(Call Proc_60_4_583C44("UsbDogFD181" & "<r>" & var_88 & "<r>", "F1DD7CDB1328DB1E")) 'String //初步判断是FD181加密狗Call Proc_88_0_5C2170(var_E4)var_88 = CStr(var_E4)var_A0 = "": var_A4 = "" 'Ignore thisvar_B4 = "" 'Ignore thisElseIf (var_88 = "ERR:open") Thenvar_88 = Call Proc_42_6_57E0AC("Err_Dog_Open")End IfEnd If复制代码 隐藏代码If (var_A0 <> vbNullString) ThenNewIfNullPr clsdno 'Ignore thisNewIfNullPr clsdno 'Ignore thisvar_B4 = CVar(Call Proc_60_4_583C44(var_94.GetModelNumber() & "<r>" & var_94.GetSerialNumber() & "<r>" & CStr(CLng(var_B4)) & "<r>", "F1DD7CDB1328DB1E")) 'String //对获取到的硬盘信息进行加密,这个值在下面的代码会赋值到Text1文本框中Call Proc_88_0_5C2170(var_E4)var_88 = CStr(var_E4)var_A0 = "": var_108 = "": var_A4 = "": var_10C = "": var_110 = "": var_114 = "": var_118 = "" 'Ignore thisvar_B4 = "" 'Ignore thisElsevar_88 = "NoDiseAvailable"End If
4.通过跟进Proc_60_4_583C44可知是modRij对称加密类逆向分析3 通过加密狗导入函数库跟进(正向推进)
1.通过IDA PRO对三个加密狗API文件进行分析导出表,可获得参数头文件和数据类型,利用文本查找工具定位到frmmain的code段中有加载外部DLL文件的函数复制代码 隐藏代码
Private Declare Sub et_AdjustTimer Lib "ft_et299_api"()
'VA: 4EC034
Private Declare Sub et_GetTimeLicense Lib "ft_et299_api"()
'VA: 4EBFE8
Private Declare Sub et_SetTimeLicense Lib "ft_et299_api"()
'VA: 4EBF9C
Private Declare Sub et_GetCountLicense Lib "ft_et299_api"()
'VA: 4EBF50
Private Declare Sub et_SetCountLicense Lib "ft_et299_api"()
'VA: 4EBF04
Private Declare Sub et_RSAPrivateDecrypt Lib "ft_et299_api"()
'VA: 4EBEB4
Private Declare Sub et_RSAPrivateEncrypt Lib "ft_et299_api"()
'VA: 4EBE58
Private Declare Sub et_RSAPublicDecrypt Lib "ft_et299_api"()
'VA: 4EBE0C
Private Declare Sub et_RSAPublicEncrypt Lib "ft_et299_api"()
'VA: 4EBDC0
Private Declare Sub et_RSASetKey Lib "ft_et299_api"()
'VA: 4EBD78
Private Declare Sub et_RSAGenKey Lib "ft_et299_api"()
'VA: 4EBD30
Private Declare Sub et_TDesDecrypt Lib "ft_et299_api"()
'VA: 4EBCE8
Private Declare Sub et_TDesEncrypt Lib "ft_et299_api"()
'VA: 4EBCB4
Private Declare Sub et_SetKeyEx Lib "ft_et299_api"()
'VA: 4EBC70
Private Declare Sub MD5_HMAC Lib "ft_et299_api"()
'VA: 4EBC2C
Private Declare Sub et_HMAC_MD5 Lib "ft_et299_api"()
'VA: 4EBBE8
Private Declare Sub et_SetKey Lib "ft_et299_api"()
'VA: 4EBBA4
Private Declare Sub et_GetSNEx Lib "ft_et299_api"()
'VA: 4EBB60
Private Declare Sub et_SetSNEx Lib "ft_et299_api"()
'VA: 4EBB1C
Private Declare Sub et_GetSN Lib "ft_et299_api"()
'VA: 4EBAC0
Private Declare Sub et_TurnOffLED Lib "ft_et299_api"()
'VA: 4EBA78
Private Declare Sub et_TurnOnLED Lib "ft_et299_api"()
'VA: 4EBA30
Private Declare Sub et_GenRandom Lib "ft_et299_api"()
'VA: 4EB9E8
Private Declare Sub et_ResetSecurityState Lib "ft_et299_api"()
'VA: 4EB998
Private Declare Sub et_SetupToken Lib "ft_et299_api"()
'VA: 4EB950
Private Declare Sub et_ChangeUserPIN Lib "ft_et299_api"()
'VA: 4EB918
Private Declare Sub et_ResetPIN Lib "ft_et299_api"()
'VA: 4EB8D4
Private Declare Sub et_GenSOPIN Lib "ft_et299_api"()
'VA: 4EB890
Private Declare Sub et_Verify Lib "ft_et299_api"()
'VA: 4EB84C
Private Declare Sub et_GenPID Lib "ft_et299_api"()
'VA: 4EB808
Private Declare Sub et_Write Lib "ft_et299_api"()
'VA: 4EB7C4
Private Declare Sub et_Read Lib "ft_et299_api"()
'VA: 4EB784
Private Declare Sub et_CloseToken Lib "ft_et299_api"()
'VA: 4EB72C
Private Declare Sub et_OpenToken Lib "ft_et299_api"()
'VA: 4EB6E4
Private Declare Sub et_FindToken Lib "ft_et299_api"()
'VA: 4EB5C0
Private Declare Sub FD181ChkCalc Lib "fd181"()
'VA: 4EB560
Private Declare Sub FD181GetRand Lib "fd181"()
'VA: 4EB518
Private Declare Sub FD181CloseDev Lib "fd181"()
'VA: 4EB4D0
Private Declare Sub FD181SetPID Lib "fd181"()
'VA: 4EB48C
Private Declare Sub FD181GetPID Lib "fd181"()
'VA: 4EB448
Private Declare Sub FD181SetDispInfo Lib "fd181"()
'VA: 4EB3FC
Private Declare Sub FD181GetAuthorityData Lib "fd181"()
'VA: 4EB3C0
Private Declare Sub FD181SetAuthorityData Lib "fd181"()
'VA: 4EB370
Private Declare Sub FD181SetUserPassword Lib "fd181"()
'VA: 4EB320
Private Declare Sub FD181SetSuperPassword Lib "fd181"()
'VA: 4EB2D0
Private Declare Sub FD181VerifyUserPassword Lib "fd181"()
'VA: 4EB280
Private Declare Sub FD181VerifySuperPassword Lib "fd181"()
'VA: 4EB22C
Private Declare Sub FD181GetDID Lib "fd181"()
'VA: 4EB1C8
Private Declare Sub FD181LedClose Lib "fd181"()
'VA: 4EB180
Private Declare Sub FD181LedOpen Lib "fd181"()
'VA: 4EB138
Private Declare Sub FD181DevRead Lib "fd181"()
'VA: 4EB0F0
Private Declare Sub FD181DevWrite Lib "fd181"()
'VA: 4EB0A8
Private Declare Sub FD181OpenDev Lib "fd181"()
'VA: 4EB060
Private Declare Sub FD181FindDev Lib "fd181"()
'VA: 4EAF28
Private Declare Sub rc_GetLicenseInfo Lib "rcgranddogw32"()
'VA: 4EAEDC
Private Declare Sub rc_Upgrade Lib "rcgranddogw32"()
'VA: 4EAE98
Private Declare Sub rc_GetUpgradeRequestString Lib "rcgranddogw32"()
'VA: 4EAE44
Private Declare Sub rc_ExecuteFile Lib "rcgranddogw32"()
'VA: 4EADFC
Private Declare Sub rc_DefragFileSystem Lib "rcgranddogw32"()
'VA: 4EADB0
Private Declare Sub rc_VisitLicenseFile Lib "rcgranddogw32"()
'VA: 4EAD64
Private Declare Sub rc_DeleteDir Lib "rcgranddogw32"()
'VA: 4EAD1C
Private Declare Sub rc_DeleteFile Lib "rcgranddogw32"()
'VA: 4EACD4
Private Declare Sub rc_WriteFile Lib "rcgranddogw32"()
'VA: 4EAC6C
Private Declare Sub rc_ReadFile Lib "rcgranddogw32"()
'VA: 4EAC28
Private Declare Sub rc_CreateFile Lib "rcgranddogw32"()
'VA: 4EABE0
Private Declare Sub rc_CreateDir Lib "rcgranddogw32"()
'VA: 4EAB98
Private Declare Sub rc_GetRandom Lib "rcgranddogw32"()
'VA: 4EAB50
Private Declare Sub rc_ConvertData Lib "rcgranddogw32"()
'VA: 4EAB08
Private Declare Sub rc_SignData Lib "rcgranddogw32"()
'VA: 4EAAA8
Private Declare Sub rc_DecryptData Lib "rcgranddogw32"()
'VA: 4EAA60
Private Declare Sub rc_EncryptData Lib "rcgranddogw32"()
'VA: 4EAA18
Private Declare Sub rc_SetKey Lib "rcgranddogw32"()
'VA: 4EA9D4
Private Declare Sub rc_ChangePassword Lib "rcgranddogw32"()
'VA: 4EA988
Private Declare Sub rc_VerifyPassword Lib "rcgranddogw32"()
'VA: 4EA93C
Private Declare Sub rc_CheckDog Lib "rcgranddogw32"()
'VA: 4EA8E4
Private Declare Sub rc_GetDogInfo Lib "rcgranddogw32"()
'VA: 4EA89C
Private Declare Sub rc_GetProductCurrentNo Lib "rcgranddogw32"()
'VA: 4EA84C
Private Declare Sub rc_OpenDog Lib "rcgranddogw32"()
'VA: 4EA5A8
Private Declare Sub rc_CloseDog Lib "rcgranddogw32"()
'VA: 4EA494
然后根据加密狗常规函数调用经验,使用文本批量查找工具对以上函数名进行查找.
常规加密狗验证,首先要查找设备,打开设备,读取数据,为了高效我们只定位以上几个关键API.
2.示例:
比如我们查找rc_OpenDog,这个是和狗建立连接,我们在所有代码中搜索,定位到modReg.bas文件的Proc_30_13_5EBBF4方法中,然后我们再搜索Proc_30_13_5EBBF4,发现这个子方法并没有被任何程序调用,所以我们就可以软件中并不是使用这个加密狗模块.
3.最后通过排除法最终确定通过搜索FD181OpenDev,定位到了
modfd181.bas文件中的Proc_79_9_573054方法
所以我们确定在VB Decompiler中code段的modfd181类中就是处理加密狗数据的代码内容了
整理笔记1
frmmain的Form_Load负责弹窗/验证授权
frmlogin是免费版网络验证窗口
frmzc是硬盘版授权&加密狗授权验证窗口
frmGetZCHao是生成加密硬盘ID的窗口(生成注册号)
ModRij是调用对称加密解密的模块 Proc_60前缀标志
modFD181是加密狗通信模块 Proc_79前缀标志
第一阶段总结
主框架的核心代码段分布已经完成,找到了主要的分析节点,接下来就是继续深入解析,并找到关键点
在不更改源程序的情况下只有两种过验证的方法
1.通过生成硬盘绑定模式的注册信息来实现正版验证
技术要点:将软件改为硬盘版(需要改代码),通过分析验证过程来伪造验证文件.[具体验证文件是什么还需深入分析]
2.通过伪造加密狗来实现验证(需要改代码,因为我已经有了加密狗版的安装程序,所以优先考虑这种方法)
技术要点:需要C++编写FD181.dll文件,补齐所有头文件
3.网络验证本身就是功能受限,所以不考虑
那么接下来的工作就是分析代码了
分析过程[由深到浅,逆向推进]
加密狗验证逆向推进
1.首先工具中(VB Decompiler,以下简称工具),code段定位到modFD181类的Proc_79子方法组,选中子方法并在每个子方法右键,选择查看引用(Find references),如果没有弹出窗口就说明这个子方法没有被使用过,最后结果为:
Proc_79_9
Proc_79_10
Proc_79_13
Proc_79_16
共4个子方法被调用过,而且均指向Proc_30_15,
双击后跳转到modReg的Proc_30_15方法,所以可以确定modReg类就是软件验证的类,重点关注!
Proc_79_9分析:将传入的16位String转成byte数组并传给FD181OpenDev来获取返回值,
通过官方资料SDK资料
aHR0cHM6Ly93d3cudGFvZG9jcy5jb20vcC00OTY5OTA0ODIuaHRtbA==
返回handle(大于0的整数/指针)
Proc_79_10分析:效验密码,具体略
Proc_79_13分析:FD181GetDID:获取设备编号
Proc_79_16:FD181DevRead:读取数据
2.我们转到Proc_30_15,具体分析加密狗数据交互流程(需参考以上四个子方法)
Private Sub Proc_30_15_59651C'Data Table: 4979BCDim var_A8 As LongDim var_CC As VariantPopAdLdVar 'Ignore thisvar_A8 = Proc_79_9_573054(CVar("F92DB2AFE056B4B5")) //获取设备指针,大于0If (var_A8 < 1) Thenvar_8C = "ERR:open"Elsevar_98 = Call Proc_79_13_56DD84(var_A8) //返回加密狗IDIf (var_98 = vbNullString) Thenvar_8C = "ERR:GetDID"Elsevar_98 = CStr(Left(CVar(Call Proc_28_24_62E754(var_98)), &H10)) //返回MD5后的设备IDvar_E0 = "" 'Ignore thisvar_CC = "" 'Ignore thisCall Proc_79_10_57DE04(var_CC, var_A8, var_98) //效验密码var_CC = "" 'Ignore thisIf (CLng(var_CC) < 0) Thenvar_8C = "ERR:password"Elsevar_A4 = Call Proc_79_16_576E3C(var_A8, 1, &H24) //读取加密狗数据,36位If (var_A4 = vbNullString) Thenvar_8C = "ERR:ReadData"Elsevar_AC = Split(var_A4, "#", -1, 0) //字符串拆分数组var_CC = "" 'Ignore thisvar_98 = var_98 & var_AC(1) //组合数据var_98 = Call Proc_31_14_606B88(var_98) //自定义加密var_98 = CStr(Left(CVar(Call Proc_31_15_606408(var_98 & "QuickMake")), &H10)) //二次自定义加密var_E0 = "" 'Ignore thisvar_CC = "" 'Ignore thisIf (var_98 <> var_AC(2)) Then //比较处理后数据(数据效验)var_8C = "ERR:NOTCMP"Elsevar_8C = var_98End IfEnd IfEnd IfEnd IfEnd Ifvar_88 = var_8CExit Sub
End Sub
总结
:只需要按照上面代码及其调用的子方法代码梳理清楚并通过C++编译,并返回对应的数据即可完全实现加密狗的数据交互,
3.继续通过查找引用,查找Proc_30_15被调用的方法
Private Sub Proc_30_14_55447C(arg_10) '55447C'Data Table: 4979BCvar_94 = CVar(Proc_30_15_59651C()) 'VariantResult = arg_10: Exit Sub
End Sub
,然后继续查找引用,定位Proc_30_14被哪些方法引用了
结果如下:
frmzc.Combo1_Click
modReg.Proc_30_0
modReg.Proc_30_16
frmGetZCHao.Combo1_Click
frmDog.Tmer1_Timer
由此可见,Proc_30_14就是所有检测获取加密狗数据的最终方法,也算是一个爆破点,只要在这里返回正确的加密数据即可,至于这个数据有什么限制还需要具体分析,这里不做过多说明.
当然不排除以上这些代码内容中有没有写入在其他目前未知的地方进行的全局变量的标志检测.
硬盘授权模式逆向推进
1.继续上面提到的frmGetZCHao类Form_Load窗体加载事件和
Combo1_Click下拉框点击事件中的clsdno类
查看引用Proc_55两个子方法,只在当前类调用,忽略
然后使用文本批量查找工具查找导出的工程,
搜索:
GetModelNumber
GetSerialNumber 硬盘序列号,这个很重要
在这四个frmgetzchao,frmzc,modreg,modwmihdd类中有使用
然后我们用查看引用逆推看哪些是未被使用的代码
frmgetzchao,frmzc这两个类是获取硬盘数据,不太可能是启动验证的代码块,所以我们暂时分析后两个
2.查看引用逆向跟踪引用
GetSerialNumber
Proc_106_3(modWMIHDD)
Proc_81_13(modDiscSize)
frmzc.Combo1_Click
frmzc.Command5_Click
modReg.Proc_30_12
frmGetZCHao.Combo1_Click
最终还是回到了这三个方法里面
所以我们我们可以得出结论:
modreg是最有可能是后台验证数据的方法段.
3.我们分析一下这个申请码是怎么生成的 frmGetZCHao类的Combo1_Click点击事件
ElseCall Proc_81_13_56B030(CLng(MemVar_6AFF28)) //获取硬盘容量NewIfNullPr clsdno 'Ignore thisvar_94.CurrentDrive = CByte(MemVar_6AFF28)NewIfNullPr clsdno 'Ignore thisvar_A0 = var_94.GetSerialNumber()If (var_A0 <> vbNullString) Then //硬盘序列号不为空NewIfNullPr clsdno 'Ignore thisNewIfNullPr clsdno 'Ignore thisvar_B4 = CVar(Call Proc_60_4_583C44(var_94.GetModelNumber() & "<r>" & var_94.GetSerialNumber() & "<r>" & CStr(CLng(var_B4)) & "<r>", "F1DD7CDB1328DB1E")) 'String //组合硬盘名和序列号,进行加密Call Proc_88_0_5C2170(var_E4) //看不明白变量来源,代码是编码转换,常规加密手段var_88 = CStr(var_E4)var_A0 = "": var_108 = "": var_A4 = "": var_10C = "": var_110 = "": var_114 = "": var_118 = "" 'Ignore thisvar_B4 = "" 'Ignore thisElsevar_88 = "NoDiseAvailable"End IfEnd If'Ignore thisSet var_94 = NothingIf (var_88 = "NoDiseAvailable") Thenvar_88 = Call Proc_42_6_57E0AC("Msg_DiskUnAble")End IfMe.Text1.Text = var_88var_8C = vbNull 'Ignore thisExit Sub
反正也看不懂具体的代码功能,这个还需要VB的程序员具体分析
整理笔记2
modFD181类中使用了4个狗头(加密狗头文件)的函数
modReg类中Proc_30_14是加密狗数据交互的桥梁
硬盘版的申请代码加密方法已找到
第二阶段总结
1.如果要伪造加密狗,需要补全所有API,并转换VB代码为C++代码
2.爆破方式需要对Proc_30_14进行编译,根据上下文来构建数据
3.硬盘模式对虚拟机无效,因为虚拟机无法生成硬盘序列号.
似乎陷入了僵局…
别忘了前面提到的对称加密modRij类(Proc_60),无论是加密狗还是硬盘都是用了这个类的方法进行加密,那么我们看这个类里面的具体代码
分析过程[通过加密解密寻找硬盘验证逻辑]
分析Rij
Proc_4
NewIfNullPr cRijndael 'Ignore thisvar_D4 = var_CC.ArrayEncrypt(StrConv(var_8C, &H80, 0), var_9C, 0) //数组加密var_88 = Call Proc_60_0_58C420(var_9C, (UBound(var_9C, 1) + 1), (&H80 / 8)) //编码转换
Proc_5
Call Proc_60_1_59DE20(var_8C, var_9C) //编码转换NewIfNullPr cRijndael 'Ignore thisvar_D4 = var_CC.ArrayDecrypt(var_98, var_9C, 0) //数组解密
查看Proc_5的引用,哇塞,好多地方都使用了,包括各软件功能块的配置数据解密.大概有20个之多,
通过代码对比整合,得出结果
大部分功能类窗口都是用了
MemVar_6AFF34 = Call Proc_60_5_57F48C(Proc_59_1_58D9AC(MemVar_6AF9C0.picSn), "F1DD7CDB1328DB1E")
完整验证代码段
If (Dir(CVar(App.Path & "\sn.bmp"), 0) <> vbNullString) Then //判断软件目录下是否存在sn.bmp文件PopAdLdVar 'Ignore thisPopAdLdVar 'Ignore thisPopAdLdVar 'Ignore thisPopAdLdVar 'Ignore thisNewIfNullPr Me 'Ignore thisvar_A0 = Me.Global.AppPopAdLdVar 'Ignore thisNewIfNullPr Me 'Ignore thisMe.Global.LoadPicture CVar(App.Path & "\sn.bmp"), var_B8, var_C8, var_D8, var_E8 //加载图片数据(字符)NewIfNullPr frmmain 'Ignore thisSet var_F4 = MemVar_6AF9C0.picSnfrmmain.picSn.Picture = var_EC //这里应该就是存放数据的地方var_A4 = "" 'Ignore thisvar_A0 = "": var_F0 = "" 'Ignore thisvar_9C = "" 'Ignore thisNewIfNullPr frmmain 'Ignore thisMemVar_6AFF34 = Call Proc_60_5_57F48C(Proc_59_1_58D9AC(MemVar_6AF9C0.picSn), "F1DD7CDB1328DB1E") //解密数据var_A4 = "" 'Ignore thisvar_A0 = vbNull 'Ignore thisEnd IfElseMemVar_6AFF34 = MemVar_6AFF20 & "|||||||||||||||||||||||||||||"End If
通过分析感觉应该是水印之类的东西,具体功能不详.略过
又失败了,没关系我们继续,换个思路
既然是硬件绑定模式,又没有输入注册码的框框,那肯定是给的授权文件,我们全文搜索 Dir( 和 App.Path
一个是目录拼接,另一个是软件当前路径
通过关键代码查找可用信息
1.工具内CTRL+F调出来搜索框,去掉在活动窗口搜索的选项,搜索Dir(
sn.bmp bip.bmp sn.txt
经过对已有文件数据和综合经验过滤,最终发现以上3个可疑文件
2.分析文件功能和行为
其中对sn.bmp我们排除掉,前面分析过了,没什么用
定位bip.bmp在modCheckID类中,我们要通过交叉引用分析具体功能和作用.
定位sn.txt在modReg模块中,只有Open关键字进行读取操作.
通过对modCheckID类中所有代码分析,应该是从服务器获取黑名单用户,跳过(frmmain的Form_Load最后代码使用,还有UnLoad关闭窗体事件中也使用了)
剩下的就是modReg类,这就是我在前面为什么不跟进这个类,这个类是个关键类,大概率所有验证的内容都在这个类里面
所有的地方都找遍了,最后专心搞modReg类,通过上面的反复横跳,大家应该对VB Decompiler比较了解了吧,呵呵~我专门坑新人
重头戏 分析关键类
1.我们对modReg类每个子方法进行查找引用,综合分析
Proc_30_0
Proc_30_1
Proc_30_2
Proc_30_3
Proc_30_4
Proc_30_5
Proc_30_12
Proc_30_14
以上方法被其他类调用了,
%%%%% 夜深了,有空继续更新内容 %%%%%%%%%%%
其他补充
关于反调试
在frmmain类的Form_Load事件中
var_98 = "参数设定"MemVar_6AF00C = Me.CaptionMe.findsomething.Enabled = True //这个是定时器
事件代码:
Private Sub findsomething_Timer() '557180'Data Table: 4C132CDim var_8C As Stringvar_8C = Call Proc_53_1_585BB0(Me.hWnd) //AntiCrack类If (var_8C <> vbNullString) ThenEndEnd IfExit Sub
End Sub
方法代码
Private Sub Proc_53_1_585BB0(arg_C) '585BB0'Data Table: 4933FCDim var_94 As Longvar_88 = vbNullStringSetLastSystemError 'Ignore thisvar_94 = GetForegroundWindow() //获取活动窗口If (var_94 <> arg_C) ThenGetWindowText(var_94, var_8C, &H100) //获取窗口标题SetLastSystemError 'Ignore thisvar_8C = var_A0var_9C = "" 'Ignore thisvar_9C = var_8Cvar_8C = var_9Cvar_90 = Left$(var_9C, CLng((InStr(1, CVar(var_8C), Chr(0), 0) - 1)))var_9C = "" 'Ignore thisvar_B0 = "" 'Ignore thisvar_B0 = "" 'Ignore thisIf CBool(InStr(1, LCase(var_90), "numega", 0)) Then //检测调试器var_88 = "BADSOFT"End Ifvar_B0 = "" 'Ignore thisIf CBool(InStr(1, LCase(var_90), "softice", 0)) Then //检测调试器var_88 = "BADSOFT"End IfEnd IfExit SubIDE.GoTo loc_585BAD 'Ignore thisIDE.GoTo loc_585C73 'Ignore this
End Sub
呵呵,我就笑了这都啥年代了,还用这种陈旧的调试工具?不过还真可以添加到工具库试试效果.