DELPHI內(nèi)聯(lián)匯編好象有得天獨厚的優(yōu)勢,尤其是API的調(diào)用,處理好各成員參數(shù)后,可以直接CALL API名稱。利用內(nèi)聯(lián)匯編我們可以為程序添加各種異常,添加反調(diào)試代碼,添加花指令,還可以令某些難寫的注冊機簡單化等.我把DELPHI內(nèi)聯(lián)匯編的一點點使用心得寫出來,目的是想與大家交流,挖掘更多的這方面的領(lǐng)域。也希望大家能夠指正一些錯誤。
一、 數(shù)據(jù)格式
整型數(shù)據(jù):8位的用AL返回,16位的用AX返回,32位的用EAX返回。
BYTE(8位):BYTE、CHAR、SHORTINT、BOOLEAN
WORD(16位): SMALLINT、WORD
DWORD(32位):INTEGER、LONGWORD、ANSISTRING、POINTER、CLASS、LONGINT、STRING
ST(0):SINGLE、DOUBLE、EXTENDED、COM
如:
var
ByteVar: Byte;
WordVar: Word;
IntVar: Integer;
begin
asm
MOV AL,ByteVar
MOV BX,WordVar
MOV ECX,IntVar
end;
end;
實型:用ST(0)返回
指針:用EAX返回
長字符串:用EAX返回其所在地址
變量:可用@Result返回
16進制的表示方式:
如果是0-9開頭的16進制值直接在后面加H或在前面加$號,如:1AH,$1A
如果是字母開頭的前面加0再在后面跟H,或者直接用$號,如:0AH,$A
幾個修飾符:
OFFSET 返回內(nèi)存地址中的立即數(shù)
[....] 返回內(nèi)存地址,與OFFSET相反,如:MOV EAX,OFFSET [XXXX]=MOV EAXX,[OFFSET XXXX]=MOV EAX,XXXX
HIGH 返回高8位的立即數(shù)
LOW 返回低8位的立即數(shù)
& 防止變量與匯編中的寄存器同名而在前面加& 號,如:
EAX:INTEGER; ...
MOV &EAX,10H 這里的&EAX不是EAX寄存器
. .號的一種用法:
var
STR: Word; ..
MOV DL,STR.Byte或DL,Byte(STR)
二、 嵌入式匯編的格式
Delphi是使用ASM……END來標志匯編語句
如:
ASM
mov al,1
mov bl,al
END;
一個簡單加法函數(shù):
FUNCTION SUM(X,Y:INTEGER):INTEGER;
BEGIN
ASM
MOV EAX,X
ADD EAX,Y
MOV @RESULT,EAX
END;
END;
Byte轉(zhuǎn)換為16進制字符串:
function ByteToHex(Src: Byte): String;
begin
SetLength(Result, 2);
asm
MOV EDI, [Result]
MOV EDI, [EDI]
MOV AL, Src
MOV AH, AL // Save to AH
SHR AL, 4 // Output High 4 Bits
ADD AL, '0'
CMP AL, '9'
JBE @@OutCharLo
ADD AL, 'A'-'9'-1
@@OutCharLo:
AND AH, $f
ADD AH, '0'
CMP AH, '9'
JBE @@OutChar
ADD AH, 'A'-'9'-1
@@OutChar:
STOSW
end;
end;
三、 可用的寄存器
32位寄存器EAX EBX ECX EDX ESP EBP ESI EDI
16位寄存器AX BX CX DX SP BP SI DI
8位寄存器AL BL CL DL(低8位) AH BH CH DH(高8位)
16位段寄存器CS DS SS ES
32位段寄存器 FS GS
以及協(xié)處理器寄存器堆棧 ST
一個ASM statement 必須保護EDI,ESI,ESP,EBP和EBX寄存器,但是可以自由的修改EAX,ECX和EDX寄存器。
默認情況下,delphi使用“register”方式,若參數(shù)在3個以內(nèi), 將分別使用eax、edx和ecx,如果超過三個,則用堆棧傳遞。返回參數(shù)的存放視長度而定,例如8位用al返回,16位用ax,32位用eax,64位用用兩個32位寄存器edx:eax,其中eax是低位。如果你想用EBX寄存器,接得這樣寫:
asm
push ebx
mov ebx,2
mov IntVar,ebx
pop ebx
end;
如:FUNCTION(T1,T2,T3:INTEGER):INTEGER,可以默認為T1存在EAX中,T2存在EDX中,T3存在ECX中。
DELPHI的標簽名一般都以@開頭,比如@exit、@001等
四、 CALL的應(yīng)用
在匯編中寫代碼要保存寄存器現(xiàn)場(保存使用前的寄存器狀態(tài),使用Push壓棧和Pop從棧中彈出),不過這一切對于Delphi的嵌入式匯編是沒有必要的(除非你自己要使用Push和Pop),因為Delphi已經(jīng)幫你做了,不必擔(dān)心會使數(shù)據(jù)丟掉。
DELPHI內(nèi)聯(lián)匯編中同樣可以用匯編中CALL的功能。
比如:
asm
CALL @1
JMP @EXIT
@1:
MOV EAX,1
MOV SN,EAX
RETN
@exit:
end;
call的第二種用法,在匯編代碼中直接調(diào)用FUNCTION函數(shù),如:
function cacl(eax: integer):integer;
var
...
begin
....
Result:=code;
end;
調(diào)用時可以直接CALL CACL:
ASM
CALL CACL
...
END
編語句中的Call語句,可以用于調(diào)用其它過程,既可以是其它匯編程序段也可以是Delphi中的標準過程:
例如:假設(shè)新建一個窗體并在上面加了一個按鈕,在Click事件中寫入以下代碼
procedure TForm1.Button1Click(Sender: TObject);
begin
showmessage(`ok');
end;
再寫一個過程_X
function TForm1._x(var i:smallint):integer;
asm
call button1click
end;
執(zhí)行_x的結(jié)果就可以顯示消息框。
五、調(diào)用API函數(shù)
DELPHI內(nèi)聯(lián)匯編中調(diào)用API函數(shù)函數(shù)非常簡單,比如調(diào)用PostQuitMessage:
Asm
Push 0
Call PostQuitMessage(或Call SYSTEM.PostQuitMessage)
End
調(diào)用MessageBox函數(shù):
procedure TForm1.Button2Click(Sender: TObject);
var
szTitle:string;
szCaption:string;
begin
szTitle:='您好!';
szCaption:='這是一個在內(nèi)嵌匯編中調(diào)用stdcall類型函數(shù)的例子.';
asm
PUSH MB_OK+MB_ICONINFORMATION
PUSH szTitle
PUSH szCaption
PUSH 0
CALL MessageBox
end;
end;
調(diào)用GetFileSize函數(shù)
function stdcalldemo: Integer;
var
FH: THandle;
begin
FH:= FileOpen(’c: oot.ini’,fmOpenRead);
asm
push 0
push FH
call GetFileSize
mov @Result,eax
end;
Result:= GetFileSize(FH,0);//此句就相當于上面的匯編調(diào)用方式
FileClose(FH);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
showmessage(IntToStr(stdcalldemo));
end;
六、匯編的調(diào)試。
如果發(fā)現(xiàn)匯編通不過,就要注意停下后的位置的代碼:如變量的跟蹤、斷點、堆棧查看……可以在關(guān)鍵代碼處下斷,停下后打開View菜單的Debug Windows的CPU VIEW窗口,F(xiàn)8單步跟蹤。如:
Unit1.pas.62: PUSH MB_OK+MB_ICONINFORMATION
00455E8F 6A40 push $40
Unit1.pas.63: PUSH szTitle
00455E91 FF75FC push dword ptr [ebp-$04]
Unit1.pas.64: PUSH szCaption
00455E94 FF75F8 push dword ptr [ebp-$08]
Unit1.pas.65: PUSH 0
00455E97 6A00 push $00
Unit1.pas.66: CALL MessageBox
00455E99 E8FA0DFBFF call MessageBox
Unit1.pas.69: end;
00455E9E 33C0 xor eax,eax
七、常見易錯語句。
MOV ESI,DOWRD PTR SS:[TEXT] 對(TEXT為STRING)
MOV ESI,DOWRD PTR [TEXT] 對(段寄存器CS,DS,SS,ES可省略)
MOV AL,DOWRD PTR SS:[TEXT] 錯(DWORD為32位)
MOV AL,BYTE PTR [TEXT] 對
MOV EAX,BYTE PTR [TEXT] 錯(DWORD為8位)
MOV AL,WORD PTR [TEXT] 錯(DWORD為16位)
MOV EAX,WORD PTR [TEXT] 錯
MOV AX,WORD PTR [TEXT] 對
MOV [A],EAX
MOV BYTE PTR[EDI],'A'
MOV AL,[EDI]
MOV EAX,X //X指向的值賦值給EAX
MOV EAX,[EAX] //X指向的地址賦值給EAX
MOV DOWRD PTR[ESP],EAX 對
MOV DOWRD PTR[ECX],EAX 對
MOV DOWRD PTR[ECX+4],EAX 對
MOV DOWRD PTR[ECX+EDI],EAX 對
MOV DOWRD PTR[ESI],EAX 錯
MOV DOWRD PTR[EDX],EAX 錯
MOV DOWRD PTR[EBX],EAX 錯
.....
比較詳細的例子可以看一下
http://bbs./showthread.php?s=&threadid=26382
http://bbs./showthread.php?s=&postid=222986#post222986
里的注冊機代碼,更多的內(nèi)容還需要你補充…。