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

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

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

[复制链接]
发表于 2013-1-4 11:37:28 | 显示全部楼层 |阅读模式
Delphi内联汇编好象有得天独厚的优势,尤其是API的调用,处理好各成员参数后,可以直接CALL API名称。利用内联汇编我们可以为程序添加各种异常,添加反调试代码,添加花指令,还可以令某些难写的注册机简单化等.我把Delphi内联汇编的一点点使用心得写出来,目的是想与大家交流,挖掘更多的这方面的领域。也希望大家能够指正一些错误。7 f3 x4 ^# a" n6 |
' v8 O1 s5 B( ]" l
一、 数据格式
  B  Q# m/ p4 y/ f* {& R# R* Q5 |整型数据:8位的用AL返回,16位的用AX返回,32位的用EAX返回。" z& V4 k/ y6 p4 J% t; Z
BYTE(8位):BYTE、CHAR、SHORTINT、BOOLEAN
' ^& ]( h9 G' B( V7 p* {$ eWORD(16位): SMALLINT、WORD$ T- H8 D9 W, M8 _7 f( P
DWORD(32位):INTEGER、LONGWORD、ANSISTRING、POINTER、CLASS、LONGINT、STRING4 s- w! |: V+ \7 k9 W. v
ST(0):SINGLE、DOUBLE、EXTENDED、COM4 N; E6 a3 `. `3 Y
如:0 o1 j$ q; v( a: y5 {
var
" t3 H5 D4 H! |1 S' A9 P) a! P( oByteVar: Byte;+ V. i. W% i! {3 E
WordVar: Word;
4 c7 W& s1 T/ U0 z1 ]IntVar: Integer;1 h$ U9 i4 u; v! f" E; F
begin
; ^6 }  ]( g- C* d) G9 F9 Masm" N! n( L$ p/ u) l4 x, c) W3 r/ w
MOV AL,ByteVar
4 y) X- ]! {8 L- rMOV BX,WordVar; ^' X( c* G  G
MOV ECX,IntVar
! g: J8 K5 F1 c: f9 O, lend;/ V/ X4 ?3 p7 f4 c6 X! ]
end;
! B2 r3 w( S2 R实型:用ST(0)返回( Z+ A4 R) ]8 F7 ]# m" n
  指针:用EAX返回
+ P5 S% X  x& c7 _8 [  长字符串:用EAX返回其所在地址* f# E1 {. n# v/ P& s# B- o
  变量:可用@Result返回; h5 D$ G( n/ F
16进制的表示方式:
; V) H2 j0 o2 W5 q  Q/ F% l如果是0-9开头的16进制值直接在后面加H或在前面加$号,如:1AH,$1A
  @4 x* q5 W9 ], I! X  y4 c0 T  X如果是字母开头的前面加0再在后面跟H,或者直接用$号,如:0AH,$A
