【文章标题】: Riijj CrackMe9 分析
【文章作者】: hawking
【作者邮箱】: rich_hawking@hotmail.com
【软件名称】: Riijj CrackMe 9
【软件大小】: 320K
【下载地址】: http://bbs1.pediy.com:8081/showthread.php?s=&threadid=36592
【加壳方式】: 未知
【使用工具】: OllyICE PEiD
【操作平台】: win2k
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
本人菜鸟,刚开始学习加密解密的时候就是通过Riijj大侠的几个CrackMe入的门。Riijj大侠针对自写的几个CrackMe进行了深入浅出的分析,令我等初学者受益匪浅。
首先按照惯例用PEiD载入查一下看看有没有加壳,结果是Nothing found [Overla]*,我们再点一下EP Section 后面的 > 按钮,可以看出程序只有四个常用的段,由此推测程序很可能没有加壳。
运行程序看一下,程序有两个文本框,分别用来存放name及key,还有一个Register按钮。随便输入name及key,点按钮后无反应。
OllyICE 载入,提示代码段可能被压缩加密或包含大量嵌入数据(跟一般的没有加壳的程序载入的时候不一样),不分析继续。
00410380 > 55
push ebp ;OEP 停在这里
00410381 E9 357C0000
jmp 00417FBB
00410386 - E9 0FBE4C3C
jmp 3C8DC19A
0041038B 64:68 3ED24100
push 0041D23E
00410391 C3
retn
00410392 - E9 8B4D1068
jmp 68515122
00410397 0F6D ???
; 未知命令
00410399 41
inc ecx
程序到处都是jmp,跳来跳去的。不管,F7单步,去掉无用的push XXXXXXXX
retn 指令后整理出程序入口处代码如下:
00410380 > 55
push ebp
00417FBB 8BEC
mov ebp,
esp
0041134C 6A FF
push -1
00419090 68 08014200
push 00420108
00419634 68 4C104100
push 0041104C
004102CD 64:A1 00000000
mov eax,
dword ptr fs:[0]
00416626 50
push eax
0041A808 64:8925 0000000>
mov dword ptr fs:[0],
esp
0041594D 83EC 58
sub esp, 58
0041A520 53
push ebx
00411789 56
push esi
00412DF6 57
push edi
00418801 8965 E8
mov dword ptr [
ebp-18],
esp
00418B51 FF15 64004200
call dword ptr [<&KERNEL32.GetVersion>]
; KERNEL32.GetVersion
0041BE34 33D2
xor edx,
edx
典型的Microsoft Visual C++ 程序入口点代码。^-^
F9跑起来。
在程序界面上的文本框内输入
Registration name: hawking
Registration key: 123456
我们来看看如何定位到它的处理代码段,由于是VC++代码,我们可以通过消息断点来定位。
点工具栏上的W图标打开OD窗口窗口,打开之后可以看到按钮Register 句柄002302FA,ID 为3EA,父窗口句柄0019027C(您看到的和我看到的也许不一样)
右键在ClassProc上设置消息断点 202 WM_LBUTTONUP 这样就能在您单击Register注册按钮的时候将程序断下来了。
点击程序界面上的Register按钮后中断在模块USER32系统领空。
77E00DFC > 55
push ebp ;中断在这儿
77E00DFD 8BEC
mov ebp,
esp
77E00DFF 8B4D 08
mov ecx,
dword ptr [
ebp+8]
77E00E02 56
push esi
77E00E03 57
push edi
77E00E04 E8 ED07FFFF
call 77DF15F6
我们要返回到自己的程序代码段。打开内存窗口,在riijjcm9 .text区段上F2设置访问中断。 F9跑
00410050 8B4424 08
mov eax,
dword ptr [
esp+8]
;停在这里
00410054 E9 01890000
jmp 0041895A
00410059 - E9 0F85918B
jmp 8BD2856D
0041005E 0000
add byte ptr [
eax],
al
看看堆栈
0012FB94 77DF1EF0 返回到 USER32.77DF1EF0
0012FB98 0019027C
;眼熟 父窗口句柄
0012FB9C 00000135
;消息号 不是我们想要的111
0012FBA0 41011245
0012FBA4 002302FA
0012FBA8 002302FA
0012FBAC DCBAABCD
按几下F7之后又回到了USER32系统领空。
77DF1EF0 817C24 04 CDABB>
cmp dword ptr [
esp+4], DCBAABCD
77DF1EF8 0F85 C4910300
jnz 77E2B0C2
77DF1EFE 83C4 08
add esp, 8
77DF1F01 5D
pop ebp
77DF1F02 C2 1400
retn 14
看来没有断下来,继续上面的操作,在我们的代码段下断点,F9运行
00410050 8B4424 08
mov eax,
dword ptr [
esp+8]
;停在了上次相同的地址
00410054 E9 01890000
jmp 0041895A
;这里应该就是程序用来处理消息的代码段了
00410059 - E9 0F85918B
jmp 8BD2856D
0041005E 0000
add byte ptr [
eax],
al
00410060 68 8B214100
push 0041218B
00410065 C3
retn
再瞅瞅堆栈,这回应该是处理我们刚才引发的按钮消息的地方了。
0012FC60 77DF1EF0 返回到 USER32.77DF1EF0
0012FC64 0019027C
;父窗口句柄
0012FC68 00000111
;WM_COMMAND
0012FC6C 000003EA
;按钮ID
0012FC70 002302FA
0012FC74 002302FA
0012FC78 DCBAABCD
一路F8
00410050 8B4424 08
mov eax,
dword ptr [
esp+8]
0041895A 3D 10010000
cmp eax, 110
0041AF11 ^\0F85 ADE4FFFF
jnz 004193C4
004193C4 3D 11010000
cmp eax, 111
;按钮命令
00411462 /0F85 2E5A0000
jnz 00416E96
00417AB0 66:817C24 0C EA>
cmp word ptr [
esp+C], 3EA
;按钮ID = 3EA
004129A6 /0F85 EA440000
jnz 00416E96
00419323 56
push esi
来到这里
00419323 56
push esi
00413059 8B7424 14
mov esi,
dword ptr [
esp+14]
00414129 57
push edi
00416CE0 8B3D E0004200
mov edi,
dword ptr [<&USER32.EnableWindow>]
; USER32.EnableWindow
0041861D 6A 00
push 0
;false
0041A518 56
push esi ;按钮句柄
0041212F FFD7
call edi ; USER32.EnableWindow 这里禁用了Register按钮,后面还应该有一个对应的call恢复按钮状态
00416D45 E8 B2220000
call 00418FFC
F7跟进去
00418FFC 8B0D B0264300
mov ecx,
dword ptr [4326B0]
;父窗口句柄
004119E9 81EC BC000000
sub esp, 0BC
0041AA9E 8D4424 20
lea eax,
dword ptr [
esp+20]
0041A49C 53
push ebx
00419A11 56
push esi
004175DF 57
push edi ; USER32.EnableWindow
00410169 8B3D 9C004200
mov edi,
dword ptr [<&USER32.GetDlgItemTextA>
; USER32.GetDlgItemTextA
0041A823 6A 32
push 32
;Count
0041B298 50
push eax ;Buffer
004108E0 68 E8030000
push 3E8
;Control ID
0041CEE7 51
push ecx ;hWnd
0041807F FFD7
call edi ; USER32.GetDlgItemTextA 取name
00418B37 8D9424 94000000
lea edx,
dword ptr [
esp+94]
004171C2 8BF0
mov esi,
eax ;eax中存放的是name长度
0041DA8D A1 B0264300
mov eax,
dword ptr [4326B0]
0041831B 6A 32
push 32
004170B4 52
push edx
0041472E 68 E9030000
push 3E9
00415286 50
push eax
00414F64 FFD7
call edi ; USER32.GetDlgItemTextA 取key
0041752F 85F6
test esi,
esi ;name长度为0的话则end
00416380 BB 857B0100
mov ebx, 17B85
0041DE2A ^\0F84 044FFFFF
je 00412D34
00419AC4 83F8 14
cmp eax, 14
;key长度小于20的话则end
0041D609 ^\0F82 2557FFFF
jb 00412D34
我们输入的key长度不够,重新来过。在0041D609处下断,Ctl+F2重来,输入一个20位的key
0041A09F 33C9
xor ecx,
ecx
00410CC9 8BC1
mov eax,
ecx
00417B5A 33D2
xor edx,
edx
004196CC F7F6
div esi
0041E04F 8BC3
mov eax,
ebx
00413AAD BB C9010000
mov ebx, 1C9
00413527 69C0 8F1E0000
imul eax,
eax, 1E8F
00410C72 0FBE7C14 2C
movsx edi,
byte ptr [
esp+
edx+2C]
004103AE 33D2
xor edx,
edx
00413397 F7F3
div ebx
00411697 03FA
add edi,
edx
00412A77 41
inc ecx
0041AA0D 8BDF
mov ebx,
edi
004105F3 83F9 32
cmp ecx, 32
004109C2 885C0C 5F
mov byte ptr [
esp+
ecx+5F],
bl
00415C87 ^\0F82 3CB0FFFF
jb 00410CC9
伪代码:
ebx = 0x17B85
;
for (
int i = 0
; i < 0x32 ; i++ )
{
ebx = name[i% strlen(name)] + (
ebx * 0x1E8F ) % 0x1C9
;
temp[i] =
ebx & 0xFF
;
}
004138DB 33C9
xor ecx,
ecx
004156A8 55
push ebp
00413098 85F6
test esi,
esi
0041929F BD 01000000
mov ebp, 1
0041C3BE /0F86 63100000
jbe 0041D427
00417707 F6C1 01
test cl, 1
0041CA16 ^\0F85 163BFFFF
jnz 00410532
0041C4EC 0FBE540C 30
movsx edx,
byte ptr [
esp+
ecx+30]
004178D7 0FAFEA
imul ebp,
edx
00413F2E /E9 68840000
jmp 0041C39B
00410532 0FBE7C0C 30
movsx edi,
byte ptr [
esp+
ecx+30]
00419A54 8BC5
mov eax,
ebp
00416BC9 33D2
xor edx,
edx
00415F0F F7F7
div edi
00410186 8BEA
mov ebp,
edx
0041C39B 41
inc ecx
00412B6A 3BCE
cmp ecx,
esi
00412637 /0F82 CA500000
jb 00417707
伪代码:
ebp = 1
;
for (
int i = 0
; strlen(name) > 0 && i < strlen(name) ; i++ )
{
if ( i % 2 == 0 )
ebp = name[i] *
ebp ;
else
ebp =
ebp % name[i]
;
}
0041D427 B9 07000000
mov ecx, 7
004145EE 33C0
xor eax,
eax
0041A8FF 8D7C24 10
lea edi,
dword ptr [
esp+10]
0041818C BE 857B0100
mov esi, 17B85
004106F0 F3:AB
rep stos dword ptr es:[
edi]
00416E78 66:AB
stos word ptr es:[
edi]
004110F1 33FF
xor edi,
edi
伪代码:
key[30] = { 0 }
;
esi = 0x17b85
;
00410387 0FBE4C3C 64
movsx ecx,
byte ptr [
esp+
edi+64]
0041D23E 8BC1
mov eax,
ecx
004174F9 33D2
xor edx,
edx
00410258 0FAFC5
imul eax,
ebp
00415821 BB 32000000
mov ebx, 32
0041D961 F7F3
div ebx
00413744 33C0
xor eax,
eax
0041B514 8A4414 64
mov al,
byte ptr [
esp+
edx+64]
004149EE 85C0
test eax,
eax
00411D65 /0F86 C46E0000
jbe 00418C2F
0041AD8A 8BD8
mov ebx,
eax
004176D2 8BC6
mov eax,
esi
0041029C 33D2
xor edx,
edx
0041BA27 69C0 8F1E0000
imul eax,
eax, 1E8F
004154B1 BE C9010000
mov esi, 1C9
00419528 F7F6
div esi
004128BF 33D1
xor edx,
ecx
00416766 4B
dec ebx
00418B2E 8BF2
mov esi,
edx
0041A4B1 ^\0F85 1BD2FFFF
jnz 004176D2
00418C2F 8BC6
mov eax,
esi
004140AE 33D2
xor edx,
edx
0041D412 B9 1A000000
mov ecx, 1A
00419602 F7F1
div ecx
00414F86 80C2 41
add dl, 41
004145DB 88543C 10
mov byte ptr [
esp+
edi+10],
dl
0041B977 47
inc edi
00412596 83FF 14
cmp edi, 14
00412939 ^\0F82 48DAFFFF
jb 00410387
伪代码:
for (
int i = 0
; i < 0x14 ; i++ )
{
unsigned long ti = temp[i] < 0x80 ? temp[i] : temp[i] ^ 0xFFFFFF00
;
int tii = temp[ ( ti *
ebp ) % 0x32 ]
;
if ( tii > 0)
{
while ( tii != 0 )
{
esi = ( (
esi * 0x1E8F ) % 0x1C9 ) ^ ti
;
tii--
;
}
}
key[i] =
esi % 0x1A + 0x41
;
}
00416FB5 33C0
xor eax,
eax
0041DACD 5D
pop ebp ; 0012FC7C
00412FB3 8A9404 94000000
mov dl,
byte ptr [
esp+
eax+94]
;用户输入key
0041DAB8 8A4C04 0C
mov cl,
byte ptr [
esp+
eax+C]
;计算所得key
00416919 3AD1
cmp dl,
cl ;比较key与您输入的key 将此处改为 cmp cl,cl即可爆破
00411C3B /0F85 F3100000
jnz 00412D34
00412DE1 40
inc eax
0041DE20 83F8 14
cmp eax, 14
00412000 /0F82 AD0F0000
jb 00412FB3
0041C1BE E8 429CFFFF
call 00415E05
F7跟进
00415E05 A1 AC264300
mov eax,
dword ptr [4326AC]
0041B51F 6A 00
push 0
0041841A 68 68004300
push 00430068
; ASCII "Riijj crackme 9"
004139EF 68 4C004300
push 0043004C
; ASCII "Registration successful !"
004106DF 50
push eax
00413953 FF15 A0004200
call dword ptr [<&USER32.MessageBox>
; USER32.MessageBoxA 成功!
到这里整个CrackMe就基本分析完了。
--------------------------------------------------------------------------------
【经验总结】
由于Riijj大侠这个CrackMe的变形代码基本都是
push XXXXXXXX
retn 这个形式的,加上程序本身代码量不大,所以可以一步一步地跟并整理。但是如果代码量大或者是变形的方式再多一些的话,跟起来就更困难了。
本文没有什么技术含量,只是菜菜写的第一篇脱文,也算是个开始吧。高手莫笑。
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2006年12月19日 21:00:02
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课