繁体   English   中英

使用__stdcall和损坏的堆栈的思想实验(C ++)

[英]Thought experiment with __stdcall and corrupted stack (C++)

我今天在函数指针这个主题上徘徊,我想到了以下情形:

__stdcall int function (int)
{
    return 0;
}

int main()
{
    (*(int(*)(char*,char*))function)("thought", "experiment");
    return 0;
}

否则此代码将破坏堆栈,那么如果我运行此代码,我会看到哪些类型的问题?

我会自己进行调查,但是我要离开开发机器一周。

编辑:稍等一下,我一直在想更多。 正如评论中所观察到的那样,这段代码的目的是要在说完所有内容后在堆栈上保留一个参数(调用方将两个参数放在堆栈上,被调用方(只希望有一个参数)仅弹出一个参数) )。 但是,由于我的演员表没有提及调用约定,所以至少在调用者看来,我是否放弃了stdcall? int function(int)仍会从堆栈中弹出一个参数,但是由于强制转换,调用者是否会恢复为认为该函数是__cdecl(默认值)? (即弹出三个参数?)

编辑2:正如罗布所确认的,第二个问题的答案是肯定的。 如果要在堆栈上保留参数,则必须重新声明__stdcall:

(*(__stdcall int(*)(char*,char*))function)("thought", "experiment");

您正在调用该函数,就好像它是_cdecl一样,这意味着调用者将推入参数并清理堆栈。

接收函数是_stdcall,这意味着被调用方清除了堆栈。 被调用方希望有一个参数,因此会从堆栈中弹出4个字节。

当函数返回时,调用者将弹出两个指针(之前已将其推入两个指针),因此您的堆栈被破坏了4个字节。

两种调用约定都使用相同的返回机制,并且具有相同的注册规则(不保留eax,ecx和edx)。 有关更多详细信息,请参见Wikipedia

根据堆栈框架的布局和对齐方式,这种不匹配可能会导致多种影响。 如果幸运的话,您就可以摆脱它。 否则,您可能会弄乱主函数的返回地址,从而导致该程序在分支到who-knows-where时崩溃。 如果编译器注入了某种堆栈保护以捕获损坏,则它很可能会检测到该异常并中止程序。

不,它绝对不会导致蓝屏。 没有用户模式进程能够做到这一点。 即使此类错误出现在内核模式代码中,也只有在访问无效内存或将错误参数传递给函数之后才会发生BSOD。

您只是在破坏进程的私有内存,并且此破坏以后可能(也可能不会)导致无效的操作(例如,取消引用指向无效内存的指针)。 发生这种情况时,操作系统将终止您的进程,但不会立即终止。

我认为在这种情况下,您将有“不确定的行为”。

C标准开始 :(我认为在C ++中是相同的)

768如果使用转换后的指针来调用其类型与指向的类型不兼容的函数,则该行为是不确定的。

编辑:在大多数操作系统上,这种类型的错误不会在整个操作系统中引起问题。 但这会在程序中引起未定义的问题。 用户模式程序很难引起蓝屏。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM