首页
社区
课程
招聘
小试Watch法分析kiTo's kiTo KGNmeAGAiN
发表于: 2006-8-14 20:46 5697

小试Watch法分析kiTo's kiTo KGNmeAGAiN

2006-8-14 20:46
5697

小试Watch法分析kiTo's kiTo KGNmeAGAiN
=========================================================
Watch分析法即以程序变量为分析对象,搞清楚程序的整个框架。
与一般的过程(代码)分析方法有所不同。
下面随手下载了一个crackme做示范
=========================================================
该crackme作者是这么说的:
kiTo's kiTo KGNmeAGAiN
Download kiToKGNmeAGAiN.zip, 106 kb
Browse contents of kiToKGNmeAGAiN.zip
Keygen this little baby and submit your solution.

Difficulty: 2 - Needs a little brain (or luck)
Platform: Windows
Language: Assembler

Published: 06. Aug, 2006
Downloads: 9
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
眼睛不小心在这个上面晃了一下:
Difficulty: 2 - Needs a little brain (or luck)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
首先分析程序大体是如何执行是不可避免的。
==========================================================
运行程序,看到的是一个常规界面的CRACKME。
用OD加载发现开头就有个CALL,按ENTER进去,首先是一个GetVersion(),以后会用到。
输入at eip回到入口点
向下几行,看到:
00401018  |.  68 33104000   PUSH kiToKGNm.00401033                   ; |DlgProc = kiToKGNm.00401033
于是输入:
at 00401033
进入消息处理函数
(这个地址居然就在ExitProcess()下面。)
凭经验判断这个00401033函数的主干是一大堆case,于是看到很多jnz,验证了猜想。
-------------------------------------
看待这个JNZ(前者),预测它是关键的case,后者是爆破点。
按下F9运行,输入name、serial,果然在这里停了下来。
0040105B  |.  817D 10 EC030>CMP [ARG.3],3EC
00401062  |.  75 3E         JNZ SHORT kiToKGNm.004010A2
00401064  |.  FF75 08       PUSH [ARG.1]
00401067  |.  E8 9F000000   CALL kiToKGNm.0040110B
0040106C  |.  0BC0          OR EAX,EAX
0040106E  |.  75 16         JNZ SHORT kiToKGNm.00401086
00401070  |.  6A 40         PUSH 40                                  ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
00401072  |.  68 4B304000   PUSH kiToKGNm.0040304B                   ; |Title = "kiTo - KgnMe AGAiN!"
00401077  |.  68 03304000   PUSH kiToKGNm.00403003                   ; |Text = "Bra, om du inte har gjort en keygen \xE4n, s\xE5 \xE4r det den \xE4nda l\xF6sningen ;)"
0040107C  |.  FF75 08       PUSH [ARG.1]                             ; |hOwner
0040107F  |.  E8 8E090000   CALL <JMP.&user32.MessageBoxA>           ; \MessageBoxA
一路F8知道爆破点前面:
0040106C  |.  0BC0          OR EAX,EAX
0040106E  |.  75 16         JNZ SHORT kiToKGNm.00401086        ;爆破点
看看这里的EAX是怎么出来的。
就在这条语句上面有个CALL:
00401067  |.  E8 9F000000   CALL kiToKGNm.0040110B
按下ENTER进去:
在这个函数的最后,发现了我们最喜欢的东西:
004011BB  |.  68 6A334000   PUSH kiToKGNm.0040336A                   ; /String2 = "123456"
004011C0  |.  68 38334000   PUSH kiToKGNm.00403338                   ; |String1 = "B150-2E4"
004011C5  |.  E8 24080000   CALL <JMP.&kernel32.lstrcmpA>            ; \lstrcmpA
004011CA  |.  C9            LEAVE
004011CB  \.  C2 0400       RETN 4

拿这个“B150-2E4”试试,果真是注册码。
===============================================================
下面就是要分析这个B150-2E4是怎么来的。
程序的EP处的那个CALL最先被怀疑。
它调用了GetVersion,
GetVersion结束后,其实只是变动了eax的值,在写注册机的时候可以照样画葫芦,不用管他。
PUSH 4031A8:
DS:[4031A8]这个值存储的是GetVersion返回的EAX的十六进制的ANSI串。
接下来的这行:
004010C7  |.  83C4 0C       ADD ESP,0C
wprintf是__cdecl的函数,需要自己平衡堆栈。

