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

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

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

[复制链接]
发表于 2013-1-4 11:37:28 | 显示全部楼层 |阅读模式
Delphi内联汇编好象有得天独厚的优势,尤其是API的调用,处理好各成员参数后,可以直接CALL API名称。利用内联汇编我们可以为程序添加各种异常,添加反调试代码,添加花指令,还可以令某些难写的注册机简单化等.我把Delphi内联汇编的一点点使用心得写出来,目的是想与大家交流,挖掘更多的这方面的领域。也希望大家能够指正一些错误。
/ P# ~2 `+ E  N, n7 [9 [/ H* p
  h! f# y% X0 C: s2 r' E; [一、 数据格式4 A$ ?) ^- K0 C8 R2 G) i/ ?
整型数据:8位的用AL返回,16位的用AX返回,32位的用EAX返回。
: k& e2 @* p9 gBYTE(8位):BYTE、CHAR、SHORTINT、BOOLEAN
, ^0 E- d4 I& J- R; \WORD(16位): SMALLINT、WORD
) u0 c; n2 a, e. Z* }DWORD(32位):INTEGER、LONGWORD、ANSISTRING、POINTER、CLASS、LONGINT、STRING
, x- R9 z0 c) f9 H9 m1 B9 vST(0):SINGLE、DOUBLE、EXTENDED、COM$ U$ B# k- K% C# q; m/ d
如:
4 S" L/ V& q9 F. A6 k: xvar  f3 Q* K. o1 G6 v5 {$ ?* P
ByteVar: Byte;( d8 i" s# y  y3 }. w
WordVar: Word;- O# H2 Y; l2 T, ~6 Y8 L
IntVar: Integer;; }' C* g7 X0 x
begin
/ a3 T- p1 q' N, |" Q: k% G0 F0 pasm
5 R6 M5 x7 E' j5 w1 k' H6 @MOV AL,ByteVar3 J6 i4 m0 m+ V, c9 V6 K7 c0 t9 a
MOV BX,WordVar. G, j5 ^$ A- D( L9 ]# H( R$ K
MOV ECX,IntVar
1 H; L/ C6 `% q! {4 h. @end;
/ v0 Y' M" l" N+ b% m9 d8 @end;$ N0 e5 N% }2 c2 E
实型:用ST(0)返回
" N( t0 q3 O4 D6 U/ X7 ?' |2 Q, l  g7 R  指针:用EAX返回* c3 Z: T; |* z+ I1 v
  长字符串:用EAX返回其所在地址
5 x5 ?6 o0 U; L/ l! X  变量:可用@Result返回
2 W* o: q0 S( p% A1 ]' q16进制的表示方式:
9 W, C! s1 m. o, [7 d' A如果是0-9开头的16进制值直接在后面加H或在前面加$号,如:1AH,$1A3 l" U' j7 v  D% j: r7 E. C" U
如果是字母开头的前面加0再在后面跟H,或者直接用$号,如:0AH,$A
% s: S  M5 |% m/ N+ f- C- Q几个修饰符:9 Y  h# T3 S+ ~+ J
OFFSET 返回内存地址中的立即数1 u  Q9 b) R! Y2 q" y; \
[....] 返回内存地址,与OFFSET相反,如:MOV EAX,OFFSET [XXXX]=MOV EAXX,[OFFSET XXXX]=MOV EAX,XXXX
. C8 u1 k. c& s7 ?HIGH 返回高8位的立即数8 s1 S* y* c6 ]: u, I. K
LOW 返回低8位的立即数+ o# F9 t: z. K6 Y2 f
& 防止变量与汇编中的寄存器同名而在前面加& 号,如:% N  h( v; t1 |
EAX:INTEGER; ...7 v! |+ o% C) y" m' H
MOV &EAX,10H 这里的&EAX不是EAX寄存器
5 i0 Y1 x5 J  J6 {3 G) X, u+ E& |' y. .号的一种用法:7 |! X8 u# z/ b* @' E+ w2 {1 L# ~
var 3 K1 R. o0 ]- c7 @
STR: Word; ..
9 u0 {5 D$ H2 y$ ?% b+ FMOV DL,STR.Byte或DL,Byte(STR)
# ~4 u( y9 o* I3 g7 O6 O9 P+ k3 S$ \1 v: k7 H2 Q$ I
二、 嵌入式汇编的格式& Q4 F$ m1 C2 l7 `7 D
  Delphi是使用ASM……END来标志汇编语句
6 ]$ ~& f* o  `$ T, {   如:
0 l; j5 p; x+ a8 E, r8 F" PASM
3 Z5 Q8 x+ U/ e9 `   mov al,1
7 m( E" s8 \0 _- x   mov bl,al
. P9 b% g! @: K; X9 O2 W; E' W   END;
0 S- C* Y8 T$ h9 I! s: r2 y2 H. M一个简单加法函数:
$ d  p8 M$ J) X5 y8 T- LFUNCTION SUM(X,Y:INTEGER):INTEGER;9 g  _+ A4 q, m/ Y
BEGIN
  J2 C5 r$ F* S# z, kASM6 s; l) f4 X" Z: F( U/ ?2 y- u
MOV EAX,X2 E9 c+ J6 O8 y: E/ g+ @( Y, E
ADD EAX,Y9 [5 I9 X' m4 E
MOV @RESULT,EAX
, W& E, d: [+ [& m  Q" [# E" W! n! gEND;
- M2 p( r5 d( C# [( BEND;
  y+ ]  _5 R, J0 [- RByte转换为16进制字符串:1 m) p, w9 Y/ ~. V6 t' _, N1 K
function ByteToHex(Src: Byte): String;
& i$ k( X; k/ l& dbegin
3 _( S: I2 O3 V, T2 jSetLength(Result, 2);
, x  ?4 x. |( e. R* X; jasm( u7 r; B' g+ o0 |+ {1 G
MOV EDI, [Result]
4 d  ^  c6 E: J4 n7 CMOV EDI, [EDI]# \" c) M- @! r, @. R  E
MOV AL, Src: M4 X, J  ?  P  A- G! w
MOV AH, AL // Save to AH4 l( C' k! f3 Q5 ?$ y& X# d
SHR AL, 4 // Output High 4 Bits
; l9 i/ P9 \8 n1 R7 Y- [. L! {$ s* {8 xADD AL, '0'* u( A: }6 @0 T
CMP AL, '9'
1 H% D3 T' h0 ^" B8 ^' oJBE @@OutCharLo! e* u) Z+ a7 v1 w, }  m$ H* U* n: k
ADD AL, 'A'-'9'-1
( V! I$ c! m, }" S@@OutCharLo:
9 b; s/ {: ~+ Q2 Y! M# o3 Y( v6 _AND AH, $f7 Q* K! m; J- p" T9 Z# B$ C
ADD AH, '0'  g* R9 r9 Z) \: ^/ G8 k/ ^
CMP AH, '9'( Q) \+ K! f9 L  o
JBE @@OutChar
  l2 d- }/ n  L) n6 h1 r4 dADD AH, 'A'-'9'-1
* k+ ?4 d6 a+ Y" Z0 S: O@@OutChar:
! X. ?6 h5 _% [3 QSTOSW
4 W5 _6 f; u4 M- Q& p) Gend;
1 ]. ]) c2 `+ e9 d6 F) Hend;$ x7 G, {8 C$ ?/ K# ?- b
三、 可用的寄存器
" B' b/ H& ~! l3 U32位寄存器EAX EBX ECX EDX ESP EBP ESI EDI( ^2 H* V9 K' g/ K7 V
 16位寄存器AX BX CX DX SP BP SI DI
2 K' C/ k1 F9 C2 Y( i' Q 8位寄存器AL BL CL DL(低8位) AH BH CH DH(高8位)
. ^4 _9 b0 d( C4 P) [ 16位段寄存器CS DS SS ES
7 T9 o8 w* v/ \3 b1 G8 t32位段寄存器 FS GS5 M8 G: B( R8 a" y
 以及协处理器寄存器堆栈 ST( f( o: s3 i  Y
一个ASM statement 必须保护EDI,ESI,ESP,EBP和EBX寄存器,但是可以自由的修改EAX,ECX和EDX寄存器。( e' q; b1 F8 `9 ]0 O- A+ t- b/ f
默认情况下,delphi使用“register”方式,若参数在3个以内, 将分别使用eax、edx和ecx,如果超过三个,则用堆栈传递。返回参数的存放视长度而定,例如8位用al返回,16位用ax,32位用eax,64位用用两个32位寄存器edx:eax,其中eax是低位。如果你想用EBX寄存器,接得这样写:2 Q9 O0 _5 F* C! H, m  W! w
asm
5 X! R! u1 ]4 `. E5 R2 qpush ebx
3 h- a6 A# ^) Y+ umov ebx,27 Z' B+ a% e7 a$ k# S) b, i; j9 p; Z* X
mov IntVar,ebx
3 j" p, f# s: W3 q  Y( E$ B7 Ipop ebx3 }  k! C! t3 x3 P% d( v1 \" x
end;
9 Z4 e3 {6 t, T: K8 Q4 h如:FUNCTION(T1,T2,T3:INTEGER):INTEGER,可以默认为T1存在EAX中,T2存在EDX中,T3存在ECX中。; K7 f% X5 x: |% W8 K
DELPHI的标签名一般都以@开头,比如@exit、@001等
0 s' w. a9 R# v0 k6 k四、 CALL的应用% n" B, k4 W, n4 L9 ^" e" {
在汇编中写代码要保存寄存器现场(保存使用前的寄存器状态,使用Push压栈和Pop从栈中弹出),不过这一切对于Delphi的嵌入式汇编是没有必要的(除非你自己要使用Push和Pop),因为Delphi已经帮你做了,不必担心会使数据丢掉。
3 X) f( m6 U0 z  cDELPHI内联汇编中同样可以用汇编中CALL的功能。! v! t3 c+ E2 G; I0 i. E/ h
比如:
+ A1 T. y8 X; `4 o4 ^6 E  C# {2 y/ aasm
# m2 t3 m7 _8 G6 M+ m/ KCALL @1
  \: r2 V) e) I# S- B( K/ [JMP @EXIT
' ?- t% Y1 J6 B@1:
# s5 q; W8 c5 L( S. _. q* TMOV EAX,1; d, S! l& y* [- d& s$ ?
MOV SN,EAX0 ^7 G2 V& e- p( M3 ^# h
RETN9 F( X/ \& D& ~7 f
@exit:$ v+ U: A3 q5 a0 G: S
end;0 u& f  o7 g0 Y! q
call的第二种用法,在汇编代码中直接调用FUNCTION函数,如:
' x8 S) \. v5 g& ~  D2 G) hfunction cacl(eax: integer):integer;! R+ Q3 y# J& x1 _3 l7 q% g! @
var+ d$ {% S, y1 t3 e( a6 o. ]
...: T7 F* y# A" A( l. T# t- u
begin
) `- ]5 V* \, f* [9 l3 w9 t....! A5 J% p6 P+ y$ a+ @
Result:=code;
7 P, O. R* T3 O% Uend;   K0 U" @# S/ M0 i/ W! l
调用时可以直接CALL CACL:
: t5 L( f; P1 _. ~ASM' P6 P- z2 B+ m6 b% C# y. N4 z
CALL CACL0 n+ a$ J$ j0 m& A& V- `
...
- o4 x+ E( u' d$ P8 m% ZEND
$ |3 p8 r# @( n3 H% }& u& j编语句中的Call语句,可以用于调用其它过程,既可以是其它汇编程序段也可以是Delphi中的标准过程:7 ~& Y  V, j3 H2 j. X/ R
  例如:假设新建一个窗体并在上面加了一个按钮,在Click事件中写入以下代码0 r& y% w8 X$ N$ W/ y
  procedure TForm1.Button1Click(Sender: TObject);( @( |  \- ]7 ~& Q0 ~
  begin- [2 Q7 k7 `' J) `. o1 }' f/ a* [9 B
   showmessage(`ok');
: g% Z5 ], x5 ?  end;
; L7 Z* {7 \3 k4 d0 P5 e# j  再写一个过程_X
' T7 x: L# f- t" ~8 E) |! E  function TForm1._x(var i:smallint):integer;
5 G) W  H/ R5 B) o0 _  asm, Q- P! k; P8 g6 ^: K+ X: ~
   call button1click
9 f7 {: F3 {3 F6 J4 C( B  end;
+ R* R, b0 ]) J' J9 b) j  执行_x的结果就可以显示消息框。
1 N5 B9 U+ a$ E五、调用API函数6 o& w" ?3 q9 Z% \4 e( W) S$ u
DELPHI内联汇编中调用API函数函数非常简单,比如调用PostQuitMessage:
9 m) @- ~' h0 Y% W7 [/ QAsm- e8 o5 `! U& F( r1 ~6 H
Push 00 _7 h! Y! L/ I% q+ j+ Y% [
Call PostQuitMessage(或Call SYSTEM.PostQuitMessage)/ _3 A: B- G3 ?8 N0 h
End
3 ^  x7 \+ h2 ]' A0 W调用MessageBox函数:
  c5 J6 T, t) zprocedure TForm1.Button2Click(Sender: TObject);. B/ F! k: `: ~' F" K
  var& u/ n8 i& @2 S6 \
   szTitle:string;
8 A5 @' H9 t0 L& \6 f1 H   szCaption:string;
7 N: n! z. {$ H, J$ X( E' I  begin$ ~0 n! c, x8 D9 G( ?
   szTitle:='您好!';1 I( O, c, ]$ t8 q. T
   szCaption:='这是一个在内嵌汇编中调用stdcall类型函数的例子.';
: E$ E* v5 l3 \& |. e   asm
; v! e4 b2 m* I! u8 J3 _, g    PUSH MB_OK+MB_ICONINFORMATION2 f2 Z8 P0 q! k% U
    PUSH szTitle! s5 J6 L: n0 Q8 y
    PUSH szCaption
7 d  Q  I' w3 L3 n- x# F* ^    PUSH 0  b0 X( A  w4 ], t) p+ p4 S
    CALL MessageBox# D3 F3 [/ M+ e% r5 P8 I. p( Z; o* o
   end;
9 y' f+ S5 h+ }3 B% ]  end;
0 a" a; R+ e  H4 }调用GetFileSize函数
3 x8 d9 [* H+ v% t& ~% H  zfunction stdcalldemo: Integer;
$ R) i  H5 |6 J+ u9 n4 @var$ ]; q7 r  S9 a8 a' k" w4 I/ h$ X
FH: THandle;/ }9 R7 H4 e: h3 p/ O  m4 ]/ N
begin/ Q5 F$ m0 {# W( o' g  [0 v
FH:= FileOpen(’c: oot.ini’,fmOpenRead);4 z9 P7 t1 ]' X# c: H
asm
+ z* t" L! d' {& Cpush 0, k8 R+ d& R& n* d, i
push FH" ^  n' K! i$ Y; c+ o/ M
call GetFileSize( g+ A% G3 r( ]5 g$ m7 C! L
mov @Result,eax
+ B# j9 a" Z  S$ q5 C+ K9 k; `end; + M/ N% ^' W; w4 ~6 u
Result:= GetFileSize(FH,0);//此句就相当于上面的汇编调用方式8 ~6 L6 `5 k) U' K+ O$ V
FileClose(FH);
7 ?4 j/ C5 F9 m1 P: L9 xend;, z( l" ]* [) q: @4 Y
procedure TForm1.Button1Click(Sender: TObject);
/ {9 O7 \' C  Pbegin. h( L7 ~8 q1 K
showmessage(IntToStr(stdcalldemo));- P; ~; R& E1 O' Y. l: i: p, \
end;, {$ y) Q' {- k8 ^4 T' ]/ m6 f% n. P
六、汇编的调试。2 e+ c4 I6 D0 v1 ]$ f, p* ]
如果发现汇编通不过,就要注意停下后的位置的代码:如变量的跟踪、断点、堆栈查看……可以在关键代码处下断,停下后打开View菜单的Debug Windows的CPU VIEW窗口,F8单步跟踪。如:8 X6 p: u2 s2 j( l% V; k
Unit1.pas.62:     PUSH MB_OK+MB_ICONINFORMATION$ F" v+ A3 X7 M) B- P/ G2 }
00455E8F 6A40 push $40
* v# A' }4 M6 T3 ~) x2 i& EUnit1.pas.63:     PUSH szTitle, r0 g' S9 D9 K, t. O0 C0 \
00455E91 FF75FC push dword ptr [ebp-$04]: V- {! ?' f$ z, v% H8 T
Unit1.pas.64:     PUSH szCaption* F. j( M0 M6 X& p
00455E94 FF75F8 push dword ptr [ebp-$08]& T" M+ U* H9 g& [- r* ?
Unit1.pas.65:     PUSH 09 ]1 Z* p& Z- ?" Q+ E0 @. @# w: r
00455E97 6A00 push $00. L$ u3 [5 Q3 w! d1 `6 c5 t7 o& [
Unit1.pas.66:     CALL MessageBox* B* v8 v* j2 j7 I8 l2 [7 Z
00455E99 E8FA0DFBFF call MessageBox3 j. ^( f9 O( Q6 V
Unit1.pas.69:   end;
# m( L9 S4 Y8 w# i  c  u00455E9E 33C0 xor eax,eax& B- [: B6 @0 a  e4 h+ f# \
七、常见易错语句。
- Z0 k, y- V' R0 I0 NMOV ESI,DOWRD PTR SS:[TEXT] 对(TEXT为STRING)
) ?" {1 Q+ e$ mMOV ESI,DOWRD PTR [TEXT] 对(段寄存器CS,DS,SS,ES可省略)
% q" U9 V$ A- z- p+ }5 FMOV AL,DOWRD PTR SS:[TEXT] 错(DWORD为32位)
1 g* M; e$ z( V4 m$ r6 t' vMOV AL,BYTE PTR [TEXT] 对: q& @  ~& l, v; m
MOV EAX,BYTE PTR [TEXT] 错(DWORD为8位); B- w  W5 d$ l8 k5 J/ v& f
MOV AL,WORD PTR [TEXT] 错(DWORD为16位)+ R: h3 x: y+ M
MOV EAX,WORD PTR [TEXT] 错. y9 A9 ^1 B# a$ p0 U
MOV AX,WORD PTR [TEXT] 对* Z' d6 d% I' m/ y9 X
MOV [A],EAX
1 |( j+ K; u0 x' T  `& M7 uMOV BYTE PTR[EDI],'A'
. p/ s% [' D. K9 |3 l, b8 k( gMOV AL,[EDI]/ y' k$ f8 V$ f7 c
MOV EAX,X //X指向的值赋值给EAX! U% U. {" U+ q6 {- j
MOV EAX,[EAX] //X指向的地址赋值给EAX
( n: m4 D! i6 f; W# Y) f- aMOV DOWRD PTR[ESP],EAX 对
0 }& C( w! n2 j, [MOV DOWRD PTR[ECX],EAX 对
2 B6 g' M" |8 l  ?1 ]; V8 D( sMOV DOWRD PTR[ECX+4],EAX 对
3 a1 _. y0 k7 ~* P# OMOV DOWRD PTR[ECX+EDI],EAX 对3 S0 F+ V% w) f$ `5 S+ y/ J+ U
MOV DOWRD PTR[ESI],EAX 错
7 p, ~+ p9 j- _$ NMOV DOWRD PTR[EDX],EAX 错
; Z! g5 W: H/ O! `MOV DOWRD PTR[EBX],EAX 错) h1 M( l+ G0 M
  u4 F. r! v* H1 X: i
后期资源网,打造没有广告、免除隐藏回复的全开放式影视技术交流平台。 你的所求就是我们服务的宗旨!!!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

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

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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