我可以在Delphi中动态编译代码并执行它吗?

我可以在Delphi中动态编译代码并执行它吗?,delphi,winapi,assembly,compilation,interpreter,Delphi,Winapi,Assembly,Compilation,Interpreter,是否可以生成一个字节数组,然后让Windows像普通代码一样执行它? 假设我们有一些汇编代码: inc ecx 这是程序的一部分。使用Nasm编译后,我们得到一个EXE,其中上面的行被转换为如下内容: 00000035 41 是否有可能创建一个字节数组,用上面的字节填充它并执行-这样增量就实际发生了 我已经制作了我的超级简单的解释语言,但由于它是解释的,所以速度相当慢。我不想为它编写一个真正的编译器,但我想让它更快—编译并动态运行。我认为具有数据执行预防(DEP)功能的现代处理器将不允许

是否可以生成一个字节数组,然后让Windows像普通代码一样执行它? 假设我们有一些汇编代码:

inc  ecx
这是程序的一部分。使用Nasm编译后,我们得到一个EXE,其中上面的行被转换为如下内容:

00000035 41 
是否有可能创建一个字节数组,用上面的字节填充它并执行-这样增量就实际发生了


我已经制作了我的超级简单的解释语言,但由于它是解释的,所以速度相当慢。我不想为它编写一个真正的编译器,但我想让它更快—编译并动态运行。

我认为具有数据执行预防(DEP)功能的现代处理器将不允许这样做。
请注意,有几个pascal脚本库可用于此目的。

绝对可以。支持数据执行预防的处理器和操作系统可能会犹豫不决,但这很容易避免。只需调用将内存块标记为可执行。最好使用
VirtualAlloc
分配计划执行的内存。这样,您就有了一整页专门用于可执行代码的内存。如果调用
VirtualProtect
使分配给
GetMem
的任意内存可执行,它实际上会以这种方式标记整个页面,因此您可能会意外地将某些数据标记为可执行。如果数据被泄露,它可能会被执行。这正是DEP要保护的,所以最好将数据和可执行代码保存在单独的保护区域中

请记住,将文本代码转换为机器代码的任务是编译,因此如果您不想编写真正的编译器,您可能根本不想生成机器代码。

const
const
   size = 32768;
type
   TFuncInt = function(param: Integer): Integer; // EAX -> EAX
   TByteArray = array[0..size-1] of Byte;
   PByteArray = ^TByteArray;
var
   arr: PByteArray;
   func_param: Integer;
   func_result: Integer;
begin
   arr := VirtualAlloc(nil, size, $3000, $40);
   if arr <> nil then begin
     arr[0] := $40;  // inc EAX
     arr[1] := $C3;  // ret
     func_param := 77;
     func_result := TFuncInt(arr)(func_param);  // 78
     VirtualFree(arr, 0, $8000);
  end;
end;
尺寸=32768; 类型 TFuncent=函数(参数:整数):整数;//EAX->EAX TByteArray=字节的数组[0..size-1]; PByteArray=^TByteArray; 变量 arr:pbyte阵列; func_参数:整数; func_结果:整数; 开始 arr:=VirtualAlloc(无,大小$3000,$40); 如果arr为nil,则开始 arr[0]:=$40;//埃克斯公司 arr[1]:=$C3;//ret 函数参数:=77; func_结果:=tfuncent(arr)(func_参数);//78 VirtualFree(arr,0,$8000); 结束; 结束;
我知道它们是,就像ReObject的Pascal脚本一样。但我不想用Pascal语言编写,我需要一些非常简单的东西。DEP不会阻止通过VirtualAlloc()或VirtualProtect()显式标记为执行的内存中的指令执行。有一些框架,比如VCL和ATL,可以动态地分配可执行内存卡盘作为回调thunk使用,而DEP可以很好地实现这一点。还有一些表达式计算器可以做到这一点。但它们通常模仿堆栈机器,因此,如果代码是PICThank,则只需要加载一个带有堆栈指针的寄存器。它是“编译”,但没有所有EXE头、外部库链接等。所以它应该更容易。你仍然需要重新定位(修复)它。除非您不使用任何数据(或在启动时通过在寄存器中传递的指针间接寻址),并且仅在分支或PIC附近使用数据,否则您的代码版本将无法编译页面\执行\读写。您应该手动定义它。或者用数值代替。那么就定义它。我不在乎你的开发环境有多过时;不要使用简单的数字。它们对任何阅读代码的人来说都毫无意义。