Visual C++在函数末尾追加0xCC(int3)字节

Visual C++ appends 0xCC (int3) bytes at the end of functions

本文关键字:0xCC int3 字节 追加 C++ 函数 Visual      更新时间:2023-10-16

这是我第一次来这里,我真的希望你们能帮助我,因为我现在已经没有主意了。

我已经找了几个小时的答案,但没有找到一个真正有效的答案。

我想直接将代码注入正在运行的进程中。是的,你读对了。我正在尝试将代码注入另一个应用程序,信不信由你,这只是为了扩展它的功能

我在Windows上使用Visual Studio 2012速成版。

我有以下代码:

__declspec(naked) void Foo()
{
    __asm
    {
        // Inline assembly code here
    }
}
__declspec(naked) void FooEnd() {}
int main()
{
    cout << HEX(Foo) << endl;
    cout << HEX(FooEnd) <<  endl;
    cout << (int)FooEnd - (int)Foo << endl;
    // Inject code here using WriteProcessMemory
    return 0;
}

为了保持可读性,大部分代码都被删除了,不过我可以根据要求发布它的其他部分。

输出如下:

0x010B1000
0x010B1010
16

生成的大小实际上是不正确的。函数是按正确的顺序编译的(确保使用/order),但编译器在每个方法后面添加了一堆0xCC(int 3)字节,从而扩展了它的大小,因此我无法获得包含实际可执行代码的实际(有用)字节数。

在另一个stackoverflow问题中,有人说禁用"编辑并继续"会使这些额外的字节消失,但不管怎样,这对我来说都不起作用

我还尝试使用Release设置而不是Debug,更改了一系列优化设置,但这些都没有任何效果。你认为解决方案是什么?我可能遗漏了一些显而易见的东西。

无论如何,这(在你看来)是获得函数长度(可读性、可靠性、易用性)的最佳方式吗?

我希望我解释了我必须做的一切,以便你能够提供帮助。如果您还有其他问题,请随时留言。

感谢您的时间和努力。

正如Devolus所指出的,编译器在代码后面插入这些额外的字节,以便在合理的(通常可被16整除)起始地址上对齐下一个函数。

编译器实际上是在试图帮助您,因为0xCC是断点指令,如果指令指针在执行过程中的任何时候意外指向函数外部,代码都会进入调试器(如果附加)。

出于你的目的,这些都不应该让你担心。您可以将0xCC填充视为函数的一部分。

在注入代码时不需要额外的填充,所以可以丢弃它们。复制它们也应该很好,这只会导致额外的几个字节的复制。不管怎样,你注入的内存很可能会被一个页面对齐的块所占用,所以你并没有通过剥离它来真正获得任何东西。

但是,如果你真的想把它去掉,一个简单的解决方案就是从下一个函数之前的最后一个字节向后迭代,直到没有更多的0xcc字节。

即:

__declspec(naked) void Foo()
{
   __asm
   {
      _emit 0x4A
      _emit 0x4B
   }
}
__declspec(naked) void FooEnd() {}

int main(int argc, char** argv)
{
   //start at the last byte of the memory-aligned code instead of the first byte of FooEnd
   unsigned char* fooLast = (unsigned char*)FooEnd-1;
   //keep going backwards until we don't have a 0xcc
   while(*fooLast == 0xCC)
      fooLast--;
   //fooLast will now point at the last byte of your function, so you need to add 1
   int length = ((int)fooLast - (int)Foo) + 1;
   //should output 2 for the length of Foo
   std::cout << length;
}

编译器会插入额外的字节来创建内存对齐,因此您不能丢弃它,因为您将使用下一个函数作为标记。

另一方面,由于您无论如何都是在汇编中编写注入的代码,因此您也可以编写代码,对其进行编译,然后将二进制形式放入字节数组中。我就是这么做的,因为这样你就有了确切的长度。