吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 6489|回复: 12
收起左侧

[CrackMe] 【吾爱2013CM大赛解答】-- LoveKido Update-- JoyChou 算法分析 + 注册机源码

  [复制链接]
playboysen 发表于 2013-12-20 21:14
CM是什么?Crackme是什么?这是什么东西?楼主发的什么?
他们都是一些公开给别人尝试破解的小程序,制作 Crackme 的人可能是程序员,想测试一下自己的软件保护技术,也可能是一位 Cracker,想挑战一下其它 Cracker 的破解实力,也可能是一些正在学习破解的人,自己编一些小程序给自己破解,KeyGenMe是要求别人做出它的 keygen (序号产生器), ReverseMe 要求别人把它的算法做出逆向分析, UnpackMe 是要求别人把它成功脱壳,本版块禁止回复非技术无关水贴。

本帖最后由 playboysen 于 2013-12-20 21:17 编辑

本文针对以下CM:
http://www.52pojie.cn/thread-228422-1-2.html

本机Win7 x64直接运行主程序,提示“发现调试器”??好莫名,我的OD还木有打开呢!!
不管它,OD载入后在代码入口点附近发现了“MSVCR90._decode_pointer”的注释,难道这个是MFC程序(一般可以用工具定位按钮事件地址;而且OD可以直接导入库显示出库函数)??

