一个直接执行二进制代码思路,请高手看一下。(63分)

  • 主题发起人 主题发起人 crazymoon
  • 开始时间 开始时间
C

crazymoon

Unregistered / Unconfirmed
GUEST, unregistred user!
我有一个思路。
在一个程序中,将一个函数的内容从内存中读出来,保存在文件中。
注: 似乎连续两个函数在内存中的位置是紧邻的,从而可以确定前一个函数的内存长度。
在另一个程序中,从上个文件中读取函数内容,并在内存申请一块空间,
将其放进去,控制程序直接运行这一段函数,这种思路有可行吗?
请高手赐教!
以下是我做的一些尝试:
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
Button3: TButton;
Memo1: TMemo;
Edit1: TEdit;
Button4: TButton;
Button1: TButton;
Button2: TButton;
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);

private
public
P:procedure;
procedure MsgInt(x:integer);
end;

var
P1,P2:Pointer;
b:Pointer;
v:integer;
Form1: TForm1;

Code:PByte;
Str:String;
Data:Longint;
num:integer;
oa:integer;
procedure Test1;
procedure Test2;
procedure xx;
implementation

uses ex;

{$R *.dfm}
procedure SavePointerContent2File(P:Pointer;Size:integer;FName:string);
var Mstrm:TmemoryStream;
begin
//将内存内容写入流文件
Mstrm:=TmemoryStream.Create ;
MStrm.Write(P^,Size);
MStrm.SaveToFile(FName) ;
MStrm.Free ;
end;
procedure ReadPointerContent2File(var Dest;FName:string);
var Mstrm:TmemoryStream;
begin
//从流文件中读取
Mstrm:=TmemoryStream.Create ;
MStrm.LOadFromFile(FName) ;
Mstrm.Position:=0;
MStrm.ReadBuffer(Dest,Mstrm.Size);
MStrm.Free ;
end;
procedure AddCode(const CodeByte:Byte);//将数据赋给指针指向的位置
begin
Code^:=CodeByte;
Inc(Code);
Inc(num);
end;
procedure RunCode;
asm
Call Code
end;

procedure Test(PA:Integer);
begin
{执行机器码,每执行一个字节,移动指针,并计数;
最后,移动指针,返回原位置}
num:=0;
Code:=VirtualAlloc(nil, 4096, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
AddCode($E8);//CALL
Data:=Longint(PA) - 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($C3);//RET
Dec(Code,num);//指针移动,返回首地址

RunCode;
end;

procedure CallTest(PA:Pointer);
begin
{执行机器码,每执行一个字节,移动指针,并计数;
最后,移动指针,返回原位置}
num:=0;
Code:=VirtualAlloc(nil, 4096, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
AddCode($E8);//CALL
Data:=Longint(Integer(PA)) - 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($C3);//RET
Dec(Code,num);//指针移动,返回首地址

RunCode;
end;
procedure Test1;
begin
showmessage('xxxxxxxxxxxxxxx1');
end;
procedure xx;
var x:string;
begin
showmessage('xxx1');
end;
procedure Test2;
begin
showmessage('OK2');
end;

procedure TForm1.MsgInt(x: integer);
begin
showmessage(inttostr(x));
end;

procedure TForm1.Button3Click(Sender: TObject);
var Mstrm:TmemoryStream;
PSize:integer;
begin
P1:=Ptr(integer(@Test1));
P2:=Ptr(integer(@Test2));
PSize:=integer(p2)-integer(p1);

v:=Integer(VirtualAlloc (nil,PSize,MEM_COMMIT, PAGE_EXECUTE_READWRITE));
if v=0 then showmessage('nil');

p:=ptr(v);
Move(P1, p,PSize);
p;
//Test(v);
// CallTest(P);
end;


procedure TForm1.Button4Click(Sender: TObject);
var xx:Array of byte;
begin
P1:=Ptr(integer(@Test1));
P2:=Ptr(integer(@Test2));
CallTest(P1);
end;
 
对于绝对跳转就会出错了.
 
很不保险,一些API需要重定位的
 
如果不涉及其它内容
只有一些计算操作应该没问题
 
可行,这就是常说的扫描代码。
和‘白河愁’说的一样。涉及到一些地址的重定位问题。所以你的代码要能自定位。
而且RTL中一些特性也不能用。Class等高级特性更不要想了。
我在盒子上的作品,用了这样的技术。你可以看一下。
http://www.2ccc.com/article.asp?articleid=3771
 
感谢各位!
懂了很多知识,现在还有一个问题,
我把函数拷贝到内存后,怎么执行它呢?
好像每次到这一步,都出错。
 
注意普通函数和类/对象函数的区别,一般就不容易错了。
 
请高手能否做个最简单的DEMO,
我做的总是有点问题。
gjinkui@163.com
 
呵呵,你这个需求,难道就是为了防破解?
 
如果这样,建议采用 res捆绑,然后释放建立内存映射文件(不在磁盘中生成)--这样执行方式不支持98,遗憾!执行后销毁内存映射!
这样的代码请参考 delphi核心编程 书籍!
 
API要能自动重定位,不要有全局或静态的变量,不能用RTL和class等,更不要调用或跳转到其他自定义函数,搞好寄存器保护和堆栈平衡...
 
难度太大,不搞了
 
后退
顶部