分享
 
 
 

脚本解释程序解释如果动态执行API函数

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

本文介绍如何让你的脚本解释程序解释执行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;

//API调用过程

procedure DOAPI(ParamList : PAPIParamList ;

APIProc , ReturnPara : PAPIParama); stdcall;

begin

asm

PUSH EDX;

PUSH EBX;

PUSH ECX;

PUSH EAX; //保护现场

MOV EBX , ParamList;

MOV EBX , [EBX]; //TAPIParamList

MOV EAX , [EBX-4]; //High Array

DEC EAX;

@Loop1: //循环从High((ParamList^) DownTo 0

CMP EAX , -1;

JZ @ParamaOver;

MOV EBX , ParamList;

MOV EBX , [EBX];

MOV ECX , EAX;

IMUL ECX , APIParamaSize

ADD EBX , ECX;

Call InitParam; //整理参数

DEC EAX;

JMP @Loop1;

@ParamaOver:

MOV EBX , [APIProc]; //从APIProc参数那里得到API的入口地址

MOV EBX , [EBX + $4];

Call EBX; //调用API函数

//处理函数返回结果

MOV EBX , ReturnPara;

CMP EBX , $0; //是否是NIL

JZ @ExitThisProc;

CMP DWORD [EBX] , atPointer;

JZ @IntegerMode;

CMP DWORD [EBX] , atInteger;

JZ @IntegerMode;

CMP DWORD [EBX] , atReal;

JZ @RealMode;

CMP DWORD [EBX] , atByte;

JZ @ByteMode;

CMP DWORD [EBX] , atShortInt; //ShortInt 和 Byte处理方法一样

JZ @ByteMode;

CMP DWORD [EBX] , atSmallInt;

JZ @SmallIntMode;

CMP DWORD [EBX] , atWord; //Word 和 SmallInt处理方法一样

JZ @SmallIntMode;

CMP DWORD [EBX] , atLongWord; //Word 和 SmallInt处理方法一样

JZ @IntegerMode;

CMP DWORD [EBX] , atCardinal; //Cardinal 和 SmallInt处理方法一样

JZ @IntegerMode;

CMP DWORD [EBX] , atInt64;

JZ @Int64Mode;

CMP DWORD [EBX] , atSingle;

JZ @SingleMode;

CMP DWORD [EBX] , atDouble; //Double 和 Real处理方法一样

JZ @RealMode;

CMP DWORD [EBX] , atComp;

JZ @CompMode;

CMP DWORD [EBX] , atCurrency; //Currency 和 Comp处理方法一样

JZ @CompMode;

CMP DWORD [EBX] , atVarPointer;//Currency 和 Integer处理方法一样

JZ @IntegerMode;

CMP DWORD [EBX] , atBoolean; //Boolean 和 Byte处理方法一样

JZ @ByteMode;

CMP DWORD [EBX] , atLongBool; //LongBool 和 Integer处理方法一样

JZ @IntegerMode;

CMP DWORD [EBX] , atObject; //Object 和 Integer处理方法一样

JZ @IntegerMode;

JMP @ExitThisProc; //无效模式就退出

@IntegerMode:

MOV EBX , [EBX+$4];

//整数模式,就直接设置TAPIParama.Address指向的Integer的值

MOV [EBX] , EAX;

JMP @ExitThisProc;

@RealMode:

MOV EBX , [EBX+$4];

fstp qword ptr [EBX]; //接收浮点数

Wait;

JMP @ExitThisProc;

@ByteMode:

MOV EBX , [EBX+$4];

MOV [EBX] , AL;

JMP @ExitThisProc;

@SmallIntMode:

MOV EBX , [EBX+$4];

MOV [EBX] , AX;

JMP @ExitThisProc;

@Int64Mode:

MOV EBX , [EBX+$4];

MOV [EBX] , EAX;

MOV [EBX+4] , EDX;

JMP @ExitThisProc;

@SingleMode:

MOV EBX , [EBX+$4];

fstp dword ptr [EBX];

Wait;

JMP @ExitThisProc;

@CompMode:

MOV EBX , [EBX+$4];

fistp qword ptr [EBX];

Wait;

JMP @ExitThisProc;

@ExitThisProc:

POP EAX; //恢复现场

POP ECX;

POP EBX;

POP EDX;

end;

end;

补充几句:API参数调用时,如果是Var就是传Var的指针,

如果是结构也是传结构的指针,PChar也是

如果是整数或者Smallint那几个,就是直接传值

如果是浮点数,Var就是传指针,值的话就直接传值

到此为止动态调用API的过程已经全部写完。

蓝色光芒原创,转载请保留这些信息。:)

http://www.1285.net/

zgf@1285.net

下面我们来看看怎么使用这个函数

下面是调用SendMessage的过程

var

//参数的值,也可以不要这几个,因为SendMessage没有传指针的参数

IntList : array [1..4] of integer;

ReturnInt : integer;

ParamList : TAPIParamList;

ReturnPara : TAPIParama;

APIProc : TAPIParama;

i : integer;

begin

IntList[1] := Handle;

IntList[2] := WM_Close;

IntList[3] := 0;

IntList[4] := 0;

SetLength(ParamList,4);

for i:=Low(ParamList) to High(ParamList) do begin

ParamList[i].ParamType := atinteger;

ParamList[i].Address := @IntList[i];

end;

APIProc.ParamType := atProgram;

APIProc.Address := @SendMessage; //API函数的入口地址

ReturnPara.ParamType := atinteger;

ReturnPara.Address := @ReturnInt;

DOAPI(@ParamList,@APIProc,@ReturnPara);

//返回值被保存到ReturnInt里了。

end;

不难看出,我们在解释程序里面只需要解释用户定义的API函数地址,

API的参数类型,API的返回值类型,API参数的值,并整理这些数据,

放到一个Array of Integer 或者Array of Real..里面,传给DOAPI就

可以了。取回结果,并交给解释器处理

结构调用的例子:

var

SD : TSystemTime;

ParamList : TAPIParamList;

APIProc : TAPIParama;

begin

SetLength(ParamList,1);

ParamList[0].ParamType := atPointer;

ParamType[0].Address := @SD;

APIProc.ParamType := atProgram;

APIProc.Address := @GetSystemTime;

DOAPI(@ParamList,@APIProc,NIL);

//SD这个结构里就有当前的日期和时间了

end;

如果参数或者结果是对象

var

OBJ : TObject;

....

ParamList[0].ParamType := atObject;

ParamType[0].Address := @OBJ;

....

看起来好麻烦,调用一个API需要作这么复杂的事情,直接调用

GetSystemTime(SD)不就好了吗?写解释程序好象就这个样:(

从字符串翻译成程序来运行就这么回事,如:VB,VF

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有