这个注册机编写器以前一直是我自己为写注册机而编写的,通过它只要略有汇编基础很快就能写出一个注册机。而不需要再过多的了解程序的指令算法。 整个程序体实际上只是我用汇编写的一个模板。所以大家也可以在其中自定义自己的界面和提示信息。可以用VC++或BC++等资源编辑工具自行修改key1.res资源文件,但请不要修改它们对应的ID号。
9 H3 l8 z) h5 [ N9 ` 通过动态调试或反汇编例子程序可以得到以下注册码的计算过程:
5 s9 G( Q w" W0 r8 } Bxxxx:00401077 CALL GetCommandLineA
# {' G! W8 k) A4 S6 D' [xxxx:0040107C CMP BYTE PTR [EAX],22 ^' d! ?: T; {' b' [
xxxx:0040107F JNZ 401082
5 M ~2 ?; v$ Dxxxx:00401081 INC EAX
9 w" |/ m3 N1 a! \xxxx:00401082 MOV CX,WORD PTR [EAX]
# b: a4 S- X1 C+ M1 g* Z! }xxxx:00401085 MOV WORD PTR [0040306C],CX
5 [' S( T- u/ s0 n4 v8 G, Txxxx:0040108C MOV WORD PTR [0040306E],5C 9 P! y0 V1 }4 `. U Z& C& L) V
xxxx:00401095 PUSH 0
7 V5 S. R# n0 Q& i/ n- Z0 e0 F3 ixxxx:00401097 PUSH 0
4 C7 p+ P/ u! F8 jxxxx:00401099 PUSH 0
$ o7 b U" c/ _xxxx:0040109B PUSH 0
( E$ ^+ d; L+ _; |% hxxxx:0040109D PUSH DWORD 00403058 0 H3 t; h( W% k! ^* R
xxxx:004010A2 PUSH 0
e) H: Z) j4 U' Z! |: Y0 N; Txxxx:004010A4 PUSH 0 ! h& ]& B' f- T! Y5 r( j
xxxx:004010A6 PUSH DWORD 0040306C 3 {4 a6 }( _7 W- i' X5 M9 x4 D" a
xxxx:004010AB CALL GetVolumeInformationA / O" q7 u3 f$ j0 w/ i
………… ………… 5 _ H) b- d y4 g5 a; t6 [
………… ………… + D; w2 q- J6 [- G
xxxx:0040111E MOV EAX,1 5 b5 L# g/ h% v
xxxx:00401123 CPUID ' L" f" j: ^! ]1 Y; V% D
xxxx:00401125 MOV ECX,DWORD PTR [00403058] 5 Q% b8 m+ W8 ?- z) U" N; F' g
xxxx:0040112B XOR EDX,EDX
7 a4 k# M4 v7 C: J. @ axxxx:0040112D MUL ECX
; ^# x$ ]. o5 [6 x5 W3 y7 Dxxxx:0040112F ADD EAX,EDX / p& b* b ^9 C$ t" i9 E& d, F) Y
xxxx:00401131 PUSH EAX 6 y7 ~" N0 i7 |& v! h
xxxx:00401132 PUSH DWORD 0040303E ; 在这里下D 40303E可以看到数据窗口中显示为“%1X”, E6 }6 Y, j' F" `
xxxx:00401137 PUSH DWORD 0040305C * q( R+ _5 J/ R: X, ~; ]4 f
xxxx:0040113C CALL wsprintfA! Q8 h; l1 i8 v$ y }# d _
对于以上的指令并不需要过多的了解它在干什么,只要将其中的每个地址改成一个变量地址的声明,然后再原封不动的抄到注册机编写器的代码窗口中即可。
$ w: a, \; B: Y# `5 E 这是写好的声明:: f) @6 X( p& L7 z! K
a1 dd 0 | ; 这是一个双字的内存空间,对应于上面的403058。0 n" R- {$ z V% P m$ l* b
;(因为40109D处的指令是DWORD 403058,所以用dd,如果是WORD就用dw,如果是BYTE就用db) | a2 dd 0 | ; 对应于上面的40306C | a3 db "%1X",0 | ; 对应于上面的40303E指向的字符串 | a4 db 20 dup (0) | ; 这是20个字节的内存空间,用来存放输出的注册码,对应于上面的40305C | 输入如图所示:( f, A5 h! ~7 H! k. ]; ?) B) Q# K
这是写好的程序代码:: X4 X" _- R9 k' n9 h/ J
CALL GetCommandLineA CMP BYTE PTR [EAX],22h | ; 后面加h表示是十六进制 | JNZ n1 | | INC EAX | | n1: | | MOV CX,WORD PTR [EAX] | | MOV WORD PTR a2,CX | | MOV WORD PTR a2+2,5Ch | | PUSH 0 | | PUSH 0 | | PUSH 0 | | PUSH 0 | | LEA EAX,a1 | ; 令EAX指向a1 | PUSH EAX | | PUSH 0 | | PUSH 0 | | LEA EAX,a2 | | PUSH EAX | ; 令EAX指向a2 | CALL GetVolumeInformationA | ; 当然这几条语句也可以直接写成
( x6 Q/ E) r8 ^: ^) F* O: \6 Y# Yinvoke GetVolumeInformationA,addr a2,0,0,addr a1,0,0,0,0" J" J! w9 z1 q# g; y
的形式 | MOV EAX,1 | | CPUID | | MOV ECX,a1 | | XOR EDX,EDX | | MUL ECX | | ADD EAX,EDX | | PUSH EAX | | LEA EAX,a3 | ; 令EAX指向a3,也就是指向字符“%1X”。 | PUSH EAX | | LEA EAX,a4 | | PUSH EAX | | CALL wsprintfA | | LEA EAX,a4 | ; 令EAX指向a4。因为程序最后显示的就是EAX寄存器所指向的内存地址的数据。 | 输入如下图所示:
! @. E! r5 O3 R. {3 g' ^" M 可以看到这与上面的反汇编代码基本相同。点击编译就可以很容易的得到一个注册机了。
/ Z$ r) ~, Z$ {# k 生成的注册机如下图所示(这只是我写的外观,你也可以自行修改):' m* h v: L, C7 F2 {4 ] J
需要说明的是因为这只是我写的一个模板,所以我也在程序中使用了几个变量。5 M" L7 Y* S7 D7 N7 K6 a; |# ~, Z$ c
请不要再重复声明:hCursorHandle、hInstance、hIcon、hTempEbp、hInput、hMode以免出错。
& B; c. h$ Z4 d 还有就是你一定要在指令结束时令EAX指向正确的注册码地址。
/ m( A$ h) }& y6 U, z0 Y, J 这种算注册码的方法不是直接从用户所输入的序列号来计算注册码的,所以并不适用于所有情况。有时我们可能需要根据用户所填入的序列号来计算注册码。考虑到这种情况所以我在程序初使时令EAX指向第一个编辑框(也就是输入序列号的窗口)收到用户输入的数据,令EBX指向第二个编辑框收到用户输入的数据,令ECX指向第三个编辑框收到用户输入的数据。你如果要对用户输入的序列号或用户名等信息进行操作,那么可以就对EAX、EBX、ECX进行操作。
5 V; }3 \& x+ |2 ^ 下面的代码是本例根据用户所填入的序列号来计算注册码的方法:
* M1 G: h/ p0 a2 `; D$ CMOV ECX,EAX | ; EAX指向用户输入的八位序列号,现在暂将它移动到ECX寄存器 | XOR EBX,EBX | ; 以下是一段典型的将内存中的ASCII码转换为十六进制代码。 | n1: | | MOVZX EAX,BYTE PTR [ECX] | | OR AL,AL | | JZ n3 | | CMP AL,3Ah | | JC n2 | | SUB AL,7 | | n2: | | SUB AL,30h | | SHL EBX,4 | | ADD EBX,EAX | | INC ECX | | JMP n1 | | n3: | ; 我想以上的一段代码应该懂汇编就能写的出(如果不是很明白,那么你对我编写好的注册机用TRW调试一次就知道了)。 | PUSH EBX | ; 最后的十六进制结果都保存在寄存器EBX中: C/ D) k2 v, t* F$ k1 L
; 将EBX入栈,这是为了将EBX寄存器的数据保存起来。因为经过CPUID这个指令后EBX的值将被修改。然后后面就和上面一样照抄程序中的指令。以下计算注册码的方法很简短。但在实际的破解过程中,程序的算法可能会相当复杂。这就需要你通过调试或反汇编将关键的运算指令都找出来,再写进来。 | MOV EAX,1 | | CPUID | | POP ECX | ; 恢复EBX的值到ECX寄存器 | XOR EDX,EDX | | MUL ECX | | ADD EAX,EDX | | PUSH EAX | | LEA EAX,a3 | ; 令EAX指向a3,也就是指向字符“%1X”。 | PUSH EAX | | LEA EAX,a4 | | PUSH EAX | | CALL wsprintfA | | LEA EAX,a4 | ; 令EAX指向a4。因为程序最后显示的就是EAX寄存器所指向的内存地址的数据。 | 下图分别是采用方案二和方案三编译后的窗口界面:; ?) d) h: r6 s. w. |: @
如果你不采用这种方法编写那么也可以使用程序中的另一个功能“另类注册机”。它和CrackCode2000一样,也是通过拦截程序指令并显示出注册码。 我之所以再写一个是因为以前的CrackCode2000提供的拦截选项非常有限,而且也不对Wide格式(出现在VB程序中用00将ASCII码分隔开)提供支持,还有一个毛病是在有些程序中会出现莫名的非法操作或无法获得注册码的情况(就好比这个例子程序)。 另外它的界面也太简陋了,只是一个消息框。所以我用汇编写了这个另类注册机非常小巧,它最多可以设置100个断点(其实可以更多,但好象没这个必要),以及在每个断点处中断多少次,如下图所示:4 y! y% t8 R2 S& ~
对于以上界面的说明:程序名称和中断地址的设置,这个我想用不着多说,会破解的人都懂。 而获取注册码的方式上需要说明一下,我是这样考虑的:寄存器方式-因为注册码可能是会放在寄存器中比较,并且可能经过十进制或十六进制的转换, 所以就提供了一个寄存器方式及十进制或十六进制的选项。 内存方式-是指:如设置为EDX,即指注册码保存在EDX所指向的内存地址中(而不是寄存器里)这样就为获取注册码提供了更多的选择。
; u6 h7 q; c; D6 Z3 H1 z% x 可以自定义在弹出的对话框中将显示的主页、邮件和窗口标题,如下图所示:
! G$ t6 Y" o8 W1 J2 E) W1 z3 ] 生成的注册机有二个可选界面如下图所示:
! [3 [" r: U* S8 s d 需要说明的一点是这个对话框只在拦截成功的时候出现。9 v/ Z( c; j( q# d0 O
除此之外还有一个制作破解补丁的附加工具,制作界面如图所示。 i: g$ B9 ?1 N; z, g3 l
这是完成界面。
. ~; a+ X6 {' H' R9 b. u& t" e
: @* n7 g2 c. a |