到一些黑客站点上转转,发现那些最受欢迎、点击次数最多的文章都是一些“教菜鸟使用木马”“入侵初级教程”之类文章,而“Outlook Express HTML邮件超长字节href值缓冲溢出缺陷”“PHP fopen()函数易遭到CRLF Injection攻击”这种文章却乏人问津,尽管这或许才是真正高手所关心的。 `rQA9;Tn2
O$KLQ '0"n
现在看雪论坛上后一种文章逐渐增多,当然是因为大家的水平都提高了,但也给刚入门的菜鸟带来了麻烦,来了之后什么也看不懂,在高手看来不是问题的问题常常困扰新手们很长时间:为什么这里是关键跳转,那边是重要CALL?为什么有的CALL要跟进,有的CALL只需带过?我按照高手所写的一步步做下去成功了,可为什么要这样做呢?我想更有不少人好不容易破了一个明码比较的软件,想贴出来又怕为高手所不屑而做罢。 \y{C>!WX4
cbNrto9
因此我找了一个非常简单的CrackMe(如果你是高手,只静态调试应该就可以搞定了:)),从头到尾仔仔细细地写出了分析过程,在里面加入了些我认为应该注意的地方,希望能对刚入门的朋友有些帮助。我不是什么高手,最多算是破解得熟练一点儿了而已,也许这样才更能了解新手们的难处吧。 F!'y47QD
R9^Vk*`gFU
这里我用W32Dasm作为静态反汇编的工具,各位可能有用C32Asm或者其他的,基本功能其实应该差不多。 0)+F}SyyD
5hg:@i',
先胡乱输入用户名和注册码,点"Check the Serial",看看错误信息是什么(如果出现“注册码正确”的话就别在这儿看了,赶紧买彩票去:D)好出来了,“This serial is *NOT* Valid!! Try again... : UNREGISTERED”。
GMr jZ
P|l62!m<
好了运行W32Dasm把它反汇编,在串式参考(string reference)中找吧,注意当字串较长时有时不能完全显示,这时只要找前面一段就行了,比如这次就是,找到"This serial is *NOT* Valid!! Try ",就是它了,双击来到引用该字串的地方。(PS:有时错误信息在代码中会不止一次出现,这时只要多次双击就能找到其他的地方。) gQ6_]~4
=#
<!s!
下面我要引用代码了(这是在W32DASM里的形式,如果你用OD或SI动态跟踪时形式会略有不同)。不要被这么多代码搞晕了,建议先跳过代码看我的后面的说明,再从代码中对照。 i^f*Em1
iz.J._&
B<%cqz@
代码:-------------------------------------------------------------------------------- C8W#$a
* Possible Reference to Dialog: DialogID_0001, CONTROL_ID:0066, "" db -h=L|
| _)XQb1]
:00401085 6A66 push 00000066 ;输入用户名的文本框ID {<+B>6^
:00401087 53 push ebx ;对话框句柄 C9OEB6
;UUpkOQO(
* Reference To: USER32.GetDlgItem, Ord:0000h UTwXN |'|
| !LJE o>D
:00401088 E8159C0000 Call 0040ACA2 ;得到文本框句柄 }:+SA
:0040108D 6A64 push 00000064 ;得到字符串的最大长度 UI2TW)^2
:0040108F 8D9548FFFFFF lea edx, dword ptr [ebp+FFFFFF48] AS5'j
:00401095 52 push edx ;EDX是存取字符串的地址 OEiu,Y|@l
:00401096 50 push eax ;EAX是上面得到的文本框句柄 fab.%$
`) y<X#[8
* Reference To: USER32.GetWindowTextA, Ord:0000h kx{LY`pY
| \3"jW1Wb
:00401097 E8129C0000 Call 0040ACAE ;得到用户名,在[ebp+FFFFFF48] cV$an
{{6D4M|s
* Possible Reference to Dialog: DialogID_0001, CONTROL_ID:0068, "" IN8G4\r
| O:E0htdWr
:0040109C 6A68 push 00000068 ;同样的操作,输入注册码的文本框ID !),eEy
:0040109E 53 push ebx 9epMw-)k
.}9Lj
* Reference To: USER32.GetDlgItem, Ord:0000h _jb'HP
| ]-j.\+(*
:0040109F E8FE9B0000 Call 0040ACA2 H@xHkqan
:004010A4 6A64 push 00000064 ;~-ZN?8
:004010A6 8D8DE4FEFFFF lea ecx, dword ptr [ebp+FFFFFEE4] 9])Id;+91
:004010AC 51 push ecx nR]*RIp5
:004010AD 50 push eax AQ&vq$
v M'!WVs
* Reference To: USER32.GetWindowTextA, Ord:0000h Z9G4in8
| [uwn\-
:004010AE E8FB9B0000 Call 0040ACAE ;得到注册码,在[ebp+FFFFFEE4] 6gabnW3
%+htA0aX
* Possible Reference to Dialog: DialogID_0001, CONTROL_ID:0067, "" d"yJ0F
| <.#jp([W>
:004010B3 6A67 push 00000067 ;这个是最下面的提示的文本框的ID Im?/#t X
:004010B5 53 push ebx MDQ:6Ri
7 7'OR;b$
* Reference To: USER32.GetDlgItem, Ord:0000h /!J xiGn
| F Uz1P
:004010B6 E8E79B0000 Call 0040ACA2 ;得到句柄 p$G3<Z&7
:004010BB 8BF0 mov esi, eax ;放在ESI备用 s2(7z9jR
:004010BD 8D8548FFFFFF lea eax, dword ptr [ebp+FFFFFF48] rb}fP
#j
:004010C3 50 push eax ;指向用户名 k( Ik+=u
:004010C4 E867050000 call 00401630 ;得到用户名长度 #D#kw*c
:004010C9 59 pop ecx wpp!H<')
:004010CA 8945D8 mov dword ptr [ebp-28], eax ;长度放在[ebp-28] B uso
`G
:004010CD 8D95E4FEFFFF lea edx, dword ptr [ebp+FFFFFEE4] CzY18-L@EX
:004010D3 52 push edx ;指向注册码 b)x0;8<
:004010D4 E857050000 call 00401630 ;得到注册码长度 k]C k%[d
:004010D9 59 pop ecx qO38vY){
:004010DA 68EAB04000 push 0040B0EA 5Ok3y|cEx
:004010DF E84C050000 call 00401630 R!%HQA1U
:004010E4 59 pop ecx GqNOWK2O
:004010E5 680EB14000 push 0040B10E IA&V?{OE@I
:004010EA E841050000 call 00401630 (,t[`z
:004010EF 59 pop ecx &SPY'GQ!
:004010F0 837DD803 cmp dword ptr [ebp-28], 00000003 >Ut: -}CS
:004010F4 7E7B jle 00401171 ;用户名长度不能小于等于3 si)>:e
:004010F6 90 nop y$bY
8L
:004010F7 90 nop ;du},>T$n
:004010F8 90 nop k0N>J8y
:004010F9 90 nop 7sQHz.4
:004010FA 33C9 xor ecx, ecx >q&5Z
:004010FC 33D2 xor edx, edx AG}j'
:004010FE 33DB xor ebx, ebx E:M,nSc)53
:00401100 33C0 xor eax, eax M;b3-
i
:00401102 837DD832 cmp dword ptr [ebp-28], 00000032 0HU0p!yt&
:00401106 7D69 jge 00401171 ;用户名长度不能大于等于32h 64#Ri!RR}
:00401108 90 nop A?lR[`'u\
:00401109 90 nop kppi>!6
:0040110A 90 nop 0>BI[x@
:0040110B 90 nop Iox )-
<XG]aYBR
* Referenced by a (U)nconditional or (C)onditional Jump at Address: T?f{.a)
|:0040111C(C) GVA%iE.
| _0gdt4
:0040110C 0FBE840D48FFFFFF movsx eax, byte ptr [ebp+ecx-000000B8];依次取用户名的字符 gg rYf*
:00401114 41 inc ecx ;ECX为循环变量 S'qT+pP
:00401115 33C1 xor eax, ecx ;取的字符与循环变量XOR ,{S $&g*
:00401117 03D8 add ebx, eax ;把结果累加到EBX '" %0UflJS
:00401119 3B4DD8 cmp ecx, dword ptr [ebp-28] ;循环变量与用户名长度相比 )sdHJ
:0040111C 75EE jne 0040110C ;如果未取完就跳回继续 Rh)XYCM
:0040111E 6BC006 imul eax, 00000006 ;最后一轮计算的结果在EAX, 乘6 5EVypw?]x
:00401121 C1E307 shl ebx, 07 ;前面累加结果左移7位 &}Wi@;G]2
:00401124 03C3 add eax, ebx ;相加 k
Qr
:00401126 8945C8 mov dword ptr [ebp-38], eax p&Qm[!
:00401129 FF75C8 push [ebp-38] ;把上面结果压栈 G8__6v~
-hm/lxyU
* Possible StringData Ref from Data Obj ->"%lX" ?.F^Oi6
u
| p.8
:0040112C 6838B44000 push 0040B438 ;一个转换的标识 e4Qjx*[G
:00401131 8D8D80FEFFFF lea ecx, dword ptr [ebp+FFFFFE80] VK*`&D<P
:00401137 51 push ecx ;存放转换结果的地址 R\7r!38
:00401138 E8873D0000 call 00404EC4 ;数字转为十六进制字串 [QQM/ ?
:0040113D 83C40C add esp, 0000000C oxeu%wj_
:00401140 8D8580FEFFFF lea eax, dword ptr [ebp+FFFFFE80] d
oEuKT
:00401146 50 push eax ;上面转换的字串 u1UCe
:00401147 8D95E4FEFFFF lea edx, dword ptr [ebp+FFFFFEE4] YRBJ(v"9
:0040114D 52 push edx ;假注册码 <>f;g"qS
`<v$+mG
* Reference To: KERNEL32.lstrcmpA, Ord:0000h Bnk<e
| <+
[N*
:0040114E E8339C0000 Call 0040AD86 ;比较 tw
zV-8\
:00401153 85C0 test eax, eax S~fP$L5
:00401155 750D jne 00401164 ;这里就是关键的跳转 |X XO0
GLZ*5kw
* Possible StringData Ref from Data Obj ->"Congratulations! IF this number " 0$-|Th:o
->"comes *FROM YOUR* keygen, Write " V;CRs\aYf
->"a tutorial dude ;)." (vD==n9Hd
| K$}K2w
:00401157 683CB44000 push 0040B43C ;指向表示成功的字符串 $iy!:Did
:0040115C 56 push esi ;ESI还记得么?那个提示文本框的句柄
F{Yr8(UHA
T@P~A)>yo
* Reference To: USER32.SetWindowTextA, Ord:0000h (7!pc
| >)*d/ ^
:0040115D E8289B0000 Call 0040AC8A ;显示出来 q)C
Xu
:00401162 EB18 jmp 0040117C e2V;6N
8q6Le{G
* Referenced by a (U)nconditional or (C)onditional Jump at Address: CXz9bhn<4
|:00401155(C) @C[p? ak
| W]bytsl
(Lh!7g/0N
* Possible StringData Ref from Data Obj ->"This serial is *NOT* Valid!! Try " P<[)
qq@;
->"again... : UNREGISTERED" )`Qr=DIsW
| wfu`(4
:00401164 6890B44000 push 0040B490 ;开始时停在这句,向上找跳转 LB$0'dZU
:00401169 56 push esi ;ESI提示文本框的句柄 z$g__q-
&jg>X+;
* Reference To: USER32.SetWindowTextA, Ord:0000h |7Z}#eP//
| `RU RC"
:0040116A E81B9B0000 Call 0040AC8A >OjK0jiPf
:0040116F EB0B jmp 0040117C i~<.@&vt
0/z$W.!
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses: u!It';j
|:004010F4(C), :00401106(C) pR`nQM-D
| sUxEm}z
0d~?|Nv -
* Possible StringData Ref from Data Obj ->"Name must contain more than 4 " CL(D&8v8~
->"chars and less than 50 chars !!" Yyw3+3
| DmB?.l-
:00401171 68C9B44000 push 0040B4C9 ;用户名不符合要求跳到这里
2Mw`
:00401176 56 push esi ;ESI提示文本框的句柄 v`7~#Avhz
L0%W;m
* Reference To: USER32.SetWindowTextA, Ord:0000h R"F: (
| bi-z%!Z
:00401177 E80E9B0000 Call 0040AC8A
VIod6Vk
!0KNA1w,
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses: Ycxv=Et
|:00401162(U), :0040116F(U) ~qA\u5sB9@
| Te^_gdf
:0040117C 5F pop edi @'J[T: e
:0040117D 5E pop esi h?->A#
:0040117E 5B pop ebx G/1V4-@
:0040117F 8BE5 mov esp, ebp {q);1Nnf
:00401181 5D pop ebp ;整理一下返回了 i$!K{H1{9
:00401182 C3 ret 97}l`z;Z
-------------------------------------------------------------------------------- 0v3
8LBH)
双击后光标停在401164这一句。很明显,如果我们来到这句时我们就死翘翘了,而如果我们的注册码正确的话当然不会来到这一句(废话太多了:p)那么这一句上面就肯定会有一个条件跳转的指令。(这是找爆破点时的基本思想)向上找找看,找到了: M^/ZpKeT"
~yRKNH*M
:00401155 750D jne 00401164 Z?."cuTt
Dv=pX.Z+
正好跳到401164错误信息那一句。呵呵,如果你想爆破的话,只要把750D改成740D(je,把条件反过来,注册码错误就显示正确信息:D)或者改成EB0D(jmp,无条件跳转,不管三七二十一就正确)。 @@6c{r^P
{>X2\.Rl
OK,我们不能满足于此啊,咱们看看它的算法是怎样的,也像那些神秘兮兮的高手似的写一个注册机出来。:D msZ3%L
a#/~rNRY
我先给各位补一点课,就是对函数的调用。除了一些DELPHI程序之外,对函数参数的传递大都用堆栈来完成,简单地说就是把函数的各个参数先PUSH进去,然后再CALL这个函数。在函数内部呢,一般[ebp+8]是第一个参数,[ebp+C]是第二个参数,每次多加4依此类推。而函数内部的局部变量常用[ebp-4][ebp-8]...等等。(原因讲起来有点复杂,先记住就行了)函数的返回值在EAX里。 05YsLNh
o-<.8Z}>at
一般来说,软件的判断注册部分都是一个函数,在函数开头最经典的两句就是 =$<