( |$ Q' \" A/ Q4 o几个修饰符:  d+ Q$ ~2 \- p* B6 n: S- F
OFFSET 返回内存地址中的立即数
2 Y+ x% S. {7 I: G[....] 返回内存地址,与OFFSET相反,如:MOV EAX,OFFSET [XXXX]=MOV EAXX,[OFFSET XXXX]=MOV EAX,XXXX5 ^3 W6 H5 h% [' z
HIGH 返回高8位的立即数
' C$ P' e9 T. ~3 V, tLOW 返回低8位的立即数5 Y% b; u! D7 w
& 防止变量与汇编中的寄存器同名而在前面加& 号,如:
( [* x) ^* n" g! AEAX:INTEGER; ...
2 Q3 i0 I: ]  h# l) YMOV &EAX,10H 这里的&EAX不是EAX寄存器; q( G2 d$ X; x; M
. .号的一种用法:- s3 f' `! I4 y
var
& U2 [+ V& ]/ ^: `( c4 OSTR: Word; ..; u8 U8 P$ y/ D$ F. n) N* R6 E% C
MOV DL,STR.Byte或DL,Byte(STR)
) L3 }# n9 g1 X" h1 {: y. h2 `5 v7 w) `5 d2 o. ]
二、 嵌入式汇编的格式
/ I4 l2 I1 c, x- W% t  Delphi是使用ASM……END来标志汇编语句
/ ~5 \/ d$ D! t   如:
7 _, r& n( m) Q" L6 U5 n3 FASM
" X& [! C" w7 p$ P. \, ^   mov al,1# V+ e4 p% V' y& `
   mov bl,al
! x- o: R& i+ d, x( i& ^   END;
: n; r) R- f* p+ v1 ]! y6 X0 t一个简单加法函数:
8 Z4 h% l/ E4 z& z/ bFUNCTION SUM(X,Y:INTEGER):INTEGER;# N' D5 {; {& C1 q8 O
BEGIN
  L, `3 V9 y; A& q$ t; j: l9 i3 J8 _( TASM: t# F, z$ ^7 y) b0 p5 Q: P8 L
MOV EAX,X/ a5 y& A4 C* u7 [
ADD EAX,Y
! I9 p' j" q- W4 \MOV @RESULT,EAX
- w! i. p' ]- ^, uEND;
8 W- y: g2 X  t# LEND;
% m6 M: k9 X$ f& VByte转换为16进制字符串:
8 V1 j2 {8 |; M8 y8 X9 l4 P9 |function ByteToHex(Src: Byte): String;
% {$ @$ c- t# |; obegin
8 C) A, s# @8 q- uSetLength(Result, 2);$ g) e* S& P. D- N$ l! C1 n) s
asm
" }2 J4 W6 D* x$ K9 vMOV EDI, [Result]
4 D, d, B( G& U1 vMOV EDI, [EDI]2 A3 t) g$ o' ?) t/ D3 z/ H
MOV AL, Src
& H* ~2 R' M; N; c9 vMOV AH, AL // Save to AH% u! [0 p% D8 Z1 W2 p' u
SHR AL, 4 // Output High 4 Bits
/ l9 u  J- ^" v, I! M( H7 F" }& x  tADD AL, '0'
4 C) @9 L, j: H- r7 s% u# i6 [+ ACMP AL, '9'1 \% ]( p7 U9 Q+ k
JBE @@OutCharLo: Y0 t% w% n/ m' w# T
ADD AL, 'A'-'9'-1
1 _$ x- B3 Q% M5 ~: Q6 M@@OutCharLo:
% u, Z( \# H% }0 ]; \9 r9 _AND AH, $f
' {/ [4 k' }( cADD AH, '0'" P% `' Z5 h: }9 l6 ?# ?0 G
CMP AH, '9'# T- N) |" V3 P  \; b
JBE @@OutChar
0 v5 s/ C3 ?  t6 ~ADD AH, 'A'-'9'-1
/ A- l% ~) w' }( W+ V@@OutChar:
5 X" J( I2 K: U1 _STOSW
1 S) h2 d* d5 G$ E6 A# I$ n' D4 Kend;
' G# b0 N4 g# s  Z! ?2 I+ Xend;: Z. D5 j6 {7 D' U5 l6 H
三、 可用的寄存器
# x! T6 x# Z0 k32位寄存器EAX EBX ECX EDX ESP EBP ESI EDI
6 d/ f5 u7 C$ I5 T- V 16位寄存器AX BX CX DX SP BP SI DI4 k8 n; b, F4 K0 v9 U
 8位寄存器AL BL CL DL(低8位) AH BH CH DH(高8位)
/ D% _  L1 o! R8 z+ l0 K4 q 16位段寄存器CS DS SS ES; Q: ^! w- {: P& k9 V% _
32位段寄存器 FS GS
; E. i$ ]3 R; t# M" q; Q 以及协处理器寄存器堆栈 ST9 B) n7 y' B% k5 R% F" T$ l
一个ASM statement 必须保护EDI,ESI,ESP,EBP和EBX寄存器,但是可以自由的修改EAX,ECX和EDX寄存器。7 u% n; ]  S6 w9 b
默认情况下,delphi使用“register”方式,若参数在3个以内, 将分别使用eax、edx和ecx,如果超过三个,则用堆栈传递。返回参数的存放视长度而定,例如8位用al返回,16位用ax,32位用eax,64位用用两个32位寄存器edx:eax,其中eax是低位。如果你想用EBX寄存器,接得这样写:4 A4 ^% ~& r& p9 {  S" I( |
asm
7 G& h- h. C4 S! S( t  g. apush ebx3 m" ?/ s- P% t
mov ebx,2
$ a1 _+ u( n% b  F! ~$ [mov IntVar,ebx
9 K. i4 `& H# {5 h8 m* J% Z8 Mpop ebx1 H8 L* k% P4 s3 ^
end;% X. H: O6 p* T
如:FUNCTION(T1,T2,T3:INTEGER):INTEGER,可以默认为T1存在EAX中,T2存在EDX中,T3存在ECX中。9 R( ?% N/ F& d; T/ p+ B  G
DELPHI的标签名一般都以@开头,比如@exit、@001等8 ~; P- t0 c- c( r$ o
四、 CALL的应用
" V1 |) ~: O/ H; j: k- s% m& W8 n+ D在汇编中写代码要保存寄存器现场(保存使用前的寄存器状态,使用Push压栈和Pop从栈中弹出),不过这一切对于Delphi的嵌入式汇编是没有必要的(除非你自己要使用Push和Pop),因为Delphi已经帮你做了,不必担心会使数据丢掉。
7 t# p0 `6 m( CDELPHI内联汇编中同样可以用汇编中CALL的功能。( P2 _% f& r* U
比如:
+ b2 a$ {# f; J- c0 l2 Lasm
: y' x# x- U  P* P1 n1 bCALL @1
  e2 p- L# p$ Z* A. _/ S) n8 q6 xJMP @EXIT9 i3 o( ~& `- ]" f8 P6 f
@1:1 f- U1 z/ r8 l) B, I' K: p
MOV EAX,1
, |( \! A5 q! L/ }4 p' q2 {MOV SN,EAX
2 c+ [* j' H5 s9 u/ n, FRETN
0 C$ y8 w; j/ n1 S4 y6 j- @@exit:& L; L  _0 |$ _( L7 s2 i) y$ e
end;
1 Z2 t! I$ N( w5 tcall的第二种用法,在汇编代码中直接调用FUNCTION函数,如:/ h- }- c, A: p% L( ~
function cacl(eax: integer):integer;6 m' G# P. F- o6 V; Q3 W
var
" h. y: G2 I- l+ a...' u# L/ d2 M' X- s8 R* W# _/ U; H1 A4 D
begin" {! `, a1 H( ?5 m
....- `' `% m( E7 Q, W+ u  M7 J4 Q
Result:=code;
, M/ j9 \; Z' h0 B+ _9 m1 P2 Yend; # ~5 b- N$ g; j0 G1 v# ~
调用时可以直接CALL CACL:& ^' T' v" W+ U% n0 C+ U
ASM
2 O- @4 x% l0 R, ~9 WCALL CACL- p1 t+ A4 c: r  a( E& q
...9 K$ T: y/ k& g9 t) O3 v1 @, W
END8 @) D9 g# Z' ~6 ^6 R6 S7 I! Q
编语句中的Call语句,可以用于调用其它过程,既可以是其它汇编程序段也可以是Delphi中的标准过程:
: X/ L( @( ?/ F8 H& H3 `) H. o  例如:假设新建一个窗体并在上面加了一个按钮,在Click事件中写入以下代码
; c* m: q4 T+ k! ?) m( T! f  t4 @  procedure TForm1.Button1Click(Sender: TObject);( U% J- e! X7 r+ G/ T+ i# t( m
  begin. _2 {5 r7 H- o* R0 g8 r
   showmessage(`ok');
# Z+ b: D. }# J, }( b. B/ d9 o  end;
% J8 a5 v( T1 U7 H  再写一个过程_X8 k( a! t+ h4 D* {& \
  function TForm1._x(var i:smallint):integer;; V2 o# n: c  e# H
  asm0 K7 x" k7 M# a3 r9 c- n* D6 ]9 d
   call button1click
( D% l' v6 N* M  end;! E/ L% A6 v$ i2 a; Q6 H# u
  执行_x的结果就可以显示消息框。( F& ~& y* t9 @% q, e4 [4 k
五、调用API函数
. M9 `8 i* J& E: f4 NDELPHI内联汇编中调用API函数函数非常简单,比如调用PostQuitMessage:3 ^! |; E+ V4 Z; j+ V$ J
Asm
5 z8 l6 u% e. O& D6 w4 K0 aPush 01 V0 W( r( u+ N6 m
Call PostQuitMessage(或Call SYSTEM.PostQuitMessage)" h4 [7 d6 [; Z$ i  Q# b
End
3 A& t1 v* z. v0 i调用MessageBox函数:. G7 X$ g$ H2 b6 M, z/ h
procedure TForm1.Button2Click(Sender: TObject);
1 P) k; s8 ~4 A2 A1 o' `  var* [9 g5 y6 Y) U3 L
   szTitle:string;9 c0 q3 m! N6 ?, \4 E& t: F' n
   szCaption:string;0 j4 }: C. c/ Q, A% n' O
  begin
. k8 F8 c5 ]7 q   szTitle:='您好!';
& g8 f4 ?+ v. n8 Y  n$ Q/ J/ T   szCaption:='这是一个在内嵌汇编中调用stdcall类型函数的例子.';
$ T1 w4 [6 f3 d" P   asm$ G  Z& s5 w6 m3 W$ z
    PUSH MB_OK+MB_ICONINFORMATION6 V, q! ?! t7 r1 `6 G# V
    PUSH szTitle& x, x6 t: Z' G" _. S/ s
    PUSH szCaption
' H3 E2 @; i! D7 W& ^9 h    PUSH 0
4 H4 Z, |* g2 g5 l) @    CALL MessageBox
2 q" v: z7 y1 u5 u- |$ m# A   end;
* P5 P# o( c, c) Z0 P6 K5 H* b  end;
, b- ?# w" O8 {3 S调用GetFileSize函数* K7 x, D# }# @9 B
function stdcalldemo: Integer;) M0 a$ F3 s" G9 H: j( r
var
* c9 c) T. S  [  S% {FH: THandle;
# E3 C9 U6 h9 P, l7 p4 bbegin
. c2 `: t9 _5 p: Y) i  wFH:= FileOpen(’c: oot.ini’,fmOpenRead);
  Z' P1 o+ Q; B/ W, \" `2 ^asm4 M8 z4 B) V, B7 Y% e" X
push 0/ o1 S1 H! T) Q( B. L$ Z* B" @
push FH; ^0 R, S4 X( G
call GetFileSize$ ?) J3 M- e6 x* q, P6 {" F/ |
mov @Result,eax
  u2 p+ m3 y! b( uend; - |0 z; ]" R3 P, f  C
Result:= GetFileSize(FH,0);//此句就相当于上面的汇编调用方式, t+ m# j& V+ E( `
FileClose(FH);
3 r8 C2 t( R) ~# O& fend;
& q- g, t- U$ o# x  |procedure TForm1.Button1Click(Sender: TObject);
: B3 s# X; X* M6 ^2 Y5 @begin' J/ W' ]" x  v5 B( ]
showmessage(IntToStr(stdcalldemo));
' b) Z: z; [- E# H& Zend;0 t6 r1 s2 d$ F% ?# _1 E7 E
六、汇编的调试。7 v" x1 o; d! L
如果发现汇编通不过,就要注意停下后的位置的代码:如变量的跟踪、断点、堆栈查看……可以在关键代码处下断,停下后打开View菜单的Debug Windows的CPU VIEW窗口,F8单步跟踪。如:' N4 i2 o+ C9 X& {
Unit1.pas.62:     PUSH MB_OK+MB_ICONINFORMATION, W" m2 e% [  \
00455E8F 6A40 push $40/ m9 r* }8 _* K3 G, a# {
Unit1.pas.63:     PUSH szTitle
- C: L9 Y# f# D+ e00455E91 FF75FC push dword ptr [ebp-$04]* t( J6 K  g/ b4 T
Unit1.pas.64:     PUSH szCaption  j& V7 g' f2 K, S
00455E94 FF75F8 push dword ptr [ebp-$08]
4 u: t, L& l( Z; JUnit1.pas.65:     PUSH 0, x: `# y# _: g9 z3 g. C
00455E97 6A00 push $002 u  a+ |- A3 y+ a# x" D' ]
Unit1.pas.66:     CALL MessageBox/ V: W7 Z; H: `. C. R4 T  i8 L( c
00455E99 E8FA0DFBFF call MessageBox
' `; X! h+ [& W2 ^6 B% ?4 G) VUnit1.pas.69:   end;; l. f; ~- l( M
00455E9E 33C0 xor eax,eax
8 ~6 F- S( k& F' Z1 h2 V) Y七、常见易错语句。& y5 b  }8 |# R5 m3 f7 ~
MOV ESI,DOWRD PTR SS:[TEXT] 对(TEXT为STRING)9 k& I, \6 M7 ]+ P# N
MOV ESI,DOWRD PTR [TEXT] 对(段寄存器CS,DS,SS,ES可省略)
; j+ o$ N- N. M% F& j: l2 aMOV AL,DOWRD PTR SS:[TEXT] 错(DWORD为32位)
! |# H, C) V. ^; G  }5 _- l: `8 o7 MMOV AL,BYTE PTR [TEXT] 对. `% I1 R: K# m& m' e2 R
MOV EAX,BYTE PTR [TEXT] 错(DWORD为8位)
" y- E# I5 m" m1 U+ c; ~$ ZMOV AL,WORD PTR [TEXT] 错(DWORD为16位)
2 e* R; y# @; ]) _( \/ K; K6 f; N8 xMOV EAX,WORD PTR [TEXT] 错
% U& L! c+ T  h( ]6 w3 i2 ~MOV AX,WORD PTR [TEXT] 对
8 u2 e; R: h; p; d7 hMOV [A],EAX; `* M8 B( B1 }3 l
MOV BYTE PTR[EDI],'A'
$ R/ U6 b* a/ m. a% LMOV AL,[EDI]
8 i8 X4 a. I% h( E/ c# o5 xMOV EAX,X //X指向的值赋值给EAX# T1 h, D' _7 ]4 b
MOV EAX,[EAX] //X指向的地址赋值给EAX: Q/ {% ]& i# T% m' Y8 A) w
MOV DOWRD PTR[ESP],EAX 对$ J% L- I$ Y+ J+ p3 M3 Y7 x
MOV DOWRD PTR[ECX],EAX 对
% {8 h" v/ s. ]" OMOV DOWRD PTR[ECX+4],EAX 对) e, @$ m4 w/ I/ ^, R
MOV DOWRD PTR[ECX+EDI],EAX 对0 r8 y9 q! f' Q$ `
MOV DOWRD PTR[ESI],EAX 错
# G- M6 T1 z# I; {) FMOV DOWRD PTR[EDX],EAX 错
3 [, ~$ o4 }/ }7 D" x7 XMOV DOWRD PTR[EBX],EAX 错- F* e3 d9 }0 v# m& K# {. W7 M
2 g  z: l  k$ u8 B
后期资源网,打造没有广告、免除隐藏回复的全开放式影视技术交流平台。 你的所求就是我们服务的宗旨!!!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

GMT+8, 2024-5-3 01:14 , Processed in 0.120172 second(s), 20 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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