打开菜单“窗口——可执行模块”如图,看到了mfc90u等,好办多了
确保OD\Lib目标下有诸如“mfc90u.lib”之类的lib文件(如有需要请下载附件),然后导入库(未导入库之前mfc函数都显示为“mfc90u.#1048”,如图)




导入库后,重新加载CM,Ctrl+N打开名称窗口MFC函数均已显示出函数名(如图)

OK,我们来研究调试器检测,OD中查看Unicode字符串轻松找到“检测到虚拟机”,猜测调试器检测代码也在附近(注意由于操作系统差异故代码虚拟地址可能不同)
[AppleScript] 纯文本查看 复制代码
013D1A39   .  FF15 10413>call dword ptr ds:[<&SkinH.SkinH_Attach>]                            ;  SkinH.SkinH_Attach
013D1A3F   .  6A 00      push 0
013D1A41   .  68 EB03000>push 3EB
013D1A46   .  8BCE       mov ecx,esi
013D1A48   .  E8 310B000>call <jmp.&mfc90u.#2904_CWnd::GetDlgItem>                            ;  获取某控件句柄?
013D1A4D   .  8BC8       mov ecx,eax
013D1A4F   .  E8 240B000>call <jmp.&mfc90u.#2360_CWnd::EnableWindow>                          ;  貌似有猫腻儿
013D1A54   .  E8 37FAFFF>call CrackMe?013D1490
013D1A59   .  85C0       test eax,eax
013D1A5B   .  0F85 AF000>jnz CrackMe?013D1B10                                                 ;  1
013D1A61   .  E8 CAFAFFF>call CrackMe?013D1530
013D1A66   .  85C0       test eax,eax
013D1A68   .  0F85 A2000>jnz CrackMe?013D1B10                                                 ;  2
013D1A6E   .  E8 FDFBFFF>call CrackMe?013D1670
013D1A73   .  85C0       test eax,eax
013D1A75   .  0F85 95000>jnz CrackMe?013D1B10                                                 ;  3
013D1A7B   .  E8 50FCFFF>call CrackMe?013D16D0
013D1A80   .  85C0       test eax,eax
013D1A82   .  0F85 88000>jnz CrackMe?013D1B10                                                 ;  4
013D1A88   .  E8 83F9FFF>call CrackMe?013D1410
013D1A8D   .  E8 2EF9FFF>call CrackMe?013D13C0
013D1A92   .  E8 A9F8FFF>call CrackMe?013D1340
013D1A97   .  E8 64F5FFF>call CrackMe?013D1000
013D1A9C   .  85C0       test eax,eax
013D1A9E   .  75 54      jnz short CrackMe?013D1AF4                                           ;  5
013D1AA0   .  E8 9BF7FFF>call CrackMe?013D1240
013D1AA5   .  85C0       test eax,eax
013D1AA7   .  75 4B      jnz short CrackMe?013D1AF4                                           ;  6
013D1AA9   .  E8 F2F7FFF>call CrackMe?013D12A0
013D1AAE   .  85C0       test eax,eax
013D1AB0   .  75 42      jnz short CrackMe?013D1AF4                                           ;  7
013D1AB2   .  FF15 6C403>call dword ptr ds:[<&KERNEL32.GetCurrentProcess>]                    ; [GetCurrentProcess
013D1AB8   .  8D4C24 10  lea ecx,dword ptr ss:[esp+10]
013D1ABC   .  51         push ecx
013D1ABD   .  50         push eax
013D1ABE   .  C74424 18 >mov dword ptr ss:[esp+18],0
013D1AC6   .  FF15 68403>call dword ptr ds:[<&KERNEL32.CheckRemoteDebuggerPresent>]           ;  kernel32.CheckRemoteDebuggerPresent
013D1ACC   .  837C24 10 >cmp dword ptr ss:[esp+10],1
013D1AD1   .  74 21      je short CrackMe?013D1AF4                                            ;  8
013D1AD3   .  E8 B8F8FFF>call CrackMe?013D1390
013D1AD8   .  85C0       test eax,eax
013D1ADA   .  75 18      jnz short CrackMe?013D1AF4                                           ;  9
013D1ADC   .  B8 0100000>mov eax,1
013D1AE1   .  8B4C24 14  mov ecx,dword ptr ss:[esp+14]
013D1AE5   .  64:890D 00>mov dword ptr fs:[0],ecx
013D1AEC   .  59         pop ecx
013D1AED   .  5F         pop edi
013D1AEE   .  5E         pop esi
013D1AEF   .  5B         pop ebx
013D1AF0   .  83C4 10    add esp,10
013D1AF3   .  C3         retn
013D1AF4   >  6A 10      push 10                                                              ; /Style = MB_OK|MB_ICONHAND|MB_APPLMODAL
013D1AF6   .  68 D4473D0>push CrackMe?013D47D4                                                ; |Title = "错误"
013D1AFB   .  68 DC473D0>push CrackMe?013D47DC                                                ; |Text = "检测到调试器"
013D1B00   .  6A 00      push 0                                                               ; |hOwner = NULL
013D1B02   .  FF15 28413>call dword ptr ds:[<&USER32.MessageBoxW>]                            ; \MessageBoxW
013D1B08   .  6A 00      push 0                                                               ; /ExitCode = 0
013D1B0A   .  FF15 44403>call dword ptr ds:[<&KERNEL32.ExitProcess>]                          ; \ExitProcess
013D1B10   >  6A 10      push 10                                                              ; /Style = MB_OK|MB_ICONHAND|MB_APPLMODAL
013D1B12   .  68 90473D0>push CrackMe?013D4790                                                ; |雅蠛蝶
013D1B17   .  68 98473D0>push CrackMe?013D4798                                                ; |检测到虚拟机 by joychoumessageboxauser32.dll
013D1B1C   .  6A 00      push 0                                                               ; |hOwner = NULL
013D1B1E   .  FF15 2C413>call dword ptr ds:[<&USER32.MessageBoxA>]                            ; \MessageBoxA
013D1B24   .  6A 00      push 0                                                               ; /ExitCode = 0
013D1B26   .  FF15 44403>call dword ptr ds:[<&KERNEL32.ExitProcess>]                          ; \ExitProcess

注释中标注的1-9跳转,全都会提示调试器或虚拟机,也懒得一个个NOP
要跳就让它使劲跳!直接修改013D1AF4和013D1B10代码为“jmp 013D1AB2”,另存起来即可成功过检测!

打开修改后的主程序,发现有个灰色按钮(我先入为主的以为,应该是填入正确的信息后程序会自动启用“通关”按钮,所以花费近一个小时尝试下API断点、条件断点等等,无论什么断点都无法中断,几欲放弃最后才发现是要先手工启用按钮才会读取编辑框内容,晕!)

再看上段代码的前几行,GetDlgItem和EnableWindow很明显就是程序启动时禁用了按钮,修改013D1A3F代码为“push 1”即可启用“通关”按钮

由于已经导入库,我们Ctrl+N打开名称窗口找到“mfc90u.#2909_CWnd::GetDlgItemTextW”回车,看看有几处调用


在两处call调用上F2断点,随便输入第一关key点击“通关”按钮测试,成功断下
[AppleScript] 纯文本查看 复制代码
00F51D0B   .  E8 4408000>call <jmp.&mfc90u.#374_CDialog::CDialog>
00F51D10   .  C74424 18 >mov dword ptr ss:[esp+18],CrackMe.00F54B44
00F51D18   .  8D4424 0C  lea eax,dword ptr ss:[esp+C]
00F51D1C   .  50         push eax
00F51D1D   .  68 E903000>push 3E9
00F51D22   .  8BCE       mov ecx,esi
00F51D24   .  C68424 B00>mov byte ptr ss:[esp+B0],1
00F51D2C   .  E8 6B08000>call <jmp.&mfc90u.#2909_CWnd::GetDlgItemTextW>         ;  读取第一关Key
00F51D31   .  8B4C24 0C  mov ecx,dword ptr ss:[esp+C]
00F51D35   .  8B41 F4    mov eax,dword ptr ds:[ecx-C]
00F51D38   .  6A 02      push 2
00F51D3A   .  83C0 FE    add eax,-2
00F51D3D   .  50         push eax
00F51D3E   .  8D5424 18  lea edx,dword ptr ss:[esp+18]
00F51D42   .  52         push edx
00F51D43   .  8D4C24 18  lea ecx,dword ptr ss:[esp+18]
00F51D47   .  FF15 2842F>call dword ptr ds:[<&mfc90u.#4519_ATL::CStringT<wchar_>;  Mid
00F51D4D   .  C68424 A80>mov byte ptr ss:[esp+A8],2
00F51D55   .  8B4424 10  mov eax,dword ptr ss:[esp+10]
00F51D59   .  8B35 0441F>mov esi,dword ptr ds:[<&MSVCR90._wtoi>]                ;  MSVCR90._wtoi
00F51D5F   .  50         push eax
00F51D60   .  FFD6       call esi                                               ;  <&MSVCR90._wtoi>
00F51D62   .  8B4C24 10  mov ecx,dword ptr ss:[esp+10]
00F51D66   .  51         push ecx
00F51D67   .  8BD8       mov ebx,eax
00F51D69   .  C68424 940>mov byte ptr ss:[esp+94],0EF
00F51D71   .  C68424 950>mov byte ptr ss:[esp+95],0E3
00F51D79   .  C68424 960>mov byte ptr ss:[esp+96],0F0
00F51D81   .  C68424 970>mov byte ptr ss:[esp+97],98
00F51D89   .  C68424 980>mov byte ptr ss:[esp+98],9D
00F51D91   .  C68424 990>mov byte ptr ss:[esp+99],0FD
00F51D99   .  C68424 9A0>mov byte ptr ss:[esp+9A],0
00F51DA1   .  FFD6       call esi                                               ;  <&MSVCR90._wtoi>
......
00F51E9D   >  6A 00      push 0                                                 ; /Style = MB_OK|MB_APPLMODAL
00F51E9F   .  C6840C 980>mov byte ptr ss:[esp+ecx+98],0                         ; |
00F51EA7   .  8D8C24 980>lea ecx,dword ptr ss:[esp+98]                          ; |
00F51EAE   .  51         push ecx                                               ; |Title
00F51EAF   .  8BD1       mov edx,ecx                                            ; |
00F51EB1   .  52         push edx                                               ; |Text
00F51EB2   .  6A 00      push 0                                                 ; |hOwner = NULL
00F51EB4   .  FF15 2C41F>call dword ptr ds:[<&USER32.MessageBoxA>]              ; \MessageBoxA
00F51EBA   .  8D4C24 18  lea ecx,dword ptr ss:[esp+18]
00F51EBE   .  E8 8905000>call <jmp.&mfc90u.#2208_CDialog::DoModal>

看到了_wtoi,好像是将宽字符转换为整型数字什么的,看来第一关key应该是个数值,接着是很长一堆简单运算然后MessageBox,也懒得一行行分析,IDA加载后F5分析当前过程

大概是这么个意思,试一试
[Python] 纯文本查看 复制代码
for j in range(88888):
    if j%3==1 and j%5==2 and j%7==4 and j%13==6 and j%17==8:
        print u"第一关key: %d " % j


经测试第一关key输入“18232”会弹出“下一关”对话框,输入其它数字虽弹出乱码不过也可以直接进入第二关,嗯应该没什么问题

还记得上面我们在““mfc90u.#2909_CWnd::GetDlgItemTextW””两处调用call上都设置了断点吗??随便输入第二关key,OD立即断下了
[AppleScript] 纯文本查看 复制代码
00F52091   .  E8 0605000>call <jmp.&mfc90u.#2909_CWnd::GetDlgItemTextW>         ;  获取第二关key
00F52096   .  8B3D 4065F>mov edi,dword ptr ds:[F56540]                          ;  EDI = 机器码
00F5209C   .  8BC7       mov eax,edi                                            ;  EAX = EDI =机器码
00F5209E   .  33C9       xor ecx,ecx                                            ;  ecx = 0
00F520A0   .  8D70 02    lea esi,dword ptr ds:[eax+2]
00F520A3   >  66:8B10    mov dx,word ptr ds:[eax]                               ;  ***begin***
00F520A6   .  83C0 02    add eax,2
00F520A9   .  66:85D2    test dx,dx
00F520AC   .^ 75 F5      jnz short CrackMe.00F520A3
00F520AE   .  2BC6       sub eax,esi
00F520B0   .  D1F8       sar eax,1                                              ;  EAX = LEN(机器码)
00F520B2   .  74 3F      je short CrackMe.00F520F3                              ;  ***end***
00F520B4   .  8BEF       mov ebp,edi                                            ;  EBP = EDI = 机器码
00F520B6   .  8D5424 30  lea edx,dword ptr ss:[esp+30]
00F520BA   .  2BEA       sub ebp,edx
00F520BC   .  8D6424 00  lea esp,dword ptr ss:[esp]
00F520C0   >  8D444D 00  lea eax,dword ptr ss:[ebp+ecx*2]                       ;  真正的第二关key生成算法
00F520C4   .  66:8B5404 >mov dx,word ptr ss:[esp+eax+30]                        ;  机器码从首字节开始逐位参与运算
00F520C9   .  66:42      inc dx
00F520CB   .  66:83F2 1F xor dx,1F                                              ;  (每一字节 + 1) xor 0x1F
00F520CF   .  8BC7       mov eax,edi
00F520D1   .  66:89544C >mov word ptr ss:[esp+ecx*2+30],dx
00F520D6   .  41         inc ecx                                                ;  ECX 作为计数器
00F520D7   .  8D70 02    lea esi,dword ptr ds:[eax+2]
00F520DA   .  8D9B 00000>lea ebx,dword ptr ds:[ebx]
00F520E0   >  66:8B10    mov dx,word ptr ds:[eax]                               ;  ***begin***
00F520E3   .  83C0 02    add eax,2
00F520E6   .  66:85D2    test dx,dx
00F520E9   .^ 75 F5      jnz short CrackMe.00F520E0
00F520EB   .  2BC6       sub eax,esi
00F520ED   .  D1F8       sar eax,1                                              ;  EAX = LEN(机器码)
00F520EF   .  3BC8       cmp ecx,eax                                            ;  ***end***
00F520F1   .^ 72 CD      jb short CrackMe.00F520C0
00F520F3   >  33C0       xor eax,eax
00F520F5   .  66:89444C >mov word ptr ss:[esp+ecx*2+30],ax                      ;  最后一字节置零(以截断字符串)
00F520FA   .  8D4C24 14  lea ecx,dword ptr ss:[esp+14]
00F520FE   .  FF15 6042F>call dword ptr ds:[<&mfc90u.#296_ATL::CStringT<wchar_t>
00F52104   .  C64424 64 >mov byte ptr ss:[esp+64],1
00F52109   .  8B0D 4065F>mov ecx,dword ptr ds:[F56540]                          ;  机器码
00F5210F   .  8B41 F4    mov eax,dword ptr ds:[ecx-C]                           ;  LEN(机器码)
00F52112   .  8B35 3042F>mov esi,dword ptr ds:[<&mfc90u.#2537_ATL::CStringT<wch>;  Format
00F52118   .  8D1400     lea edx,dword ptr ds:[eax+eax]                         ;  EDX = 2*LEN(机器码)
00F5211B   .  83F2 11    xor edx,11                                             ;  EDX = EDX ^ 0x11
00F5211E   .  52         push edx
00F5211F   .  8D4424 18  lea eax,dword ptr ss:[esp+18]
00F52123   .  68 B04CF50>push CrackMe.00F54CB0                                  ;  %d
00F52128   .  50         push eax
00F52129   .  FFD6       call esi                                               ;  Format
00F5212B   .  83C4 0C    add esp,0C
00F5212E   .  8D4C24 10  lea ecx,dword ptr ss:[esp+10]
00F52132   .  FF15 6042F>call dword ptr ds:[<&mfc90u.#296_ATL::CStringT<wchar_t>
00F52138   .  8D4C24 30  lea ecx,dword ptr ss:[esp+30]
00F5213C   .  51         push ecx
00F5213D   .  8D5424 14  lea edx,dword ptr ss:[esp+14]
00F52141   .  68 2C4BF50>push CrackMe.00F54B2C                                  ;  %s
00F52146   .  52         push edx
00F52147   .  C64424 70 >mov byte ptr ss:[esp+70],2
00F5214C   .  FFD6       call esi                                               ;  Format
00F5214E   .  8D4424 20  lea eax,dword ptr ss:[esp+20]
00F52152   .  50         push eax
00F52153   .  8D4C24 2C  lea ecx,dword ptr ss:[esp+2C]
00F52157   .  51         push ecx
00F52158   .  8D4C24 24  lea ecx,dword ptr ss:[esp+24]
00F5215C   .  E8 2F02000>call CrackMe.00F52390                                  ;  Concatenate

算法一目了然,设ID为机器码
[Python] 纯文本查看 复制代码
regCode = ""
for j in range(len(ID)):
        regCode = regCode + chr((ord(ID[j])+1) ^ 0x1F)

regCode =  regCode + str((2*len(ID)) ^ 0x11)


OK,完整注册机代码如下
[Python] 纯文本查看 复制代码
#-------------------------------------------------------------------------------
# Name:        LoveKido Update-- JoyChou
# Author:      Playboysen
# Created:     20/12/2013
# Version:     Python2.7 && Win7 X64
#-------------------------------------------------------------------------------
#!/usr/bin/env python

for j in range(88888):
    if j%3==1 and j%5==2 and j%7==4 and j%13==6 and j%17==8:
        print u"第一关key: %d" % j

ID = raw_input(u"请输入机器码:")
regCode = ""
for j in range(len(ID)):
        regCode = regCode + chr((ord(ID[j])+1) ^ 0x1F)

regCode =  regCode + str((2*len(ID)) ^ 0x11)
print u"第二关key: %s" % regCode


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册[Register]

x

免费评分

参与人数 3热心值 +3 收起 理由
Kido + 1 吾爱破解2013CM大赛,有你更精彩!
JoyChou + 1 分析得不错.Python的注册机很nice
吾爱扣扣 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

吾爱扣扣 发表于 2013-12-20 21:24
膜拜楼主! 会Python的geeker啊! 又涨姿势了! 导入Lib可以显示函数名~!
 楼主| playboysen 发表于 2013-12-20 21:29
吾爱扣扣 发表于 2013-12-20 21:24
膜拜楼主! 会Python的geeker啊! 又涨姿势了! 导入Lib可以显示函数名~!

用到的lib文件已经打包备用,解压后放在OD\Lib文件夹下,然后OD菜单“调试——选择导入库”即可

python只是略知皮毛,不会C编程伤不起啊
文本处理一向是python强项,不用编译源码调试随便修改
一般的注册机都是几行代码搞定了,简单易懂(复杂的确实也不会(╰_╯)#)

点评

呵呵,大大谦虚了  发表于 2013-12-20 21:38
Thend 发表于 2013-12-20 21:35
学到了一招。然后导入lib库,可以直接显示函数名称

点评

MFC封装的函数都是以数字ID表示的,所以要用导入库都可以解析函数名。  发表于 2013-12-20 22:19
这只猪 发表于 2013-12-20 21:40
坐看楼主直播教程
小人物大智慧 发表于 2013-12-20 21:57
这个不得不回帖了 算法分析 有深度  下载CM试试 然后回来看大大的分析 感谢
JoyChou 发表于 2013-12-20 22:17
分析到不错,python的keygen很nice
战股神 发表于 2013-12-20 22:59
牛人膜拜,牛人膜拜!
 楼主| playboysen 发表于 2013-12-20 23:43
JoyChou 发表于 2013-12-20 22:17
分析到不错,python的keygen很nice

对imul这个指令不太明白,请教一事

如图,设eax = 0x92492493 , ecx= 0x4738
那么执行了“imul ecx”之后,edx不是应该等于“0x28B2”吗????怎么会等于“0xFFFFE17A”???


以下是Python中的计算结果,我觉得这样才正确


求解释

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册[Register]

x
L4Nce 发表于 2013-12-21 11:39
playboysen 发表于 2013-12-20 23:43
对imul这个指令不太明白,请教一事

如图,设eax = 0x92492493 , ecx= 0x4738

应该是eax是负的,imul是带符号的。你这么算是没有符号的
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止回复与主题无关非技术内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-29 10:09

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表