执行存放在的数据区的机器指令的方法

来源:互联网 发布:博客ios优化 编辑:程序博客网 时间:2024/05/22 13:59

转载请标明是引用于 http://blog.csdn.net/chenyujing1234

编译工具:VS2005

 

最近在论坛上看到这个主题,想对此做些总结。

 

基本知识:

1. 在32bit flat模式,Windows对代码section是有保护的,一般不允许修改,对于数据section,可读可写可执行。所以执行数据section的代码是没有问题的,代码section和数据section是统一编址的。用一条call指令即可实现。
  2. 在16bit dos 模式,dos对代码段没有保护,故代码段依然是可写的,你可以在代码段预留一块空间,将数据区的指令复制到代码段保留区,然后执行。如果你非要运行数据段的代码,则比较麻烦,需要修改cs寄存器。

我们的电脑是32 bit flat的,故数据段是可读可写可执行的,所以执行数据段的代码没有问题。

这里可以用下面的例子说明这一点:

 

#include <stdio.h>#include <stdlib.h>#include <Windows.h>typedef int (*lpfn_add_c)(int a, int b);char bin_pattern[]={0x8b, 0x44, 0x24, 0x08,0x8b, 0x4c, 0x24, 0x04,0x03, 0xc1,0xc3,};int main(int argc, char* argv[]){char bytecode[16];int a,b,c;lpfn_add_c g_fn_add;memset(bytecode,0,sizeof(bytecode));memcpy(bytecode,bin_pattern,sizeof(bin_pattern));a=3;b=5;// 用下面的方法做过渡int *temp = (int*)bytecode;g_fn_add= (lpfn_add_c)(temp);// 编译出错//  error C2440: “类型转换”: 无法从“char [16]”转换为“lpfn_add_c”//g_fn_add= (lpfn_add_c)(bytecode);//接下来去执行在数据区的代码c=g_fn_add(a,b);printf("a=%d,b=%d,a+b=%d\n",a,b,c);return 0;}


 

.386.model flat           ; 32 bit memory modeloption casemap :none  ; case sensitiveWriteFile   PROTO        STDCALL:DWORD,:DWORD,:DWORD,:DWORD,:DWORDCloseHandle PROTO        STDCALL:DWORDExitProcess PROTO        STDCALL:DWORDwsprintfA   PROTO        C:DWORD,:VARARG includelib user32.libincludelib kernel32.lib        .const_formatString    db    '%d+%d=%d',0dh,0ah,0            .data?        ;非初值化的数据,不占可执行文件空间_buff        db        128 dup (?)align        4_tmp1        dd      ?    _c            dd        ?        .data        ;初值化的数据fun_add        db        8bh, 44h, 24h, 08h, 8bh, 4ch, 24h, 04h,03h, 0c1h, 0c3halign          4_a            dd        3_b            dd        5        .code_start:                mov     eax,_a        mov     edx,_b                push    eax        push    edx                lea        ebx, fun_add   ;eax 执行函数的地址        call    ebx                mov    _c, eax            ;返回值 --> 全局变量 _c                invoke  wsprintfA, addr _buff, addr _formatString, _a, _b, _c        add     esp, 20         ;5 * dword?        invoke  WriteFile,7,OFFSET _buff,32,OFFSET _tmp1,0    ; 输出到控制台,输出32个字符                                                              ; 7是标准输出文件的句柄        invoke  ExitProcess, 0                                ; 退出进程end _start


 

把上面的汇编保存为test.asm

编译test.asm成exe  的方法是:

编译ASM时得添加规则:

 右击项目-> 自定义生成规则->

此时编译会提示:

1>LINK : fatal error LNK1221: 无法推导出子系统,必须定义它

这时要在工程属性->链接->命令行下添
/subsystem:console

再编译,产生exe了。