封心锁爱 发表于 2013-12-15 13:56

【吾爱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





[版权声明]: 本文原创于封心锁爱, 转载请注明作者并保持文章的完整, 谢谢!

bambooqj 发表于 2013-12-15 14:15

页: [1]
查看完整版本: 【吾爱2013CM大赛解答】-- CM -- BambooQJ简单分析