获取C ++函数的“大小”(长度)?

时间:2012-01-02 20:51:05

标签: c++

  

可能重复:
  How to get the length of a function in bytes?

我正在制作一个Hooking程序,用于将方法插入指定的内存部分。

我需要获取本地C ++函数的长度,我使用了强制转换来获取函数的位置,但是如何获得长度呢?

int GetFuncLen()
{
  int i = 0;
  while((DWORD*)Function+i<max)
  {
    if((DWORD*)Function+i==0xC3)
    {
      return i;
    }
    i++;
  }
}

工作?

5 个答案:

答案 0 :(得分:5)

您的代码似乎是特定于操作系统,编译器和机器架构。

(我对Windows一无所知)

如果未定义max,则可能是错误的。

它是特定于操作系统的(可能仅限Windows),因为DWORD不是标准的C ++类型。您可以使用intptr_t(来自<cstdint>标题)。

您的代码是特定于编译器的,因为您假设每个已编译的函数都具有明确定义的唯一端,并且不与其他某些函数共享任何代码。 (有些编译器能够进行这样的优化,例如使用跳转指令使两个函数共享一个共同的结尾或代码块)。

您的代码是特定于机器的,因为您假设最后一条指令是RET编码的0xC3,这是特定于x86&amp; x86-64(不适用于Alpha或ARM,传闻Windows已被移植或被移植)。此外,该字节可能出现在其他指令或内联常量中(如Mat评论)。

我不确定二元函数结束的概念是否具有明确的含义。但如果确实如此,我希望链接器可能知道它。在某些系统上,例如在具有ELF可执行文件的Linux上,编译器和链接器会生成每个函数的大小。

也许您最好需要在给定地址附近找到符号。我不知道Windows是否具有这样的功能(在Linux上,来自<dlfcn.h>的{​​{3}} GNU函数可能很有用)。也许您的操作系统提供了等效的服务?

答案 1 :(得分:5)

没有。原因有几个。

1)如果0xC3位于需要新指令的位置,则它只是一个'ret'指令。可能很容易有其他指令在其操作数中包含0xc3字节,并且您只能获得部分代码。

2)根据编译器及其设置,任何给定的函数都可以有多个“ret”指令。同样,你只能获得部分功能。

3)函数经常使用像“switch”语句这样的结构,它使用位于ret指令之后的“跳转表”。同样,你只能获得部分功能。

你正在尝试做的事情无论如何都不可能发挥作用。

最大的问题是各种汇编指令通常会使用偏移而不是绝对地址来引用特定的内存区域。因此,尽管极小的函数可能有效,但任何调用其他函数的函数都可能会失败。

假设您正在尝试将这些函数加载到外部进程中,并且您尝试在Windows上执行此操作,则更好的解决方案是使用DLL注入将DLL加载到目标进程中。

如果你真的需要注入内存,那么你需要一个特定平台的汇编语言解析器来更新相关指令的所有内存地址,这是一项非常复杂的任务。或者您可以用汇编语言编写函数,并确保除了引用自己的代码部分之外没有使用相对偏移量,这样做更容易一些,但是你可以做的更多限制。

答案 2 :(得分:2)

您可以强制将您的函数单独放入一个部分(参见例如http://msdn.microsoft.com/en-us/library/s20kdbse(v=VS.71).aspx)。

我认为如果你定义一个部分,在其中声明一个变量,在其中定义你的函数,然后在其中定义另一个变量,那么两个变量的地址将覆盖你的函数。

最好是将两个变量和函数放在不同的部分中,然后使用部分合并来控制它们在结果代码中出现的顺序(参见How to refer to the start-of a user-defined segment in a Visual Studio-project?

正如其他人所指出的那样,你可能无法对此做任何有用的事情,而且它根本不是便携式的。

答案 3 :(得分:1)

执行此操作的唯一可靠方法是使用虚函数编译代码(但不运行它),反汇编并手动计算长度,然后取出该数字并替换为虚拟号码,并重新编译您的程序。

当我需要这样做时,我只是猜测功能应该有多大。只要你的猜测不小(而且不太大)你应该没有问题。

答案 4 :(得分:1)

您可以使用

  • objdump的

获取具有外部链接的对象的大小。否则,您可以获取编译器的汇编输出(gcc -S,例如)并手动汇编,您将有机会查看长度字段的名称:

        .file   "test.cpp"
        .text
        .globl  main
        .type   main, @function
main:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movl    %edi, -4(%rbp)
        movq    %rsi, -16(%rbp)
        movl    $0, %eax
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE0:
        .size   main, .-main
        .ident  "GCC: (Ubuntu 4.6.0-3~ppa1) 4.6.1 20110409 (prerelease)"
        .section        .note.GNU-stack,"",@progbits

参见.size main, .-main评估:它计算函数大小