【文章标题】: Devoney CrackMe2.0分析
【文章作者】: yugung
【软件名称】: Devoney
's CrackMe 2.0; Find the secret text
【软件大小】: 3k
【下载地址】: http://www.crackmes.de/
【加壳方式】: 无壳
【编写语言】: Asm32
【使用工具】: peid+OD+IDA
【操作平台】: Windows
【作者声明】: 我是一只小菜鸟,偶有所得,愿与大家分享。
--------------------------------------------------------------------------------
【详细过程】
偶然在crackme.de上看到这个cm,感觉还算新颖,顺手分析了一下,把过程发上来与大家分享。不当之处,敬请指正。
1.Peid侦壳,无可,32位汇编编写。
2.整个程序的交互界面为DialogBoxIndirectParamA创建的一对话框,由DialogBoxIndirectParamA的参数不难找到回调
函数的位置在.text:004011A2处。输入的字符串由GetDlgItemTextA获取
3.关键代码如下:
.text:004011E6
push 48
; nMaxCount
.text:004011E8
push offset szInput
; lpString
.text:004011ED
push 65h
; nIDDlgItem
.text:004011EF
push [
ebp +hWnd]
; hDlg
.text:004011F2
call GetDlgItemTextA
.text:004011F2
.text:004011F7
mov edx ,
offset szInput
.text:004011FC
mov ebx , -1
.text:00401201
mov ecx , -1
.text:00401201
.text:00401206
.text:00401206 NextInByte:
; CODE XREF: DialogFunc+B4j
.text:00401206
; DialogFunc+D6j DialogFunc+F8j
.text:00401206
; DialogFunc+11Dj DialogFunc+138j
.text:00401206
; DialogFunc+14Cj ...
.text:00401206
inc ebx
.text:00401207
mov cl ,
ss :[
edx +
ebx ]
.text:0040120B
test cl ,
cl
.text:0040120D
jz TreatComplete
.text:0040120D
.text:00401213
cmp ebx , 0
.text:00401216
ja short Is_1
.text:00401216
.text:00401218
sub cl , 5Bh
.text:0040121B
mov byte ptr ss :szByteList+1,
cl
.text:00401222
mov byte ptr ss :szByteList+6,
cl
.text:00401229
mov byte ptr ss :szByteList+0Bh,
cl
.text:00401230
mov byte ptr ss :szByteList+0Dh,
cl
.text:00401237
mov byte ptr ss :szByteList+10h,
cl
.text:0040123E
mov byte ptr ss :szByteList+11h,
cl
.text:00401245
mov byte ptr ss :szByteList+12h,
cl
.text:0040124C
add cl , 72h
.text:0040124F
mov byte ptr ss :szSecretText+15h,
cl
.text:00401256
jmp short NextInByte
.text:00401256
.text:00401258
; ---------------------------------------------------------------------------
.text:00401258
.text:00401258 Is_1:
; CODE XREF: DialogFunc+74j
.text:00401258
cmp ebx , 1
.text:0040125B
ja short Is_2
.text:0040125B
.text:0040125D
add cl , 0Bh
.text:00401260
mov byte ptr ss :szByteList,
cl ; "1234567890123456789"
.text:00401267
mov byte ptr ss :szByteList+0Ch,
cl
.text:0040126E
sub cl , 3
.text:00401271
mov byte ptr ss :szSecretText+14h,
cl
.text:00401278
jmp short NextInByte
.text:00401278
.text:0040127A
; ---------------------------------------------------------------------------
.text:0040127A
.text:0040127A Is_2:
; CODE XREF: DialogFunc+B9j
.text:0040127A
cmp ebx , 2
.text:0040127D
ja short Is_3
.text:0040127D
.text:0040127F
add cl , 25h
.text:00401282
mov byte ptr ss :szByteList+2,
cl
.text:00401289
mov byte ptr ss :szByteList+7,
cl
.text:00401290
sub cl , 3
.text:00401293
mov byte ptr ss :szSecretText+16h,
cl
.text:0040129A
jmp NextInByte
.text:0040129A
.text:0040129F
; ---------------------------------------------------------------------------
.text:0040129F
.text:0040129F Is_3:
; CODE XREF: DialogFunc+DBj
.text:0040129F
cmp ebx , 3
.text:004012A2
ja short Is_4
.text:004012A2
.text:004012A4
sub cl , 42h
.text:004012A7
mov byte ptr ss :szByteList+4,
cl
.text:004012AE
mov byte ptr ss :szByteList+9,
cl
.text:004012B5
add cl , 35h
.text:004012B8
mov byte ptr ss :szSecretText+17h,
cl
.text:004012BF
jmp NextInByte
.text:004012BF
.text:004012C4
; ---------------------------------------------------------------------------
.text:004012C4
.text:004012C4 Is_4:
; CODE XREF: DialogFunc+100j
.text:004012C4
cmp ebx , 4
.text:004012C7
ja short Is_5
.text:004012C7
.text:004012C9
sub cl , 21h
.text:004012CC
mov byte ptr ss :szByteList+5,
cl
.text:004012D3
mov byte ptr ss :szByteList+0Ah,
cl
.text:004012DA
jmp NextInByte
.text:004012DA
.text:004012DF
; ---------------------------------------------------------------------------
.text:004012DF
.text:004012DF Is_5:
; CODE XREF: DialogFunc+125j
.text:004012DF
cmp ebx , 5
.text:004012E2
ja short Is_6
.text:004012E2
.text:004012E4
add cl , 85h
.text:004012E7
mov byte ptr ss :szByteList+0Eh,
cl
.text:004012EE
jmp NextInByte
.text:004012EE
.text:004012F3
; ---------------------------------------------------------------------------
.text:004012F3
.text:004012F3 Is_6:
; CODE XREF: DialogFunc+140j
.text:004012F3
cmp ebx , 6
.text:004012F6
ja short Is_7
.text:004012F6
.text:004012F8
sub cl , 2Ch
.text:004012FB
mov byte ptr ss :szByteList+3,
cl
.text:00401302
jmp NextInByte
.text:00401302
.text:00401307
; ---------------------------------------------------------------------------
.text:00401307
.text:00401307 Is_7:
; CODE XREF: DialogFunc+154j
.text:00401307
cmp ebx , 7
.text:0040130A
ja short over
.text:0040130A
.text:0040130C
sub cl , 3Ah
.text:0040130F
mov byte ptr ss :szByteList+8,
cl
.text:00401316
add cl , 3Fh
.text:00401319
mov byte ptr ss :szSecretText+18h,
cl
.text:00401320
jmp NextInByte
.text:00401320
.text:00401325
; ---------------------------------------------------------------------------
.text:00401325
.text:00401325 over:
; CODE XREF: DialogFunc+168j
.text:00401325
sub cl , 2Bh
.text:00401328
mov byte ptr ss :szByteList+0Fh,
cl
.text:00401328
.text:0040132F
.text:0040132F TreatComplete:
; CODE XREF: DialogFunc+6Bj
.text:0040132F
push lpNumberOfBytesWritten
; lpNumberOfBytesWritten
.text:00401335
push nSize
; nSize
.text:0040133B
push offset szByteList
; lpBuffer
.text:00401340
push offset AddrToWrite
; lpBaseAddress
.text:00401345
push hThisProcess
; hProcess
.text:0040134B
call WriteProcessMemory
.text:0040134B
.text:00401350
nop
.text:00401350
.text:00401351
.text:00401351
; void AddrToWrite
.text:00401351 AddrToWrite:
; DATA XREF: DialogFunc+19Eo
.text:00401351
nop
.text:00401352
nop
.text:00401353
nop
.text:00401354
nop
.text:00401355
nop
.text:00401356
nop
.text:00401357
nop
.text:00401358
nop
.text:00401359
nop
.text:0040135A
nop
.text:0040135B
nop
.text:0040135C
nop
.text:0040135D
nop
.text:0040135E
nop
.text:0040135F
nop
.text:00401360
nop
.text:00401361
nop
.text:00401362
nop
.text:00401363
nop
.text:00401364
nop
4.分析:
整个CM有点smc的意思。
在数据段中定义了一个19byte的字节串
szByteList
db '1234567890123456789' ,0
根据输入字符串的不同,程序将动态更新这个字节串的内容;并调用WriteProcessMemory将其写入text:00401351开始的
19个字节。注意! 这19个字节的内容不是随便什么值就可以的,否则很容易就会一起程序异常。
具体写入什么内容呢?查看一下输入表,可以看到函数MessageBoxA,但纵观整个程序并没有见到对其进行调用的地方;
看来是留给我们自己调用了 ^_^
5.详解MessageBoxA
对于这个函数大家并不陌生,但是现在我们要从字节的角度来观察对这个函数的调用。先找个例子看看,MessageBoxA调用
过程对应的字节码张什么样子? 下面是我找的一个例子,
004046E7 . 6A 40
push 40
; /Style =
004046E9 . 68 A4364100
push CrackMe_.004136A4
; |Title =
004046EE . 68 4C364100
push CrackMe_.0041364C
; |Text =
004046F3 . 50
push eax ; |hOwner
004046F4 . FF15 DC204100
call dword ptr ds :[<&USER32.MessageBoxA>]
; \MessageBoxA
上述这个调用过程正好占用19个字节,我们就在这基础上进行修改。
首先,MessageBoxA的调用过程涉及两个字符串,分别用于Title和Text,问:从哪里来?
作者已经给我们准备好了,数据段里早定义了两个字符串
.data :00403025 szSecretText
db 'The Secret Text is: 00000' ,0
.data :0040303F szCheckAtHttp
db 'Check at http://members.lycos.nl/wietsite/fp.php?x=secret_text' ,0
技术上,哪个做Title,哪个做Text都无所谓。考虑到这里我们选择szSecretText做Text,另一字符串做Title解得的SecretText更加有意义, 则这两个参数对应的10各字节应为
"68 3f 30 40 00 68 25 30 40 00" (
感谢aalloverred的指正 )
6.拼凑19个字节的值
对原CM的反汇编代码进行分析,可知19个字节按照数值的不同可以分为9组(各字节按其次序用0~0x12标识):
1,6,b,d,10,11,12
0,c
2,7
4,9
5,a
e
3
8
f
细心的朋友会发现 第2,4,5,6字节和第7,9,0xA,0xB字节这正好与上一部分分析得到的10个字节相符合。
由此,可以确定19个字节具有如下的形式:
?? ?? 68 25 30 40 00 68 3f 30 40 00 ?? ?? ?? ?? ?? ?? ??
又1,6,b,d,10,11,12 这7个字节值相等,故进一步得出:
?? 00 68 25 30 40 00 68 3f 30 40 00 ?? 00 ?? 00 00 00
同前面我们找的调用MessageBoxA的例子进行比较,易知0,0xC两个字节为6a
==>6a 00 68 25 30 40 00 68 3f 30 40 00 6a 00 ?? ?? 00 00 00
下面就call MessageBoxA语句对应的字节码了,注意:现在只有两个字节可以变动了!
如果我们直接使用
"call MessageBoxA" ,利用OD的汇编功能可知对应的字节码为 E8 93 F1 94 77, 显然不是我们所
需要的;换一个角度,考虑到 .text:00401396处为
"jmp ds:MessageBoxA" , 我们间接的
"call 00401396" .
对应的字节码为
"E8 32 00 00 00" , 所以可以填补未知的两个字节。
最后得到, 所需的19个字节的值为
"6a 00 68 25 30 40 00 68 3f 30 40 00 6a 00 e8 32 00 00 00"
7.反推输入字符串
由反汇编代码可知,上述9组数值由输入字符串的前九个字符的Ascii通过加减运算得到。
具体比较简单,只给出结果, 前九个字符字节值为
"5B 5F 43 72 61 63 51 79 5D" ,
对应的字符串为
"[_Crack_]"
输入此字符串,程序自动算出对应的SecretText为
"greed"
Done
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2007年02月04日 17:30:09
[培训]科锐软件逆向50期预科班报名即将截止,速来!!! 50期正式班报名火爆招生中!!!
上传的附件: