后期资源网|非编软件网|杉宫竹苑|非编插件|高清视频素材|音频素材|非编软件汉化

 找回密码
 立即注册
后期非编系统发布及其详细简介后期非编系统VIP专享下载区影视后期非编模版免费下载区网站注册及其办理VIP业务说明
查看: 837|回复: 0

[教程] 如何在DELPHI中使用汇编

[复制链接]
发表于 2013-1-4 11:37:28 | 显示全部楼层 |阅读模式
Delphi内联汇编好象有得天独厚的优势,尤其是API的调用,处理好各成员参数后,可以直接CALL API名称。利用内联汇编我们可以为程序添加各种异常,添加反调试代码,添加花指令,还可以令某些难写的注册机简单化等.我把Delphi内联汇编的一点点使用心得写出来,目的是想与大家交流,挖掘更多的这方面的领域。也希望大家能够指正一些错误。% t" z+ @8 X/ M" O5 h* G" K
+ }2 q2 ~9 `$ R/ o/ c
一、 数据格式
* |( x6 w1 }, l+ r! }整型数据:8位的用AL返回,16位的用AX返回,32位的用EAX返回。
' B: e9 }" W3 Y8 @' p* R$ d4 `BYTE(8位):BYTE、CHAR、SHORTINT、BOOLEAN / J* E% L: q1 f) }  d( C
WORD(16位): SMALLINT、WORD" e/ w8 Y# X. Q( A( ~# t8 o
DWORD(32位):INTEGER、LONGWORD、ANSISTRING、POINTER、CLASS、LONGINT、STRING/ T0 b7 \' h7 R5 c- P* R
ST(0):SINGLE、DOUBLE、EXTENDED、COM$ {5 a0 a% w* y$ A
如:- Z: q" f; j; B# b! x
var
+ n: i  J# }+ [1 w- k4 J- N0 pByteVar: Byte;( D3 v$ b% ~$ w0 L% W
WordVar: Word;
, _9 i- r8 G7 n9 S: VIntVar: Integer;
4 D) o9 I, |$ }" y* T. u- m& ?begin
5 X0 s2 T0 C& Y* E. j6 \; uasm6 X  u' G+ {7 g# b! j1 ?
MOV AL,ByteVar
. W2 {. Y' |0 q9 z. ?5 tMOV BX,WordVar/ F* C- w- h+ C+ {
MOV ECX,IntVar) ~9 p8 f/ ?* L
end;
, k6 u1 w% O: B( J3 d0 x  ]8 @end;4 h& @: ~: w6 M* m
实型:用ST(0)返回4 x: ?/ F, k6 l/ c" a& ~( e
  指针:用EAX返回% `; X) E! t0 ?7 `9 x- `
  长字符串:用EAX返回其所在地址' A1 C+ T3 A# Y8 K( ]9 r3 ^, H
  变量:可用@Result返回
5 S2 e! i: W) U9 c9 f- q2 [& z1 {16进制的表示方式:
, _, Z9 U$ E. b如果是0-9开头的16进制值直接在后面加H或在前面加$号,如:1AH,$1A
* O4 _  G! w& u7 ]3 M5 t0 h5 Y$ ^如果是字母开头的前面加0再在后面跟H,或者直接用$号,如:0AH,$A# T& c0 C2 [+ }" u- K
几个修饰符:, n0 x4 `; x5 L; P) w; u  d
OFFSET 返回内存地址中的立即数. s+ ~+ Y$ D9 Q; n4 S9 [" m
[....] 返回内存地址,与OFFSET相反,如:MOV EAX,OFFSET [XXXX]=MOV EAXX,[OFFSET XXXX]=MOV EAX,XXXX
7 S; f1 n- A9 c) |! SHIGH 返回高8位的立即数" b, J7 O' h( R6 y
LOW 返回低8位的立即数
! b4 `% @! y- t# a! M. {+ Y0 }& 防止变量与汇编中的寄存器同名而在前面加& 号,如:
5 S0 y8 D( O3 X  R+ h  S: sEAX:INTEGER; ...
8 Q& M+ {( E# y# O" T5 E4 WMOV &EAX,10H 这里的&EAX不是EAX寄存器
) t# m; \; e4 @5 _2 t6 `, ?. .号的一种用法:
: S3 H% `; Y1 h( V) U" \1 l4 `  ^var 9 ], p( j; s9 P" o" Z7 z
STR: Word; ..
, [2 W$ [  k: z- o2 p4 E& IMOV DL,STR.Byte或DL,Byte(STR). N& B+ S; E) c6 I9 V1 b' m1 D

9 }8 R8 |  c& i1 i  J二、 嵌入式汇编的格式0 h  d8 f( X' m* Z* M
  Delphi是使用ASM……END来标志汇编语句; c( w" g- W/ D- d  K. [/ ^
   如:' M* x0 O+ K, B' k: Q
ASM+ _) ~, E, a2 {( p0 S4 ?
   mov al,1
7 V8 c6 S! O0 D0 W   mov bl,al
* U/ l; T& R$ i   END;
  C& `1 S  B9 w) L3 F& q9 w一个简单加法函数:9 i$ e, i: }  K- v! a
FUNCTION SUM(X,Y:INTEGER):INTEGER;
  N+ S$ d! @& x9 [8 C' zBEGIN
) o- P' o7 d0 H# NASM$ _# ?+ O! @5 [0 R9 H, \5 a- x2 G
MOV EAX,X% I! [# s! [7 x9 Y- ~1 A2 ?4 u
ADD EAX,Y7 x- u/ R2 O. ^% G0 i  e$ C4 d4 `
MOV @RESULT,EAX/ D3 H1 h6 i, _5 O8 Y' n" q( X
END;; R, T1 G" \( C! O1 ^1 X) N
END;
$ O# X, ~5 K2 R) S: |* OByte转换为16进制字符串:& s- f+ {( Y/ f. w# c% c9 o: M
function ByteToHex(Src: Byte): String;
% r! D/ o; T4 pbegin$ Q3 @1 }4 [+ c/ v) Y: B
SetLength(Result, 2);! U& H; S! e( t5 W# A2 s$ T# }
asm4 A- ?2 [  Z' Z4 p4 K1 R
MOV EDI, [Result]
9 n5 }9 l) R4 WMOV EDI, [EDI]
2 l6 V/ P7 N; }+ K, u$ X. MMOV AL, Src( {9 I. f  ]6 ]  M5 N2 M
MOV AH, AL // Save to AH  z% C$ N+ n$ x7 d
SHR AL, 4 // Output High 4 Bits
6 x6 Q7 ]9 K3 S+ x/ O' w7 u7 `, ZADD AL, '0'1 I: o" @# M' c# T* F+ t
CMP AL, '9'* o! [  {+ i0 D+ T
JBE @@OutCharLo
- C6 }6 Y' }, k( Y( ]! E4 _ADD AL, 'A'-'9'-1
( E7 h( T4 u6 a@@OutCharLo:
: F' t0 B. B1 MAND AH, $f
) `% [% A' r. U, mADD AH, '0'; Q2 a& b) z, F' X* d
CMP AH, '9'; N' M3 [* R" R4 y5 K* ~. H) w
JBE @@OutChar
+ H( |" ~- V, e/ @) gADD AH, 'A'-'9'-1
- ]# K3 b4 G1 x& {4 G@@OutChar:
/ w8 ~- W1 g, {# P2 m+ {8 [STOSW) W' H5 ^4 j4 D: p$ |
end;
2 }) f" C4 X0 I' _3 f6 I: oend;
6 J* P9 v$ \/ Z8 A; f4 n9 O0 p0 L* T三、 可用的寄存器
) }) Q- j" a' w1 ^: Q+ _# R32位寄存器EAX EBX ECX EDX ESP EBP ESI EDI+ R  F# S6 C+ ~% g/ J5 K
 16位寄存器AX BX CX DX SP BP SI DI/ v5 {9 E# P4 \; z
 8位寄存器AL BL CL DL(低8位) AH BH CH DH(高8位)
1 o3 n& d- I) ^9 J4 N7 K 16位段寄存器CS DS SS ES
, K, i- N4 i4 z7 _32位段寄存器 FS GS
- E" d0 g$ j' i; \, R0 z0 O2 h/ [ 以及协处理器寄存器堆栈 ST
, W1 n. b9 Q7 h, ]. X) }* `  u5 @一个ASM statement 必须保护EDI,ESI,ESP,EBP和EBX寄存器,但是可以自由的修改EAX,ECX和EDX寄存器。
+ K5 {8 d! Y8 |8 R' ^0 A& b% I# u默认情况下,delphi使用“register”方式,若参数在3个以内, 将分别使用eax、edx和ecx,如果超过三个,则用堆栈传递。返回参数的存放视长度而定,例如8位用al返回,16位用ax,32位用eax,64位用用两个32位寄存器edx:eax,其中eax是低位。如果你想用EBX寄存器,接得这样写:& @% n2 x" k4 F8 A
asm
5 Z( \! v. ]1 Z, h# a' G1 O+ H! gpush ebx
9 r5 A9 Z% u8 \9 J9 o, ^3 O% F/ ?0 Lmov ebx,2' s! D$ E/ E) K/ o6 j
mov IntVar,ebx
! F; j; U$ P  ]' W4 @2 @# a& m: |pop ebx
, j0 }/ ~! R$ r( D& ^  T- H( wend;/ u, i' A8 x3 H7 h& ]. K
如:FUNCTION(T1,T2,T3:INTEGER):INTEGER,可以默认为T1存在EAX中,T2存在EDX中,T3存在ECX中。
8 O# j. }( b! |+ L' T- MDELPHI的标签名一般都以@开头,比如@exit、@001等
6 P. P  N& B: I7 P- e) H1 L四、 CALL的应用  w* S. b; k% `% n. p
在汇编中写代码要保存寄存器现场(保存使用前的寄存器状态,使用Push压栈和Pop从栈中弹出),不过这一切对于Delphi的嵌入式汇编是没有必要的(除非你自己要使用Push和Pop),因为Delphi已经帮你做了,不必担心会使数据丢掉。- X( U$ T4 O3 K- G+ V& l' h( c
DELPHI内联汇编中同样可以用汇编中CALL的功能。7 U9 q8 y0 q" r0 k
比如:) I0 O* N* L! Z. E9 d/ A+ @5 d
asm
' a8 F! u$ `. S# B5 e/ V! ?  mCALL @1
! N/ F; k2 X% \JMP @EXIT
4 C; {9 X* k0 _7 W4 q3 m$ n@1:0 |8 o' Y3 l5 {/ _# d/ G6 R4 Q
MOV EAX,1
9 b8 A" `- b, x1 l$ {9 ]2 HMOV SN,EAX. d7 B6 I2 S+ I% D
RETN* \/ [) ?9 V: W, w0 V
@exit:3 Y3 C: H3 i! c( P7 r0 s
end;0 J/ d+ x3 W; ^  V
call的第二种用法,在汇编代码中直接调用FUNCTION函数,如:
2 v! J7 f7 [& F$ ~5 l9 ?function cacl(eax: integer):integer;/ \; M/ p! `2 `
var' q* g: ]" L8 `) T
...
2 ?. f9 \; [7 {3 ^! f5 n8 bbegin
5 ^, ~& S5 r+ y- U( `8 p1 }  m....
! J  C/ _1 E3 ]5 o2 w/ v5 ~. `Result:=code;
* Z9 b' M& {6 l& _7 Z% K4 yend; 3 H" n# |5 L$ }7 D
调用时可以直接CALL CACL:
! Z2 c" N! l5 Y+ X9 [ASM
9 [' U  B1 _; |# ?( I. d5 s( gCALL CACL
$ {+ ]. c' J  d...$ p+ e1 G6 y) Z: J) _+ |3 i
END
0 o* ~2 B4 C6 f* E8 i; U% a) l编语句中的Call语句,可以用于调用其它过程,既可以是其它汇编程序段也可以是Delphi中的标准过程:
9 U6 A$ S" @& ?* q# A# i  例如:假设新建一个窗体并在上面加了一个按钮,在Click事件中写入以下代码
0 c- W. P: F' m2 L! s0 J* h  procedure TForm1.Button1Click(Sender: TObject);6 j$ Q) a0 }2 D* K7 T
  begin6 B& ^: N% d3 g
   showmessage(`ok');; [# f2 Z% E; R
  end;
' E( w) `- ]% Q# X: _  再写一个过程_X) D3 R7 z) A9 P2 n
  function TForm1._x(var i:smallint):integer;
- {  f4 o  v9 o7 T" Y5 T9 S  asm; L+ w" y4 U: Y# \. V# L
   call button1click
# u2 x3 v0 Q& p% X" V6 l; f9 F  end;
$ }- [. ]' o: Y$ V6 {  执行_x的结果就可以显示消息框。7 g) {$ F- |# {5 Z9 f! [
五、调用API函数1 p8 N$ A) f% Y  ]
DELPHI内联汇编中调用API函数函数非常简单,比如调用PostQuitMessage:
$ o: v6 }" T2 E0 |! aAsm+ N7 W# T5 u3 N/ y# ?7 {
Push 07 \/ m3 k5 g4 M3 t: G7 k7 f6 G
Call PostQuitMessage(或Call SYSTEM.PostQuitMessage)
; \+ Y: p6 U4 MEnd9 W9 o, U' v8 R  M2 @* V
调用MessageBox函数:$ U( I. ~8 S: ^4 _: m/ v3 G; b
procedure TForm1.Button2Click(Sender: TObject);
+ C6 i% P$ c* c3 N6 E7 B  var% g; d+ y! _* V% n6 d, h0 ]$ ]4 s
   szTitle:string;
1 l% Y5 ?5 F: K( }8 B   szCaption:string;
9 A( ?0 T+ n1 l* A5 W  begin4 w3 R/ @: G6 ]( _5 _/ }8 T' r
   szTitle:='您好!';
3 K+ e! I  y4 h   szCaption:='这是一个在内嵌汇编中调用stdcall类型函数的例子.';
7 R9 d& o& a8 ]* e" R# a! y1 L- W   asm
+ z- o, n# ?! h* n7 L6 D! a( y; w    PUSH MB_OK+MB_ICONINFORMATION
# [/ K9 [2 G9 h) K7 l% A    PUSH szTitle# @& P) y5 P* n) w
    PUSH szCaption% u6 H. [( A% N/ k6 r
    PUSH 0
/ P7 P% d) k5 A: a& D, L    CALL MessageBox
6 ?. {1 P3 ^2 Z! D5 h   end;2 n2 X- ~- `! |( p
  end;# ]/ c, R8 r1 i* N
调用GetFileSize函数' ^! m( I# C8 ^5 I, |3 u. Z
function stdcalldemo: Integer;/ S" x1 r; N/ A) D  _+ Y2 b
var2 Z9 {/ k; V$ s9 E  V# X0 l) L' @  [
FH: THandle;
6 Y( b* S& O. I) e% Gbegin+ w- w# e* [/ u( t
FH:= FileOpen(’c: oot.ini’,fmOpenRead);1 x+ F! Q4 V1 _2 n5 N) X. j! ^# r- m
asm
4 f- F5 X2 {0 }1 R, R8 ~* `) ipush 0
& O& H2 A: T: Z0 ?6 `, o5 P7 xpush FH* y: R1 y; B; Z7 G1 @# T3 [
call GetFileSize
0 `# j3 I, Q; Dmov @Result,eax
! K1 X0 Y; k  e4 c9 H8 g! y! `4 Vend;
' ?" _6 N0 D7 `$ [/ Z/ T4 E! j( ]Result:= GetFileSize(FH,0);//此句就相当于上面的汇编调用方式- h0 ?* Z! b4 z* h
FileClose(FH);
# U: P& g( _7 g2 a2 E- k' @0 e/ aend;: g1 Y. U4 K+ ]
procedure TForm1.Button1Click(Sender: TObject);
4 h+ Q4 N# V; y4 \9 ybegin
7 z# B$ [; T, M# P  w' Vshowmessage(IntToStr(stdcalldemo));3 R# M1 g( ]- n9 M
end;& _' x1 y5 J/ K( J7 y
六、汇编的调试。  ?6 p, M+ }3 g6 h: j* m
如果发现汇编通不过,就要注意停下后的位置的代码:如变量的跟踪、断点、堆栈查看……可以在关键代码处下断,停下后打开View菜单的Debug Windows的CPU VIEW窗口,F8单步跟踪。如:
4 @/ B4 c$ D! ]. CUnit1.pas.62:     PUSH MB_OK+MB_ICONINFORMATION% k2 \! i; _6 ^
00455E8F 6A40 push $40+ @7 A7 W! y- X4 o3 N/ A6 b/ l
Unit1.pas.63:     PUSH szTitle
& o0 j' |( m& a00455E91 FF75FC push dword ptr [ebp-$04]
+ C+ T6 e5 B2 M" R$ ZUnit1.pas.64:     PUSH szCaption
$ x8 x+ s/ w& M  Y00455E94 FF75F8 push dword ptr [ebp-$08]
& s# n% E/ ]8 W  g, N% ?4 I9 LUnit1.pas.65:     PUSH 0
2 K3 j, k( \8 Z( I( b  M% u5 d00455E97 6A00 push $00
2 y  ~1 n$ h! r+ a+ k6 ]% LUnit1.pas.66:     CALL MessageBox
+ R/ ^, s/ p; n5 C8 a) M. P) _  k00455E99 E8FA0DFBFF call MessageBox
" m  u& X; E  ~6 M0 D; k8 y' o# }; ?' SUnit1.pas.69:   end;/ Q! i2 {, q& F/ k
00455E9E 33C0 xor eax,eax
9 y2 q: J# C( C* ]) l* y七、常见易错语句。
- S( E  |  _& cMOV ESI,DOWRD PTR SS:[TEXT] 对(TEXT为STRING)
% o' q* _0 H4 r# W/ F$ N! R+ zMOV ESI,DOWRD PTR [TEXT] 对(段寄存器CS,DS,SS,ES可省略)4 `& b* V& z4 I/ J( H4 q
MOV AL,DOWRD PTR SS:[TEXT] 错(DWORD为32位)
. B& B+ k! I8 I6 FMOV AL,BYTE PTR [TEXT] 对" c" [  O+ v# [
MOV EAX,BYTE PTR [TEXT] 错(DWORD为8位)1 x  x) A1 M  R& }7 Z
MOV AL,WORD PTR [TEXT] 错(DWORD为16位)
! p/ `$ y  \) j% Z$ Q6 r$ pMOV EAX,WORD PTR [TEXT] 错5 s( R% i" X' c5 n! t  Z" L8 z
MOV AX,WORD PTR [TEXT] 对
8 h: e8 ^( @6 L$ A8 T5 ]MOV [A],EAX$ c6 j4 d6 D3 Q
MOV BYTE PTR[EDI],'A': O2 r% O" p  ?$ g9 b
MOV AL,[EDI]
7 [+ B& a, P3 z1 P( c. NMOV EAX,X //X指向的值赋值给EAX# w1 ]- a& m3 K
MOV EAX,[EAX] //X指向的地址赋值给EAX
+ Y+ I8 U" |& I. d( u0 x8 KMOV DOWRD PTR[ESP],EAX 对
/ x# N5 X& U' i. oMOV DOWRD PTR[ECX],EAX 对
" D2 l6 x' c7 s/ {8 o# B" r, AMOV DOWRD PTR[ECX+4],EAX 对
7 M8 B% F/ x0 J, W' q0 IMOV DOWRD PTR[ECX+EDI],EAX 对
) C8 q, E$ v& A1 e2 U% JMOV DOWRD PTR[ESI],EAX 错
0 ?* P. E. Y* K0 wMOV DOWRD PTR[EDX],EAX 错0 \  N" t: `6 C. ~7 {* e6 f+ d
MOV DOWRD PTR[EBX],EAX 错3 T1 j: q& l! S4 z9 y
; R! ?1 m; c5 O5 y$ B
后期资源网,打造没有广告、免除隐藏回复的全开放式影视技术交流平台。 你的所求就是我们服务的宗旨!!!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|后期资源网

GMT+8, 2024-5-19 07:04 , Processed in 0.106192 second(s), 20 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表