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

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

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

[复制链接]
发表于 2013-1-4 11:37:28 | 显示全部楼层 |阅读模式
Delphi内联汇编好象有得天独厚的优势,尤其是API的调用,处理好各成员参数后,可以直接CALL API名称。利用内联汇编我们可以为程序添加各种异常,添加反调试代码,添加花指令,还可以令某些难写的注册机简单化等.我把Delphi内联汇编的一点点使用心得写出来,目的是想与大家交流,挖掘更多的这方面的领域。也希望大家能够指正一些错误。
$ n0 r+ D: J. ]! o) i6 I& j5 A5 p7 C1 N0 \% ]
一、 数据格式. k* g( v6 h& U5 w8 D+ ]% [) k
整型数据:8位的用AL返回,16位的用AX返回,32位的用EAX返回。7 E% u/ [, F" f0 n1 p& I, b
BYTE(8位):BYTE、CHAR、SHORTINT、BOOLEAN . e+ Q- |, G, ^' B; M+ p, d
WORD(16位): SMALLINT、WORD8 R  S) U3 h. C, T  v% {
DWORD(32位):INTEGER、LONGWORD、ANSISTRING、POINTER、CLASS、LONGINT、STRING
/ g5 `5 B# }. ^  NST(0):SINGLE、DOUBLE、EXTENDED、COM
3 w: [( h: |, X0 T' A如:
% A7 P! S: a8 p$ f2 |) q7 Avar
; k5 o) C. @/ z% t# y2 p7 \ByteVar: Byte;, R3 y, O$ K8 O$ `0 C
WordVar: Word;
" U, W, c+ F4 l7 U6 dIntVar: Integer;
+ O* `- R7 X2 Lbegin/ E5 o, u; q0 g: X! p
asm
- A7 \, R. V; I0 T/ M  L7 p& GMOV AL,ByteVar
5 L. M" ?* K! S; {MOV BX,WordVar
% N! F* [5 {. W0 T# ^8 @0 g# FMOV ECX,IntVar: T8 ?6 V6 b, \! [; P
end;
1 \! W& W/ K* ]8 A% e# D" A6 ~end;; C. [! c$ b' O# R' y
实型:用ST(0)返回
7 K6 ^6 Q1 ~" @( {+ R  指针:用EAX返回- [8 v% S4 @, M2 ]5 d) [( n* `
  长字符串:用EAX返回其所在地址" |1 n# U! g/ H/ v' A! z
  变量:可用@Result返回
& h( p) P: V1 r9 L5 R; a- ?16进制的表示方式:  Y7 [! Z" D# b% g$ O' R4 q
如果是0-9开头的16进制值直接在后面加H或在前面加$号,如:1AH,$1A9 W% l" t' |: O1 n! Z& @% k
如果是字母开头的前面加0再在后面跟H,或者直接用$号,如:0AH,$A+ _( P/ ]9 S+ X6 k
几个修饰符:
9 g  a$ S+ e2 L$ b  n0 Y6 YOFFSET 返回内存地址中的立即数0 ?+ d/ P2 {: I) K# Y
[....] 返回内存地址,与OFFSET相反,如:MOV EAX,OFFSET [XXXX]=MOV EAXX,[OFFSET XXXX]=MOV EAX,XXXX
1 G5 I0 ]0 }/ a$ a5 K$ q$ E; m  Z, THIGH 返回高8位的立即数. B6 O9 m2 \+ }5 j0 n
LOW 返回低8位的立即数" e% e$ A. Z4 m0 j% A
& 防止变量与汇编中的寄存器同名而在前面加& 号,如:
- i* E4 L5 B! X+ [; j6 \EAX:INTEGER; ...
2 ^+ {* u, o5 v. [  |! G0 V6 ^* qMOV &EAX,10H 这里的&EAX不是EAX寄存器7 {8 V8 p: h1 @; k+ G+ I
. .号的一种用法:
6 U( T5 x# w6 s  n7 Z: B/ svar
, K$ k  P6 |; \$ @$ USTR: Word; ..
* O; f( T2 k0 I& A3 p' f) ZMOV DL,STR.Byte或DL,Byte(STR)* {+ a  u6 Z2 d- R% ~7 v

5 t* I& c7 ^! D8 V  F二、 嵌入式汇编的格式
: n! b8 g  z9 P) r; p  Delphi是使用ASM……END来标志汇编语句
% p( |3 Q6 [* H3 J* O   如:; S4 F( a7 C4 w  o  f8 \
ASM
, Q4 J, b" ?( N* N9 N   mov al,1
4 q" g& k+ v2 ]: r   mov bl,al/ g+ C' S+ T: H
   END;
- e- B" M: C5 w+ U# q" {一个简单加法函数:! ?* A$ j- @  [+ N, ]' @  d% [
FUNCTION SUM(X,Y:INTEGER):INTEGER;6 R/ h1 C1 t! g2 S
BEGIN& M9 x9 P) ]/ b. `5 I5 _
ASM
. v7 o7 {6 H) e6 B9 k' mMOV EAX,X
1 B: F9 E' J6 y( ]ADD EAX,Y
4 g+ C9 ]% z" S- J" [* |8 Y! OMOV @RESULT,EAX
$ h" }8 U1 Q: C, ]; JEND;
! \* r2 z0 Y! d% v8 GEND;: N7 x3 w0 p" D! k" Z9 g, L4 s3 g
Byte转换为16进制字符串:5 r8 L. k& u( ^" w* N' p
function ByteToHex(Src: Byte): String;
6 g1 s7 |$ I! L: Q$ h/ pbegin
. {; R% x. M' U/ b* ESetLength(Result, 2);
# A4 m, g; s$ ^3 _/ pasm% X. Q' g1 O  c: p7 |
MOV EDI, [Result]. i4 o! D1 f: F/ P8 q6 x
MOV EDI, [EDI]
+ c, ^! n9 ]" Q; e$ xMOV AL, Src4 p- C" _+ Z9 j/ f$ G: ~# v' _
MOV AH, AL // Save to AH1 t) h# i' F8 \
SHR AL, 4 // Output High 4 Bits, H2 s! N( B1 a
ADD AL, '0'; ^2 i6 s# [1 b: M; u0 e: O- Y& P
CMP AL, '9'
' t* d8 v! H" `/ I+ {) i' gJBE @@OutCharLo. I8 x* R% D3 [+ R! {. B+ y9 C# K
ADD AL, 'A'-'9'-19 H! C' e9 d0 x
@@OutCharLo:1 z. K8 A+ A( c( B0 R
AND AH, $f
# K$ f3 I6 _! V" H) ^! fADD AH, '0'
% E- f$ @/ F7 Y# Q7 ]1 qCMP AH, '9'
/ g' D0 \* V; ?+ o& n; WJBE @@OutChar
3 ^& `; n; Y! W( w; ^4 N4 ?ADD AH, 'A'-'9'-15 G0 S4 F. k2 n7 c" g4 U5 i3 g2 I) C
@@OutChar:
3 M" u7 i1 S7 n1 A9 E' m- bSTOSW( Q+ H; s% J, r4 }/ k
end;" f. D, [. Z* O( E
end;
4 b) }2 j, a* I8 b% ?5 ]* G三、 可用的寄存器' ^& I. F5 p2 B$ G! D1 \" F6 T
32位寄存器EAX EBX ECX EDX ESP EBP ESI EDI* `- `1 u% _6 y% a5 t1 y
 16位寄存器AX BX CX DX SP BP SI DI
, D- ]/ T4 A" S+ V: Q 8位寄存器AL BL CL DL(低8位) AH BH CH DH(高8位)
% K( _9 G: R. O( x 16位段寄存器CS DS SS ES$ a- r4 A% G7 m  w0 f9 a
32位段寄存器 FS GS
( V3 `2 u" j- o1 s 以及协处理器寄存器堆栈 ST
" H- s; V' W7 q, d, }一个ASM statement 必须保护EDI,ESI,ESP,EBP和EBX寄存器,但是可以自由的修改EAX,ECX和EDX寄存器。7 ~3 [0 _1 z  ?" m% v
默认情况下,delphi使用“register”方式,若参数在3个以内, 将分别使用eax、edx和ecx,如果超过三个,则用堆栈传递。返回参数的存放视长度而定,例如8位用al返回,16位用ax,32位用eax,64位用用两个32位寄存器edx:eax,其中eax是低位。如果你想用EBX寄存器,接得这样写:
% F3 w! p1 [* a4 o% k! U- l1 V# _asm
# F/ r3 `" m& _' hpush ebx0 S6 [  a( i, Z" w5 v% E* Z  `
mov ebx,2
( Q1 Q& v! W: A0 ~- B6 X4 ]1 b. ~mov IntVar,ebx
# o& q7 n4 q0 g4 e1 _. Qpop ebx- h. {1 B# _+ A. S  I  i4 S
end;
0 f) k: _0 ^9 @- M如:FUNCTION(T1,T2,T3:INTEGER):INTEGER,可以默认为T1存在EAX中,T2存在EDX中,T3存在ECX中。+ V2 Y! }' L9 I" k' Q
DELPHI的标签名一般都以@开头,比如@exit、@001等
0 A, ~/ N* q+ j6 f1 Q四、 CALL的应用3 H: k, T- s* q, a, L# K" L
在汇编中写代码要保存寄存器现场(保存使用前的寄存器状态,使用Push压栈和Pop从栈中弹出),不过这一切对于Delphi的嵌入式汇编是没有必要的(除非你自己要使用Push和Pop),因为Delphi已经帮你做了,不必担心会使数据丢掉。
9 `  K  O. r  z$ RDELPHI内联汇编中同样可以用汇编中CALL的功能。
+ Y: Q% q3 y0 S* n3 I* h比如:' A/ `% H$ E1 i; _6 Z* y( e
asm! o% Q# {+ D% u6 c
CALL @1
/ q# w# X( |: V. m, pJMP @EXIT
9 |9 l3 c  x7 {8 Y& [@1:" n; [* j! q* K, N
MOV EAX,1- f+ V: r* w& b: z; K
MOV SN,EAX6 t4 @8 J+ s* O4 q8 Y9 Y/ Q$ m
RETN, v8 K" V( K9 t, t
@exit:/ u. x6 V# w) T+ n! K# f8 ^
end;
. D  }; r+ v& [- scall的第二种用法,在汇编代码中直接调用FUNCTION函数,如:
' w* g4 W8 f# m( s  J0 K* [function cacl(eax: integer):integer;; ~7 g1 N4 q* N$ Y. C8 z) X
var. B4 J- D. @7 ~7 x1 U4 _# U
...
1 J+ _5 @6 M! Pbegin
6 {! i) W5 d* L5 V  Z9 `; k....
8 b* L* T: R8 d' {0 HResult:=code;
9 O% i/ E; B+ _5 e( Z$ hend;
1 W! a( \( N7 h7 B4 [% v- |& t( A调用时可以直接CALL CACL:% p5 p. \* R& ?* m) h, O6 I
ASM& t# P$ x. Z9 a5 v! d# U" @
CALL CACL0 z, |8 A; g6 }6 _2 R, G$ m( e0 ?
...
' j4 `) {7 \5 d: b3 uEND
. T! y3 Q5 ^0 {3 c. D编语句中的Call语句,可以用于调用其它过程,既可以是其它汇编程序段也可以是Delphi中的标准过程:
. R4 s' W3 V2 L6 ~  例如:假设新建一个窗体并在上面加了一个按钮,在Click事件中写入以下代码& b, C4 b' _# t8 m; V0 F
  procedure TForm1.Button1Click(Sender: TObject);" _0 c3 O. J. O% m! o
  begin
  D( W; V% K4 K! s. Q6 j6 i   showmessage(`ok');
8 B: M+ W0 i( z* O  end;, d# ?5 i" V" p, H
  再写一个过程_X* L3 A0 f# l& ~( b0 F) Z/ f
  function TForm1._x(var i:smallint):integer;+ v) }8 q" c4 w( F! K9 g
  asm
5 e9 k5 h! L$ H   call button1click
9 N# [0 o5 z- A  end;8 ~; |  |6 s# G& J# Z' b% K# Y1 j
  执行_x的结果就可以显示消息框。8 L+ D. X  V* i5 B
五、调用API函数
$ B, J6 Q* R& l" [9 H  sDELPHI内联汇编中调用API函数函数非常简单,比如调用PostQuitMessage:
, g/ j5 q- h4 u* |Asm
$ b, ^; r: P: C& Q1 bPush 0
+ D1 y1 Z* A1 ?# A( OCall PostQuitMessage(或Call SYSTEM.PostQuitMessage)
4 M3 T4 t- K, _0 g1 g" ~( {End
5 l2 T- k# w4 u9 t  F调用MessageBox函数:
1 ~0 H8 L1 [& }: l6 H( z6 F: Bprocedure TForm1.Button2Click(Sender: TObject);6 M0 \5 g5 ]! }( ?) Y/ I
  var, q& s- L! W$ N4 t. J, l1 j
   szTitle:string;
6 \# }8 G! `/ G# Z  i, A   szCaption:string;
( X( f' T9 Y; ~3 c3 S  begin
2 B$ ^0 q% m0 c! f1 N   szTitle:='您好!';
$ a+ A$ M$ `! o) `$ D   szCaption:='这是一个在内嵌汇编中调用stdcall类型函数的例子.';
" c! s# m2 @+ l: h  \9 P   asm& o- w0 H: t9 Q( L' J4 B
    PUSH MB_OK+MB_ICONINFORMATION/ o  z: r( R% H
    PUSH szTitle
% j- @; @% J( [! O2 W/ C  `: C2 F7 J    PUSH szCaption
5 S. f: E0 i3 k! s* F    PUSH 0
% g4 ], T3 P7 v1 @    CALL MessageBox8 j6 F7 x; }7 W( H: Z
   end;
2 u% h" w6 |8 ]- X' y. ^: ]  end;
+ z4 j6 i) W& |7 v; E( w调用GetFileSize函数
2 f0 i# T. Y, D7 z- u& X  L! y7 tfunction stdcalldemo: Integer;
& A+ A2 c+ A, Yvar' _8 L+ f" N# F# G" G
FH: THandle;
" T# o! @! g; Y, `: H) d+ O0 s" a1 wbegin
) P" i2 i4 m0 y7 v9 JFH:= FileOpen(’c: oot.ini’,fmOpenRead);
( a% L) b' y. Z) Z: M7 a6 Gasm1 {( }  f3 \* ]7 ^+ |* a' D
push 0
. S* h: Z8 Q6 l5 W/ Xpush FH5 n% q/ i/ x! y7 }, l6 p
call GetFileSize( @. L# |  P; W
mov @Result,eax
; d3 b: c6 U9 N# ^end;
0 o5 P+ y! C0 J3 X$ OResult:= GetFileSize(FH,0);//此句就相当于上面的汇编调用方式
/ p9 {& r5 X8 p1 s; M! a0 t& w( bFileClose(FH);
* H' f* t& }4 e/ oend;# T* t  F. v5 |! K# `
procedure TForm1.Button1Click(Sender: TObject);6 A0 }5 f) ~! u. h4 Y* B6 u1 A. v4 s
begin
% u5 M: M; c8 J7 i% i! h. h: k, gshowmessage(IntToStr(stdcalldemo));
! B$ O; x% a9 k% e- oend;3 h9 f- Q. x, |# {
六、汇编的调试。
) @/ J$ }- |" R如果发现汇编通不过,就要注意停下后的位置的代码:如变量的跟踪、断点、堆栈查看……可以在关键代码处下断,停下后打开View菜单的Debug Windows的CPU VIEW窗口,F8单步跟踪。如:& V: ~- ^% y  i1 Q2 ]
Unit1.pas.62:     PUSH MB_OK+MB_ICONINFORMATION' {( F/ O3 |9 m& ^, k$ H$ q! N: @
00455E8F 6A40 push $40
0 a9 m! M7 F7 K' ~* Z  f1 zUnit1.pas.63:     PUSH szTitle
; r  M8 ~& @" H8 N& X00455E91 FF75FC push dword ptr [ebp-$04]
1 j9 `9 C" |7 |% A9 mUnit1.pas.64:     PUSH szCaption4 d6 W. X6 Z. c: ~
00455E94 FF75F8 push dword ptr [ebp-$08]( E; N" f/ V# I, h+ i4 z5 T+ F2 R; A
Unit1.pas.65:     PUSH 0* z& E+ ?5 v, c6 r, @, j& u
00455E97 6A00 push $00, {+ V0 ~9 ~  M! P3 q
Unit1.pas.66:     CALL MessageBox4 M4 N! L0 v! V. \4 D1 K! u
00455E99 E8FA0DFBFF call MessageBox
) u- g5 A3 n8 UUnit1.pas.69:   end;
: m, ~' O5 f" A, `3 M* W4 [00455E9E 33C0 xor eax,eax& i- G0 G3 W! q# h. _6 t9 V1 M# T& K
七、常见易错语句。
7 U3 o. n) d+ MMOV ESI,DOWRD PTR SS:[TEXT] 对(TEXT为STRING)5 v9 \( q, g/ i: p1 p0 v+ s8 L: b: a
MOV ESI,DOWRD PTR [TEXT] 对(段寄存器CS,DS,SS,ES可省略)2 J$ [$ d% z! B+ _' \* u% q
MOV AL,DOWRD PTR SS:[TEXT] 错(DWORD为32位)  I" V  s4 B. d, l
MOV AL,BYTE PTR [TEXT] 对. R* Q% U; K7 m2 ^' Q% C& P
MOV EAX,BYTE PTR [TEXT] 错(DWORD为8位)# V- l$ v, M* s. j4 b3 ^; Q1 g0 l
MOV AL,WORD PTR [TEXT] 错(DWORD为16位)2 w9 }& R3 s) ?+ O4 I
MOV EAX,WORD PTR [TEXT] 错
1 v8 Z8 I* w6 A1 _7 NMOV AX,WORD PTR [TEXT] 对# Z. [% j( z# z9 L$ n$ R
MOV [A],EAX( X2 z) ~( y" r) k& y3 u
MOV BYTE PTR[EDI],'A'/ z2 z# }, h7 K$ L. P" ]
MOV AL,[EDI]$ W3 D) x& g3 ]  u/ o
MOV EAX,X //X指向的值赋值给EAX
+ `5 t8 D: H6 E1 ^" h" vMOV EAX,[EAX] //X指向的地址赋值给EAX
* k/ w3 @' c; Q6 [2 I- V4 V& {MOV DOWRD PTR[ESP],EAX 对
* d7 K, Q" m6 U6 U) w, |: y& GMOV DOWRD PTR[ECX],EAX 对
( g8 P& S( ^% t* p' M2 s$ E7 qMOV DOWRD PTR[ECX+4],EAX 对) a% ~4 @, Y: L! ^" y4 Y
MOV DOWRD PTR[ECX+EDI],EAX 对
" F/ F; K# ?, RMOV DOWRD PTR[ESI],EAX 错
% i7 g" y/ p# V! RMOV DOWRD PTR[EDX],EAX 错
6 g% C9 O! _% j7 @/ YMOV DOWRD PTR[EBX],EAX 错
  ^. ]. V0 z1 `  x. B9 H/ [) Y9 A
3 g& O1 n7 m$ a% }) e3 Z
后期资源网,打造没有广告、免除隐藏回复的全开放式影视技术交流平台。 你的所求就是我们服务的宗旨!!!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

GMT+8, 2024-5-18 17:06 , Processed in 0.119577 second(s), 20 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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