目标
使用学习版XYplorer时,打开新标签页和设置菜单,很大几率会出现咖啡图案和提示“There is a problem with your license key!”错误并程序退出。很烦人,今天我们来解决这个问题。
开始
基本工具
XYplorer 23.80
x64dbg
VB Decompiler v11.5 pro(XYplorer是VB写的)
切入点
由于是程序退出,先在x64dbg里下了ExitProcess断点,发现追不回去。在网上发现了这个帖子,他帖子里是跳出对话框,和我们现在的情况不一样,但是帖子里有个截图,如下图
图中弹出对话框CALL前面有一个vbaStrCopy调用引起了我的注意,那就下个bp __vbaStrCopy
断点试试。
启动程序,下bp __vbaStrCopy
断点,发现被断下来的次数也太多了,需要做条件筛选。
观察x64dbg寄存器,发现EDX总是字符串,ESP是调用返回地址
那么编辑vbaStrCopy断点条件如下图
现在点新标签页,直到出现咖啡图案和错误提示。出现咖啡图案后,程序会自动退出。我们再看看x64dbg的日志窗口
“There is a problem with your license key!”字符串已经出现了。按说我们要去追踪这个82A4E地址,但别着急,之前提到的帖子截图里,有个UNICODE字符串"31180B…."和"nep",我们日志这里也出现了,那按照他帖子截图的代码,应该是出现这两个字符串后调用对话框,对话框代码再复制"There is a problem"字符串。因此我们也先追踪717566地址的"31180B…."字符串看看。
717566地址
删除vbaStrCopy断点,重启程序,按CTRL+G来到717566地址,上下翻动查看,发现这段代码还挺长。不要紧,我们换用VB Decompiler软件。
打开VB Decompiler,载入XYplorer程序,也按CTRL+G来到717566地址,发现717566地址属于switch case 14分支。
代码段中有coffee、picList1.Refresh、Global.Unload字样,那这很明显,这段代码段的功能就是显示咖啡图案并且程序退出。因此我们不能让这段代码运行。
switch分支
看看switch分支选择在哪里。VB Decompiler 717566代码段往上拉到顶,有一句
1 | loc_00716D74: Select Case Me |
这句就是分支选择语句。切换到x64dbg,按CTRL+G跳转到716D74地址
1 2 3 4 5 6 | 00716D62 | 8B46 3C | mov eax,dword ptr ds:[esi+0x3C] | 00716D65 | 8945 D0 | mov dword ptr ss:[ebp-0x30],eax | 00716D68 | 8D48 FF | lea ecx,dword ptr ds:[eax-0x1] | 00716D6B | 83F9 1B | cmp ecx,0x1B | 00716D6E | 0F87 790C0000 | ja xyplorer.7179ED | 00716D74 | FF248D 807A7100 | jmp dword ptr ds:[ecx*4+0x717A80] | |
ecx的值是由eax传过来的。在716D62行下断点,CTRL+F2重启程序并运行。
先得知道正常的switch分支段。经我随便尝试,取消最大化时,会触发断点。被断下来时[esi+0x3C]=0x18。0x18的十进制是24,对应switch 24分支,地址是007177BF。
1 | loc_007177BF: Case 24 |
在Xyplorer里点新建标签页加号,多点几次直至被断下。此时[esi+0x3C]=0xE。E的十进制是14,也就对应switch 14分支。
由于我们不能让14分支代码执行,可以用一个jmp指令强制跳转14分支到24分支。
14分支开头代码:
1 2 3 4 5 6 7 | 007174AD | 8B16 | mov edx,dword ptr ds:[esi] | 007174AF | 56 | push esi | 007174B0 | FF92 58170000 | call dword ptr ds:[edx+0x1758] | 007174B6 | 8B06 | mov eax,dword ptr ds:[esi] | 007174B8 | 56 | push esi | 007174B9 | FF90 F0040000 | call dword ptr ds:[eax+0x4F0] | 007174BF | 50 | push eax | |
直接修改7174AD行,改为jmp强制跳转到24分支去。
1 2 3 4 5 6 7 8 9 | 007174AD | E9 0D030000 | jmp xyplorer.7177BF | 007174B2 | 90 | nop | 007174B3 | 90 | nop | 007174B4 | 90 | nop | 007174B5 | 90 | nop | 007174B6 | 8B06 | mov eax,dword ptr ds:[esi] | 007174B8 | 56 | push esi | 007174B9 | FF90 F0040000 | call dword ptr ds:[eax+0x4F0] | 007174BF | 50 | push eax | |
好,现在我们重启XY程序运行试试。XY程序目前我们点击新标签页加号,程序已经不会出错。但经常会点击后不打开新标签页。这实际上就是程序从14分支跳到24分支,还不是正常的程序流程。
那么接下来我们从根源上追踪[esi+0x3C]这个代码分支选择数值是哪里来的。
[esi+0x3C] 写入追踪
在
1 | 00716D62 | 8B46 3C | mov eax,dword ptr ds:[esi+0x3C] | |
行上下断点,XY程序里点几次新标签页,程序断下来。转储跟随[esi+0x3C]地址,如下图
我这里是FFC1FC地址,这个地址每次重启XY程序都不一样。
在FFC1FC地址下断点-硬件写入-字节,发现会被多次断下。那我们再用条件断点筛选一下。我们需要当FFC1FC地址数值为E时断下,因此可以如图设置
设置好后,让XY程序运行,继续点新标签页直至断下
虽然断在了716B8B行,但其实是716B88行修改的数值,ESI+3C就是FFC1FC,EDI=E。
切换到VB Decompiler的716B8B地址,整个函数如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | Private Sub Proc_0_1046_716A10(arg_C, arg_10, arg_14, arg_18, arg_1C) '716A10 loc_00716A5A: If arg_14 Then loc_00716A68: If global_60 = arg_C Then GoTo loc_00716B59 loc_00716A70: If global_60 = 0 Then GoTo loc_00716B59 loc_00716A79: If arg_C = 24 Then GoTo loc_00716B59 loc_00716A82: var_8004 = frmMain.tmrDelay_Timer loc_00716AA6: If global_60 Then loc_00716ABC: ReDim var_30() loc_00716B1C: var_801C = Proc_3_153_7D66F0("setDelayedAction (" & CStr(arg_C) & "): could not trigger queued because " & CStr(global_60), var_30, 0) loc_00716B51: GoTo loc_00716C41 loc_00716B56: End If loc_00716B59: End If loc_00716B5F: If global_00716C42.Reset <> 23 Then loc_00716B68: If global_00716C42.Reset <> 19 Then loc_00716B72: If arg_18 Then loc_00716B76: If global_00716C42.Reset Then GoTo loc_00716C05 loc_00716B7C: End If loc_00716B7F: var_8020 = .Proc_0_1047_717AF0(0) loc_00716BA7: frmMain.tmrDelay.Interval = arg_10 loc_00716BE1: frmMain.tmrDelay.Enabled = True loc_00716C05: End If loc_00716C05: End If loc_00716C0A: GoTo loc_00716C41 loc_00716C40: Exit Sub loc_00716C41: ' Referenced from: 00716B51 loc_00716C41: ' Referenced from: 00716C0A End Sub |
虽然看不太明白,但大概是设置了一个Delay_Timer,之后设置了frmMain.tmrDelay的值。
这里我尝试将00716B5F行强行jmp,发现无效,因此只有继续回溯看是哪个函数调用了这个代码段。
1 2 | loc_00716B5F: If global_00716C42.Reset <> 23 Then 00716B5F | 0F84 A0000000 | je xyplorer.716C05 | |
谁调用了716A10
删除硬件断点,在716B88行上下条件断点(中断条件EDI==E),继续点XY的新标签页直至断下。
断下后,F8单步运行,直至返回调用函数,可以看到是5C1FF2调用的。
1 | 005C1FF2 | FF90 50170000 | call dword ptr ds:[eax+0x1750] | |
切换到VB Decompiler,CTRL+G来到5C1FF2地址,代码如下
1 2 3 4 5 6 7 8 9 | Private Sub Proc_0_455_5C1F10(arg_C, arg_10, arg_14, arg_18, arg_1C, arg_20, arg_24, arg_28, arg_2C, arg_30, arg_34) '5C1F10 loc_005C1FAC: var_28 = arg_10 loc_005C1FBC: If global_00BCF088 Then loc_005C1FD5: var_8004 = frmMain.Proc_0_617_5FC560(0, 0, 0, 0, 0, ) loc_005C1FE3: If Proc_12_4_829930(, , ) Then loc_005C1FF2: var_800C = frmMain.Proc_0_1046_716A10(14, 100, 0, 0, var_5C) loc_005C1FFE: GoTo loc_005C2FA3 loc_005C2003: End If loc_005C2003: End If |
很明显,只要屏蔽loc_005C1FE3: If Proc_12_4_829930(, , ) Then
即可。
切换到x64dbg,CTRL+G到005C1FE3地址,直接将
1 | 005C1FE3 | 74 1E | je xyplorer.5C2003 | |
改为jmp跳转
1 | 005C1FE3 | EB 1E | jmp xyplorer.5C2003 | |
测试效果
此时之前我们设置的断点00716B88 | 897E 3C | mov dword ptr ds:[esi+0x3C],edi |
仍然有效,如果jmp修改有效,则这个断点不会再触发。
现在继续点击XY程序的新建标签页,点了十几次,都没有触发716B88断点,也没有出现点击却不打开新标签页。说明修改成功。
解决XY配置选项错误
新标签页的问题解决了,但打开XY的工具-配置选项时,仍然会出现咖啡图案。
确保上面提到的716B88行条件断点启用,然后打开XY的配置选项,如果成功打开配置选项了,那就关了重新打开,直至断下。
仍然断在716B88行,并且EDI=E,F8单步运行到上级函数(或者CTRL+F9运行到返回也可以),返回到了
1 2 | 006D7A8F | FF91 50170000 | call dword ptr ds:[ecx+0x1750] | >>>006D7A95 | 68 E87B6D00 | push xyplorer.6D7BE8 | |
同样,切换到VB Decompiler,CTRL+G到6D7A95看看。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | Private Sub Proc_0_912_6D7890 loc_006D78FE: If global_00BD2468 Then loc_006D790B: If global_00BD246A = 0 Then loc_006D7962: var_800C = "Please unlock the trial version under the Help menu." & vbCrLf & Chr(13) & Chr(10) & "If you haven't purchased a license yet: Click OK to open the online order page." loc_006D79D5: var_8014 = Proc_113_34_B374F0(Proc_70_15_969FC0("Trial Version Expired", 0, var_58, 0, 0), global_00464718, Proc_70_15_969FC0(var_800C, 0, var_5C, 0, 0), 6, 3, -1, 0, var_60, Form()) loc_006D7A17: If var_8014 - 1 + 1 = 0 Then GoTo loc_006D7B9D loc_006D7A27: var_58 = &H16 loc_006D7A36: If frmMain.menHelpWeb_Click(var_58) >= 0 Then GoTo loc_006D7B9D loc_006D7A48: var_8018 = CheckObj(Me, global_0046F344, 4776) loc_006D7A58: End If loc_006D7A58: End If loc_006D7A5A: var_801C = Proc_83EC20(global_006D7BE8, 0, 0) loc_006D7A62: If var_801C = 0 Then loc_006D7A6F: If global_00BD13CC = 0 Then loc_006D7A7D: If Proc_12_4_829930(0, 0, 0) Then loc_006D7A8F: var_8024 = frmMain.Proc_0_1046_716A10(14, 100, 0, 0, var_58) loc_006D7A9A: GoTo loc_006D7BD5 loc_006D7A9F: End If loc_006D7AB4: If var_14 <= 7 Then loc_006D7AD6: var_8028 = frmMain.Proc_0_622_5FDD10(var_14, var_94) loc_006D7AF6: var_14 = var_14(1) loc_006D7AF9: GoTo loc_006D7AAA loc_006D7AFB: End If loc_006D7AFD: var_802C = Proc_0_913_6D7C00(Me) loc_006D7B5E: var_8034 = frmConfig.Show 3, var_40 loc_006D7B8F: Set global_00BD3348 = {DDA30E3B-B946-4670-B887C909445C231F}() loc_006D7B98: var_8038 = Proc_0_913_6D7C00(Me) loc_006D7B9D: End If loc_006D7B9D: End If loc_006D7BA2: GoTo loc_006D7BD5 loc_006D7BD4: Exit Sub loc_006D7BD5: ' Referenced from: 006D7A9A loc_006D7BD5: ' Referenced from: 006D7BA2 End Sub |
很明显这是先判断、验证序列号,之后执行frmConfig.Show。
修改同样,屏蔽loc_006D7A7D: If Proc_12_4_829930(0, 0, 0) Then
。
x64dbg里CTRL+G跳到006D7A7D地址,je直接修改为jmp即可。
1 | 006D7A7D | 74 20 | je xyplorer.6D7A9F | |
修改后,打开XY的配置选项,再也不会出现咖啡图案了。
Proc_12_4_829930(0, 0, 0)
是判断序列号是否有问题的函数,有兴趣的同学可以研究一下。
总结
本文没什么难度,XYplorer没加壳,用VB Decompiler几乎和读源代码没什么区别。
修改的地方
x64dbg补丁:
标签页特征码:
E8 ?? ?? ?? ?? 66 85 C0 74 1E 8B 06
改为
E8 ?? ?? ?? ?? 66 85 C0 EB 1E 8B 06
配置选项特征码:
E8 ?? ?? ?? ?? 66 85 C0 74 ?? 8B ?? ?? 8D ?? ?? 52 53
改为
E8 ?? ?? ?? ?? 66 85 C0 EB ?? 8B ?? ?? 8D ?? ?? 52 53
成品补丁:
文章评论
谢谢您king1027