内联汇编中慎用eax,ecx,edx

本文通过一个C++程序示例,探讨了在内联汇编中使用eax,ecx,edx寄存器的风险。在VC6环境下,这些寄存器通常不会被保存,可能导致意外的值改变。文章通过内联汇编、直接调用、汇编调用和ShellCode模式调用四种方式展示了函数调用的不同结果,强调了在特定环境下,特别是Release模式下,使用ecx可能引起程序崩溃的问题。" 115679523,8467132,JAVA基础编程:PTA辅助教学平台实践,"['JAVA', '编程教学', 'PTA平台', '基础编程题']

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

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <wtypes.h>


// 测试vc6默认对寄存器保存情况:

// ebp总是在函数开始push, ebx、esi、edi如果用到也会push, eax、ecx、edx则永远不push

int asm_add(int a, int b)
{
__asm
{
mov eax, a
add eax, b
mov esi, eax
mov edi, eax
mov ebx, eax
mov ecx, eax
mov edx, eax
}
}


int add(int a, int b)
{
    return a + b;
}


int main( void )
{
int result = 0;
//0. 调用内联汇编add
result = asm_add(100, 200);
printf("asm_add result=%d\n", result);


//1. 直接调用add
result = add(1, 2);
printf("C++ call result=%d\n", result);


//2. 汇编调用
__asm
{
push 3
push 4
call add
mov result, eax
add esp, 8
}
printf("ASM call result=%d\n", result);


//3. ShellCode 模式调用
// 注意:通过函数名得到的地址是 jmp Add 指令的地址,而不是add函数的实际地址
// jmp Add机器码格式为:jmp(占一字节) + 四字节偏移地址,共占5字节
// (DWORD*)(JmpAddr+1)为偏移值,由于JmpAddr为jmp Add 指令的地址
// 因此需要加上jmp Add自身的5个字节,得到函数Add的实际地址
    BYTE* JmpAddr = (BYTE*)add;
    DWORD offset = *((DWORD*)(JmpAddr + 1)) + 5;
    BYTE* pFuncAddr = (BYTE*)(((DWORD)JmpAddr) + offset);
// 将函数Add的数据拷贝到FuncByte
BYTE FuncByte[512] = {0};
    for(int i=0; i<512; i++)
    {
        if((FuncByte[i] = pFuncAddr[i] ) == 0xC3)
break;
    }

    __asm
{
        lea eax, FuncByte
push 5
push 6
mov edx, 1 ;设置标志 用ecx时,在 Release 下会崩溃
;Release 模式下,add 中用到ecx,其值被修改,
;且函数退出是没有还原
call __label
__label:
        cmp edx, 0
je __ret
xor edx, edx ;清楚标志
jmp eax ;调用Add函数
__ret:
        mov result, eax ;获取返回值
add esp, 8 ;平衡push 100,push 200
    }
printf("ShellCode call result=%d\n", result);


system("pause");
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值