最近闲来无事,看了一些前辈们的破解教学视频,灰常激动有木有!!!于是随便找了一款软Udm(Universal Maps Downloader)来练练手,加深一下理解,错误的地方还请各位看官多多批评指正。这款软件是从谷歌地图、雅虎地图、必应地图上搜索下载图片用的,没有什么用处,本来嘛,也不是出于什么商业目的。
先来看看这款软件简约的令人发指的操作界面。
呵呵,够简陋吧,一点都不像59.95$的软件吧。不过我倒是挺欣赏这种风格,没什么花哨的地方,毕竟讲究的是功能第一嘛!废话不多说,先来看看这款软件有木有加壳:
很幸运,DiE检测结果显示Universal Maps Downloader这款软件没有加壳,而且还是C++语言编写的。其实拿这款软件小试牛刀,最重要的原因就是:它没加壳!虽然脱壳的地位很重要,想学破解必学脱壳,我认为对于新手来说还是从简单的做起比较好,一口吃不了个大胖子么(其实是脱壳教程把我看晕了)。
一般来说,破解的第一步就是用假注册码测试目标软件的“生理反应”,像错误提示、重启验证什么的,以便于我们确定采取什么样的分析方式。用25位假注册码测试该软件,发现是最常见的错误弹框提示:
那,像这样的错误提示型反应,一般是F12暂停查看堆栈或者直接搜索文本信息,首先用第一种方法看看能不能找到关键代码部分,用Ollydbg载入—>F9运行—>输入假码—>F12暂停,这样程序就暂停了,然后点击菜单栏K按钮来到这里:
我们可以发现来自umd的调用一共有3个,在参数里并没有出现我们想要的MessageBoxA或者MessageBoxW。没办法,再用第二种方法试试。
Ollydbg载入—>F9运行—>输入假码—>点确定—>汇编窗口右键搜索—>所有参考的文本字符串。
这样我们就来到了文本字符串这里,右键搜索文本。
输入“wrong serial number”,去掉区分大小写,勾上整个范围,然后点确定:
然后我们就定位到了错误提示文本字符串:
这里我们发现有两个我们想要的文本字符串,不过没关系,鉴于它们的地址离得很近,随便跟随一个就可以,而且用篮框框住的 ASCII "D3BD9115AFD78174",是不是很可疑?双击跟随错误提示文本,我们就来到了关键代码段:
第一个错误提示文本向上走,在最近的一个call,F2下断点。然后点F9运行,再点一下注册框确定按钮,可以看到程序就在0040E1F1处成功断下来了。
下面简单分析了一下代码,首先是判断注册码是否为空:
0040E1FC 837D FC 00 cmp dword ptr ss:[ebp-4],0 ; 判断注册码是否为空
0040E200 74 08 je short umd.0040E20A
0040E202 8B45 FC mov eax,dword ptr ss:[ebp-4]
0040E205 8B48 FC mov ecx,dword ptr ds:[eax-4]
0040E208 EB 02 jmp short umd.0040E20C
0040E20A 33C9 xor ecx,ecx
0040E20C 83F9 19 cmp ecx,19
0040E20F 74 4F je short umd.0040E260 ; 注册码不为空则跳转
0040E211 66:C745 88 2000 mov word ptr ss:[ebp-78],20
0040E217 BA A3E14C00 mov edx,umd.004CE1A3 ;ASCII "Wrong serial number!"
F8往下走一段,就来到了“伪算法”部分,为什么叫伪算法呢?在后面的分析中大家就会明白了。
0040E2D2 8A13 mov dl,byte ptr ds:[ebx] ; 算法部分
0040E2D4 33C0 xor eax,eax
0040E2D6 8816 mov byte ptr ds:[esi],dl ; 取一位注册码
0040E2D8 B9 03000000 mov ecx,3
0040E2DD 66:C745 88 4400 mov word ptr ss:[ebp-78],44
0040E2E3 8A06 mov al,byte ptr ds:[esi]
0040E2E5 99 cdq
0040E2E6 F7F9 idiv ecx
0040E2E8 8D45 C8 lea eax,dword ptr ss:[ebp-38]
0040E2EB 8A5413 01 mov dl,byte ptr ds:[ebx+edx+1] ; 除法所得余数加一然后取下一位
0040E2EF E8 78A60B00 call umd.004C896C
0040E2F4 FF45 94 inc dword ptr ss:[ebp-6C]
0040E2F7 8D55 C8 lea edx,dword ptr ss:[ebp-38]
0040E2FA 8D45 F8 lea eax,dword ptr ss:[ebp-8]
0040E2FD E8 EEA70B00 call umd.004C8AF0
0040E302 FF4D 94 dec dword ptr ss:[ebp-6C]
0040E305 8D45 C8 lea eax,dword ptr ss:[ebp-38]
0040E308 BA 02000000 mov edx,2
0040E30D E8 9AA70B00 call umd.004C8AAC
0040E312 47 inc edi ; 计数器加一
0040E313 46 inc esi
0040E314 83C3 04 add ebx,4 ; 下次循环右移4位
0040E317 83FF 06 cmp edi,6 ; 判断是否循环6次
0040E31A ^ 7C B6 jl short umd.0040E2D2
经过上一步,程序就将输入的25位假码转换成了6位,然后加上z头和rh尾,之后就是关键的假码二次处理了。
0040E37D FF4D 94 dec dword ptr ss:[ebp-6C] ; 取6次循环算出的假码加上z头和rh尾
0040E380 8D45 C0 lea eax,dword ptr ss:[ebp-40]
0040E383 BA 02000000 mov edx,2
0040E388 E8 1FA70B00 call umd.004C8AAC
0040E38D FF4D 94 dec dword ptr ss:[ebp-6C]
0040E390 8D45 C4 lea eax,dword ptr ss:[ebp-3C]
0040E393 BA 02000000 mov edx,2
0040E398 E8 0FA70B00 call umd.004C8AAC
0040E39D 6A 01 push 1
0040E39F 8D8D 5CFFFFFF lea ecx,dword ptr ss:[ebp-A4]
0040E3A5 51 push ecx
0040E3A6 6A 09 push 9
0040E3A8 837D F8 00 cmp dword ptr ss:[ebp-8],0 ; 假注册码运算结果与0比较
0040E3AC 74 05 je short umd.0040E3B3
0040E3AE 8B45 F8 mov eax,dword ptr ss:[ebp-8]
0040E3B1 EB 05 jmp short umd.0040E3B8
0040E3B3 B8 BFE14C00 mov eax,umd.004CE1BF
0040E3B8 50 push eax
0040E3B9 8D95 04FFFFFF lea edx,dword ptr ss:[ebp-FC]
0040E3BF 52 push edx
0040E3C0 E8 472E0000 call umd.0041120C ; 关键call,假码二次处理
0040E3C5 66:C745 88 5C00 mov word ptr ss:[ebp-78],5C
0040E3CB 8D8D 5CFFFFFF lea ecx,dword ptr ss:[ebp-A4]
0040E3D1 83C4 14 add esp,14
0040E3D4 33D2 xor edx,edx
0040E3D6 B8 08000000 mov eax,8
0040E3DB FF71 04 push dword ptr ds:[ecx+4]
0040E3DE FF31 push dword ptr ds:[ecx]
0040E3E0 8955 B8 mov dword ptr ss:[ebp-48],edx
0040E3E3 8D55 B8 lea edx,dword ptr ss:[ebp-48]
0040E3E6 FF45 94 inc dword ptr ss:[ebp-6C]
0040E3E9 E8 9A0B0400 call umd.0044EF88
0040E3EE 8D55 B8 lea edx,dword ptr ss:[ebp-48]
0040E3F1 8D45 F4 lea eax,dword ptr ss:[ebp-C]
0040E3F4 E8 DBA40B00 call umd.004C88D4
0040E3F9 FF45 94 inc dword ptr ss:[ebp-6C]
0040E3FC FF4D 94 dec dword ptr ss:[ebp-6C]
0040E3FF 8D45 B8 lea eax,dword ptr ss:[ebp-48]
0040E402 BA 02000000 mov edx,2
0040E407 E8 A0A60B00 call umd.004C8AAC
0040E40C 66:C745 88 0800 mov word ptr ss:[ebp-78],8
0040E412 66:C745 88 6800 mov word ptr ss:[ebp-78],68
0040E418 BA C0E14C00 mov edx,umd.004CE1C0 ; ASCII "D3BD9115AFD78174"
0040E41D 8D45 B4 lea eax,dword ptr ss:[ebp-4C]
0040E420 E8 77A40B00 call umd.004C889C
0040E425 FF45 94 inc dword ptr ss:[ebp-6C]
0040E428 8D55 B4 lea edx,dword ptr ss:[ebp-4C]
0040E42B 8D45 F4 lea eax,dword ptr ss:[ebp-C]
0040E42E E8 5DA70B00 call umd.004C8B90 ; 关键call,假码二次处理结果与D3BD9115AFD78174比较
0040E433 50 push eax
0040E434 FF4D 94 dec dword ptr ss:[ebp-6C]
0040E437 8D45 B4 lea eax,dword ptr ss:[ebp-4C]
0040E43A BA 02000000 mov edx,2
0040E43F E8 68A60B00 call umd.004C8AAC
0040E444 59 pop ecx
0040E445 84C9 test cl,cl
0040E447 0F84 D3000000 je umd.0040E520 ; 关键跳转,如果跳转则注册码错误
可以看到有两个关键跳转,0040E3C0处假码二次处理和0040E42E处处理结果与D3BD9115AFD78174比较。
0040E3C0地址处F7步入:
0041120C 55 push ebp
0041120D 8BEC mov ebp,esp
0041120F 53 push ebx
00411210 56 push esi
00411211 57 push edi
00411212 8B7D 0C mov edi,dword ptr ss:[ebp+C]
00411215 8B5D 08 mov ebx,dword ptr ss:[ebp+8]
00411218 53 push ebx
00411219 53 push ebx
0041121A E8 E5F4FFFF call umd.00410704 ; 32位数据入栈
0041121F 83C4 08 add esp,8
00411222 33F6 xor esi,esi
00411224 3B75 18 cmp esi,dword ptr ss:[ebp+18]
00411227 7D 15 jge short umd.0041123E
00411229 8B45 10 mov eax,dword ptr ss:[ebp+10]
0041122C 50 push eax
0041122D 57 push edi
0041122E 53 push ebx
0041122F 53 push ebx
00411230 E8 FBF4FFFF call umd.00410730
00411235 83C4 10 add esp,10
00411238 46 inc esi
00411239 3B75 18 cmp esi,dword ptr ss:[ebp+18]
0041123C ^ 7C EB jl short umd.00411229
0041123E 53 push ebx
0041123F 8B55 14 mov edx,dword ptr ss:[ebp+14]
00411242 52 push edx
00411243 53 push ebx
00411244 E8 8FF5FFFF call umd.004107D8 ; 关键call,对32位数据进行运算,步入
00411249 83C4 0C add esp,0C
0041124C 5F pop edi
0041124D 5E pop esi
0041124E 5B pop ebx
0041124F 5D pop ebp
00411250 C3 retn
32位数据是用来参与核心运算的,其运算结果要与D3BD9115AFD78174进行比较。跟进之后:
00410704 55 push ebp
00410705 8BEC mov ebp,esp
00410707 8B45 0C mov eax,dword ptr ss:[ebp+C]
0041070A 33D2 xor edx,edx
0041070C 8950 14 mov dword ptr ds:[eax+14],edx
0041070F 8950 10 mov dword ptr ds:[eax+10],edx
00410712 C700 01234567 mov dword ptr ds:[eax],67452301 ; 0012F158堆栈地址填充67452301
00410718 C740 04 89ABCDE>mov dword ptr ds:[eax+4],EFCDAB89 ; 0012F15C堆栈地址填充EFCDAB89
0041071F C740 08 FEDCBA9>mov dword ptr ds:[eax+8],98BADCFE ; 0012F160堆栈地址填充98BADCFE
00410726 C740 0C 7654321>mov dword ptr ds:[eax+C],10325476 ; 0012F164堆栈地址填充10325476
0041072D 5D pop ebp
0041072E C3 retn
实际上就是在0012F158—0012F164填充67452301EFCDAB8998BADCFE10325476
00411244对应的调用步入之后,对32数据的运算是在00410786的调用里:
00410786 E8 D1000000 call umd.0041085C ; 二次注册码产生的地方
一跟进去直接吓了一跳,洋洋洒洒940行,丹都碎了。鉴于自己能力有限,就放弃治疗,不打算分析这个算法了,那位大神如果有兴趣可以分析一下,这里我就把它的头和尾贴出来了事。
0041085C 55 push ebp
0041085D 8BEC mov ebp,esp
0041085F 83C4 BC add esp,-44
00410862 53 push ebx
00410863 56 push esi
00410864 57 push edi
00410865 8B45 0C mov eax,dword ptr ss:[ebp+C]
...............
...............
...............
...............
004111FB E8 E8CC0A00 call umd.004BDEE8
00411200 83C4 0C add esp,0C
00411203 5F pop edi
00411204 5E pop esi
00411205 5B pop ebx
00411206 8BE5 mov esp,ebp
00411208 5D pop ebp
00411209 C3 retn
另一很大的问题出现了,这个数据跟输入的假码没有太大关系,随便用几个假码一试,发现这个32位假码67452301EFCDAB8998BADCFE10325476是不变的。那什么变了呢?与D3BD9115AFD78174进行比较的运算出来的16位数据变了。也就是说我们输入的假码决定的是最终算出的16位注册码是个什么样子,跟踪一下也没发现集体操作在哪里,鉴于算法部分太长(940行!),不太容易分析,就爆破一下,浅尝则止吧(哪位大神如果分析出来,一定要教教小弟)。
最简单的方法莫过于爆破了:
0040E447 /0F84 D3000000 je umd.0040E520 ; 关键跳转,如果跳转则注册码错误
这里,je改成jne就行了,或者手动pach一下也可以。就写这么多吧,新手小白,没分析出来算法,希望大家多多批评指正。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)