下去直到这里:
004010CA  |.  68 DA314000   PUSH kiToKGNm.004031DA                   ;  ASCII "NTE0MDA4Mjg="
004010CF  |.  6A 08         PUSH 8
004010D1  |.  68 A8314000   PUSH kiToKGNm.004031A8                   ;  ASCII "51400828"
004010D6      E8 C5070000   CALL kiToKGNm.004018A0
CALL kiToKGNm.004018A0是一大堆运算,处理结果只和进栈的字符串、数字有关(大概是某加密算法),若是分析程序框架,可以暂时不去管它。
这个函数的末尾,又是一次这个算法。
004010F9  |.  68 3E324000   PUSH kiToKGNm.0040323E
004010FE  |.  6A 10         PUSH 10
00401100  |.  68 0C324000   PUSH kiToKGNm.0040320C                   ;  ASCII "51400828NTE0MDA4Mjg="
00401105  |.  E8 96070000   CALL kiToKGNm.004018A0

到此才分析完程序一开头的这个CALL
=========================================
回到爆破点附近
00401064  |.  FF75 08       PUSH [ARG.1]
这个ARG.1因该是WndProc(消息处理函数)的 hwnd(窗口句柄)参数。
00401064  |.  FF75 08       PUSH [ARG.1]
00401067  |.  E8 9F000000   CALL kiToKGNm.0040110B
按下F4运行到这个CALL的地方。输入Name,Serial
Press Enter进入kiToKGNm.0040110B函数。
00401115  |.  6A 32         PUSH 32                                  ; /Count = 32 (50.)
00401117  |.  68 70324000   PUSH kiToKGNm.00403270                   ; |Buffer = kiToKGNm.00403270
0040111C  |.  68 E9030000   PUSH 3E9                                 ; |ControlID = 3E9 (1001.)
00401121  |.  FF75 08       PUSH [ARG.1]                             ; |hWnd
00401124  |.  E8 E3080000   CALL <JMP.&user32.GetDlgItemTextA>       ; \GetDlgItemTextA
~~~~~~~~~~~~~~~~
在kiToKGNm.00403270这个地方存放NAME。
接下去第3次调用到CALL kiToKGNm.004018A0函数。
计算出字符串放在 4032A2。
接着是几个字符串cat、len操作
直到这里:
00401161  |.  A3 A0314000   MOV DWORD PTR DS:[4031A0],EAX
看上去应该是第一次访问DWORD PTR DS:[4031A0],不管他
下去之后就生成了注册码。
到此,初步分析完成
====================================================================================================
下面精确分析。
这趟分析,须搞清楚每个用到的地址(变量、函数)对应的是什么。是“变量分析法”的关键!
(不要看简短的几行,这几行上花费的时间不会比上面的短。)
~~~~~~~~~~~~~~~
函数部分:
        004010AB        程序一开始的CALL
        004018A0        把该函数命名成f1,声明: __stdcall f1(IN LPTSTR strin,IN DWORD ncode,OUT LPTSTR strout);凭经验应该是把strin以ncode为密钥加密成strout字符串
        0040110B        __stdcall f2(HWND hWin) 以该CRACKME的窗口句柄为输入参数,生成明码SERIAL,经过strcmp和输入进行比较。是关键函数!
                                (须注意:这里的参数――窗口句柄经过观察和试验,只是用来作为其中GetDlgItemxxxx的参数,并不参与注册码运算!)
        004017A8        __stdcall f3(void) 访问了6个数据段变量,无堆栈变量
        004017E8        __stdcall f4(LPTSTR str1,DWORD ncode),其中调用004011D0进行运算
        00401848        __stdcall f5(void)
其中很多函数调用的:
        004011D0        是个大头,也是这个程序加密算法的关键,其中用了很多的lea代替add、mul做运算。此函数的细节,这里篇幅有限,不予列举。
                        (这个函数十分有趣,它虽然无堆栈输入,却自行读取堆栈内容,作为密钥。这给写注册机带来了干扰。我已经仔细的学习过,得到了许多防crack的技巧。建议大家仔细研究。)

变量部分:        (有些是不断变动的,按程序执行的时间先后顺序排列)

类型声明:

