程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 運行期間生成代碼的動態執行

運行期間生成代碼的動態執行

編輯:Delphi

  程序要執行首先要分配內存,在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;
  就完成了上面代碼的動態調用執行。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved