c++ - 修补 C/C++ 函数以仅返回而不执行

标签 c++ c visual-c++ gcc

我想避免在大型项目中执行一个系统功能。不可能重新定义它或添加一些 ifdef 逻辑。所以我想将代码修补为仅 ret 操作。

函数是:

void __cdecl _wassert(const wchar_t *, const wchar_t *, unsigned);

和:

void __dj_assert(const char *, const char *, int, const char *) __attribute__((__noreturn__));

所以我需要在 Visual C++ 编译器上修补第一个,在 GCC 编译器上修补第二个。

对于 x86/x64,我能否直接在 _wassert/__dj_assert 函数的地址处编写 ret 指令?

更新:

我只想像这样修改函数体:

*_wassert = `ret`;

或者像这样复制另一个函数体:

void __cdecl _wassert_emptyhar_t *, const wchar_t *, unsigned)
{
}

for (int i = 0; i < sizeof(void*); i++) {
    ((char*)_wassert)[i] = ((char*)_wassert_empty
}

更新 2:

我真的不明白为什么有这么多人反对沉默的asserts。事实上,RELEASE 模式下没有断言,但没人关心。我只想能够在 DEBUG 模式下打开/关闭断言。

最佳答案

您需要了解特定处理器 calling conventions 和系统 ISAABI。有关 x86 和 x86-64 调用约定,请参见 this

有些调用约定在结语中需要不止一条 ret 机器指令,您必须考虑到这一点。顺便说一句,某些函数的代码通常位于 只读 code segment 中,您需要一些肮脏的技巧来修补它并在其中写入。

您可以编译一个具有相同签名的无操作函数,并要求编译器显示发出的汇编代码(例如,如果使用 GCC,则使用 gcc -O -Wall -fverbose-asm -S ....)

在 Linux 上,您可以使用动态链接器 LD_PRELOAD tricks 。如果使用最近的 GCC 您可能会考虑使用 MELT 对其进行自定义,但我认为在您的特定情况下不值得...

但是,显然有一些 assert 故障。如果没有任何 undefined behavior,您的程序不太可能继续运行。因此,实际上,您的程序很可能会在您建议的“修复”时在其他地方崩溃,并且您会浪费更多时间。 最好花足够的时间来纠正原来的错误,并改进你的开发过程。您的方法是推迟关键错误更正,并且您极有可能花更多的时间避免错误修复,而不是像您应该的那样正确处理它(现在,而不是以后)。 避免增加您的 technical debt 并使您的代码库更加错误和腐烂。

我的感觉是,您通过修补二进制文件以避免 assert-s 的方法无处可去(除了大失败)。您应该找出违反的原因,并改进代码(删除过时的 assert,或改进它,或更正 assert 检测到的其他地方的错误)。

关于c++ - 修补 C/C++ 函数以仅返回而不执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32986043/

相关文章:

c++ - __FILE__、__LINE__ 和 __FUNCTION__ 在 C++ 中的用法

c - POSIX getline() - EOF 上的行缓冲区状态?

c++ - 我应该为富客户端应用程序选择什么 Windows API?

c - 为什么我的代码无法检测到 ' ' 中的空格?

c - 在 Linux 上的 C 程序中从套接字描述符获取 struct socket*、struct sock *

c++ - 为什么Visual Studio生成的C++ "Hello World"项目看起来有点奇怪?

windows - 在我的应用程序退出前将终止的线程上调用 CoUninitialize 是否重要?

c++ - 了解在 C++ 中打印链接列表的错误

c++ - std::bind 如何以及为何使指针保持事件状态

c++ - 将 irr::c8 转换为 wchar_t*