|
编者:昨天一个叫aqtata的朋友发给我了个最新的密界文集, 本来想打包下载,可那样很多朋友
# L' T& J N: ?会看不到里面的好文章.于是我决定把其中较浅显通俗的一些文章发到文章区,希望能对您有所帮助 ) r: A! |5 H$ [0 p* ^9 I
作者 : Detten Detten@tiscali.be
& D3 M6 Y" j) b/ L1 F来源 : _blank>http://biw.rult.at/& w/ I2 z6 u! g0 `
* V3 [. l5 B2 O翻译 : nbw _blank>http://www.vxer.com/* F- S) F' }: ]! t, z+ L7 T
% \6 j' Y, v8 ^. c
1、前言
6 x9 e% ^: A. v6 I 一但破解了一个程序,你就想把成果共享给别人。为了不用把整个破解后的程序上传,你可以制作一个小补丁来修改程序中必要的字节。
1 o/ b! P- }' a 那如何来写呢?
U0 u) D8 T& E5 m% q0 S" U; Z===〉首先找到需要打补丁的文件。大多数补丁认为该文件处在自己当前目录下。
- y% o0 R" t% q; F/ o( A7 Z" z) M* g
===〉如果找到,打开该文件。1 q/ _& T* a( R# i. f7 t$ ^3 t
- v+ H2 l7 _# j' W
===〉然后检查打开的文件是不是和所破解的文件。比如我们可以检查文件大小,或者随机检查一些字节,或者最好检查将要被修改的字节。5 h/ e% J- W; ^( [
6 B5 @0 \+ d8 g# n, x! M) z===〉如果以上都无误,我们可以做需要调整
4 I7 d# a# ?2 P# R3 A$ m 把文件指针移动到指定位置,然后写入新的操作码。
# q8 t2 W) K/ I G. P. T5 O
: ^5 b9 V* |( q% a9 { q===〉关闭文件,给出提示结果。0 X8 |! v* j: G! m j W$ }
: D0 Z, C( d. @1 x! \/ F1 F. @* J- z+ C下面找一个你破解的文件,然后开始....1 y2 g/ O! G( k0 y" s% B4 Q
) Z$ B' \( f8 H! ?# D" x J$ T/ B
2、必要的API
N: p/ q8 w% J$ G3 v0 k3 f 做这个程序需要用到什么API呢?
) R! K% t3 y! t( v' l
- q3 ~+ \6 P& Z0 M- z0 S0 f( o! ]HANDLE CreateFile( 1 }. Q7 ~$ _, J; {+ k/ E
; I7 x, w$ [7 v% t
LPCTSTR lpFileName, // pointer to name of the file 3 r. ?1 X* \9 o7 i1 s: @) t/ Z
DWORD dwDesiredAccess, // access (read-write) mode 1 M) M# P& N$ j
DWORD dwShareMode, // share mode
: z5 [" O6 P. \LPSECURITY_ATTRIBUTES lpSecurityAttributes, // pointer to security attributes 6 c2 y m7 v: D" _
DWORD dwCreationDistribution, // how to create
0 z5 |3 K9 T2 E4 X* ~DWORD dwFlagsAndAttributes, // file attributes
~# v& t2 N# b- T9 I0 cHANDLE hTemplateFile // handle to file with attributes to copy
5 g6 f3 N) i9 n6 ` u);* e# B' S0 I/ e8 `/ W
+ p+ l t- q0 _" J
这个API函数用来打开或者创建文件。) a. Y/ `0 C- T( r) \' |! ]
dwDesiredAccess 应该设置为: 'GENERIC_WRITE OR GENERIC_READ' ,因为需要读写文件;
% u, F$ {6 ] K5 ?dwShareMode = 'FILE_SHARE_WRITE OR FILE_SHARE_READ'7 o- U y- r% A* ^& h2 S0 {$ K( q7 F
dwCreationDistribution = 'OPEN_EXISTING' 我们只需要打开文件,如果文件不存在函数将返回失败,然后我们给出提示信息。& V3 g$ l* R" h7 p6 v
可以察看WIN32.HLP获取详细信息,如果你没有这个API库,可以找相关资料。1 a/ N) ~2 H% _4 z9 ]. e% d
如你所见,这个API函数返回我们需要文件句柄。我们可以利用这个句柄做下一步:写文件。
: W" U' m- \" b8 N" o
o( d0 U" t' T' _7 DBOOL WriteFile( + T ]- l' P1 j. t4 ^
HANDLE hFile, // handle to file to write to ) Z' @5 Z1 x! R, B7 l( x( j
LPCVOID lpBuffer, // pointer to data to write to file
8 W$ E; e3 ?4 `' VDWORD nNumberOfBytesToWrite, // number of bytes to write
" I7 X& w* F( z/ R: ^4 CLPDWORD lpNumberOfBytesWritten, // pointer to number of bytes written
9 w1 v3 i( D9 N- bLPOVERLAPPED lpOverlapped // pointer to structure needed for overlapped I/O$ t8 v2 m2 Z( H/ s! s8 C
);
3 {# H* a1 s: {! r" r3 K9 S2 X" f, A: {& ]
我们用这个函数把2个字节写入需要打补丁的文件(当然是在正确的位置)[译者:作者的例子是写2个字节,我们做的时候根据需要]; q H- R6 _5 O: ]4 B
涉及到的hFile句柄就是CreateFile函数的返回值。( O# m, L2 _7 |! }9 X" J
! ]3 J- O" B- V+ plpOverlapped应该指向一个 OVERLAPPED 结构,我们需要用它设定正确的文件指针。
) P' I6 G. s( Y' u7 m0 @& M1 x6 C6 e& m8 ^. `+ [4 q/ D0 Q
typedef struct _OVERLAPPED { // o
; {) Y& ~! R- L- E' l2 |( PDWORD Internal;
- F! u" Q3 E: p% N: u0 v$ w" O- vDWORD InternalHigh;
8 x7 C# U. n& F0 g$ pDWORD Offset; 4 g9 H- R, N; z; T
DWORD OffsetHigh; 3 Y/ i3 P! a# g1 R/ P1 x
HANDLE hEvent;
( R$ i4 r% X5 }( }( F2 f} OVERLAPPED;
$ g0 S0 b F j+ _Offset的内容是需要写入的地址。(译者:注意不是内存中的虚拟地址)+ u: }! Y [5 S- m8 P5 C' Z
( l& @" Q! e5 x: T5 P
3、目标
3 i" b& y% O B7 T9 t6 D5 n: a 目标程序是Crackme5.exe,假定我们现在获取不到正确的序列号,而需要对他打补丁(译者:这个程序我也没有,大家知道意思就行)
7 T Z. L$ Z* f 当然你肯定是不错的Cracker 并且很快找出来了需要修补的地方:0 C: L8 b7 R# O( {( }; C
! X$ m5 `# J0 ^
Offset 53Fh : 74h, 15h -> 90h, 90h5 \; U3 W; J$ l9 v& t9 L, L5 |( |7 K
- |" s a. u( S
以上就是我们所需要的所有信息。! |) K8 c& F" e3 g8 e g
. L5 F" \$ u- u, i- B
4、代码) N |/ O: J2 D8 L* Z/ ]& {: B
/ O/ _+ [0 M/ u+ t& T, u386
! C0 J9 V: j* r2 y3 ^0 Y- D.model flat,stdcall3 v( y! a& ?" d0 }$ b6 P
option casemap:none
! n- y7 U: m& p' |) M/ x( L3 ainclude \masm32\include\windows.inc" i; o) X. v3 X2 r; V; a
include \masm32\include\user32.inc( n; b H4 @- j8 Y
include \masm32\include\kernel32.inc) y/ K5 `' Z/ M# J$ ?1 }0 W
includelib \masm32\lib\user32.lib, A- H" T3 E: }7 [- ]* N8 h9 v
includelib \masm32\lib\kernel32.lib, i! Q' I! E* ?! W: c& v. l
( z1 ]8 p$ i( e) Q+ g0 Z! } |7 f( }! A4 t6 i
.data
1 }& L3 g4 u' ZFileName db "Crackme5.exe",0
2 e8 E5 i% @' t8 rAppName db "Crackme 5 Patch",0 ?9 z- L- ]! ]8 [0 @: M$ J
Done db "File patched succesfully !",0) R# w4 s1 b+ h
NoFile db "Can't find crackme5.exe !",0
# ?' a% O3 }1 C. s, u3 L5 DReFile db "Wrong version of crackme5.exe !",0% A2 K2 j( R2 W' c2 @" U
WrFile db "Error writing to crackme5.exe !",0+ b7 E. h' Z* r! F
RBuffer db 75h, 15h+ [% n* \! ?1 J" W* b
WBuffer db 90h,90h
( v5 N6 G( s6 w# I( j* xOffsetPos OVERLAPPED <NULL,NULL,53Fh,NULL,NULL> # [$ o2 z$ c4 f5 y
) V/ S0 Y$ s% W7 {" M- Q
.data?
: |2 m3 s& o9 P& v3 d; Y
- f* {: \2 z2 {) T7 a3 j) k FhInstance HINSTANCE ?
4 D$ s. I$ W* D2 T; p/ _. KCommandLine LPSTR ?
+ D# C( N9 W2 D0 F& D$ khwndname HWND ?
, r" v k/ E1 K. _* ThFile HANDLE ?
: ?5 G @$ [9 x; F! d+ qNumb dd ?7 r- j1 t3 u6 I6 Y& @1 S
Buffer db 2 dup(?) 2 W' J0 M& z1 R5 L4 F: g3 P
2 ^" l! M9 u7 V
3 `* j7 Q& P/ O.const T) n: |! H$ E7 a% r2 D+ M
) z% a/ C' T- q+ \
.code
! s. G" s$ w L* o/ E' ystart:- o$ Q8 K- s$ @. n2 F) B/ y; B
( q7 g* Q- E- j2 Ginvoke GetModuleHandleA, NULL
: O1 e+ j: {+ k/ Q% X2 qmov hInstance,eax
8 l5 F; x+ m, |$ h- o. X: A) B
0 i6 c: |! d& [+ ainvoke CreateFile,ADDR FileName, GENERIC_READ OR GENERIC_WRITE, FILE_SHARE_READ OR FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL " B. m* f1 D6 h, X7 } i3 A
: |+ @, J* S' e6 E.IF eax!=INVALID_HANDLE_VALUE
; M( E; J8 [7 f! I- ? l2 H& X9 {- s4 a8 P: |+ M9 z2 a0 f; c
mov hFile, eax ; 存储文件句柄
. P, Q6 a( q8 M5 `! iInvoke ReadFile, hFile, ADDR Buffer, 2, ADDR Numb, ADDR OffsetPos ; 读取要修改的2个字节/ V" {' E U* I8 ~& l4 V o
mov ax, word ptr [Buffer] * |( Q+ v' w7 I8 j, Z
.IF ax == word ptr [RBuffer] ; 如果判断正确 (75h,15h) 就覆盖他们 :-)
# v% ~0 H2 R7 M7 f: FInvoke WriteFile, hFile, ADDR WBuffer, 2, ADDR Numb, ADDR OffsetPos ;写入新的代码(90h 90h), _7 g# J# i2 u3 z1 Z) m& \
.IF Numb == 2 ; 如果返回值为 2, 弹出成功信息
& N: O" Y; j; ]# ]push MB_OK
% R! e& g4 o3 n4 @3 zpush OFFSET AppName
( W, c" e" \& t, W" O# Ppush OFFSET Done ; 弹出信息地址入栈
6 y. A+ m2 t2 _ H% F/ Y5 r.ELSE ;如果返回值不是2,那么弹出错误信息
; d# R. s- z1 W- D2 p' _0 Tpush MB_OK OR MB_ICONINFORMATION
( B4 i/ Q) |4 s4 W0 apush OFFSET AppName
7 _0 P! H( l1 q2 Ypush OFFSET WrFile
3 q5 m; N( [ I+ e" n1 C8 F1 h.ENDIF - U2 N2 {# ?: N+ s) Q% E
.ELSE ; 如果读取的2个字节不正确,弹出文件选择错误信息1 Z0 {# _6 Q6 M
push MB_OK OR MB_ICONINFORMATION
3 p) U) R( D7 c$ m0 n( j0 p% g6 epush OFFSET AppName
# P7 t; ?0 v1 j8 L, v! }# kpush OFFSET ReFile ! P& O7 Z- a& I( ~8 M2 d6 z
.ENDIF / B% N* o# n6 N5 y( ^6 s( Q
% C% H- k( i4 G1 b. @/ N" o @.ELSE ; 如果未获得文件句柄,弹出文件不存在信息; e& g! Q: {% G+ `" K
push MB_OK OR MB_ICONINFORMATION/ V3 Q6 ?/ H. d+ b* y0 U
push OFFSET AppName6 ^- T& s( E# e1 y8 Z# }
push OFFSET NoFile z( I. w9 J, i5 t- n9 q( t+ y
.ENDIF
" p9 T& W, x2 s0 Z# W. ?# [/ Y2 j' {" _: H
push NULL2 O3 c" Z e6 I9 D6 p( P
Call MessageBox% D6 j; O9 K6 U& Y6 C: @
invoke CloseHandle, hFile ; 关闭文件2 g4 a4 `2 q1 L9 z5 o
invoke ExitProcess,eax ; 退出' |) A2 w/ T* [7 S( ~
# L& }0 N7 X2 I, R! Fend start1 ?% ^0 V8 u" ^0 W1 d
4 u; {2 V0 a- o$ N$ i! ?& a* S* _ 如果你看懂了上面的代码,就可以制作自己的文件补丁。当然也可以编写的更人性化一些,比如添加上选择文件路径的对话框,但那就是另外一个题目了。
' `& w: n. A, S7 F5 A5 F
* P) _1 V( g1 W% Ovar currentpos,timer;+ h$ |4 g+ j3 i* Z
$ Z1 G) D: c4 J" {0 ^function initialize()1 N2 G2 u; c& h( j$ a
{
# c6 z. p1 z% i" M+ u( \) ~timer=setInterval("scrollwindow()",10);
4 d5 r* `7 j1 Y3 r& K9 O}
' |; d+ q' i X2 w# i# Q7 Wfunction sc(){
" ?7 |2 N) n/ z' x rclearInterval(timer);- P& ?" s! Y2 ~
}
* g$ A9 n5 @' A2 W ?function scrollwindow()# r3 M' ]' b2 z' {
{% B- I. h9 a0 t4 w0 n
currentpos=document.body.scrollTop;
) [1 d, S) }4 w3 Zwindow.scroll(0,++currentpos);
! B- e" B9 }1 g5 yif (currentpos != document.body.scrollTop)
9 c4 s- _; x) j9 U$ L$ ysc();
) l$ M. H% J4 }; c, L}2 C6 q1 X+ T0 Q" O" ~" K
document.onmousedown=sc9 D7 x" V z) f$ I/ T% |' Q! i, ]
document.ondblclick=initialize
: |4 K. X7 w* c" v1 u9 @0 z
4 I0 i6 F. h$ j9 L
$ N' B P4 C. k |