¤¤¤解释执行stdcall规范的API函数¤¤¤
蓝色光芒 2004-11-26 01:09:39 本文介绍如何让你的脚本解释程序解释执行stdcall规范的API函数
你需要有汇编语言基础,在编写动态调用API程序的时候才用得到,
不废话了开始!
调用API的关键所在就是接口的整理,比如我们在Delphi里面调用API
如:
TSendMessage = Function(hWnd: HWND;
Msg: UINT;
wParam: WPARAM;
lParam: LPARAM): LRESULT; stdcall;
Var
SMG : TSendMessage;
SMG := GetProcAddress(...);
然后我们就可以调用SendMessage函数了,但是我们想一想,如果我们
要写自己的解释程序,难道什么接口我们都在Delphi里定义好,这显然
不正确,因此就有了本文的研究。
本文的核心:让你的程序适应在不需要事先定义任何接口的情况下,根
据用户自定义的接口调用几乎所有形式的stdcall规范的API函数。
//定义API最多的参数个数,如果换动态数组就不需要了
Const
APIParamaMax = 10;
APIParamaSize = 8;
Type
//API参数描述
TAPIParama = Record
ParamType : LongWord; //参数类型
Address : Pointer; //参数地址
end;
PAPIParama = ^TAPIParama;
TAPIParamList = array of TAPIParama; //参数列表
PAPIParamList = ^TAPIParamList; //列表指针
一看TAPIParama的定义,估计很多朋友就明白了,我们需要分两步走,
第一步,整理用户的调用数据,第二步根据这个列表调用API函数
我们再定义一些常量
{API Param Types}
atNULL = $000; //作为返回值类型时,舍弃返回值
atByte = $001;
atShortint = $002;
atSmallint = $003;
atWord = $004;
atInteger = $005;
atLongWord = $006;
atLongint = $007;
atCardinal = $008;
atInt64 = $009;
atReal = $00A;
atSingle = $00B;
atReal48 = $00C; //放弃
atDouble = $00D;
atComp = $00E;
atCurrency = $00F;
atExtended = $010;
atVarPointer = $011;
atBoolean = $012;
atLongBOOL = $013;
atObject = $014;
atProgram = $100; //保存的是API函数地址
atPointer = $101;
OK,我们开始弄程序
调用API的主程序
procedure DOAPI(ParamList : PAPIParamList ; //一个参数列表
APIProc , //保存API地址的
ReturnPara : PAPIParama); stdcall;
//ReturnPara 如果API是函数并且需要返回值 否则设置成NIL
implementation
//ParamList参数整理过程,这里是处理各种API参数的
//根据TAPIParama.ParamType的值来处理参数
//EBX 为参数的指针地址,即PAIPParama
//ECX,EDX 在过程中被使用,使用前请保护ECX,EDX的值,如果ECX,EDX的值需要保护
procedure InitParam;stdcall;
asm
CMP EBX , $0; //参数是否=NIL
JZ @ExitThisProc;
CMP DWORD PTR [EBX] , atPointer; //atPointer模式
JZ @JPPointer;
CMP DWORD PTR [EBX] , atInteger; //atInteger模式
JZ @IntegerMode;
CMP DWORD PTR [EBX] , atReal; //Real模式
JZ @RealMode;
CMP DWORD PTR [EBX] , atByte; //Byte模式 处理过程和Integer一样
JZ @IntegerMode;
CMP DWORD PTR [EBX] , atShortInt; //ShortInt模式 处理过程和Integer一样
JZ @IntegerMode;
CMP DWORD PTR [EBX] , atSmallInt; //SmallInt模式 处理过程和Integer一样
JZ @IntegerMode;
CMP DWORD PTR [EBX] , atWord; //Word模式 处理过程和Integer一样
JZ @IntegerMode;
CMP DWORD PTR [EBX] , atLongWord; //LongWord模式 处理过程和Integer一样
JZ @IntegerMode;
CMP DWORD PTR [EBX] , atCardinal; //Cardinal模式 处理过程和Integer一样
JZ @IntegerMode;
CMP DWORD PTR [EBX] , atInt64; //Int64模式 处理过程和Real一样
JZ @RealMode;
CMP DWORD PTR [EBX] , atSingle; //Single模式 处理过程和Integer一样
JZ @IntegerMode;
CMP DWORD PTR [EBX] , atDouble; //Double模式 处理过程和Real一样
JZ @RealMode;
CMP DWORD PTR [EBX] , atComp; //Comp模式 处理过程和Real一样
JZ @RealMode;
CMP DWORD PTR [EBX] , atCurrency; //Currency模式 处理过程和Real一样
JZ @RealMode;
CMP DWORD PTR [EBX] , atExtended;
JZ @ExtendedMode;
CMP DWORD PTR [EBX] , atVarPointer; //VarPointer模式 处理过程和Integer一样
JZ @IntegerMode;
CMP DWORD PTR [EBX] , atBoolean; //Boolean模式 处理过程和Byte一样
JZ @IntegerMode;
CMP DWORD PTR [EBX] , atLongBool; //LongBool模式 处理过程和Integer一样
JZ @IntegerMode;
CMP DWORD PTR [EBX] , atObject; //Object模式 处理过程和Integer一样
JZ @IntegerMode;
JMP @ExitThisProc;
@IntegerMode: //整数模式
MOV EBX , [EBX+$4]; //TAPIParama.Address的地址
ADD EBX , -$4; //减4,因为在后面加了4
JMP @JPPointer;
@RealMode :
ADD EBX , $4; //TAPIParama.Address的地址
MOV EBX , [EBX] //得到实际的浮点数的地址
POP ECX; //取出RET后的EIP
PUSH DWORD PTR [EBX+4]; //API参数Real入伐
PUSH DWORD PTR [EBX]; //API参数Real入伐
PUSH ECX; //RET后的EIP入伐
JMP @ExitThisProc;
@ExtendedMode:
ADD EBX , $4;
MOV EBX , [EBX]
POP ECX; //取出RET后的EIP
MOV DX , [EBX+6];
PUSH EDX; //API参数入伐
PUSH DWORD PTR [EBX+4]; //API参数入伐
PUSH DWORD PTR [EBX]; //API参数入伐
PUSH ECX; //RET后的EIP入伐
JMP @ExitThisProc;
@JPPointer:
ADD EBX , $4;
@ParamStart:
POP ECX; //取出RET后的EIP
PUSH [EBX] //API需要的参数入伐
PUSH ECX; //RET后的EIP入伐
@ExitThisProc:
end;