带壳调试《XXX面试真题600道详解》
1.试运行:
机器码:CD48047047390
注册码:87654321
提示:密码已存储,在需要的时候调用。
2.上RegMon.exe:
12.68640137 gwyinterview.ex:1448 OpenKey HKCU\CLSID\{242A8E4F-A261-2211-2211-00C04FB9603F}\05110wsyy7120801 NOT FOUND
12.68645573 gwyinterview.ex:1448 SetValue HKCR\CLSID\{242A8E4F-A261-2211-2211-00C04FB9603F}\05110wsyy7120801\yyzcm SUCCESS "636877907888216"
12.68652916 gwyinterview.ex:1448 CloseKey HKCR\CLSID\{242A8E4F-A261-2211-2211-00C04FB9603F}\05110wsyy7120801 SUCCESS
3.查壳脱壳:
ASPack 2.12 -> Alexey Solodovnikov [Overlay]
OD载入,取消继续分析:
00574001 g>pushad
00574002 call gwyinter.0057400A
00574007 jmp 45B444F7
...
005743AF popad
005743B0 jnz short gwyinter.005743BA
005743B2 mov eax,1
005743B7 retn 0C
005743BA push gwyinter.0051DD7C
005743BF retn 返回到 0051DD7C (gwyinter.0051DD7C)
dump,Borland Delphi 4.0 - 5.0
脱壳后一运行就闪过一个框,然后退出。
估计有自校验程序。
4.自校验:KERNEL32.CreateFileA
注意堆栈,一直F9运行,看到主程序出现就停按F9,在:
0040696F call <jmp.&kernel32.CreateFileA>
有两次调用,脱壳与未脱壳进行分别跟踪,第一次调用都是一样处理,第二次调用后F8往下走,来到一个大循环,次数狂多,未脱壳的循环次数ebx=1F4,脱壳后的循环次数ebx=17A:
004E3312 > /8D45 E8 lea eax,dword ptr ss:[ebp-18]
004E3315 . |50 push eax
004E3316 . |8D95 E0EFFFFF lea edx,dword ptr ss:[ebp-1020]
004E331C . |B9 00100000 mov ecx,1000
004E3321 . |8D85 48EDFFFF lea eax,dword ptr ss:[ebp-12B8]
004E3327 . |E8 4832F2FF call upgwy.00406574
004E332C . |E8 43F5F1FF call upgwy.00402874
004E3331 . |8B55 E8 mov edx,dword ptr ss:[ebp-18]
004E3334 . |85D2 test edx,edx
004E3336 . |7E 11 jle short upgwy.004E3349
004E3338 . |8D85 E0EFFFFF lea eax,dword ptr ss:[ebp-1020]
004E333E > |33C9 xor ecx,ecx
004E3340 . |8A08 mov cl,byte ptr ds:[eax]
004E3342 . |014D EC add dword ptr ss:[ebp-14],ecx
004E3345 . |40 inc eax
004E3346 . |4A dec edx
004E3347 .^|75 F5 jnz short upgwy.004E333E
004E3349 > |4B dec ebx 循环指针,估计是计算文件大小
004E334A .^\75 C6 jnz short upgwy.004E3312
退出循环后往下继续走,发现在下面这个地方:
004E3366 . 8B45 E4 mov eax,dword ptr ss:[ebp-1C]
004E3369 . 3B45 EC cmp eax,dword ptr ss:[ebp-14]
脱壳后:堆栈 ss:[0012FA1C]=094BBC79 eax=0EDC2595
未脱壳:堆栈 ss:[0012FA1C]=0EDC2595 eax=0EDC2595
004E336C 75 13 jnz short upgwy.004E3381
修改004E336C处的跳转,然后F9运行,ok,软件加载成功。
5.脱壳爆破后运行:
提示未注册,需要key文件。
但是未脱壳的确没有这个提示,决定带壳调试。
6.如5所示,那么注册表里写入的东西没用?
6.1 OD加载未脱壳的程序,先运行到oep,然后下断bpx ADVAPI32.RegQueryValueExA,F9运行,程序都加载完毕后还是没有在堆栈里见到注册码,于是在程序里点击需要注册才能看的项目,断下,堆栈出现yyzcm,F9再一次注册码也出现了"636877907888216"。靠,看来是关键时刻才判断。
小插曲:程序断下的时候,画面鼠标挪不动,要ctrl+alt+delete后再取消就可以了。
6.2 从断点返回调用的call,接着F8步进,期间出现狂多的注册码,不过没怎么计算,注意代码下的信息窗口,一直到出现机器码(软件一般根据机器码计算,所以跟着它没错,至于注册码,可能会有很多假动作):
004CBBE6 mov eax,dword ptr ds:[eax+1003B8] ds:[014A03BC]=00E4AD30, (ASCII "CD48047047390")
004CBBEC call gwyinter.00409390 判断是否非字母数字的字符串
004CBBF1 mov ecx,dword ptr ss:[ebp-198] ds:[014A03BC]=00E4AD30, (ASCII "CD48047047390")
004CBBF7 mov eax,dword ptr ss:[ebp-4]
004CBBFA mov edx,dword ptr ds:[eax+100398] ds:[014A039C]=00E4C484, (ASCII "SHou0597!@")
004CBC00 mov eax,dword ptr ss:[ebp-4]
004CBC03 call gwyinter.004E37F0
这个call太像是关键计算,两个字符串ecx,edx,要跟。
6.3进该call看看:004CBC03 E8 E87B0100 call gwyinter.004E37F0
004E37F0 push ebp
004E37F1 mov ebp,esp
004E37F3 add esp,-24
004E37F6 push ebx
004E37F7 push esi
004E37F8 push edi
004E37F9 xor ebx,ebx
004E37FB mov dword ptr ss:[ebp-24],ebx
004E37FE mov dword ptr ss:[ebp-1C],ebx
004E3801 mov dword ptr ss:[ebp-C],ecx
004E3804 mov dword ptr ss:[ebp-8],edx
004E3807 mov dword ptr ss:[ebp-4],eax
004E380A mov eax,dword ptr ss:[ebp-8]
004E380D call gwyinter.00404100
004E3812 mov eax,dword ptr ss:[ebp-C]
004E3815 call gwyinter.00404100
004E381A xor eax,eax
004E381C push ebp
004E381D push gwyinter.004E39E8
004E3822 push dword ptr fs:[eax]
004E3825 mov dword ptr fs:[eax],esp
004E3828 mov eax,dword ptr ss:[ebp-4]
004E382B call gwyinter.004E058C
004E3830 mov dword ptr ss:[ebp-18],42
004E3837 xor eax,eax
004E3839 mov dword ptr ss:[ebp-10],eax
004E383C lea eax,dword ptr ss:[ebp-1C]
004E383F call gwyinter.00403CCC
004E3844 xor eax,eax
004E3846 mov dword ptr ss:[ebp-20],eax
004E3849 lea eax,dword ptr ss:[ebp-C]
004E384C push eax
004E384D mov eax,dword ptr ss:[ebp-C] 机器码=(ASCII "CD48047047390")
004E3850 call gwyinter.00403F4C 机器码长度
004E3855 mov ecx,eax
004E3857 mov edx,5
004E385C mov eax,dword ptr ss:[ebp-C]
004E385F call gwyinter.00404154 从机器码第5位开始截取后面的值=047047390
004E3864 mov eax,dword ptr ss:[ebp-C] 00E15968 30 34 37 30 34 37 33 39 30 047047390
004E3867 call gwyinter.00403F4C 得到047047390的长度=9
004E386C mov esi,eax
004E386E test esi,esi
004E3870 jle short gwyinter.004E3886
004E3872 mov ebx,1
004E3877 mov eax,dword ptr ss:[ebp-C]
004E387A movzx eax,byte ptr ds:[eax+ebx-1]
004E387F add dword ptr ss:[ebp-10],eax 求和047047390=1D2=ss:[ebp-10]
004E3882 inc ebx
004E3883 dec esi
004E3884 jnz short gwyinter.004E3877
004E3886 xor eax,eax
004E3888 mov dword ptr ss:[ebp-14],eax
004E388B mov eax,dword ptr ss:[ebp-8] 字符串=(ASCII "SHou0597!@")
004E388E call gwyinter.00403F4C 字符串长度
004E3893 mov esi,eax
004E3895 test esi,esi
004E3897 jle short gwyinter.004E38AD
004E3899 mov ebx,1
004E389E mov eax,dword ptr ss:[ebp-8]
004E38A1 movzx eax,byte ptr ds:[eax+ebx-1]
004E38A6 add dword ptr ss:[ebp-14],eax 求和 "SHou0597!@"=2B5=ss:[ebp-14]
004E38A9 inc ebx
004E38AA dec esi
004E38AB jnz short gwyinter.004E389E
004E38AD mov eax,dword ptr ss:[ebp-C] 截取的机器码047047390
004E38B0 call gwyinter.00403F4C 取长度
004E38B5 mov esi,eax
004E38B7 test esi,esi
004E38B9 jle gwyinter.004E39A3
004E38BF mov ebx,1
004E38C4 mov eax,dword ptr ss:[ebp-8]
004E38C7 call gwyinter.00403F4C
004E38CC inc eax
004E38CD cmp ebx,eax
004E38CF jge short gwyinter.004E391E
004E38D1 lea eax,dword ptr ds:[ebx+5] eax=1+5=6
004E38D4 mov edx,dword ptr ss:[ebp-8]
004E38D7 movzx edx,byte ptr ds:[edx+ebx-1]
004E38DC imul edx
004E38DE add eax,ebx
004E38E0 mov edx,dword ptr ss:[ebp-C]
004E38E3 movzx edx,byte ptr ds:[edx+ebx-1]
004E38E8 imul edx
004E38EA mov ecx,ebx
004E38EC add ecx,ecx
004E38EE mov edx,ecx
004E38F0 imul edx,dword ptr ss:[ebp-18]
004E38F4 add eax,edx
004E38F6 imul ecx,ebx
004E38F9 add ecx,0D
004E38FC imul ecx,dword ptr ss:[ebp-10]
004E3900 add eax,ecx
004E3902 lea edx,dword ptr ds:[ebx+ebx*2]
004E3905 add edx,0C
004E3908 imul edx,dword ptr ss:[ebp-14]
004E390C add eax,edx
004E390E mov edx,0E6
004E3913 sub edx,ebx
004E3915 mov ecx,edx
004E3917 cdq
004E3918 idiv ecx
004E391A mov edi,edx
004E391C jmp short gwyinter.004E395E
...
004E395E cmp dword ptr ss:[ebp-20],3
004E3962 jle short gwyinter.004E3972
004E3964 mov eax,edi
004E3966 mov ecx,9
004E396B cdq
004E396C idiv ecx
004E396E mov edi,edx
004E3970 jmp short gwyinter.004E397E
004E3972 mov eax,edi
004E3974 mov ecx,63
004E3979 cdq
004E397A idiv ecx
004E397C mov edi,edx
004E397E cmp edi,9
004E3981 jle short gwyinter.004E3986
004E3983 inc dword ptr ss:[ebp-20]
004E3986 lea edx,dword ptr ss:[ebp-24]
004E3989 mov eax,edi
004E398B call gwyinter.00409578 每次循环计算得到注册码的2位数
004E3990 mov edx,dword ptr ss:[ebp-24]
004E3993 lea eax,dword ptr ss:[ebp-1C]
004E3996 call gwyinter.00403F54 将004E398B计算值一个个连接起来,注意堆栈的值
004E399B inc ebx
004E399C dec esi 循环指针
004E399D jnz gwyinter.004E38C4
004E39A3 mov eax,dword ptr ss:[ebp+8]
004E39A6 mov edx,dword ptr ss:[ebp-1C]
004E39A9 call gwyinter.00403D20
004E39AE xor ecx,ecx
004E39B0 mov edx,5
004E39B5 mov eax,dword ptr ss:[ebp-4]
004E39B8 call gwyinter.004E05CC
004E39BD xor eax,eax
004E39BF pop edx
004E39C0 pop ecx
004E39C1 pop ecx
004E39C2 mov dword ptr fs:[eax],edx
004E39C5 push gwyinter.004E39EF
004E39CA lea eax,dword ptr ss:[ebp-24]
004E39CD call gwyinter.00403CCC
004E39D2 lea eax,dword ptr ss:[ebp-1C]
004E39D5 call gwyinter.00403CCC
004E39DA lea eax,dword ptr ss:[ebp-C]
004E39DD mov edx,2
004E39E2 call gwyinter.00403CF0
004E39E7 retn
004E39E8 jmp gwyinter.004036E0
004E39ED jmp short gwyinter.004E39CA
004E39EF pop edi ; 0012FC6C
004E39F0 pop esi
004E39F1 pop ebx
004E39F2 mov esp,ebp
004E39F4 pop ebp
004E39F5 retn 4
小结:
该循环对两个值进行计算:一个是机器码:"CD48047047390";一个是字符串:"SHou0597!@"。
堆栈得到一个值:0012FA54 00E62E84 ASCII "2044854858838"
6.4退出6.3的call后F8继续:
004CBC1C mov eax,dword ptr ss:[ebp-10]
堆栈 ss:[0012FC70]=014A2150, (ASCII "636877907888216")
004CBC1F mov edx,dword ptr ss:[ebp-14]
堆栈 ss:[0012FC6C]=00E62E84, (ASCII "2044854858838")
004CBC22 call gwyinter.0040405C 估计是注册码比较的地方
004CBC27 jnz short gwyinter.004CBC75 不等就完了吧?
这个注册码的判断太像自校验的判断。
7.试验:
将计算得到的注册码(?):2044854858838替换掉注册表里的"636877907888216",运行程序,呵呵,之前不能点的都可以点了。
另外脱壳爆破后的提示画面好像有麻痹作用。
8.算法总结:
程序先将输入的注册码转换成数字存在注册表里,
运行的时候没有对注册表进行读取注册码比较,一直到点击需注册才能看到的项目时,它才进行关键比较。
注册码的计算涉及到两个值,一个机器码,一个内置的字符串 "SHou0597!@"。
计算过程复杂,不过最后还是明码比较,将计算得到的注册码与注册表里的比较,相等就可以了。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)