【文章标题】: 一个入门级的CrackMe分析(适合新手)业余版
【文章作者】: NBA2005
【作者QQ号】: 382309369
【软件名称】: Crack me之 zugo.exe
【软件大小】: 28KB
【下载地址】: http://bbs.pediy.com/showthread.php?t=58867
【加壳方式】: 无
【保护方式】: 无
【编写语言】: Microsoft Visual C++ 6.0
【使用工具】: Ollydbg
【操作平台】: WIN2000
【软件介绍】: 新兵论坛的毕业生练手用的
【作者声明】: 只是想借这个简单的CRACK ME介绍一下破解的基本思想、流程和初学破解的人要了解的细节。不到之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
天下黑客出我辈
一入破解岁月催
天下软件俱免费
我等都要喝北风
前些日子,我上网玩一个小游戏,却发现网站已经关闭。听说是亏损被迫倒闭的。一位软件编写者在网上对我痛骂:就是你们的存在,弄的软件业发展艰难。我无语,因为这网站的许多FLASH我确实破解过。但我恪守破解的操守:破解但不传播,不一赢利为目的。有感一首小小打油诗,与同道共勉。做为第一课,我认为首先要学会尊重软件作者付出的辛勤的劳动。
MM求破解。好为难啊。刚刚正义凛然地说了一通大道理,却知法犯法。这在法律上要罪加一等的。临机一动,我教你破解吧,很简单的。首先,把MM喜欢听的电脑音乐暂停,然后打开OD。讲了一通F7和F8的区别,然后亲自示范。我按、按、按...怪了,F7和F8没反应。狠狠心,按F9,呼,一下就到结束了。我的汗哗哗地流啊,恰似一江春水向东流。丢不起这个人啊。赶快检查电脑键盘,好的,与网上佳丽三千聊得是浓情蜜意。回到OLLYDBG,F7和F8还是毫无反应。F7和F8啊,你快动起来啊,兄弟我求你了。等等,F7和F8...MM喜欢听的电脑音乐播放器里好象也有快捷键F7和F8。快速关掉音乐播放器。好了,不流汗的感觉就一个字:爽。破解第二课:注意破解的环境。尽量关掉不必要的应用软件,特别是支持F1-F12功能的软件。许多破解的朋友喜欢听音乐或看小电影,边破解。我就经常在破解过程中碰到这类的小麻烦。有一个英汉小词典居然还支持F4功能,让我脱壳真麻烦、真麻烦。高手常常嘴上一句:根据经验。这就是经验。
破解要有效率,必须要踩点。知己知彼,百战不怠。我的踩点一是要了解有无壳和编程语言,二要了解编程者安全上的缺陷。踩点的目的是寻找一个理想的程序切入点。最庸俗的方法就是试运行要破解的程序。双击zugo.exe,是最常见的注册对话框。试着输入三类信息:英文字母、数字和汉字。我的习惯是输入三个字符。Serials提示:masukkan at least 5 huruf。什么鸟语言?不知道,但我是聪明的富而莫死(你也猜得懂我说的是啥意思吧)。我一输入用户名,它就出来,at least 5还认得。最少五个,可能是最少五个字符?猜的对不对呢?把masukkan at least 5 huruf消去,试验输入六个字符123456。哈哈,我是聪明的富而莫死(你也猜得懂我说的是啥意思吧)。masukkan at least 5 huruf不出现了。出了另一个对话框,又是一串天书般提示,就认识BAD boy!猜是坏消息,在破解中估计是注册失败之类的意思。高手常常嘴上一句:根据经验。这就是经验。啥经验?破解的精华。啥破解高手,说白了就是靠猜。根据种种可疑的提示和线索来猜。学破解的最高境界就是学程序的编程核心思想,然后反过来猜作者的编程思路。光猜还不够,还要多次一步步地实验,来验证自己的猜想,这是一个艰辛的过程。破解第三课,也是破解的精华:猜+试验。一般人我不告诉他。菜鸟的问题:从程序开头一步步按F8能不能破解?能。我乘飞机到意大利能不能?走路到罗马行不行?
好,踩点有了结果:
1.用户名字符类型:中英文不限,数字可以。
2.用户名字符条件:at least 5。
3.用户名对错的提示:猜是Bad boy!的对话框。以后就要试验去证实我们的猜想对OR错。
破解正式开始。OD打开zugo.exe,停在这:
00401283 >/$ 55 push ebp
00401284 |. 8BEC mov ebp, esp
00401286 |. 6A FF push -1
00401288 |. 68 C0404000 push 004040C0
0040128D |. 68 6C1E4000 push 00401E6C ; SE 处理程序安装
00401292 |. 64:A1 0000000>mov eax, dword ptr fs:[0]
Bad boy!是字符串,先试试字符串查找。这是破解前辈的法宝,打遍魔教无敌手。菜鸟的问题:好象我们是魔教?呸呸呸,我们是圣教,记住了。鼠标右键于汇编代码处,点查找。这有两种选择:OD自带的所有参考文本字串和字符插件FIND ASCII。一查找,有Bad Boy、Good Boy、at least 5和messageboxa。我认识的和猜想重要的就这些。为什么?猜的。分别点三处信息,选反汇编窗口中跟随,分别看到:
第一处:
004010FB |. >push 00405098 ; ASCII "Good Boy!"
00401100 |. >push 0040507C ; ASCII "Terima kasih kerana mencuba"
.........
第二处:
00401107 |> \>push 00405070 ; ASCII "Bad Boy!"
0040110C |. >push 0040504C ; ASCII "Tidak tepat, sila cuba sekali lagi"
.........
第三处:
00401114 |. >call dword ptr [<&USER32.MessageBoxA>>; \MessageBoxA
“等等,”菜鸟来劲了。
“我来到第一处:
004010FB |. >push 00405098 ; ASCII "Good Boy!"
00401100 |. >push 0040507C ; ASCII "Terima kasih kerana mencuba"”
不会是再查找一遍字符串吧?再开始第二处吧?
当然不是。许多新手看着高手们的破文就是做不下去,其中最主要的原因就是对OD的使用上不熟练,对一些细节的问题不会处理。这总被高手以一句根据经验蒙过去了。啥经验,不就多吃了两年盐嘛。可笑的是许多破解高手也是老实地反复查找字符串。呵呵,又一位走路到罗马。
解决的方案很简单。查找的字符串窗口不要关掉。菜鸟:“我选反汇编窗口中跟随,怎么关。别蒙我了。”我是说你需要反复使用的窗口不要关掉,比如内存窗口、堆栈窗口或函数窗口等等。选窗口(W)的最下面,就是窗口集合,需要看哪个窗口就点哪个。点文本字符串参考位于...,回到可爱的字符串窗口,继续。
破解第四课:细节决定成败。适用范围:菜鸟家族。当然不是我圣教了。
004010DC |. >|mov dword ptr [ebp+C], ecx
004010DF |. >|cmp eax, ebx
004010E1 |.^ >\jl short 004010CC
004010E3 |> >push dword ptr [ebp+14]
004010E6 |. >call 00401278
004010EB |. >pop ecx
004010EC |. >mov ecx, dword ptr [ebp+C]
004010EF |. >push 0
004010F1 |. >xor ecx, 0A9F9FA
004010F7 |. >cmp ecx, eax
004010F9 |. >jnz short 00401107
004010FB |. >push 00405098 ; ASCII "Good Boy!"
00401100 |. >push 0040507C ; ASCII "Terima kasih kerana mencuba"
00401105 |. >jmp short 00401111
00401107 |> >push 00405070 ; ASCII "Bad Boy!"
0040110C |. >push 0040504C ; ASCII "Tidak tepat, sila cuba sekali lagi"
00401111 |> >push dword ptr [ebp+8] ; |hOwner
00401114 |. >call dword ptr [<&USER32.MessageBoxA>>; \MessageBoxA
OK,虽然很简单,但也不容易。然后我们到了破解的关键环节:程序流程。看了上面的程序汇编代码,你需要在程序流程的基本知识的基础上有目的地猜。不然你就走路去罗马吧。破解的关键环节:程序流程,是破解的最最基本的知识。如果你不懂,那你就撒泡尿照照你自己吧,该干啥干啥。可以说,程序流程的研判贯穿了我们破解的始终。我们可以不懂函数的种种返回值,可以不懂啥SEH异常,但不能不懂程序流程。我猜程序流程如下:
004010E3 |> >push dword ptr [ebp+14] 用户名赋值
004010E6 |. >call 00401278 对用户名处理
......................
004010F7 |. >cmp ecx, eax 比较这两值。
004010F9 |. >jnz short 00401107 程序流程两分支:对和错
对:
004010FB |. >push 00405098 ; ASCII "Good Boy!"
00401100 |. >push 0040507C ; ASCII "Terima kasih kerana mencuba"
00401105 |. >jmp short 00401111 返回程序主干
错:
00401107 |> >push 00405070 ; ASCII "Bad Boy!"
0040110C |. >push 0040504C ; ASCII "Tidak tepat, sila cuba sekali lagi"
00401111 |> >push dword ptr [ebp+8] ; |hOwner
00401114 |. >call dword ptr [<&USER32.MessageBoxA>>; \MessageBoxA
\MessageBoxA猜是信息框。
我们来验证。点004010E3 |> >push dword ptr [ebp+14] ,按F2设断点。运行F9,出现对话框,输入
NAMA: abcde
SERIALS:123456
破解老手都知道:输入连续的信息。这又是一个破解的细节。细节决定成败和效率。这样做的好处是:在猜算法时,比较直观和容易理解。用户名和序列号的位数尽量不要一样,这又是一个破解的细节。理由:有些程序的算法会拿用户名和序列号的位数反复做文章,降低猜的难度。韩国的魔兽为什么那么拽?NBA的篮球为什么那么漂亮?细节。这些细节都在破解高手的一句经验里。
我们继续。点OK。停在断处,看信息窗口:
堆栈 ss:[0012FBE4]=001367A0, (ASCII "123456")
跳转来自 004010CA
这验证了我们对004010E3 |> >push dword ptr [ebp+14]的猜想,就是用户名赋值。
004010F9 |. >jnz short 00401107 程序流程两分支:对和错
这一句怎么验证?双击,改为
004010F9 |. >jz short 00401107
即jnz >jz
运行F9,出现GOOD BOY!
重新调试,CTRL+F2,程序自动改回004010F9 |. >jnz
出现错误提示:BAD BOY!
我们的猜想又得到了验证。我是聪明的富而莫死(你也猜得懂我说的是啥意思吧)。
菜鸟又来了,“还有一句没交代呢”:
004010E6 |. >call 00401278 对用户名处理
别急,慢慢来。让我喝口茶,列位看官给个掌声。哗哗哗哗哗哗哗,好热烈!
重新调试,CTRL+F2。菜鸟:又重新来啊? 破解第五课:耐心是破解的利器。
F7进入call 00401278
00401278 /$ >push dword ptr [esp+4]
0040127C |. >call 004011ED F8粗过,再猜它的作用。以后需要还要进入细跟。
00401281 |. >pop ecx
00401282 \. >retn 这一句时,寄存器窗口出现:ECX 001367A0 ASCII “123456”
猜是ECX=123456
回到程序主干。F7到004010F7 |. >cmp ecx, eax
其中ECX的值由下算出:004010F1 |. >xor ecx, 0A9F9FA
根据汇编知识猜:0A9F9FA取或值=ECX。但EAX的值呢?看来我们对下句的理解猜错了。
004010E3 |> >push dword ptr [ebp+14] 用户名赋值
004010E6 |. >call 00401278 对用户名处理
对CALL的判断和跟踪、反复试验,贯穿了具体破解过程的始终。这个CALL似乎不是我们要找的关键CALL。只好再向上看:
004010A7 |. >mov esi, dword ptr [<&USER32.GetDlgI>; |USER32.GetDlgItemTextA
004010AD |. >push dword ptr [ebp+10] ; |Buffer
004010B0 |. >push 3E8 ; |ControlID = 3E8 (1000.)
004010B5 |. >push dword ptr [ebp+8] ; |hWnd
004010B8 |. >call esi ; \GetDlgItemTextA
004010BA |. >push dword ptr [ebp-4] ; /Count
004010BD |. >push dword ptr [ebp+14] ; |Buffer
004010C0 |. >push edi ; |ControlID => 3EA (1002.)
004010C1 |. >push dword ptr [ebp+8] ; |hWnd
004010C4 |. >call esi ; \GetDlgItemTextA
004010C6 |. >xor eax, eax
004010C8 |. >test ebx, ebx
004010CA |. >jle short 004010E3
004010CC |> >/mov ecx, dword ptr [ebp+10]
004010CF |. >|mov edx, dword ptr [ebp+C]
004010D2 |. >|add edx, ebx
004010D4 |. >|movsx ecx, byte ptr [eax+ecx]
004010D8 |. >|imul ecx, edx
004010DB |. >|inc eax
004010DC |. >|mov dword ptr [ebp+C], ecx
004010DF |. >|cmp eax, ebx
004010E1 |.^ >\jl short 004010CC
004010E3 |> >push dword ptr [ebp+14]
004010E6 |. >call 00401278 不是关键CALL,排除。
004010EB |. >pop ecx
004010EC |. >mov ecx, dword ptr [ebp+C]
004010EF |. >push 0
004010F1 |. >xor ecx, 0A9F9FA
004010F7 |. >cmp ecx, eax
004010F9 >jnz short 00401107
004010FB |. >push 00405098 ; ASCII "Good Boy!"
00401100 |. >push 0040507C ; ASCII "Terima kasih kerana mencuba"
00401105 |. >jmp short 00401111
00401107 |> >push 00405070 ; ASCII "Bad Boy!"
0040110C |. >push 0040504C ; ASCII "Tidak tepat, sila cuba sekali lagi"
00401111 |> >push dword ptr [ebp+8] ; |hOwner
00401114 |. >call dword ptr [<&USER32.MessageBoxA>>; \MessageBoxA
没有发现可疑的关键CALL,
004010A7 |. >mov esi, dword ptr [<&USER32.GetDlgI>; |USER32.GetDlgItemTextA
004010AD |. >push dword ptr [ebp+10] ; |Buffer
004010B0 |. >push 3E8 ; |ControlID = 3E8 (1000.)
004010B5 |. >push dword ptr [ebp+8] ; |hWnd
004010B8 |. >call esi ; \GetDlgItemTextA
004010BA |. >push dword ptr [ebp-4] ; /Count
004010BD |. >push dword ptr [ebp+14] ; |Buffer
004010C0 |. >push edi ; |ControlID => 3EA (1002.)
004010C1 |. >push dword ptr [ebp+8] ; |hWnd
004010C4 |. >call esi ; \GetDlgItemTextA
以上猜是出现我们输入用户名和序列的窗口,断在004010A7 重新运行验证。
004010C8 |. >test ebx, ebx
004010CA |. >jle short 004010E3
小于=at least,又是在输入用户名和序列的窗口后,你猜呢?
对了,EBX是用户名的位数,设断此处,输入用户名不同长度验证。
了不起,我们不懂什么编程,但光靠猜和耐心,反复地试验和验证,推理并证实了几乎所有语句的含义。问题来了,关键的CALL在哪呢?根据消息的顺序和程序的常见流程,用户名的位数的判断优先于用户名的处理。
004010E6 |. >call 00401278 不是关键CALL,排除。
这个结论是错误的,我们走了弯路。但更坚定了关键CALL的位置。仔细回忆,啊,被帅哥遗忘的CALL:
00401278 /$ >push dword ptr [esp+4]
0040127C |. >call 004011ED F8粗过,再猜它的作用。以后需要还要进入细跟。
00401281 |. >pop ecx
00401282 \. >retn 这一句时,寄存器窗口出现:ECX 001367A0 ASCII “123456”
猜是ECX=123456
0040127C |. >call 004011ED 关键CALL里的关键CALL
关键CALL里的关键CALL是破解的家常便饭,考验的是我们的耐心。破解老手根据经验,坚信我们一开始CALL就是关键的判
断,跟到这,粗过一遍,就能断定这就是关键的CALL。因为到00401281 |. >pop ecx; 001367C0时,堆栈窗口出现
了两个123456,我们很容易猜到这个CALL对123456做过处理,然后pop ecx。这符合一般编程的逻辑。
重新调试,CTRA+F2,停在:
0040127C |. >call 004011ED 关键CALL里的关键CALL
F7进入CALL。先不运行,向下看一遍程序,老手很容易猜出了大致的程序流程,在几个可疑处做上标签,方便以后逐步地
验证。新手就先走步到罗马吧。以后赚了美金再做飞机。高手Petnt已经给出算法了,我就不献丑了。读者可自行验证,走步
去意大利。等等,我的程序运行到哪了?按“*”就知道了。
菜尿来了,“你还没教怎么暴力破解呢!”菜尿就是尿多,哪这么多问题。破解第六课:笑对高手骂。打是疼,骂是恨铁不成钢。高手的耐心都用在破解里了。我的耐心也就只此一回,谢绝FAQ。
爆破的方法就是程序改向,根据程序流程分两种情况:
程序流程一:
判断对----》分支
判断错
程序继续
......
爆破方法:
将判断改JMP。这又有一个细节,为什么不改向呢?
JZ--》JNZ或JNZ--JZ呢?
与JMP有什么区别呢?这个问题留给你。
程序流程二:
判断错----》分支
判断对
程序继续
......
爆破方法:将判断或关键CALL NOP掉。别再问了,再问我尿你。
脱壳碰壁
爬格好累
好心菜鸟
给点安慰
啥安慰?猜
啥安慰?你自己不会试试吗
啥安慰?耐心地试试
啥安慰?细节,看我两手的动作
啥安慰?你找骂呀?
对了,笑对高手骂。
对对,鼓掌................................................................................
我是谁?我是聪明的富而莫死(你也猜得懂我说的是啥意思吧)。记住了,我是NBA2005!牛皮不是猜的!
天下黑客出我辈
一入破解岁月催
天下软件俱免费
我等都要喝北风
歌声中,NBA2005乘雕飞去!
--------------------------------------------------------------------------------
【经验总结】
天下黑客出我辈
一入破解岁月催
天下软件俱免费
我等都要喝北风
做为第一课,我认为首先要学会尊重软件作者付出的辛勤的劳动。
破解第二课:注意破解的环境。尽量关掉不必要的应用软件,特别是支持F1-F12功能的软件。
破解第三课,也是破解的精华:猜+试验。
破解的精华。啥破解高手,说白了就是靠猜。
根据种种可疑的提示和线索来猜。学破解的最高境界就是学程序的编程核心思想,然后反过来猜作者
的编程思路。
光猜还不够,还要多次一步步地实验,来验证自己的猜想,这是一个艰辛的过程。
踩点一是要了解有无壳和编程语言。
二要了解编程者安全上的缺陷。
踩点的目的是寻找一个理想的程序切入点。最庸俗的方法就是试运行要破解的程序。
最庸俗的方法就是试运行要破解的程序。
试试字符串查找。这是破解前辈的法宝,打遍魔教无敌手。
多个窗口的切换:
选窗口(W)的最下面,就是窗口集合,需要看哪个窗口
就点哪个。
破解第四课:细节决定成败。适用范围:菜鸟家族。
破解老手都知道:输入连续的信息。这又是一个破解的细节。细节决定成败和效率。细节都在破解高手的一句经验里。
破解第五课:耐心是破解的利器。
对CALL的判断和跟踪、反复试验,贯穿了具体破解过程的始终。
我们不懂什么编程,但光靠猜和耐心,反复地试验和验证,推理并证实了几乎所有语句的含义。
关键CALL里的关键CALL是破解的家常便饭,考验的是我们的耐心。破解老手根据经验粗过一遍,就能断定关键的CALL。
按“*”的含义。
跟踪关键CALL时,注意寄存器和堆栈窗口的变化有助于帮助我们猜得有理有据。
爆破的方法就是程序改向,根据程序流程分两种情况:将判断或关键CALL改JMP或NOP掉。
天下黑客出我辈
一入破解岁月催
天下软件俱免费
我等都要喝北风
--------------------------------------------------------------------------------
【版权声明】: 本文原创于NBA2005, 转载请注明作者并保持文章的完整, 谢谢!
2008年01月29日 下午 10:49:09
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)