字符串型:        403000,4031A8,4031DA,40320C,40323E,403270,4032A2,4032D4
DWORD型:        4031A0,403400
        ====================004010AB 中===============
        403000                "%X"
        4031A8                GetVersion函数返回的EAX转化成的16进制ANSI串。
        4031DA                4031A8的数值以08h为密钥由函数f1()加密
        40320C                =ansi字符串cat(4031A8,4031DA)
        40323E                以上面的40320C为原文,10h==16d为密钥f1()加密生成报文
        ===================0040110B 中================
        4032D4                =0(从下文可以得知该0是作为sz字符串结束的'\0')
        403270                输入的名字
        4032A2                输入的名字经过以 名字长度为密钥的f1()运算后得出的字符串
        4032D4                == 字符串 PTR [4032A2]        (嘻嘻,这样表示应该看得懂吧^_^)
        40323E                仍旧是上述得40323E,内容没有变化
        4032D4                = ansi字符串cat(4032A2,40323E)
        4031A0                =字符串4032D4的长度
        ===================其他函数中=================
        403400                =0
        403404                =0
        4033F0                =67452301H
        4033F4                =EFCDAB89H
        4033F8                =98BADCFEH
        4033FC                =10325476H
        ……………
时间紧迫,快要吃饭了就不多列举
这个crackme没有什么trick,既不存在花指令,也没有多线程,只是一个字“长”。(当然,和某些共享软件的注册算法比起来是简练多了。)

这里还是要提一句,它的核心函数之一:        004011D0 构思十分巧妙,它独特的获取密钥方式(不破坏堆栈的条件下,从先前的堆栈中获得,写注册机的时候大部分可以用立即数代替!!),给写KeyGen带来了一定的复杂度。盖有经验的老鸟对此并不陌生。(可惜本菜鸟才第一次碰到)

总结:

        任何程序所用到的数据,不可能只在寄存器里做运动,访问内存是必然的。我们可以抓住应用程序的这个通性,在调试跟踪的过程中按照代码执行的先后顺序记录内存的读、写情况。更清晰的掌握程序的脉络。尤其是在超高级语言(如VB)中更显出优势。可以看作是手动的Watch。我们无产阶级用的是OD,某些调试工具自己带有十分丰富的WATCH功能,只需要手动记录一下变量之间的转换关系就可以了。^_^
并不是所有变量都需要如此详细的分析,也不是所有变量的值都需要写出来,只要分析关键变量、就可以了。
希望大家也参与交流技巧。
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
这个crackme只适合于自己分析,若是把它的过程写出来……要帖好几页
对于这个crackme,Watch分析是最适合的方法
我原本看着这个crackme结构清晰,想可以写成tutorial,未料到此crackme虽然清晰,算法却十分长。又不想前功尽弃,就把大略帖出来。加密函数004011D0内部太长,反正大家记录下了之前的变量地址后基本上都能读懂。

=========================================================================================
关于KeyGen:
只怪我没有锻炼耐心,加上
破了此crackme没有什么功利价值(不能和破ShareWare相比啊)。于是注册机随便写一下。虽然说这不能叫做真正意义上的KeyGen(偷懒一下啦)。

!!!!!!!!!!!!!!!!!!!!
最后不好意思的说一句――
                大家可千万别指责我的crackme啊~~,实在不想按正规方式写了。注册算法太长。
==========================================================================================
原版CrackMe+自己写的KeyGen下载:


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 7
支持
分享
最新回复 (5)
雪    币: 338
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
分析的不错。学习!
2006-8-14 22:45
0
雪    币: 179
活跃值: (131)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
3
keygen写的好!哈哈
2006-8-15 00:23
0
雪    币: 270
活跃值: (176)
能力值: ( LV12,RANK:370 )
在线值:
发帖
回帖
粉丝
4
好一个内存注册机,思路不错
2006-8-15 11:30
0
雪    币: 2256
活跃值: (941)
能力值: (RANK:2210 )
在线值:
发帖
回帖
粉丝
5
好文章,学习了,加精鼓励一下
2006-8-15 12:16
0
雪    币: 249
活跃值: (10)
能力值: ( LV12,RANK:250 )
在线值:
发帖
回帖
粉丝
6
感谢支持
2006-8-15 16:14
0
游客
登录 | 注册 方可回帖
返回
//