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

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

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

[复制链接]
发表于 2013-1-4 11:37:28 | 显示全部楼层 |阅读模式
Delphi内联汇编好象有得天独厚的优势,尤其是API的调用,处理好各成员参数后,可以直接CALL API名称。利用内联汇编我们可以为程序添加各种异常,添加反调试代码,添加花指令,还可以令某些难写的注册机简单化等.我把Delphi内联汇编的一点点使用心得写出来,目的是想与大家交流,挖掘更多的这方面的领域。也希望大家能够指正一些错误。- T! Q( j" E! j6 @
9 ]) r& u& L" k
一、 数据格式
) `  i) d7 w; |$ ^$ R整型数据:8位的用AL返回,16位的用AX返回,32位的用EAX返回。
1 m0 @- b& `: B& {: ^BYTE(8位):BYTE、CHAR、SHORTINT、BOOLEAN
9 Z) ~# v" Z. a; v; S, X4 g/ W* rWORD(16位): SMALLINT、WORD  C# z- t$ E8 |
DWORD(32位):INTEGER、LONGWORD、ANSISTRING、POINTER、CLASS、LONGINT、STRING
, n; t. S! ]0 C1 {/ @3 f3 ?& fST(0):SINGLE、DOUBLE、EXTENDED、COM
" m* |( F4 ^; V/ ?( N! u! q如:
7 b4 Q/ a' l5 Y7 X# vvar  M: N# u5 `! V/ j1 o$ P$ U# y
ByteVar: Byte;: z" E# }+ ~0 H3 ?0 x: N3 M7 P
WordVar: Word;
  n; j( |& Q/ z1 s8 Z1 pIntVar: Integer;1 M* e6 b& {1 P0 B* A
begin( x* ^: ]* Q4 {; Q! w# q4 [! a
asm( G4 I: v! {( `2 g( R
MOV AL,ByteVar
% C' V# _2 P, p% t3 gMOV BX,WordVar
& |, o1 R3 _1 N9 |2 sMOV ECX,IntVar
- X6 B' R  m9 _6 V9 p# T) [% Q: T7 Aend;) [4 f- j% M; W; I" Z4 m6 y
end;
8 `% B8 F, S# o) C( c实型:用ST(0)返回0 @7 C: M3 x+ C1 S! D7 Q
  指针:用EAX返回
. [9 S% f  N- Y7 u  长字符串:用EAX返回其所在地址
2 P+ ?- S1 S- h" Z" s- q  变量:可用@Result返回; M! K! }1 }. P- o1 R9 M* @
16进制的表示方式:- L1 w+ f9 |7 Z9 ]5 I
如果是0-9开头的16进制值直接在后面加H或在前面加$号,如:1AH,$1A
" J+ ?* F4 B/ u' P0 q6 Y如果是字母开头的前面加0再在后面跟H,或者直接用$号,如:0AH,$A
; X  K! A- {1 e+ R9 j几个修饰符:
0 R- k. w- e& rOFFSET 返回内存地址中的立即数
6 s$ }$ i; D% O" @0 I; `[....] 返回内存地址,与OFFSET相反,如:MOV EAX,OFFSET [XXXX]=MOV EAXX,[OFFSET XXXX]=MOV EAX,XXXX
& ?  j* V) l" t1 KHIGH 返回高8位的立即数& J! v, q# m& m  a
LOW 返回低8位的立即数" N" `: V+ W% \6 H; _- A) R
& 防止变量与汇编中的寄存器同名而在前面加& 号,如:* c4 Y& z5 P6 N; V
EAX:INTEGER; ...
+ f. O4 ~5 K3 xMOV &EAX,10H 这里的&EAX不是EAX寄存器) {$ h  A& P. O8 m& ?  z
. .号的一种用法:2 b( m% {: Q# |# T
var ; U8 M% N7 x$ ^4 m# M& i* C5 u+ _
STR: Word; ..
" `, a0 f% _1 q' @6 c. PMOV DL,STR.Byte或DL,Byte(STR)0 E7 |  J, a& Q8 L, i
  f7 y) M9 `+ c2 M4 X; \6 E3 J
二、 嵌入式汇编的格式
# k% D# m1 M: F+ i7 p  Delphi是使用ASM……END来标志汇编语句
: R0 o# T' D4 L8 ?$ y( [0 a2 E   如:
7 I" \: K- _1 bASM% x: {/ R  Q- c, X3 f) C& ^; A# ~
   mov al,1  A/ i, i/ p7 a, d
   mov bl,al3 g- J$ e- z7 D8 g- v: W
   END;
2 E  a, Z8 g! A/ H1 q一个简单加法函数:8 b& @1 T+ ^+ L5 Q. ?2 J
FUNCTION SUM(X,Y:INTEGER):INTEGER;
7 O1 ]& l5 f( x9 E, c7 \BEGIN+ Z, E- q! e6 `3 T( h
ASM; U- _/ E: H( L( r
MOV EAX,X7 P) s0 U; P1 W- b8 A% {: A
ADD EAX,Y+ @6 H. D! }- E: d/ `0 T
MOV @RESULT,EAX$ O# n( s7 X6 p0 {7 z
END;
5 @( P3 X. [/ f1 j6 m( H: XEND;
+ j) U. C3 W" r8 P3 D" G) mByte转换为16进制字符串:! q6 Q( V) A+ b: \) ^+ k1 K
function ByteToHex(Src: Byte): String;
/ P9 b. [/ D0 t. Q: `begin
4 V1 C' }0 l5 k/ v, j( \7 w$ GSetLength(Result, 2);' n' O8 k4 F' z2 E8 G
asm
* H1 S: a' ?, y* l6 J4 OMOV EDI, [Result]
; ~# k. a9 }: y# k" G% QMOV EDI, [EDI], k/ M1 W) R4 {+ V5 B( V* i
MOV AL, Src/ V# T9 v% k5 T. {( P
MOV AH, AL // Save to AH
+ f$ j1 a5 h# G" a7 v  ESHR AL, 4 // Output High 4 Bits" `: Z: q6 H& l! D- C/ i. {9 e0 e
ADD AL, '0'0 j9 K' j5 f% u% r% ^0 n5 Z
CMP AL, '9'
6 q6 N6 s# J, X* m; K3 C0 WJBE @@OutCharLo
  y; `$ l4 |2 s/ f! [2 fADD AL, 'A'-'9'-1- i% W9 R% ]9 `( N" {
@@OutCharLo:# Z) W" n* H+ ~4 R+ v3 I
AND AH, $f
! Q, k8 c  A8 }' e6 C0 b2 tADD AH, '0'
" L* `# _- p2 z) _; p! Y5 hCMP AH, '9'
/ \" x$ {! _+ a+ G; ]& ]JBE @@OutChar
. g( x5 p5 s  [4 aADD AH, 'A'-'9'-14 ^! T4 T/ T+ G2 J* x# |4 F8 S5 S
@@OutChar:
8 i* l- a3 H' CSTOSW% W4 L, e0 R) q& _. J# C
end;
6 L9 t6 h! R* A6 Qend;5 v* o9 q, G+ H" E; c$ S2 R4 Y
三、 可用的寄存器/ r! q+ c7 E  o" {
32位寄存器EAX EBX ECX EDX ESP EBP ESI EDI
3 z) v; Q4 _* J- p$ s2 z3 O9 g- m 16位寄存器AX BX CX DX SP BP SI DI) j: b; D+ e# C
 8位寄存器AL BL CL DL(低8位) AH BH CH DH(高8位)3 S& ^* m, D+ y1 ]$ p2 F7 }
 16位段寄存器CS DS SS ES
9 q9 i# ~! \) O) q. N32位段寄存器 FS GS
" p" \# g! `/ z 以及协处理器寄存器堆栈 ST( N) a  h9 |  D2 J* k7 s  x0 h
一个ASM statement 必须保护EDI,ESI,ESP,EBP和EBX寄存器,但是可以自由的修改EAX,ECX和EDX寄存器。/ j9 U* q" }" m/ R
默认情况下,delphi使用“register”方式,若参数在3个以内, 将分别使用eax、edx和ecx,如果超过三个,则用堆栈传递。返回参数的存放视长度而定,例如8位用al返回,16位用ax,32位用eax,64位用用两个32位寄存器edx:eax,其中eax是低位。如果你想用EBX寄存器,接得这样写:+ d0 ]5 E! f: @0 i) ]0 P: g0 @
asm
* H# a( A, V$ z; \9 Tpush ebx
: b7 S& g+ |9 E4 v/ u8 B8 q+ Pmov ebx,2' D5 T$ e3 @# V! J0 a  k
mov IntVar,ebx
4 Q7 ?, s& ]3 a4 e/ {pop ebx
  r5 i$ x2 [& Gend;
9 y: {: v, Q7 n  Q# P6 P如:FUNCTION(T1,T2,T3:INTEGER):INTEGER,可以默认为T1存在EAX中,T2存在EDX中,T3存在ECX中。
. h% S* t- L$ o* R5 @0 SDELPHI的标签名一般都以@开头,比如@exit、@001等6 [" P3 U# T% p  [/ u: R. J: n
四、 CALL的应用
% J- {1 ?- O; q, C在汇编中写代码要保存寄存器现场(保存使用前的寄存器状态,使用Push压栈和Pop从栈中弹出),不过这一切对于Delphi的嵌入式汇编是没有必要的(除非你自己要使用Push和Pop),因为Delphi已经帮你做了,不必担心会使数据丢掉。1 G/ O" {/ V5 |
DELPHI内联汇编中同样可以用汇编中CALL的功能。! U: _) T3 z$ z# x4 a6 V2 t- \. O3 D
比如:
6 D4 v/ k, `4 O+ b2 p7 \asm
) D* f  E3 b* ^, o& WCALL @1
  s: J2 i0 h- o# KJMP @EXIT0 G# g' q" T7 `2 p+ E% \
@1:
& P" E( [( o. H7 j2 \MOV EAX,1
' y& M0 H' E1 tMOV SN,EAX/ a  I# \/ I% r3 i- Q7 }8 M
RETN3 @& B) Z+ X0 d  G; R6 P
@exit:
. v- G$ M$ W9 O; g' }end;
4 O  ]9 [" X( Dcall的第二种用法,在汇编代码中直接调用FUNCTION函数,如:
) H: Q2 c, i$ c$ Efunction cacl(eax: integer):integer;
$ G( |1 H, b5 P! @* [) J6 {var7 b3 |6 t. @0 p, j) P" N
...3 h3 u/ O% o7 O; S1 |) ?5 Y0 z$ s
begin
# {5 J3 X9 y# f: j9 M0 d6 j8 h$ Q..../ ?" P% u! [# P/ e. {
Result:=code;2 r) ?# d* o/ @* [2 P0 ?2 s
end; 5 p4 O" d& Y& K1 ^8 T& p3 Y
调用时可以直接CALL CACL:
# b# m& T7 W3 nASM
2 L7 Y, w$ F3 t' \; Z! {CALL CACL
3 |: y) x$ [, {1 k...
/ N, X# Z) |  O, h  }1 ?( S8 OEND
; b4 v" P, g! T, H) V- j5 Z% w编语句中的Call语句,可以用于调用其它过程,既可以是其它汇编程序段也可以是Delphi中的标准过程:
) [, J$ |8 j  r5 q9 a  例如:假设新建一个窗体并在上面加了一个按钮,在Click事件中写入以下代码/ h9 J1 u7 o, g( ?( W5 W4 E( a
  procedure TForm1.Button1Click(Sender: TObject);
' ^: `" W: G, y% I4 d. ~) G+ f) z+ R2 o  begin
# f  v+ e% c) g3 }: Z' U   showmessage(`ok');
" U/ C$ r4 L; R2 N! ~) j  end;2 J- g7 Y- i/ F2 t: ~+ a5 \
  再写一个过程_X" R1 v& U8 l% t# Q, c
  function TForm1._x(var i:smallint):integer;
' F1 h" S# F) ]2 Q  asm
3 V: L! R' f/ I1 n1 g/ t% ?. d   call button1click4 y# t5 |8 C4 F/ l0 e3 Z
  end;6 V; e$ t$ [! g" i
  执行_x的结果就可以显示消息框。8 E, k  @* O: {- P0 [8 q) g2 L7 F0 M+ z
五、调用API函数" k# H3 X( b3 M& I# s' D
DELPHI内联汇编中调用API函数函数非常简单,比如调用PostQuitMessage:, h1 B( D1 z; p) N' K
Asm
7 z) h; B' N5 VPush 0
, t2 }1 X. l( m$ `  ]4 CCall PostQuitMessage(或Call SYSTEM.PostQuitMessage)
. _9 [" }$ B6 K8 nEnd
0 {+ t! B& |8 n3 w% i8 G调用MessageBox函数:2 q3 W5 d  O  z9 `! j9 ^4 \
procedure TForm1.Button2Click(Sender: TObject);
( O' n( d: R# f' I) N5 r$ x4 {; |  var
9 i) S. F5 k7 Q   szTitle:string;
" }( a, N0 U+ i: x' D- z   szCaption:string;
7 Q1 E! W' E9 K, _% k5 r5 A  begin
- O0 Q  n; i; [   szTitle:='您好!';
4 n7 R  o' A& G4 b1 z* e  T   szCaption:='这是一个在内嵌汇编中调用stdcall类型函数的例子.';
- V! e9 N6 ^: \) h% Q/ B   asm
3 ]& |1 J7 p4 N  }    PUSH MB_OK+MB_ICONINFORMATION2 N' a$ H9 j& W$ y& D$ A0 Y( Z
    PUSH szTitle: |# g$ X6 }, G
    PUSH szCaption) M6 ]; o+ m5 k7 m- H4 q- i
    PUSH 0- F  v- I" e1 {& r  R* R1 c
    CALL MessageBox& L7 m6 @! c- C- U. n
   end;
) M) P$ |" Z- n* ^% ~  end;4 g# K, S8 S8 F! Q
调用GetFileSize函数
) x7 A) W3 B0 Z% r7 o  bfunction stdcalldemo: Integer;
1 H7 Q1 f. l) P( a( H9 q# W# `$ Jvar
* D: d7 p& K, `FH: THandle;: @8 r: P1 L; G8 Y
begin
8 F/ v5 u6 D  U7 q9 gFH:= FileOpen(’c: oot.ini’,fmOpenRead);
* q& I+ u2 ~+ Q/ r; Dasm
" ]+ b. p0 [5 a: F" O- V9 lpush 0* k' M$ P+ C2 ?$ B6 n3 ^- p
push FH1 S. s! ^3 e' b8 A) _/ a
call GetFileSize
' X/ J: y9 C; e/ }3 b0 wmov @Result,eax
" b+ W! y  i# @8 nend;
  n. y- }8 O/ d4 ~Result:= GetFileSize(FH,0);//此句就相当于上面的汇编调用方式
3 E+ ], B& a( A) gFileClose(FH);
% J& u7 d; x! M' q0 eend;
) Y/ n" z! z9 }* G0 \procedure TForm1.Button1Click(Sender: TObject);
" H) a& B" V$ d5 c9 f1 o+ Dbegin
( F6 [, j; @( T& A+ b2 ishowmessage(IntToStr(stdcalldemo));
: e2 F% N( }% `: M! Bend;7 S/ ?2 D' d( D: f, |- j5 U
六、汇编的调试。! Q$ J6 k& x2 Q& R
如果发现汇编通不过,就要注意停下后的位置的代码:如变量的跟踪、断点、堆栈查看……可以在关键代码处下断,停下后打开View菜单的Debug Windows的CPU VIEW窗口,F8单步跟踪。如:1 S" H  |% v8 @! e3 j
Unit1.pas.62:     PUSH MB_OK+MB_ICONINFORMATION
5 B) i/ g+ i, N* P00455E8F 6A40 push $409 ]3 u1 o" o  X6 D; O0 X
Unit1.pas.63:     PUSH szTitle
$ e6 t# o& v- s5 r00455E91 FF75FC push dword ptr [ebp-$04]4 m& B( W# v& g) F' R' s- A* {
Unit1.pas.64:     PUSH szCaption# P) O* R4 o5 Z9 w3 e4 Q
00455E94 FF75F8 push dword ptr [ebp-$08]
" n6 J0 j; J5 B1 y4 Z" AUnit1.pas.65:     PUSH 0  a) P; l) l3 A5 s+ c% A
00455E97 6A00 push $00
5 B# l- ^0 ~  X, t; n1 e2 wUnit1.pas.66:     CALL MessageBox7 }5 |- h  O7 f) `
00455E99 E8FA0DFBFF call MessageBox3 D+ h: P; `1 J+ @& {/ c" F
Unit1.pas.69:   end;3 v# D: e& A1 E: U; r- f- ?0 _7 x4 ~0 j
00455E9E 33C0 xor eax,eax
2 l% E9 B+ K/ C! b; K8 t7 r) H  {- S七、常见易错语句。
! g2 _' v/ a3 T2 O0 ^MOV ESI,DOWRD PTR SS:[TEXT] 对(TEXT为STRING)3 [8 u% M; r7 b7 O6 m8 \; C
MOV ESI,DOWRD PTR [TEXT] 对(段寄存器CS,DS,SS,ES可省略)7 [% ]7 [! ~+ G" j( ]
MOV AL,DOWRD PTR SS:[TEXT] 错(DWORD为32位)
7 S1 o! G- j2 S  JMOV AL,BYTE PTR [TEXT] 对
& Q7 W! h. @1 TMOV EAX,BYTE PTR [TEXT] 错(DWORD为8位)
2 \4 j/ ^% A( ?6 V" R: i( EMOV AL,WORD PTR [TEXT] 错(DWORD为16位). D7 G+ S( d' I. D
MOV EAX,WORD PTR [TEXT] 错
+ }# M  d# ^$ t* lMOV AX,WORD PTR [TEXT] 对5 _6 X) k3 f: k$ `: L- Q
MOV [A],EAX+ K% E1 L- U* w7 p' P6 e
MOV BYTE PTR[EDI],'A'
" ?3 b, t& n( c5 i1 bMOV AL,[EDI]0 H4 @7 m1 r+ ^3 ^
MOV EAX,X //X指向的值赋值给EAX
: c2 R+ f7 F6 ^7 q" ^: d# e3 _7 BMOV EAX,[EAX] //X指向的地址赋值给EAX
* V& g& U1 {9 ^: _7 M  kMOV DOWRD PTR[ESP],EAX 对
# @8 M! K4 G& t% IMOV DOWRD PTR[ECX],EAX 对
& @  O: `- o  E6 _MOV DOWRD PTR[ECX+4],EAX 对
1 m- ~' D1 d- l" s" v2 D6 @1 VMOV DOWRD PTR[ECX+EDI],EAX 对
3 J1 H$ ?* `" K* g5 v, @) QMOV DOWRD PTR[ESI],EAX 错! t3 ~' t8 D0 }: t# w& g7 k6 W
MOV DOWRD PTR[EDX],EAX 错. G4 d" n9 W  e4 O# R
MOV DOWRD PTR[EBX],EAX 错3 p3 A) K4 A6 K, E% H7 N9 P8 a

) Z. d9 R9 r5 I' T' K1 P" ]0 h) I
后期资源网,打造没有广告、免除隐藏回复的全开放式影视技术交流平台。 你的所求就是我们服务的宗旨!!!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

GMT+8, 2024-5-23 22:12 , Processed in 0.118088 second(s), 20 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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