极其高难的问题 在delphi里,我有一个公共单元文件,这个单元里定义了一些系统的公共函数。当我知道了函数名称的时候如何利用程序获得这些函数的地址,进而可以利用函数指针方法等动态的调用这些函数 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 我以前做过类似的,不过,是做到一个类中,然后,用RTTI来取得 by ehom 运行期间生成代码的动态执行赫赫,利用下面的功能,我们是不是可以不利用临时文件而执行一个EXE了?还有很多功能阿。 :)程序要执行首先要分配内存,在Win32下每个进程的内存地址空间都是虚拟的,其内存地址不是实际的物理地址,所以使用VirtualAlloc来完成虚拟内存的分配! LPVOID VirtualAlloc( LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect );lpAddress 为申请的内存的起始地址,在Win32中你可以自己指定申请内存的地址范围!Win32中每个进程的地址空间为4GB,从0X00000000到0XFFFFFFFF。那是否可以在这个范围内任意分配内存?答案是否定的!在这其中只有一部分是可以供Win32应用使用的。使用GetSystemInfo获取系统信息,其中的lpMinimumApplicationAddress、lpMaximumApplicationAddress分别是可以使用的最小地址和最大地址。当然这里可以简单的设其值为Null,套用MSDN中的一句话:“If this parameter is NULL, the system determines where to allocate the region.”,直接将其交给系统去处理!dwSize 为申请内存大小,以字节为单位,但如果其大小不为页的整数倍,系统将会加大内存达到页的整数倍。所以尽量按页来申请。同样可以用GetSystemInfo来获取dwPageSize。如Win9X下一页为4K,即4096字节。flAllocationType 指定申请方式,flProtect 指定内存的保护方式,具体信息可查看MSDN:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/memory/base/virtualalloc.asp这里根据需要将两参数设为MEM_COMMIT(提交已经申请的内存)、PAGE_EXECUTE_READWRITE(执行和读写) 完成了内存分配的工作后,下面就是将待执行的代码保存到内存中。机器语言指令是多字节指令,所以接下来要做的就是将一串具体数字按字节写入内存中。下面的代码完成了一段子程序的生成:var Code:PByte; Str:String; Data:Longint; num:integer; procedure AddCode(const CodeByte:Byte);//将数据赋给指针指向的位置 begin Code^:=CodeByte; Inc(Code); Inc(num); end;begin num:=0; Code:=VirtualAlloc(nil, 4096, MEM_COMMIT, PAGE_EXECUTE_READWRITE); AddCode($50);//PUSH EAX AddCode($B8);//MOV EAX Str:='Hello World!'; Data:=Longint(Pointer(PChar(Str)));//取字符串地址 AddCode(Data and $FF); AddCode(Data and $FF00 shr 8); AddCode(Data and $FF0000 shr 16); AddCode(Data and $FF000000 shr 24); AddCode($E8);//CALL Data:=Longint(@ShowMessage) - Longint(Code) - 4;//计算Showmessage的相对地址 AddCode(Data and $FF); AddCode(Data and $FF00 shr 8); AddCode(Data and $FF0000 shr 16); AddCode(Data and $FF000000 shr 24); AddCode($58);//POP EAX AddCode($C3);//RET Dec(Code,num);//指针移动,返回首地址end;也许可以通过相应技术手册来查询相应指令的含义,但在Win32下其实有种简单的理解方法。其实只要对任意一个Win32程序进行反编译,即可获得相应指令和汇编助记符的对应关系。用汇编代码表述其意义为:PUSH EAXMOV EAX,[字符串地址]CALL ShowMessagePOP EAXRET接下来,通过嵌入ASM代码:asm Call Codeend;就完成了上面代码的动态调用执行。 unit Unit1;interfaceuses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs;type p1 = procedure () of object; p2 = procedure (Str : string) of object; pp1= ^p1; pp2= ^p2; TForm1 = class(TForm) procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; FuncPointer = class public p : Array[1..2] of pointer; published procedure SetP1(); procedure DoShow(); procedure DoShow2(Str : string); procedure SetP2(); end;function GetFuncAddress( p : pointer) : pointer;var Form1: TForm1;implementation{$R *.dfm}function GetFuncAddress( p : pointer) : pointer;begin result := p;end;procedure TForm1.FormCreate(Sender: TObject);varfp : FuncPointer;aa : p1;bb : p2;begin fp := FuncPointer.Create; fp.SetP1; fp.SetP2; p1(fp.p[1]^)(); p2(fp.p[2]^)('ok');end;{ FuncPointer }procedure FuncPointer.DoShow;begin showmessage('a');end;procedure FuncPointer.DoShow2(Str: string);begin showmessage(Str);end;procedure FuncPointer.SetP1();varp3 : p1;pp3: pp1;begin p3 := DoShow; getmem(self.p[1],sizeof(p1)); p1(Self.p[1]^) := p3;end;procedure FuncPointer.SetP2();varp3 : p2;begin p3 := DoShow2; getmem(self.p[2],sizeof(p2)); p2(Self.p[2]^) := p3;end;end. DBgrid怎么加checkbox,不想用加字段的方式 如何编写程序控制让路由器断开adsl连接并从新拨号? 请问高手 :如何得到文件大小与系统显示的大小一致? 问个简单问题,顺便祝大家工作顺利,万事如意!!! ListBox1列表框的问题 微软赁什么不重视中国大陆市场? 如何突破防火墙的限制使用qq聊天???? 关于数据储存问题,高手帮帮忙 关于csv 文件格式导入Acess?(难)_在线等 ??怎么用InstallShell安装SQLServer的mdb数据库?? 新手,菜问题 高分求类似QQ,MSN等之类的漂亮的PageControl
运行期间生成代码的动态执行赫赫,利用下面的功能,我们是不是可以不利用临时文件而执行一个EXE了?还有很多功能阿。 :)
程序要执行首先要分配内存,在Win32下每个进程的内存地址空间都是虚拟的,其内存地址不是实际的物理地址,所以使用VirtualAlloc来完成虚拟内存的分配! LPVOID VirtualAlloc(
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flAllocationType,
DWORD flProtect
);lpAddress 为申请的内存的起始地址,在Win32中你可以自己指定申请内存的地址范围!Win32中每个进程的地址空间为4GB,从0X00000000到0XFFFFFFFF。那是否可以在这个范围内任意分配内存?答案是否定的!在这其中只有一部分是可以供Win32应用使用的。使用GetSystemInfo获取系统信息,其中的lpMinimumApplicationAddress、lpMaximumApplicationAddress分别是可以使用的最小地址和最大地址。当然这里可以简单的设其值为Null,套用MSDN中的一句话:“If this parameter is NULL, the system determines where to allocate the region.”,直接将其交给系统去处理!dwSize 为申请内存大小,以字节为单位,但如果其大小不为页的整数倍,系统将会加大内存达到页的整数倍。所以尽量按页来申请。同样可以用GetSystemInfo来获取dwPageSize。如Win9X下一页为4K,即4096字节。flAllocationType 指定申请方式,flProtect 指定内存的保护方式,具体信息可查看MSDN:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/memory/base/virtualalloc.asp这里根据需要将两参数设为MEM_COMMIT(提交已经申请的内存)、PAGE_EXECUTE_READWRITE(执行和读写) 完成了内存分配的工作后,下面就是将待执行的代码保存到内存中。机器语言指令是多字节指令,所以接下来要做的就是将一串具体数字按字节写入内存中。下面的代码完成了一段子程序的生成:var
Code:PByte;
Str:String;
Data:Longint;
num:integer; procedure AddCode(const CodeByte:Byte);//将数据赋给指针指向的位置
begin
Code^:=CodeByte;
Inc(Code);
Inc(num);
end;begin
num:=0;
Code:=VirtualAlloc(nil, 4096, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
AddCode($50);//PUSH EAX
AddCode($B8);//MOV EAX
Str:='Hello World!';
Data:=Longint(Pointer(PChar(Str)));//取字符串地址
AddCode(Data and $FF);
AddCode(Data and $FF00 shr 8);
AddCode(Data and $FF0000 shr 16);
AddCode(Data and $FF000000 shr 24);
AddCode($E8);//CALL
Data:=Longint(@ShowMessage) - Longint(Code) - 4;//计算Showmessage的相对地址
AddCode(Data and $FF);
AddCode(Data and $FF00 shr 8);
AddCode(Data and $FF0000 shr 16);
AddCode(Data and $FF000000 shr 24);
AddCode($58);//POP EAX
AddCode($C3);//RET
Dec(Code,num);//指针移动,返回首地址
end;也许可以通过相应技术手册来查询相应指令的含义,但在Win32下其实有种简单的理解方法。其实只要对任意一个Win32程序进行反编译,即可获得相应指令和汇编助记符的对应关系。用汇编代码表述其意义为:PUSH EAX
MOV EAX,[字符串地址]
CALL ShowMessage
POP EAX
RET接下来,通过嵌入ASM代码:
asm
Call Code
end;
就完成了上面代码的动态调用执行。
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;type
p1 = procedure () of object;
p2 = procedure (Str : string) of object;
pp1= ^p1;
pp2= ^p2;
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
FuncPointer = class
public
p : Array[1..2] of pointer;
published procedure SetP1(); procedure DoShow();
procedure DoShow2(Str : string);
procedure SetP2();
end;
function GetFuncAddress( p : pointer) : pointer;
var
Form1: TForm1;implementation{$R *.dfm}function GetFuncAddress( p : pointer) : pointer;
begin
result := p;
end;procedure TForm1.FormCreate(Sender: TObject);
var
fp : FuncPointer;
aa : p1;
bb : p2;
begin
fp := FuncPointer.Create;
fp.SetP1;
fp.SetP2;
p1(fp.p[1]^)();
p2(fp.p[2]^)('ok');
end;{ FuncPointer }procedure FuncPointer.DoShow;
begin
showmessage('a');
end;procedure FuncPointer.DoShow2(Str: string);
begin
showmessage(Str);
end;procedure FuncPointer.SetP1();
var
p3 : p1;
pp3: pp1;
begin
p3 := DoShow;
getmem(self.p[1],sizeof(p1));
p1(Self.p[1]^) := p3;
end;procedure FuncPointer.SetP2();
var
p3 : p2;
begin
p3 := DoShow2;
getmem(self.p[2],sizeof(p2)); p2(Self.p[2]^) := p3;end;end.