|
编者:昨天一个叫aqtata的朋友发给我了个最新的密界文集, 本来想打包下载,可那样很多朋友" K1 l& H1 B8 j9 j- P
会看不到里面的好文章.于是我决定把其中较浅显通俗的一些文章发到文章区,希望能对您有所帮助
8 ~- x, T! G' `作者 : Detten Detten@tiscali.be
6 s* q4 Q! l+ ^& o: m ^来源 : _blank>http://biw.rult.at/8 E4 q8 E4 V* w5 f9 ]
$ x+ H& a. N0 C% H
翻译 : nbw _blank>http://www.vxer.com/* H; K4 L J8 A. O0 {
, l3 r( m6 l, O! ~. f4 H" A
1、前言
1 D$ C3 J7 O* g9 u5 Z 一但破解了一个程序,你就想把成果共享给别人。为了不用把整个破解后的程序上传,你可以制作一个小补丁来修改程序中必要的字节。- v( Y( {: l3 i3 x& z. A7 i% ?; y* [
那如何来写呢?
6 v6 D0 W1 q8 t- I3 c* @% n/ v===〉首先找到需要打补丁的文件。大多数补丁认为该文件处在自己当前目录下。$ F: `0 j* W2 H( y
9 c7 B. N# B( X' M! U1 X! {9 W===〉如果找到,打开该文件。6 k U* Q* I* E8 a0 y. ?
" t, x2 A f- N; U$ P1 J===〉然后检查打开的文件是不是和所破解的文件。比如我们可以检查文件大小,或者随机检查一些字节,或者最好检查将要被修改的字节。
1 J- @; L% E2 Z* z- p: o( c& i/ V) q4 n$ F& E8 W
===〉如果以上都无误,我们可以做需要调整 2 S3 ]: j G# p! K* ?% O5 Z4 j
把文件指针移动到指定位置,然后写入新的操作码。
5 G% S" v; Y/ c/ F6 I! L6 ~5 m7 f; ]& _! s$ A
===〉关闭文件,给出提示结果。6 O' F( _( ]/ W
8 K8 X3 F9 L$ m z/ \# t/ l/ U下面找一个你破解的文件,然后开始....* N/ G7 l7 o/ S- k+ K, ^! {
/ T2 b0 ^4 Q4 @; }5 u" B* v2、必要的API8 u; X( s ~2 }2 ?+ `/ F# p
做这个程序需要用到什么API呢?: s5 |, u5 ~5 L- `5 \ I
: k$ X4 m! e/ ~0 \, C1 A5 O: wHANDLE CreateFile( 2 L. n$ c) S( z* B& a
# W5 ?; @1 V! }* H6 @LPCTSTR lpFileName, // pointer to name of the file 5 L; o) F B% D0 M
DWORD dwDesiredAccess, // access (read-write) mode
" b8 c6 L" D; \5 LDWORD dwShareMode, // share mode 5 Z7 |2 Z$ v: {& z! H' }; d
LPSECURITY_ATTRIBUTES lpSecurityAttributes, // pointer to security attributes ( N* Z/ d8 F6 O" z7 C- I% B
DWORD dwCreationDistribution, // how to create . z/ P i* [/ R2 P3 J
DWORD dwFlagsAndAttributes, // file attributes
7 O+ x, K4 f0 K1 KHANDLE hTemplateFile // handle to file with attributes to copy
- t2 q: t3 E' D8 ^ j, Z, U. e0 E);
+ q) X4 W6 K; f, e; \& R0 Q. p6 f; H
这个API函数用来打开或者创建文件。7 ?/ m5 |% w$ }4 I7 [4 W
dwDesiredAccess 应该设置为: 'GENERIC_WRITE OR GENERIC_READ' ,因为需要读写文件;
7 Y R* F& p/ _( Z& LdwShareMode = 'FILE_SHARE_WRITE OR FILE_SHARE_READ'7 z$ m- r2 U& M8 f; h' \, g
dwCreationDistribution = 'OPEN_EXISTING' 我们只需要打开文件,如果文件不存在函数将返回失败,然后我们给出提示信息。& F- Y- B0 m4 D0 |
可以察看WIN32.HLP获取详细信息,如果你没有这个API库,可以找相关资料。
, D. j. I3 D3 J& h1 L 如你所见,这个API函数返回我们需要文件句柄。我们可以利用这个句柄做下一步:写文件。
, U( G! Z, _$ v: x( \/ |; w7 U( ~( j, @1 q) Z; [
BOOL WriteFile( . c; A" S1 H, L' P8 Q, W5 ~$ C& ^
HANDLE hFile, // handle to file to write to H1 F1 s e0 @4 P
LPCVOID lpBuffer, // pointer to data to write to file * R' C' f/ L" j' i' y
DWORD nNumberOfBytesToWrite, // number of bytes to write ! j+ L! Z7 }3 x9 J( D8 T
LPDWORD lpNumberOfBytesWritten, // pointer to number of bytes written
, R; O$ ^1 F, Q" GLPOVERLAPPED lpOverlapped // pointer to structure needed for overlapped I/O( S0 Q2 [8 o1 N2 D) n: S
);
9 x* _! C% n! c4 H) {9 }
! n, F; ?6 G) |. A% A( N6 u8 t 我们用这个函数把2个字节写入需要打补丁的文件(当然是在正确的位置)[译者:作者的例子是写2个字节,我们做的时候根据需要]
0 X& F6 q2 J% `. ?9 c6 X 涉及到的hFile句柄就是CreateFile函数的返回值。: a4 ^8 T6 i0 n6 }' k4 u7 X4 P2 \9 W
/ c z$ f6 e2 \5 H5 YlpOverlapped应该指向一个 OVERLAPPED 结构,我们需要用它设定正确的文件指针。& \4 [3 d: ?! c, c+ I% n' f
/ }' u3 S0 l3 {% mtypedef struct _OVERLAPPED { // o
/ [3 o) W! o" C/ a7 x9 |DWORD Internal; & c# m* r/ ?$ o( ~
DWORD InternalHigh; 9 f: c5 P+ _: B0 k
DWORD Offset; & ~) s" P6 @& D) S
DWORD OffsetHigh; & c9 h& w" A( Q6 T, I0 Y' w
HANDLE hEvent;
6 a7 w3 x( n& b$ g: a} OVERLAPPED;
0 H# P( X+ G) D0 oOffset的内容是需要写入的地址。(译者:注意不是内存中的虚拟地址)9 r) u+ @7 V/ |1 i7 c/ e
6 l4 Z5 Z# ?8 I' u, F1 L) i( k% a3、目标
, E; C7 T' [6 H$ O- U( ~$ w J 目标程序是Crackme5.exe,假定我们现在获取不到正确的序列号,而需要对他打补丁(译者:这个程序我也没有,大家知道意思就行)
. {$ a* M5 u) B$ y7 ~. D" ` 当然你肯定是不错的Cracker 并且很快找出来了需要修补的地方:
' Q6 i( h) s, ^- C! |% D% H, c, a1 F* |
Offset 53Fh : 74h, 15h -> 90h, 90h0 Q I' ?1 N) g( a
; a+ u' J+ M; i6 d' m 以上就是我们所需要的所有信息。
; X7 X. r! S# j& {1 f* [' g. I" i& h3 u% p' Z5 b* ~
4、代码& s) Z" G7 ^3 t* X, g+ C
; `( I" N) A8 r2 _* H+ [
386
( X$ k# {7 a% G4 S.model flat,stdcall
! a! V! O: I* W* [- M' woption casemap:none ' M& o+ ~4 e2 F! P8 b. a5 ~
include \masm32\include\windows.inc$ N+ a; t9 }7 x/ @/ T
include \masm32\include\user32.inc% C$ R- M0 H2 f& t
include \masm32\include\kernel32.inc: R6 L U# h7 @5 q1 x& L' N
includelib \masm32\lib\user32.lib, D, R0 W! _$ q
includelib \masm32\lib\kernel32.lib
+ v- R) W3 B. Z2 {9 T a3 P( G
5 Q! Q1 T( g3 S
7 ]3 d( i! f; `5 k# R" a. R.data , I2 p Z7 P8 O- Z
FileName db "Crackme5.exe",0
( u3 x% r8 A6 X: x: e. e0 xAppName db "Crackme 5 Patch",0
+ I" Y; [1 N" {# Q3 \' o) aDone db "File patched succesfully !",0; o& @& l6 Z% S: r W2 [/ r; R
NoFile db "Can't find crackme5.exe !",07 p+ H5 n# u5 P- r9 c6 Y
ReFile db "Wrong version of crackme5.exe !",0
3 k4 ]8 P: Z8 `* F- k5 t- iWrFile db "Error writing to crackme5.exe !",0: ?; ~; \" O* O5 I$ \7 Z
RBuffer db 75h, 15h# N/ f& ^ z4 A: j. T/ H+ j
WBuffer db 90h,90h$ Y. m* Z! j1 i1 e1 Y. h
OffsetPos OVERLAPPED <NULL,NULL,53Fh,NULL,NULL> 0 N0 U4 k8 N7 }1 W5 b
2 v6 g: B; G W4 J" W
.data?% @9 \, T3 q0 I6 ^: d( C
% j% ^" `, ^3 G2 x, @" i
hInstance HINSTANCE ?
$ o' V6 t5 [1 p' o+ D" ]CommandLine LPSTR ?
7 g8 B# a2 r% Z1 D# E. k. S8 o1 x! bhwndname HWND ?4 I! ]. o. H* v: i: T8 ^1 M ^" j/ l
hFile HANDLE ?/ y9 m, y! h3 k- g$ D4 s/ l- T
Numb dd ?
9 j- x% a" ] q0 Z8 M! O8 NBuffer db 2 dup(?)
0 P: [, h1 H9 \( I
4 a; f+ R6 u t, F
, Y j4 h( u+ v& y% G% T1 v1 g1 B.const# t H/ ]& f& Y3 b. s% Y
7 b" \1 K: J; B" z' V2 R
.code+ _1 i# H9 t3 d. Q) r
start:2 X8 h: p2 k0 C; v5 v" `
# v8 g% G$ I2 V
invoke GetModuleHandleA, NULL0 y q& K, N" a6 T" Z1 z
mov hInstance,eax ' {; k* i, j5 C( n2 e; Z
, l( |# w! N8 i7 s" Linvoke CreateFile,ADDR FileName, GENERIC_READ OR GENERIC_WRITE, FILE_SHARE_READ OR FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
! D E0 t r! g+ j$ [9 z: \) `$ C) c+ O8 O* m" q$ H
.IF eax!=INVALID_HANDLE_VALUE/ T" |3 e' |2 X0 @0 ~4 u$ a) k
# B/ `0 {* t. [/ k3 W( g2 ^mov hFile, eax ; 存储文件句柄+ `# J6 K. `) Y0 b# c" d$ m
Invoke ReadFile, hFile, ADDR Buffer, 2, ADDR Numb, ADDR OffsetPos ; 读取要修改的2个字节5 W( a# F* g. r9 l }# a+ t, o9 x
mov ax, word ptr [Buffer] 1 J% @; k6 C; a. C- J i
.IF ax == word ptr [RBuffer] ; 如果判断正确 (75h,15h) 就覆盖他们 :-)9 L: a5 R, Z2 ?3 I8 u
Invoke WriteFile, hFile, ADDR WBuffer, 2, ADDR Numb, ADDR OffsetPos ;写入新的代码(90h 90h)' p7 Q6 z$ Y7 x# u
.IF Numb == 2 ; 如果返回值为 2, 弹出成功信息3 u! q- Z, C+ Z
push MB_OK
% m4 D. ~- A: q; V8 ^. r `7 U+ }2 \push OFFSET AppName; p9 Q: I7 ?% Z1 N( o: I0 }, z5 n
push OFFSET Done ; 弹出信息地址入栈
' M* n2 t. A J+ {, D. t.ELSE ;如果返回值不是2,那么弹出错误信息
' F, ~) l3 d8 E7 S5 q% [push MB_OK OR MB_ICONINFORMATION
. Z x7 c" l) `push OFFSET AppName
* `' V( w7 d/ q& U+ v/ k" e- z. Ppush OFFSET WrFile. L) p ^7 ], J S! N; t
.ENDIF ' p9 Q8 u! o0 u4 _8 {* Z
.ELSE ; 如果读取的2个字节不正确,弹出文件选择错误信息
4 d' ?& x/ V9 h! Epush MB_OK OR MB_ICONINFORMATION
: ~3 E5 \# [5 }8 }( p$ {+ Wpush OFFSET AppName @) P4 t g8 K# w
push OFFSET ReFile / ^+ r* j! m& I! Z
.ENDIF 1 Z( B4 A* Y* L! j
. K, A$ v: O: `# o
.ELSE ; 如果未获得文件句柄,弹出文件不存在信息0 @, I8 j0 o% C3 i& k, }
push MB_OK OR MB_ICONINFORMATION
P ~5 U1 z4 ~+ ^# y) gpush OFFSET AppName
* O. U$ V7 m6 W9 {6 Dpush OFFSET NoFile
: ~$ U7 M" K4 A s# [.ENDIF
/ j0 S3 v& p$ d1 ^. k7 ~
. O) h, f" n: }9 y npush NULL) x# D- Z2 a/ Z) P+ H1 a
Call MessageBox
4 k& r U0 e+ {' ~+ minvoke CloseHandle, hFile ; 关闭文件
3 b0 Y* m: _: Y* `, H# Ainvoke ExitProcess,eax ; 退出
8 y' Y0 S. a; ^7 s2 ]
6 m$ c: G" S f' r) wend start% G$ H/ q# d8 i5 Y
1 k6 p) D6 ?, y! O
如果你看懂了上面的代码,就可以制作自己的文件补丁。当然也可以编写的更人性化一些,比如添加上选择文件路径的对话框,但那就是另外一个题目了。 1 E+ F- [0 d) ~1 |
3 d* s5 F1 X. H* M, U( E( qvar currentpos,timer;. i" h, N3 x, g" j2 F
5 i, Y9 m9 w% a0 qfunction initialize()* \) Q2 W4 I* g' Q' X
{
5 }. B! `+ ?: Y0 ftimer=setInterval("scrollwindow()",10);9 h5 t ?( d' l- R) ~. _
}
1 _1 ~; v0 g+ C; e: w4 D: ofunction sc(){
; c" S+ b: Y: \ gclearInterval(timer);
- d7 e9 v5 Q2 V* w9 U0 o$ @}" [ _& `9 @0 w6 ?4 r7 o" i% v$ @
function scrollwindow()( m y$ ^: B4 A& P' D- \
{
/ w7 t) k D/ gcurrentpos=document.body.scrollTop;/ Y" J4 n& H5 I4 j
window.scroll(0,++currentpos);
2 I8 I- t9 I8 i8 jif (currentpos != document.body.scrollTop)- [8 g3 X# E0 t. y. E6 a6 A4 z
sc();
6 E3 M L' H; ]+ n}. `( g' w8 P4 A
document.onmousedown=sc4 k0 h+ V; \) A: ?9 o
document.ondblclick=initialize0 x ]/ X% \0 e8 F
7 a A9 B: Z; N4 E
% r* q6 j" Z8 A! z% W0 a! ? |