【文章标题】: 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
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
上传的附件: