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

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

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

[复制链接]
发表于 2013-1-4 11:37:28 | 显示全部楼层 |阅读模式
Delphi内联汇编好象有得天独厚的优势,尤其是API的调用,处理好各成员参数后,可以直接CALL API名称。利用内联汇编我们可以为程序添加各种异常,添加反调试代码,添加花指令,还可以令某些难写的注册机简单化等.我把Delphi内联汇编的一点点使用心得写出来,目的是想与大家交流,挖掘更多的这方面的领域。也希望大家能够指正一些错误。
% A+ `) {: v7 ]  ~9 y6 a* Z, g4 F! H. A4 N$ E% B& q, K
一、 数据格式
. r- A, l! V  L. F6 O整型数据:8位的用AL返回,16位的用AX返回,32位的用EAX返回。; U* D7 X, e* W1 i6 w5 v& c$ Y
BYTE(8位):BYTE、CHAR、SHORTINT、BOOLEAN 6 O$ Y6 H- \8 L9 `; z: `0 C
WORD(16位): SMALLINT、WORD9 d4 \: v9 b5 G, _. V' }
DWORD(32位):INTEGER、LONGWORD、ANSISTRING、POINTER、CLASS、LONGINT、STRING  T' _! i2 t- q9 _) Z7 ^) `5 |
ST(0):SINGLE、DOUBLE、EXTENDED、COM6 a" k. Y+ x( _* x+ s; G9 H. s
如:
' H" @' a5 E3 j( O  _var; b3 i/ @% p# j, w  [
ByteVar: Byte;
1 a, r8 \! W: dWordVar: Word;3 U" W- u# q/ ?+ R! d2 ^; p3 T
IntVar: Integer;/ Z! r1 _! s9 N' d& b
begin
( E/ p3 }2 P8 I% _1 ]" U6 u# Yasm6 G8 K( `( A; r- C
MOV AL,ByteVar( l3 L( r, ^/ G. z. \; B
MOV BX,WordVar6 E2 `- }9 r/ E3 N  _& o
MOV ECX,IntVar
. S2 e7 L4 F, Qend;1 g+ f6 y5 F) H! [
end;
, K6 p- |2 U4 m! t) G) v实型:用ST(0)返回' I7 |$ A& f% s! ?
  指针:用EAX返回: X  ~  W! l7 m9 d2 ?) D, H
  长字符串:用EAX返回其所在地址
) Q. J; v  i) v+ V( X& C$ K' {  变量:可用@Result返回
3 z3 {  |, ^6 C9 Z6 _5 @! Q4 f16进制的表示方式:
' T. {1 |9 C2 a1 e( C如果是0-9开头的16进制值直接在后面加H或在前面加$号,如:1AH,$1A( u% _" [7 l: W
如果是字母开头的前面加0再在后面跟H,或者直接用$号,如:0AH,$A
7 @7 K# G3 o( @; e- A几个修饰符:# D' N- U. C9 W  m$ B4 c9 c  a
OFFSET 返回内存地址中的立即数, [% o! N( B# S' P3 e/ ^* _, @
[....] 返回内存地址,与OFFSET相反,如:MOV EAX,OFFSET [XXXX]=MOV EAXX,[OFFSET XXXX]=MOV EAX,XXXX
& n4 S4 d- N0 W9 Z4 I, v- o/ I3 f+ g- jHIGH 返回高8位的立即数
3 W5 e* o  @0 zLOW 返回低8位的立即数
6 L- w6 J# |6 Z/ S! K& 防止变量与汇编中的寄存器同名而在前面加& 号,如:5 P  @$ e) D' h
EAX:INTEGER; ...8 M' b5 Y" \6 c* y, Y1 W6 J
MOV &EAX,10H 这里的&EAX不是EAX寄存器
; ?+ d5 t5 Y8 }( O4 Q: S3 g  g; W. .号的一种用法:. j- v/ `( E' ~4 v" @8 W
var / X& d9 h* @$ v5 z. }
STR: Word; ..; {) W' O& B' t7 I; l+ ]0 s/ f% `
MOV DL,STR.Byte或DL,Byte(STR); O( p8 w6 n# z, o# f& X7 q, p

( w& c8 q) \  d; c' d( K* Z0 F二、 嵌入式汇编的格式6 F! k4 j. W3 o' r4 [5 Z1 \0 Z
  Delphi是使用ASM……END来标志汇编语句( c+ Q. w0 X2 u: ^2 w$ Y# J
   如:
# x5 \8 p' f/ {3 `1 [ASM/ h$ [( _% C; d, c3 L5 h
   mov al,1/ e% _# X$ |4 q1 t4 o  m
   mov bl,al. S0 S# f# Z6 v7 U- f3 g5 G% m3 D
   END;
, l2 [+ p" i$ O2 t9 x一个简单加法函数:6 P/ P& V9 T' A# d+ ?3 p
FUNCTION SUM(X,Y:INTEGER):INTEGER;% z  e4 H% _' o$ ]
BEGIN- K4 B2 Y+ L' V# ?  M) K7 J# C3 y
ASM& Y  C: \# q- e0 t7 c' S) R" A
MOV EAX,X
! B2 p1 y$ X) P8 u% uADD EAX,Y2 R6 t) s8 s! y# L3 @4 n- V
MOV @RESULT,EAX
1 |( C* Y/ {& Z0 N7 `5 F# ]END;
+ e% {% [; X# ]1 fEND;- X( g% x, G% S' c0 R4 I; T" A
Byte转换为16进制字符串:
1 J1 j6 K4 p; R) f+ B6 Efunction ByteToHex(Src: Byte): String;: O6 s, E3 E6 |
begin
3 E) J3 A  v1 r/ y/ H. KSetLength(Result, 2);+ `. T, \' X2 H7 z( F5 C$ e
asm
2 O; ^" f+ ~3 W9 y3 ^# kMOV EDI, [Result]
% o% M( `8 i* B# N0 ~) ]MOV EDI, [EDI]; Y* L# k. \8 {) X9 o9 ~- D+ j* p
MOV AL, Src
* _; c- c4 v* g9 T- T" sMOV AH, AL // Save to AH
% m- T; M" V; M; _+ G4 I' HSHR AL, 4 // Output High 4 Bits
4 E  `* j! W* D, b3 HADD AL, '0'9 g1 w4 L0 L+ b5 k' e4 l2 k3 f
CMP AL, '9'7 r% J+ w. e  S2 U, R( u
JBE @@OutCharLo% z- w- U( E( S2 l+ F+ l+ O1 D6 a
ADD AL, 'A'-'9'-1
5 R: ]; ~# R+ w, h@@OutCharLo:2 C+ H2 P6 L3 h2 v2 ?( o' |) T
AND AH, $f
9 W7 Z! e1 Q) u- ~) MADD AH, '0'
; u! ?  V2 F8 q( jCMP AH, '9'7 t: B7 W/ `, G- ~1 q
JBE @@OutChar$ O% a2 G4 W/ X7 o& p
ADD AH, 'A'-'9'-1
8 W* W4 I2 l1 a) e4 W@@OutChar:4 o5 I& v$ @( T
STOSW
6 ~4 Q6 p* m1 ]1 T* |/ ?2 x# Jend;
) W' t, u( x8 ?8 I8 [end;6 E& M) m/ o5 v8 [; l0 X2 Z  e
三、 可用的寄存器+ F6 F  M! Z$ {( n; c2 {! @. N
32位寄存器EAX EBX ECX EDX ESP EBP ESI EDI  d$ b: b5 N- g& K
 16位寄存器AX BX CX DX SP BP SI DI! s& ~- ]; u9 i$ I/ {4 J: I# ?9 [
 8位寄存器AL BL CL DL(低8位) AH BH CH DH(高8位)! ]+ s# z, Q2 S8 M! e! `
 16位段寄存器CS DS SS ES  J! N, f6 M0 A
32位段寄存器 FS GS  l3 p0 J  W$ Z& ^7 _# l& `+ ?
 以及协处理器寄存器堆栈 ST+ o0 W, l- k5 X" c9 q
一个ASM statement 必须保护EDI,ESI,ESP,EBP和EBX寄存器,但是可以自由的修改EAX,ECX和EDX寄存器。* b- G( y- T7 w5 G, r6 Y% i
默认情况下,delphi使用“register”方式,若参数在3个以内, 将分别使用eax、edx和ecx,如果超过三个,则用堆栈传递。返回参数的存放视长度而定,例如8位用al返回,16位用ax,32位用eax,64位用用两个32位寄存器edx:eax,其中eax是低位。如果你想用EBX寄存器,接得这样写:. B! }$ _1 i- ]7 Z9 K/ }
asm5 c- ?: a7 L5 m0 B9 ~1 S& m7 Z& ^
push ebx
* d( x8 g2 d+ ^* E2 G' emov ebx,2
" [5 v# a4 n: l" @mov IntVar,ebx$ @" n# n$ d0 I; G# G1 ?
pop ebx- a" b  v) Y' h
end;1 ^; m: b$ T: x/ ~: s9 P( x
如:FUNCTION(T1,T2,T3:INTEGER):INTEGER,可以默认为T1存在EAX中,T2存在EDX中,T3存在ECX中。" @% {5 |1 V: e5 @7 M
DELPHI的标签名一般都以@开头,比如@exit、@001等, U1 a! f& f: w. x
四、 CALL的应用
9 l% J2 \' d* i/ |9 x5 s在汇编中写代码要保存寄存器现场(保存使用前的寄存器状态,使用Push压栈和Pop从栈中弹出),不过这一切对于Delphi的嵌入式汇编是没有必要的(除非你自己要使用Push和Pop),因为Delphi已经帮你做了,不必担心会使数据丢掉。
% r. ^" T: f* r0 r6 y5 JDELPHI内联汇编中同样可以用汇编中CALL的功能。
9 c7 Y; c4 \2 H( l' Q7 M2 q/ A比如:' y! Z/ @& h$ \( c4 v- a0 d& \
asm
$ ?7 O* h4 J! R& VCALL @1
) |3 E1 o- n9 w- [! wJMP @EXIT! r; a5 N- Y9 ~- K2 X
@1:
! H( T# B' O2 k' Q- [6 n' pMOV EAX,1
6 D" O2 o: v( O$ R) L" eMOV SN,EAX# o0 F" c1 s4 n  y, K% l
RETN5 k( r  f+ \( [* @0 ?
@exit:: X( {: K# i, Z6 x% v- T
end;% D' P& |, x3 r* P
call的第二种用法,在汇编代码中直接调用FUNCTION函数,如:
8 C0 H% g. H) m2 T' R; a1 ]. Ifunction cacl(eax: integer):integer;+ M& V3 u# {1 k! D1 s% K  l
var! W4 T* V/ l+ m: E
...
. g: i' V& d0 Wbegin
8 r" Q8 x# J2 }) @....
, Y. |6 L. y& G% ]" ~$ I% K4 N" T. lResult:=code;
9 @5 {/ v% s# |end; - X$ t3 Q. U: K  g: V7 M& ?
调用时可以直接CALL CACL:
) q) B3 j( h$ b4 g9 V" k3 d/ c8 _) \ASM
/ ~0 q) _0 f% M2 bCALL CACL
0 P1 y" @/ z0 _..." l  X  T, `* h
END
$ Y  i  Y! g/ y2 l8 F. N; W0 Y  X编语句中的Call语句,可以用于调用其它过程,既可以是其它汇编程序段也可以是Delphi中的标准过程:- o1 G. {4 U9 X3 r6 L" O7 x
  例如:假设新建一个窗体并在上面加了一个按钮,在Click事件中写入以下代码
/ L) r: A7 \: D# J; \  procedure TForm1.Button1Click(Sender: TObject);. d4 U; W1 b6 \4 N
  begin
4 x) y9 H. h8 T. h, z   showmessage(`ok');1 s0 q. Z- b, o* H; G
  end;
3 \3 B( G; e; S( c  再写一个过程_X/ ]) D# Z- ^& P/ ]" n# j) _5 C# P
  function TForm1._x(var i:smallint):integer;
" e1 I" z; J5 q% p# n  asm9 N, E' G" `" L* ]0 \+ V# o
   call button1click
$ I; n& s8 ?' }( N4 Z  end;9 @" a9 o5 I! a; q( {9 f
  执行_x的结果就可以显示消息框。
+ ~; ~9 c9 Y9 z2 v, ~五、调用API函数- g% x" J+ D  C
DELPHI内联汇编中调用API函数函数非常简单,比如调用PostQuitMessage:
" C$ Y3 @% ^! Q2 ]# g7 KAsm0 i" W0 c! m+ c  u
Push 0: r/ J) _' j& g. k: s! r
Call PostQuitMessage(或Call SYSTEM.PostQuitMessage)
; J+ ~0 `9 q8 [; d6 sEnd
8 p( M) a; c8 y: s调用MessageBox函数:
7 s& R4 G: [) i6 [2 a1 Zprocedure TForm1.Button2Click(Sender: TObject);
2 P8 b& r- E" Z8 G# v& {- V& q  var
) e" C& T% N& O, y  z3 Q   szTitle:string;, I/ V5 i1 A4 @2 P) G
   szCaption:string;" y4 V' O( D% w$ H. n
  begin
5 l* A9 Q, k' c3 z6 ~! @0 ?   szTitle:='您好!';6 o  B8 }) r' V/ n% F
   szCaption:='这是一个在内嵌汇编中调用stdcall类型函数的例子.';& y$ z4 q7 w0 `; x7 G( `
   asm6 ^9 \9 m+ \/ i: w/ Z
    PUSH MB_OK+MB_ICONINFORMATION
3 ~* j, f# f2 j3 h    PUSH szTitle8 d0 w) \! l0 `, q: C. t
    PUSH szCaption- h2 t& r. n8 Z- K/ H% @( Y
    PUSH 0( k9 I' ^/ ?. i# F% z- X; R) Y
    CALL MessageBox
) w: F  d. W  ?6 _8 K5 w! o   end;
2 J3 W' H2 a' \( g  V" z. I  end;
( k0 |/ Z8 B; F# s8 z& R; C调用GetFileSize函数
0 k; L" B9 {$ o5 sfunction stdcalldemo: Integer;
* [% e* g7 u7 {5 c. V# hvar6 s& h4 K) g& {$ z! i# r/ e
FH: THandle;
  _3 E  P( j( g6 wbegin% m; r5 Q# t& d. h
FH:= FileOpen(’c: oot.ini’,fmOpenRead);9 J4 t$ [8 g' Q- [. y
asm
. a$ w, z7 @, m* o2 @, j" `push 0
/ o% u5 c6 r3 L; v) y0 f5 Opush FH
, r6 E: h1 G! R" D3 n. }call GetFileSize
: z! i# j5 A% B+ S0 {mov @Result,eax( g0 N0 R8 |/ c9 C) ~& D) r  ?
end; ' G  {% I- V# j; Y* W7 M$ @* ~
Result:= GetFileSize(FH,0);//此句就相当于上面的汇编调用方式' Q1 @* L/ B$ n# t
FileClose(FH);& t0 k7 m. a, l. ~# S
end;
* r! z7 }9 L( \  `' O. nprocedure TForm1.Button1Click(Sender: TObject);' ?$ V6 ~  G% p
begin
" L" C' n0 H4 e) h& ?/ jshowmessage(IntToStr(stdcalldemo));
5 @0 c5 Q# J1 F1 V9 t& U1 C% N, e6 m% rend;
5 r+ [2 ~, ?5 q+ M% P" Q六、汇编的调试。8 f  x& T6 I  X. i! S( C* v1 b' r, o) p
如果发现汇编通不过,就要注意停下后的位置的代码:如变量的跟踪、断点、堆栈查看……可以在关键代码处下断,停下后打开View菜单的Debug Windows的CPU VIEW窗口,F8单步跟踪。如:
+ P$ O/ \% R3 G; V/ SUnit1.pas.62:     PUSH MB_OK+MB_ICONINFORMATION
2 e" I. x' C7 ]. H2 U00455E8F 6A40 push $40
. Y: `9 a6 F& z0 z% KUnit1.pas.63:     PUSH szTitle1 Z) W+ H- s2 E  ?, V
00455E91 FF75FC push dword ptr [ebp-$04]9 n8 I- X9 F6 q) x0 E
Unit1.pas.64:     PUSH szCaption6 j9 U; |' p- O) I
00455E94 FF75F8 push dword ptr [ebp-$08]- w1 \* z. t" X$ j1 ?) k' }- G9 \: u
Unit1.pas.65:     PUSH 07 V: t* V% {5 ~( D+ F: L
00455E97 6A00 push $00
1 u) g2 ~1 E- ]+ p# QUnit1.pas.66:     CALL MessageBox9 n6 S  v  B5 F% R
00455E99 E8FA0DFBFF call MessageBox
6 [, e* F% S$ AUnit1.pas.69:   end;; }5 {; R# E& ~' n- Z5 ^, V
00455E9E 33C0 xor eax,eax9 `6 C& h5 r3 {" S
七、常见易错语句。
: F- k6 V4 L. B9 v4 _MOV ESI,DOWRD PTR SS:[TEXT] 对(TEXT为STRING)5 F/ }$ B6 H5 z! W" N
MOV ESI,DOWRD PTR [TEXT] 对(段寄存器CS,DS,SS,ES可省略)+ Y. [$ ?" y; e* n0 s
MOV AL,DOWRD PTR SS:[TEXT] 错(DWORD为32位)) E$ n1 z  u# E7 |' q6 d: N
MOV AL,BYTE PTR [TEXT] 对
3 p# ~0 @5 h& e2 \, F: UMOV EAX,BYTE PTR [TEXT] 错(DWORD为8位)5 k( h' ^- T5 |2 W
MOV AL,WORD PTR [TEXT] 错(DWORD为16位)
% l/ d! R* I' t; d/ |1 C$ |  K6 D4 dMOV EAX,WORD PTR [TEXT] 错! L& \7 l3 c' G( G3 _& J
MOV AX,WORD PTR [TEXT] 对  V8 C& k0 m4 D! ^  V) A
MOV [A],EAX2 `- A' t' p& H. E) ~. i1 O
MOV BYTE PTR[EDI],'A'! o% B" O  X) j: H# o: L* H
MOV AL,[EDI]
( o1 r( t( [! y1 i: P" vMOV EAX,X //X指向的值赋值给EAX
, v% T9 t5 Z2 D. }/ X! Q/ \MOV EAX,[EAX] //X指向的地址赋值给EAX
; f2 u, W! u) M, G( ?# q3 N, sMOV DOWRD PTR[ESP],EAX 对# c- U2 k  s& W! t3 r# A+ V
MOV DOWRD PTR[ECX],EAX 对9 l; ?+ f* F* Z
MOV DOWRD PTR[ECX+4],EAX 对$ Z# @) l- q7 X5 z8 [
MOV DOWRD PTR[ECX+EDI],EAX 对6 [: W0 S, A8 Z# n0 X6 y7 F
MOV DOWRD PTR[ESI],EAX 错3 i% F; V& N6 A6 B6 o
MOV DOWRD PTR[EDX],EAX 错
9 R& ?, W' b; JMOV DOWRD PTR[EBX],EAX 错; n1 v+ a8 @4 t' |2 O% _

$ \' a; T' F" s
后期资源网,打造没有广告、免除隐藏回复的全开放式影视技术交流平台。 你的所求就是我们服务的宗旨!!!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

GMT+8, 2024-5-20 13:38 , Processed in 0.125016 second(s), 21 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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