在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
DELPHI内联汇编好象有得天独厚的优势,尤其是API的调用,处理好各成员参数后,可以直接CALL API名称。利用内联汇编我们可以为程序添加各种异常,添加反调试代码,添加花指令,还可以令某些难写的注册机简单化等.我把DELPHI内联汇编的一点点使用心得写出来,目的是想与大家交流,挖掘更多的这方面的领域。也希望大家能够指正一些错误。
一、 数据格式 整型数据: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 返回内存地址中的立即数 [....] 返回内存地址,与OFFSET相反,如:MOV EAX,OFFSET [XXXX]=MOV EAXX,[OFFSET XXXX]=MOV EAX,XXXX HIGH 返回高8位的立即数 LOW 返回低8位的立即数 & 防止变量与汇编中的寄存器同名而在前面加& 号,如: 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; 一个简单加法函数: FUNCTION SUM(X,Y:INTEGER):INTEGER; BEGIN ASM MOV EAX,X ADD EAX,Y MOV @RESULT,EAX END; END; Byte转换为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 以及协处理器寄存器堆栈 ST 一个ASM statement 必须保护EDI,ESI,ESP,EBP和EBX寄存器,但是可以自由的修改EAX,ECX和EDX寄存器。 默认情况下,delphi使用“register”方式,若参数在3个以内, 将分别使用eax、edx和ecx,如果超过三个,则用堆栈传递。返回参数的存放视长度而定,例如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的应用 在汇编中写代码要保存寄存器现场(保存使用前的寄存器状态,使用Push压栈和Pop从栈中弹出),不过这一切对于Delphi的嵌入式汇编是没有必要的(除非你自己要使用Push和Pop),因为Delphi已经帮你做了,不必担心会使数据丢掉。 DELPHI内联汇编中同样可以用汇编中CALL的功能。 比如: asm CALL @1 JMP @EXIT @1: MOV EAX,1 MOV SN,EAX RETN @exit: end; call的第二种用法,在汇编代码中直接调用FUNCTION函数,如: function cacl(eax: integer):integer; var ... begin .... Result:=code; end; 调用时可以直接CALL CACL: ASM CALL CACL ... END 编语句中的Call语句,可以用于调用其它过程,既可以是其它汇编程序段也可以是Delphi中的标准过程: 例如:假设新建一个窗体并在上面加了一个按钮,在Click事件中写入以下代码 procedure TForm1.Button1Click(Sender: TObject); begin showmessage(`ok'); end; 再写一个过程_X function TForm1._x(var i:smallint):integer; asm call button1click end; 执行_x的结果就可以显示消息框。 五、调用API函数 DELPHI内联汇编中调用API函数函数非常简单,比如调用PostQuitMessage: Asm Push 0 Call PostQuitMessage(或Call SYSTEM.PostQuitMessage) End 调用MessageBox函数: procedure TForm1.Button2Click(Sender: TObject); var szTitle:string; szCaption:string; begin szTitle:='您好!'; szCaption:='这是一个在内嵌汇编中调用stdcall类型函数的例子.'; asm PUSH MB_OK+MB_ICONINFORMATION PUSH szTitle PUSH szCaption PUSH 0 CALL MessageBox end; end; 调用GetFileSize函数 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);//此句就相当于上面的汇编调用方式 FileClose(FH); end; procedure TForm1.Button1Click(Sender: TObject); begin showmessage(IntToStr(stdcalldemo)); end; 六、汇编的调试。 如果发现汇编通不过,就要注意停下后的位置的代码:如变量的跟踪、断点、堆栈查看……可以在关键代码处下断,停下后打开View菜单的Debug Windows的CPU VIEW窗口,F8单步跟踪。如: 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 错 |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论