【吾爱2013CM大赛解答】-- CM -- BambooQJ简单分析
[文章标题]: 【吾爱2013CM大赛解答】-- CM -- BambooQJ简单分析[作者信息]: 封心锁爱
[操作平台]: Win7 Sp1
[使用工具]: OD
[软件名称]: CM -- BambooQJ
[下载地址]: http://www.52pojie.cn/thread-228424-1-1.html
这个程序有虚拟机,本鸟蛋对虚拟机没什么研究,大多时候也就是人肉跟踪,下面来说下找关键的具体过程吧:
首先输入错误会有错误提示,咱们载入程序下bp MessageBoxW,会发现不存在,这是因为程序没运行是没有加载User32.dll,我们运行后在下断点.
下完断点随便输入信息或不输入,点击校验按钮,会断下来,这是我们Alt+f9返回,会返回到模块wd180obj中,也就是下面这个地方
251BE864 C3 retn ; >> 返回到这里
251BE865 55 push ebp
251BE866 8BEC mov ebp, esp
251BE868 83EC 10 sub esp, 0x10
251BE86B 57 push edi
251BE86C 8D45 F0 lea eax, dword ptr
251BE86F 50 push eax
251BE870 FF75 08 push dword ptr
251BE873 FF15 A4062F25 call dword ptr [<&USER32.GetWindowRect>; user32.GetWindowRect
我们的目的地是主模块,然后我们多次Ctrl+f9,向着主模块进发,Ctrl+f9多次后我们会发现OD标题上没有写着任何模块,此时我们上下翻动会看见"破解成功","这个没有这么简单"等字样,在破解成功上面有个Jnz跳过了"破解成功",这里就是关键判断了.如下面代码所示,还有判断用户名和注册码是否相同的我复制,就在上面.现在我们有个疑问,为什么标题上没有写着模块名称呢?平常不是应该写着主模块的的名称吗?这是怎么回事呢?
为了弄清这个问题,我们看下这个内存地址到底属于谁,我们Alt+M打开内存窗口,我们发现主模块到了00450000就结束了,说明这个地址不在主模块,再看看程序的其他dll,也不在这些地址范围内,我们多次运行发现这个地址是会变的,那么,可以判断这个地址是动态分配的内存.
01510A00 E8 CB4EA324 call wd180vm.25F458D0
01510A05 85C0 test eax, eax
01510A07 0F85 33000000 jnz 01510A40 ; 关键判断
01510A0D 8B4D 10 mov ecx, dword ptr
01510A10 E8 EBE9A024 call wd180vm.25F1F400
01510A15 8B4D 10 mov ecx, dword ptr
01510A18 B8 A2246E01 mov eax, 0x16E24A2 ; UNICODE "破解成功"
01510A1D E8 3E70A324 call wd180vm.25F47A60
01510A22 8B4D 10 mov ecx, dword ptr
01510A25 E8 86EAA024 call wd180vm.25F1F4B0
01510A2A 8B4D 10 mov ecx, dword ptr
01510A2D 8B75 0C mov esi, dword ptr
01510A30 C706 97216E01 mov dword ptr , 0x16E2197
01510A36 E8 2522A224 call wd180vm.25F32C60
01510A3B E9 4F000000 jmp 01510A8F
01510A40 8B4D 10 mov ecx, dword ptr
01510A43 E8 B8E9A024 call wd180vm.25F1F400
01510A48 8B4D 10 mov ecx, dword ptr
01510A4B B8 B6246E01 mov eax, 0x16E24B6 ; UNICODE "这个貌似没有那么简单"
01510A50 E8 0B70A324 call wd180vm.25F47A60
下面我们走出这块内存,会走到下面的代码处
25EAC312 8B45 F4 mov eax, dword ptr
25EAC315 FFD0 call eax ; 调用动态分配的内存
25EAC317 83C4 18 add esp, 0x18
25EAC31A 5F pop edi
我们在 call eax下断,Ctrl+f2重新开始,程序运行后随便输入注册信息,点校验,断下后我们单步,走过比较注册码和用户是否相同的地方,走到下面是注意了,通过跟踪分析,得知此程序是通过密码生成用户名,首先将BambooQJ连接到密码后面,然后将QQ153442902也连接到后面,最后反转即为正确用户名, KeyGen见结尾
01510940 8B4D 10 mov ecx, dword ptr ; 到这里注意
01510943 B8 66246E01 mov eax, 0x16E2466 ; UNICODE "BambooQJ"
01510948 E8 1371A324 call wd180vm.25F47A60
0151094D 8B4D 10 mov ecx, dword ptr
01510950 E8 2B8BA124 call wd180vm.25F29480 ; 将BambooQJ连接到注册码后面
01510955 8B4D 10 mov ecx, dword ptr
01510958 B8 82246E01 mov eax, 0x16E2482 ; UNICODE "QQ153442902"
0151095D E8 FE70A324 call wd180vm.25F47A60
01510962 8B4D 10 mov ecx, dword ptr
01510965 E8 168BA124 call wd180vm.25F29480 ; 再将QQ153442902连接到后面
0151096A 8B4D 10 mov ecx, dword ptr
0151096D E8 3EEBA024 call wd180vm.25F1F4B0
01510972 8B4D 10 mov ecx, dword ptr
01510975 8B75 0C mov esi, dword ptr
01510978 C706 50216E01 mov dword ptr , 0x16E2150
0151097E E8 CD2BA224 call wd180vm.25F33550
01510983 8B4D 10 mov ecx, dword ptr
01510986 B8 03000000 mov eax, 0x3
0151098B E8 30FFA024 call wd180vm.25F208C0 ; 将上面链接好的字符串反转,形成最终的用户名
01510990 8B4D 10 mov ecx, dword ptr
下面再说下爆破打内存补丁,因为是动态分配的内存,每次都不一样,我们不能在打内存补丁时直接写动态分配内存的地址,我们需要在它分配好内存,将代码写入然后准备调用之前改变关键跳,此时我们也可以得到分配内存的地址,所以时机就是上面的
25EAC312 8B45 F4 mov eax, dword ptr
25EAC315 FFD0 call eax ; 调用动态分配的内存
这里在调用分配内存之前,eax就为分配的内存地址,接下来我们找块空白地方来写我们改数据的指令,往下翻,找到一段空白区域,我这里选择2608F4A2,然后将call eax修改为jmp 2608F4A2,如下所示
25EAC312 8B45 F4 mov eax, dword ptr
25EAC315 E9 88311E00 jmp 2608F4A2
25EAC31A 5F pop edi
下面来写2608F4A2出的指令,根据要修改的指令与分配内存首地址的偏移来修改,然后再执行被上面修改是覆盖的指令,然后跳回继续执行
2608F4A2 60 pushad
2608F4A3 66:C740 48 EB58 mov word ptr , 0x58EB ; ┓
2608F4A9 C740 4A 9090909>mov dword ptr , 0x90909090 ; ┛修改判断用户名和密码是否相同
2608F4B0 C780 37020000 9>mov dword ptr , 0x90909090 ; ┓
2608F4BA 66:C780 3B02000>mov word ptr , 0x9090 ; ┛修改关键跳
2608F4C3 61 popad
2608F4C4 FFD0 call eax ; 调用分配内存
2608F4C6 83C4 18 add esp, 0x18 ; 还原堆栈
2608F4C9^ E9 4CCEE1FF jmp 25EAC31A ; 跳回
所有这些修改我是通过吾爱云盘的Dup2.26汉化版偏移补丁修改的,见附件Dup工程
吾爱注册机:
Function GetMC(X)
End Function
Function GetName(X)
GetName=X
Name=GetName
End Function
' 因为软件是根据密码生成用户名,所以这里将密码
' 填入注册机用户名编辑框中,计算正确的用户名,然后
' 复制注册码为程序用户名,
Function GetSN()
Pw = Name
Pw = Pw & "BambooQJQQ153442902"
GetSN=StrReverse(Pw)
End Function
[版权声明]: 本文原创于封心锁爱, 转载请注明作者并保持文章的完整, 谢谢!
页:
[1]