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

本文详细介绍了在32位扁平模式下如何执行数据段的代码,并通过实例解释了相关原理。包括代码段与数据段的区别、如何在代码段预留空间复制数据段指令、以及遇到的编译错误和解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载请标明是引用于 http://blog.youkuaiyun.com/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 model
option casemap :none  ; case sensitive

WriteFile   PROTO        STDCALL:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
CloseHandle PROTO        STDCALL:DWORD
ExitProcess PROTO        STDCALL:DWORD
wsprintfA   PROTO        C:DWORD,:VARARG 

includelib user32.lib
includelib 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, 0c3h
align          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了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值