|
编者:昨天一个叫aqtata的朋友发给我了个最新的密界文集, 本来想打包下载,可那样很多朋友3 N; M$ m+ I1 z* ]! E0 U
会看不到里面的好文章.于是我决定把其中较浅显通俗的一些文章发到文章区,希望能对您有所帮助
& C4 m) L Q9 u! X- u作者 : Detten Detten@tiscali.be
% R* ~+ `6 H! j3 D* U/ e来源 : _blank>http://biw.rult.at/4 ^; W% s$ F+ @5 w
, `3 `; E' ^. a
翻译 : nbw _blank>http://www.vxer.com/
; e# K7 E- j' y* e" w9 Z) ?
9 i A1 N+ h" ?, ~1 ^3 D1、前言, D; O( E% {+ [
一但破解了一个程序,你就想把成果共享给别人。为了不用把整个破解后的程序上传,你可以制作一个小补丁来修改程序中必要的字节。
. B) {) y' l& ^. q" ^* u' ] 那如何来写呢?
d, L! E6 o& U( t8 T===〉首先找到需要打补丁的文件。大多数补丁认为该文件处在自己当前目录下。& U& M6 x: k3 n4 v7 x- {9 s
$ W) V2 R5 @$ V8 `) ^
===〉如果找到,打开该文件。' |4 k, x' w/ W. K s& _0 a2 e
* [- J4 W/ @4 a4 u) }
===〉然后检查打开的文件是不是和所破解的文件。比如我们可以检查文件大小,或者随机检查一些字节,或者最好检查将要被修改的字节。
; }5 C t5 n# z3 l% f6 {4 H' C' v
$ l, a) s4 a4 X% C* T1 g' y2 ]9 ^===〉如果以上都无误,我们可以做需要调整 9 ?* a" W1 G2 x* v
把文件指针移动到指定位置,然后写入新的操作码。# K# G2 \, g- P6 s" u
; P+ \' y1 e; W: [===〉关闭文件,给出提示结果。) z. l' Y% u* Q. d9 I+ x1 `
6 p" _' g) ?6 B% o7 ]+ ?下面找一个你破解的文件,然后开始....
, g8 o3 p* d" V' r1 X
( d& G. A, ~: z! \* ]3 i, l2、必要的API
- E8 k* q \ X: K8 V4 }$ s( c 做这个程序需要用到什么API呢?
0 Z( v; }6 W4 [2 ^' P& o# o$ ~" j6 ?, @, w' }( O
HANDLE CreateFile( - m0 N: \, W" p# u
) {6 B8 V/ `: ~& Q4 g" fLPCTSTR lpFileName, // pointer to name of the file w A$ _# v5 Z, s5 n4 d
DWORD dwDesiredAccess, // access (read-write) mode
# Y3 T5 \, C1 K! `DWORD dwShareMode, // share mode
0 W1 o* s9 _& Z% V8 |1 k# p7 cLPSECURITY_ATTRIBUTES lpSecurityAttributes, // pointer to security attributes 0 ~9 X' D( M/ q L
DWORD dwCreationDistribution, // how to create / |( J- ?; r. J. Q! E! b9 T
DWORD dwFlagsAndAttributes, // file attributes
+ P. W/ @0 h+ L6 y- qHANDLE hTemplateFile // handle to file with attributes to copy
# u+ q$ E. @- P9 l) M);' N* p( q" z8 `, y/ i) `
* P2 B7 d& W- ?5 _3 n
这个API函数用来打开或者创建文件。, `- n! g/ B$ |$ Y& }: R
dwDesiredAccess 应该设置为: 'GENERIC_WRITE OR GENERIC_READ' ,因为需要读写文件;
' b% {/ r `; Q, M3 W( i) ddwShareMode = 'FILE_SHARE_WRITE OR FILE_SHARE_READ'
# o& B2 x* c8 _dwCreationDistribution = 'OPEN_EXISTING' 我们只需要打开文件,如果文件不存在函数将返回失败,然后我们给出提示信息。7 b& r. B3 V1 N' ?; b+ j- K l ~
可以察看WIN32.HLP获取详细信息,如果你没有这个API库,可以找相关资料。* X1 ]" A5 r1 x; X9 `0 s
如你所见,这个API函数返回我们需要文件句柄。我们可以利用这个句柄做下一步:写文件。
9 h8 B& Y9 |$ _( q% t0 {2 M
, }3 `4 q1 T% D5 i! d5 eBOOL WriteFile(
3 N! t$ k! |9 ?' ~3 v1 R, VHANDLE hFile, // handle to file to write to
$ R8 r/ O2 T: `! e7 yLPCVOID lpBuffer, // pointer to data to write to file
0 z$ _1 ^% [. E8 u2 F- SDWORD nNumberOfBytesToWrite, // number of bytes to write
$ q( Q( g7 @6 L5 u! O) J/ zLPDWORD lpNumberOfBytesWritten, // pointer to number of bytes written
0 g% B* ^5 c3 k. w$ r/ _8 jLPOVERLAPPED lpOverlapped // pointer to structure needed for overlapped I/O- r1 d# A" l0 \; L' K% v( ?) w; M, v
);
: H' t7 u# d! h4 ]: }9 D# U* }; V% M& `. [5 i* P) M0 x5 L
我们用这个函数把2个字节写入需要打补丁的文件(当然是在正确的位置)[译者:作者的例子是写2个字节,我们做的时候根据需要]
, w& E1 O) d4 f/ L, Q% m4 ^ 涉及到的hFile句柄就是CreateFile函数的返回值。
- o" }2 `/ @% M7 y' j5 e8 A! g: |$ w F0 [# m) r3 `9 }% |( {
lpOverlapped应该指向一个 OVERLAPPED 结构,我们需要用它设定正确的文件指针。
% L6 ]$ i, |8 R0 ~9 ?7 A+ F) G
" j9 w# F3 Q. e# Ztypedef struct _OVERLAPPED { // o - `. _# z# D5 J: a
DWORD Internal; ' H3 P# F. e; m$ E
DWORD InternalHigh; $ Y$ Q7 N' E) p4 z) t
DWORD Offset;
, z( d- K2 ?& J5 W- y% UDWORD OffsetHigh;
2 a) z' R& v/ {% m3 M) bHANDLE hEvent; ! d2 _9 Y5 N! ^, g6 ^" M( ~# w
} OVERLAPPED;
: `3 U' v8 e+ S, H* v& _Offset的内容是需要写入的地址。(译者:注意不是内存中的虚拟地址) L% L) C k" b; g( A# Y+ ~: j& p
# _5 ?" f+ v, J6 r3、目标
2 L0 T H. Q6 I5 w 目标程序是Crackme5.exe,假定我们现在获取不到正确的序列号,而需要对他打补丁(译者:这个程序我也没有,大家知道意思就行)
) h! [9 s: D X$ n3 w 当然你肯定是不错的Cracker 并且很快找出来了需要修补的地方:
+ k3 @9 V7 x+ N9 W. Z
* \9 O, B$ x' u7 Y+ V6 ?& \& OOffset 53Fh : 74h, 15h -> 90h, 90h
, e$ F- ]2 @) \, I+ l: r5 m% [: l7 K7 T( w, J7 ^7 i* E! z
以上就是我们所需要的所有信息。
' }3 {! ?1 {1 X! P* ~
% T5 P- h/ n9 ~! `" W2 r4、代码$ m3 u* B" d7 q+ L$ r u' q) g6 T
) H6 h2 X- x4 x% |, _, U; {4 G. f386, z8 U6 \. k7 \2 a
.model flat,stdcall+ u$ Q, Y/ e. K( k
option casemap:none - J3 u- D U% j% x1 J
include \masm32\include\windows.inc
! l5 [$ B3 Q( W, o2 Hinclude \masm32\include\user32.inc2 m2 O. }7 f, Z+ C& C
include \masm32\include\kernel32.inc
9 u! i) f% [& J. ?, `5 mincludelib \masm32\lib\user32.lib
+ z3 N/ W1 \6 X: m6 Yincludelib \masm32\lib\kernel32.lib& G( x9 x+ o7 @% {
. `1 {$ y$ j4 G, M
9 v7 U: e$ o7 R1 Y: s3 c
.data ; g7 J5 n8 u# s$ d! V8 Z% @" [
FileName db "Crackme5.exe",0
. H6 |( R% C/ d: JAppName db "Crackme 5 Patch",0 j5 } r; z( X: G
Done db "File patched succesfully !",0! c8 Y' l1 R5 h! S3 w
NoFile db "Can't find crackme5.exe !",08 R$ b0 g- H j5 j. \8 Q" f
ReFile db "Wrong version of crackme5.exe !",0+ A3 M0 C; J; h$ @: z
WrFile db "Error writing to crackme5.exe !",0, N/ f" B0 Y, v- i: l
RBuffer db 75h, 15h7 x/ w2 o1 |2 p
WBuffer db 90h,90h
1 C$ r1 F* x" h3 o7 S/ yOffsetPos OVERLAPPED <NULL,NULL,53Fh,NULL,NULL> / f% K! i2 S6 \, I/ e: P
7 l' c: Z9 r* |- Y! V
.data?8 k F5 g4 N; g0 B
5 ^5 V9 V+ c( o+ Z! o# q4 A8 K
hInstance HINSTANCE ?
, a5 k% q8 ~, @CommandLine LPSTR ?/ s' D6 o, R4 O
hwndname HWND ?
) V6 q, p& w/ g$ v. thFile HANDLE ?/ j) ?" W. U7 f4 H
Numb dd ?1 w) q, f6 Z# M$ s0 f7 B& T$ z
Buffer db 2 dup(?) 5 `. m+ P. z" ^' A) c% i* V- N
1 r( z6 T( V3 {
/ Y+ j6 b* o7 ]0 V2 P/ G% V- [.const
( r! l% H/ {+ y & S8 D, }5 j0 A( p
.code( E2 X! p Y, y4 I" M2 b
start:9 F& a6 s9 q& _$ [
( I9 o8 ^6 Z' M/ U7 ?4 {& C' i. E
invoke GetModuleHandleA, NULL! k) z# Y% ]4 x K" s+ A3 q3 f
mov hInstance,eax 3 b2 d4 Z) F7 N, R+ P
- z: T0 C- A0 \ dinvoke CreateFile,ADDR FileName, GENERIC_READ OR GENERIC_WRITE, FILE_SHARE_READ OR FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
2 r+ D; P! o# y, O& m% a2 {
: g$ d1 j+ G% F I W.IF eax!=INVALID_HANDLE_VALUE+ B; f+ X% ~! A: |
/ e2 X& @9 K7 m# E. K+ E" g1 q
mov hFile, eax ; 存储文件句柄" i8 G% L/ R0 H! o' V% L7 _
Invoke ReadFile, hFile, ADDR Buffer, 2, ADDR Numb, ADDR OffsetPos ; 读取要修改的2个字节 b* p. v/ ?4 o) d
mov ax, word ptr [Buffer] 1 t+ s6 D, H7 j1 {/ l1 p0 ^1 {
.IF ax == word ptr [RBuffer] ; 如果判断正确 (75h,15h) 就覆盖他们 :-)
' M P2 h8 C, \8 sInvoke WriteFile, hFile, ADDR WBuffer, 2, ADDR Numb, ADDR OffsetPos ;写入新的代码(90h 90h)
/ x+ j3 K2 k4 n0 o.IF Numb == 2 ; 如果返回值为 2, 弹出成功信息
+ u% }9 F+ z2 ^1 n& ~push MB_OK
{/ M2 E" b+ i5 i s& E. ^3 opush OFFSET AppName. m4 ]4 k- V+ h2 L- e3 I
push OFFSET Done ; 弹出信息地址入栈
( t' q: M9 t2 P! w( b.ELSE ;如果返回值不是2,那么弹出错误信息 k; d) c6 r3 Q: m1 |+ d
push MB_OK OR MB_ICONINFORMATION
5 V% P2 u' q8 I1 Z3 S8 ]% b! _push OFFSET AppName/ B1 e4 v) q: a- U7 Q# {: c5 r0 E) W
push OFFSET WrFile+ S& B0 w$ `" h
.ENDIF
* ?$ j3 Z6 C8 e6 j0 o( W.ELSE ; 如果读取的2个字节不正确,弹出文件选择错误信息, B+ E8 C# x. M
push MB_OK OR MB_ICONINFORMATION5 u! x9 k, B! y C
push OFFSET AppName7 d7 t$ h% {' I$ Y
push OFFSET ReFile 7 n) A7 ?9 z0 z N2 y: [8 E& o; k
.ENDIF ( P& ^$ n7 W/ B# r
: r. E3 [' | h
.ELSE ; 如果未获得文件句柄,弹出文件不存在信息0 ^4 T. E: O$ u, N( q" }
push MB_OK OR MB_ICONINFORMATION
' C3 g% H. u, |+ c7 r8 Fpush OFFSET AppName' X# P, Y" H' p, S
push OFFSET NoFile
6 z0 x; L7 M+ ~.ENDIF, Z: H. J/ d! X& ]$ I
4 U: e9 @5 p2 _9 P5 ]# E! Apush NULL% t6 H+ B/ q0 w
Call MessageBox: ]+ \5 ^, ?2 H: P1 R: w$ L
invoke CloseHandle, hFile ; 关闭文件6 l. y5 n; p! T7 S0 j' q& }: k5 h0 l
invoke ExitProcess,eax ; 退出
# |7 n/ i# p% X3 g: h) S8 C( B9 t6 t6 h$ O
end start
2 h: ~& e8 ~/ _0 I 2 J1 z# U$ n8 w+ K" [
如果你看懂了上面的代码,就可以制作自己的文件补丁。当然也可以编写的更人性化一些,比如添加上选择文件路径的对话框,但那就是另外一个题目了。
- R, V8 F+ T9 s3 ^1 {" \0 V2 r0 n) s8 P1 m" }: r, Y
var currentpos,timer;
8 |9 v# D+ }: c. G/ h3 ^
" H( |0 C5 M1 a( W* zfunction initialize()
2 p: C; q4 x/ M$ Z2 w' E: S" m9 _' z `{: h* q4 ?" m p% p2 D" w- S
timer=setInterval("scrollwindow()",10);
+ ]' K! H0 U! t. y}
* q/ U. E! O {4 p5 ~function sc(){# ]6 U r& X7 H( L, G. Z4 w% u
clearInterval(timer);& m. E k- h. o8 h8 \3 f
}& N3 k/ g- W( p& u- U: x) L
function scrollwindow()
' T! r7 ?4 U: o; {! r2 n{
7 M' b8 j: a: d- J# p4 b. f$ scurrentpos=document.body.scrollTop;
( Z7 p& e7 H( nwindow.scroll(0,++currentpos);/ r$ u: N8 V( l; i, P2 m
if (currentpos != document.body.scrollTop)
" a6 Q$ `# I9 c( i, ssc();
5 ?; l" J5 V( _0 i3 m2 A' T1 @: G}( S' [* m- U: F, D; W
document.onmousedown=sc: T+ ?1 _% B+ d( I, `# r
document.ondblclick=initialize
: P% o$ w/ B( W& F) ^5 s% a% e1 v- F$ l
6 a1 i4 O4 Y1 H3 ~
|