|
编者:昨天一个叫aqtata的朋友发给我了个最新的密界文集, 本来想打包下载,可那样很多朋友# _4 Q. r8 V6 q; c* C
会看不到里面的好文章.于是我决定把其中较浅显通俗的一些文章发到文章区,希望能对您有所帮助
$ B5 ~; I$ R2 X/ U, x/ @- e作者 : Detten Detten@tiscali.be 7 n0 E% c/ b; H9 f- \; L# E. m @
来源 : _blank>http://biw.rult.at/
9 {- x: p `) h: L c7 @& O4 `5 `, x9 N, C. X
翻译 : nbw _blank>http://www.vxer.com/
% {0 z3 O, n& I7 z& G* i4 U0 P% U, R# y; }
1、前言
: S& t+ r' L ]5 Q O7 h 一但破解了一个程序,你就想把成果共享给别人。为了不用把整个破解后的程序上传,你可以制作一个小补丁来修改程序中必要的字节。- g. @+ Q. v( S" G- N5 |
那如何来写呢?7 \( s$ ]" x8 e% c8 C6 p0 z: o
===〉首先找到需要打补丁的文件。大多数补丁认为该文件处在自己当前目录下。1 a; h' ^, |9 K7 s
* M: H7 Y( _! E- a4 G9 ~4 o
===〉如果找到,打开该文件。
" }/ \ S# P9 Q* [7 y: b% h
; O4 @6 y9 z1 F1 \===〉然后检查打开的文件是不是和所破解的文件。比如我们可以检查文件大小,或者随机检查一些字节,或者最好检查将要被修改的字节。5 O; ?3 l2 _: Q5 N2 W% K4 K+ v
- f8 M+ S4 n9 |; {5 z( j( k6 c- A
===〉如果以上都无误,我们可以做需要调整
% a; o' K: W! W4 s- X 把文件指针移动到指定位置,然后写入新的操作码。: H/ ]6 H& U* _! r
) { R" Q$ [% i ]1 z
===〉关闭文件,给出提示结果。
8 r$ l$ T4 y: a8 w+ F: }3 Z/ }4 ~% L; e" q
下面找一个你破解的文件,然后开始....
1 T0 w6 ^4 o9 ~+ {( h. @& f8 V) \, Q. x
2、必要的API
6 i& E- b& S8 a+ H2 Z! \; E 做这个程序需要用到什么API呢?
: I; h5 U7 p+ L* w; O- n- Y: E
7 {. y* z4 s3 b3 @% |, K: kHANDLE CreateFile(
/ _+ ?& p$ t6 ]" V5 o" o; }1 S) U: Z
LPCTSTR lpFileName, // pointer to name of the file
0 l5 R, g% `# s7 ]" L1 F% rDWORD dwDesiredAccess, // access (read-write) mode 2 W! K, c2 D9 _9 h
DWORD dwShareMode, // share mode & E( \" o7 t; s1 l
LPSECURITY_ATTRIBUTES lpSecurityAttributes, // pointer to security attributes ) ]! |6 A, C/ X7 r6 _; Z. f
DWORD dwCreationDistribution, // how to create
6 q; O* K6 _# q" Y! ~# fDWORD dwFlagsAndAttributes, // file attributes : k7 q7 M$ t3 @4 O' I
HANDLE hTemplateFile // handle to file with attributes to copy
1 T8 i% {1 Z. H' Z6 q) Q);
5 U; P6 W9 |; {5 I) B2 c; P
- d7 k' S& j# F' i. D 这个API函数用来打开或者创建文件。 y( o/ f: C5 M9 N- V7 S
dwDesiredAccess 应该设置为: 'GENERIC_WRITE OR GENERIC_READ' ,因为需要读写文件;9 K* ~) K) y$ ^. ?4 N) w( \; N- e
dwShareMode = 'FILE_SHARE_WRITE OR FILE_SHARE_READ'
4 ^2 | m* F* K+ D; FdwCreationDistribution = 'OPEN_EXISTING' 我们只需要打开文件,如果文件不存在函数将返回失败,然后我们给出提示信息。
1 L' [& o1 L3 W" @( Q 可以察看WIN32.HLP获取详细信息,如果你没有这个API库,可以找相关资料。5 _4 q- {( W9 y0 X2 W3 C9 J( [
如你所见,这个API函数返回我们需要文件句柄。我们可以利用这个句柄做下一步:写文件。
o6 X6 @0 k. t" U/ @1 H3 E5 I9 Q( J+ s+ s) E- V" H' P
BOOL WriteFile( * ^, j6 u [" h1 f( F |/ H7 t5 ~
HANDLE hFile, // handle to file to write to 7 O K/ |! v2 R1 t
LPCVOID lpBuffer, // pointer to data to write to file
3 ^" ?6 Y! x$ I, Z& R# YDWORD nNumberOfBytesToWrite, // number of bytes to write + \6 |* W: H" w8 H2 E: Y& ]5 l
LPDWORD lpNumberOfBytesWritten, // pointer to number of bytes written " `3 J' q# V# e" K) `
LPOVERLAPPED lpOverlapped // pointer to structure needed for overlapped I/O
# s# J$ p0 l. J( C# L+ s);
* i) d' Q% H5 U+ q- G+ d ]# x% T/ ? }
我们用这个函数把2个字节写入需要打补丁的文件(当然是在正确的位置)[译者:作者的例子是写2个字节,我们做的时候根据需要]
: D& m7 z' A+ T. { 涉及到的hFile句柄就是CreateFile函数的返回值。
$ z: _( i/ T9 T- T/ L3 z4 V
( \) r3 M- I, b7 R Z' KlpOverlapped应该指向一个 OVERLAPPED 结构,我们需要用它设定正确的文件指针。
8 [/ v9 G. }# b# K
* H4 @* z; ?4 G' xtypedef struct _OVERLAPPED { // o
' T, Y. ]" s; @DWORD Internal;
+ }* [8 _0 j4 Q S* C# ~2 y3 qDWORD InternalHigh;
. e$ n3 l2 x5 D3 P' DDWORD Offset; ; b" S2 j; m6 t' L. V- s
DWORD OffsetHigh; 9 `) f5 j6 f1 E3 o' `
HANDLE hEvent; 7 v2 W* A. z( s- H1 v
} OVERLAPPED;
2 J- o# M) A+ R2 @/ iOffset的内容是需要写入的地址。(译者:注意不是内存中的虚拟地址)
5 J0 E0 x5 s1 B/ s" T
9 U. I/ f- X ^1 h/ k3、目标) Q/ D, X6 E4 z
目标程序是Crackme5.exe,假定我们现在获取不到正确的序列号,而需要对他打补丁(译者:这个程序我也没有,大家知道意思就行) % b- h9 s( \2 r$ O h
当然你肯定是不错的Cracker 并且很快找出来了需要修补的地方:# S) _" C% K3 Y* w
: i6 k+ S$ W, z5 k
Offset 53Fh : 74h, 15h -> 90h, 90h ]" J# _: P! n( G
2 |6 q |0 h7 D7 R, S 以上就是我们所需要的所有信息。' i- x( g$ M$ ^6 a* n9 m+ ]$ [3 S
4 \! |% B! t6 K/ M( `' E+ x
4、代码: G5 A2 J: K" ?: o0 x
3 P/ V' {- N9 E( \8 p
3869 k) a h( E- g. V
.model flat,stdcall9 f6 Q9 E# K3 Z% s5 i) c
option casemap:none 0 b" V9 B, { v' W7 U. z3 I
include \masm32\include\windows.inc
+ T+ D& d8 h: f5 Z S; ainclude \masm32\include\user32.inc; N8 m& A2 D# ?& U [ D
include \masm32\include\kernel32.inc' s% ]" J( U3 d. L& d
includelib \masm32\lib\user32.lib
7 k/ S a2 Z2 @includelib \masm32\lib\kernel32.lib2 X( U. Y3 _9 v [, T* Y% ]7 l
2 Y8 d% R( }; _$ c, h% Y1 e- K
+ i( `4 j! W8 {0 V& x$ G3 x0 u* ~.data
: y0 ?% o, _# t4 ?5 QFileName db "Crackme5.exe",07 F8 f* z K2 X
AppName db "Crackme 5 Patch",0. t Y. U$ q% [. p. {
Done db "File patched succesfully !",0
6 v3 ^& A. w. w2 a, q+ t5 n% U3 e& N. \NoFile db "Can't find crackme5.exe !",0- `; Q, @7 [' L7 {/ X
ReFile db "Wrong version of crackme5.exe !",0. p) ?# D( x a
WrFile db "Error writing to crackme5.exe !",0' k4 P2 I2 T- `; ^3 r& H
RBuffer db 75h, 15h
1 H6 `: {. C/ f) MWBuffer db 90h,90h; E1 {5 E( p8 j0 t/ t2 j
OffsetPos OVERLAPPED <NULL,NULL,53Fh,NULL,NULL> ) ~. k- E: h4 U" m
( _6 J% m' l7 E3 a+ O0 C! e! g
.data?' N) i! W, w5 g) }6 ?% K
8 k4 M: o# |8 c9 l6 t2 NhInstance HINSTANCE ?# r9 Y5 ~" v. |, d( } G( [
CommandLine LPSTR ?, x8 Q) e3 `5 k
hwndname HWND ?
0 A1 D$ _% r& m" }+ G9 bhFile HANDLE ?, G6 @6 U% _4 E% ^# y0 w
Numb dd ?/ F4 \1 ~/ i: T/ Q: \0 S1 T
Buffer db 2 dup(?) * {# D( `! l* ^
" Y8 T; M% l' s$ z( b/ w
3 X- B6 Z' y/ b9 ].const
; k4 ]( e B7 g
6 M9 U7 H% O0 n9 j" k.code
5 f+ M3 I5 \9 J$ t4 d+ x" Astart:4 \2 Z4 p+ _, s- i+ h
$ T, [8 `) g" y" u5 U# m* `invoke GetModuleHandleA, NULL
8 N3 p/ h! E4 e' u5 T' Qmov hInstance,eax
9 n) f& I( X2 {% X% E% n8 m( H8 U5 U' b; Z4 k e3 ]& G
invoke CreateFile,ADDR FileName, GENERIC_READ OR GENERIC_WRITE, FILE_SHARE_READ OR FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
3 }' ?9 c% G; ^' s# D% P- y
. E" s( c1 a+ U, _# D. l+ H.IF eax!=INVALID_HANDLE_VALUE
2 V E" d. [# F7 I! g( d
% w* s- D# y" T" L/ kmov hFile, eax ; 存储文件句柄
$ v. N! ~8 E2 X1 ^Invoke ReadFile, hFile, ADDR Buffer, 2, ADDR Numb, ADDR OffsetPos ; 读取要修改的2个字节* N6 O! }4 `4 X
mov ax, word ptr [Buffer] & Y* F( l) N9 Q v+ U
.IF ax == word ptr [RBuffer] ; 如果判断正确 (75h,15h) 就覆盖他们 :-) |0 E! A: ?: |0 O# X/ M, L$ J3 W
Invoke WriteFile, hFile, ADDR WBuffer, 2, ADDR Numb, ADDR OffsetPos ;写入新的代码(90h 90h)6 y% |2 p% `1 s' x( u9 z, n
.IF Numb == 2 ; 如果返回值为 2, 弹出成功信息
- O; t3 D+ ^, e F4 `4 ?push MB_OK . o" u! q2 e" s) {
push OFFSET AppName! M$ a. A: I9 T2 F* A; Z5 d k3 N
push OFFSET Done ; 弹出信息地址入栈
0 e1 m: B* N. q0 E.ELSE ;如果返回值不是2,那么弹出错误信息
6 r, t/ x$ c( D- A% }" Ppush MB_OK OR MB_ICONINFORMATION% U0 K8 X7 ^! M4 h8 ~! |* Y
push OFFSET AppName
- Y) u% X( s9 l6 Y1 Opush OFFSET WrFile, C) ~2 O" v# Q7 A1 }6 G
.ENDIF 1 `! x2 [5 U3 ]8 Y9 b6 p; B. d
.ELSE ; 如果读取的2个字节不正确,弹出文件选择错误信息
) M, c. }( P" G8 d9 [ n, Wpush MB_OK OR MB_ICONINFORMATION
6 M" X9 B8 L6 u' O0 t0 vpush OFFSET AppName
$ S) e, @ E0 `+ K8 t; W; qpush OFFSET ReFile , k: [7 x6 l& {$ N7 A
.ENDIF ! B; a; }. |/ k6 |* _8 Z
8 a% n) P$ E5 b# J9 k% A: N$ t
.ELSE ; 如果未获得文件句柄,弹出文件不存在信息' K$ l! o3 r% a4 k+ q: K0 W% M
push MB_OK OR MB_ICONINFORMATION* a% h. p2 `3 U5 {& o; v1 _
push OFFSET AppName
5 {( r3 r, Q" U; l. Y0 e# b7 Wpush OFFSET NoFile
' q t, \! e( z8 U. h.ENDIF
1 M) \- v9 |; r) i3 n
+ Q( D. ? b" W6 `) o5 P' bpush NULL: o6 o' _' ^( }" `2 r; f2 }
Call MessageBox' p5 ~, y- K" {3 ?: P9 Q4 A
invoke CloseHandle, hFile ; 关闭文件* \& A0 E! M1 D% `* D+ @! {. }
invoke ExitProcess,eax ; 退出$ Q) J2 s# t! o
1 }5 {! x9 p3 H9 Lend start
% P$ G F4 b- y$ X 8 ]1 W- g# E3 f9 }# S, `+ Q
如果你看懂了上面的代码,就可以制作自己的文件补丁。当然也可以编写的更人性化一些,比如添加上选择文件路径的对话框,但那就是另外一个题目了。 % F7 s" J9 u+ y# w' Q
/ @0 t! Y' D& Hvar currentpos,timer;3 c) b) f# q6 D* o; ?. Q
7 Y( m( J4 G1 |; r/ W2 @/ Cfunction initialize()
4 {1 r& p3 g$ ~" Z4 {" g{
8 N3 [, i& h. Y: Jtimer=setInterval("scrollwindow()",10);' w5 H2 {/ }0 P9 T5 B' m
}
1 ^; u) e: y3 n! j/ i0 ?5 Rfunction sc(){, c Z9 z1 N2 \2 G/ Z- s* U
clearInterval(timer);% k& p4 k' N: c" y( e
}
% w- b4 x- G" M5 O2 Jfunction scrollwindow()7 m1 \5 K% ] u! t( N
{
* q+ Z$ l3 G! A4 o6 Kcurrentpos=document.body.scrollTop;
" [0 b/ _* f: K, ?" o! |4 { Zwindow.scroll(0,++currentpos);6 F4 d/ o& _8 q: B+ ~1 \5 _0 n& [
if (currentpos != document.body.scrollTop)
3 }2 _& _0 _' usc();( C9 q- ?: t# I2 w5 ?' |- r; K+ }
}
. ~) R" ^3 S5 N- \0 w* tdocument.onmousedown=sc
1 j7 ~$ x; r+ M2 L [document.ondblclick=initialize1 P4 Y2 k; s; i6 @
8 y/ X5 W$ k- `+ v
. {1 H2 q/ |- e* j! T |