如何查找地址和地址C++ 的长度运行时函数 (MinGW)

发布于 2024-10-24 06:57:59 字数 3978 浏览 2 评论 0原文

由于这是我在 stackoverflow 上发表的第一篇文章,我要感谢你们所有人的宝贵帖子,这些帖子在过去给了我很大帮助。

我在 Windows-7(64) 上使用 MinGW (gcc 4.4.0) - 更具体地说,我使用诺基亚 Qt + MinGW,但 Qt 不参与我的问题。

我需要在运行时找到应用程序的特定函数的地址和长度(更重要的是),以便对这些函数进行编码/解码并实现软件保护系统。

我已经找到了一种关于如何计算函数长度的解决方案,假设静态函数在源文件中一个接一个地放置,逻辑上也按顺序放置在编译的目标文件中,然后放置在内存中。

不幸的是,只有当整个 CPP 文件使用选项“g++ -O0”(优化级别 = 0)编译时,这才是正确的。 如果我用“g++ -O2”(这是我的项目的默认设置)编译它,编译器似乎会重新定位一些函数,因此计算出的函数长度似乎既不正确又为负(!)。

即使我在源文件中放入“#pragma GCC Optimize 0”行,也会发生这种情况, 这应该相当于“g++ -O0”命令行选项。

我认为“g++ -O2”指示编译器执行一些全局文件级优化(某些函数重定位?),这不能通过使用 #pragma 指令来避免。

您知道如何防止这种情况发生,而不必使用 -O0 选项编译整个文件吗? 或者:您知道还有其他方法可以在运行时查找函数的长度吗?

我为您准备了一个小示例,以及不同编译选项的结果,以突出显示这种情况。


来源:

// ===================================================================
// test.cpp
//
// Intention: To find the addr and length of a function at runtime
// Problem:   The application output is correct when compiled with: "g++ -O0"
//            but it's erroneous when compiled with "g++ -O2"
//            (although a directive "#pragma GCC optimize 0" is present)
// ===================================================================

#include <stdio.h>
#include <math.h>

#pragma GCC optimize 0

static int test_01(int p1)
{
    putchar('a');
    putchar('\n');
    return 1;
}

static int test_02(int p1)
{
    putchar('b');
    putchar('b');
    putchar('\n');
    return 2;
}

static int test_03(int p1)
{
    putchar('c');
    putchar('\n');
    return 3;
}

static int test_04(int p1)
{
    putchar('d');
    putchar('\n');
    return 4;
}

// Print a HexDump of a specific address and length
void HexDump(void *startAddr, long len)
{
    unsigned char *buf = (unsigned char *)startAddr;
    printf("addr:%ld, len:%ld\n", (long )startAddr, len);
    len = (long )fabs(len);
    while (len)
    {
        printf("%02x.", *buf);
        buf++;
        len--;
    }
    printf("\n");
}


int main(int argc, char *argv[])
{
    printf("======================\n");
    long fun_len = (long )test_02 - (long )test_01;
    HexDump((void *)test_01, fun_len);

    printf("======================\n");
    fun_len = (long )test_03 - (long )test_02;
    HexDump((void *)test_02, fun_len);

    printf("======================\n");
    fun_len = (long )test_04 - (long )test_03;
    HexDump((void *)test_03, fun_len);

    printf("Test End\n");
    getchar();

    // Just a trick to block optimizer from eliminating test_xx() functions as unused
    if (argc > 1)
    {
      test_01(1);
      test_02(2);
      test_03(3);
      test_04(4);
    }
}

使用“g++ -O0”编译时的(正确)输出:

[注意所有函数末尾的“c3”字节(=程序集“ret”)]

======================
addr:4199344, len:37
55.89.e5.83.ec.18.c7.04.24.61.00.00.00.e8.4e.62.00.00.c7.04.24.0a.00.00.00.e8.42
.62.00.00.b8.01.00.00.00.c9.c3.
======================
addr:4199381, len:49
55.89.e5.83.ec.18.c7.04.24.62.00.00.00.e8.29.62.00.00.c7.04.24.62.00.00.00.e8.1d
.62.00.00.c7.04.24.0a.00.00.00.e8.11.62.00.00.b8.02.00.00.00.c9.c3.
======================
addr:4199430, len:37
55.89.e5.83.ec.18.c7.04.24.63.00.00.00.e8.f8.61.00.00.c7.04.24.0a.00.00.00.e8.ec
.61.00.00.b8.03.00.00.00.c9.c3.
Test End

使用“g++ -O2”编译时的错误输出: (a) 函数test_01 addr & len 似乎是正确的 (b) 函数 test_02、test_03 的长度为负,

而且很有趣。 test_02 长度也不正确。

======================
addr:4199416, len:36
83.ec.1c.c7.04.24.61.00.00.00.e8.c5.61.00.00.c7.04.24.0a.00.00.00.e8.b9.61.00.00
.b8.01.00.00.00.83.c4.1c.c3.
======================
addr:4199452, len:-72
83.ec.1c.c7.04.24.62.00.00.00.e8.a1.61.00.00.c7.04.24.62.00.00.00.e8.95.61.00.00
.c7.04.24.0a.00.00.00.e8.89.61.00.00.b8.02.00.00.00.83.c4.1c.c3.57.56.53.83.ec.2
0.8b.5c.24.34.8b.7c.24.30.89.5c.24.08.89.7c.24.04.c7.04.
======================
addr:4199380, len:-36
83.ec.1c.c7.04.24.63.00.00.00.e8.e9.61.00.00.c7.04.24.0a.00.00.00.e8.dd.61.00.00
.b8.03.00.00.00.83.c4.1c.c3.
Test End

As this is my first post to stackoverflow I want to thank you all for your valuable posts that helped me a lot in the past.

I use MinGW (gcc 4.4.0) on Windows-7(64) - more specifically I use Nokia Qt + MinGW but Qt is not involved in my Question.

I need to find the address and -more important- the length of specific functions of my application at runtime, in order to encode/decode these functions and implement a software protection system.

I already found a solution on how to compute the length of a function, by assuming that static functions placed one after each other in a source-file, it is logical to be also sequentially placed in the compiled object file and subsequently in memory.

Unfortunately this is true only if the whole CPP file is compiled with option: "g++ -O0" (optimization level = 0).
If I compile it with "g++ -O2" (which is the default for my project) the compiler seems to relocate some of the functions and as a result the computed function length seems to be both incorrect and negative(!).

This is happening even if I put a "#pragma GCC optimize 0" line in the source file,
which is supposed to be the equivalent of a "g++ -O0" command line option.

I suppose that "g++ -O2" instructs the compiler to perform some global file-level optimization (some function relocation?) which is not avoided by using the #pragma directive.

Do you have any idea how to prevent this, without having to compile the whole file with -O0 option?
OR: Do you know of any other method to find the length of a function at runtime?

I prepare a small example for you, and the results with different compilation options, to highlight the case.


The Source:

// ===================================================================
// test.cpp
//
// Intention: To find the addr and length of a function at runtime
// Problem:   The application output is correct when compiled with: "g++ -O0"
//            but it's erroneous when compiled with "g++ -O2"
//            (although a directive "#pragma GCC optimize 0" is present)
// ===================================================================

#include <stdio.h>
#include <math.h>

#pragma GCC optimize 0

static int test_01(int p1)
{
    putchar('a');
    putchar('\n');
    return 1;
}

static int test_02(int p1)
{
    putchar('b');
    putchar('b');
    putchar('\n');
    return 2;
}

static int test_03(int p1)
{
    putchar('c');
    putchar('\n');
    return 3;
}

static int test_04(int p1)
{
    putchar('d');
    putchar('\n');
    return 4;
}

// Print a HexDump of a specific address and length
void HexDump(void *startAddr, long len)
{
    unsigned char *buf = (unsigned char *)startAddr;
    printf("addr:%ld, len:%ld\n", (long )startAddr, len);
    len = (long )fabs(len);
    while (len)
    {
        printf("%02x.", *buf);
        buf++;
        len--;
    }
    printf("\n");
}


int main(int argc, char *argv[])
{
    printf("======================\n");
    long fun_len = (long )test_02 - (long )test_01;
    HexDump((void *)test_01, fun_len);

    printf("======================\n");
    fun_len = (long )test_03 - (long )test_02;
    HexDump((void *)test_02, fun_len);

    printf("======================\n");
    fun_len = (long )test_04 - (long )test_03;
    HexDump((void *)test_03, fun_len);

    printf("Test End\n");
    getchar();

    // Just a trick to block optimizer from eliminating test_xx() functions as unused
    if (argc > 1)
    {
      test_01(1);
      test_02(2);
      test_03(3);
      test_04(4);
    }
}

The (correct) Output when compiled with "g++ -O0":

[note the 'c3' byte (= assembly 'ret') at the end of all functions]

======================
addr:4199344, len:37
55.89.e5.83.ec.18.c7.04.24.61.00.00.00.e8.4e.62.00.00.c7.04.24.0a.00.00.00.e8.42
.62.00.00.b8.01.00.00.00.c9.c3.
======================
addr:4199381, len:49
55.89.e5.83.ec.18.c7.04.24.62.00.00.00.e8.29.62.00.00.c7.04.24.62.00.00.00.e8.1d
.62.00.00.c7.04.24.0a.00.00.00.e8.11.62.00.00.b8.02.00.00.00.c9.c3.
======================
addr:4199430, len:37
55.89.e5.83.ec.18.c7.04.24.63.00.00.00.e8.f8.61.00.00.c7.04.24.0a.00.00.00.e8.ec
.61.00.00.b8.03.00.00.00.c9.c3.
Test End

The erroneous Output when compiled with "g++ -O2":
(a) function test_01 addr & len seem correct
(b) functions test_02, test_03 have negative lengths,

and fun. test_02 length is also incorrect.

======================
addr:4199416, len:36
83.ec.1c.c7.04.24.61.00.00.00.e8.c5.61.00.00.c7.04.24.0a.00.00.00.e8.b9.61.00.00
.b8.01.00.00.00.83.c4.1c.c3.
======================
addr:4199452, len:-72
83.ec.1c.c7.04.24.62.00.00.00.e8.a1.61.00.00.c7.04.24.62.00.00.00.e8.95.61.00.00
.c7.04.24.0a.00.00.00.e8.89.61.00.00.b8.02.00.00.00.83.c4.1c.c3.57.56.53.83.ec.2
0.8b.5c.24.34.8b.7c.24.30.89.5c.24.08.89.7c.24.04.c7.04.
======================
addr:4199380, len:-36
83.ec.1c.c7.04.24.63.00.00.00.e8.e9.61.00.00.c7.04.24.0a.00.00.00.e8.dd.61.00.00
.b8.03.00.00.00.83.c4.1c.c3.
Test End

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

ゃ人海孤独症 2024-10-31 06:57:59

即使我在源文件中放入“#pragma GCC optimize 0”行(应该相当于“g++ -O0”命令行选项),也会发生这种情况。

我不相信这是真的:它应该相当于将 __attribute__((optimize(0))) 附加到随后定义的函数,这会导致这些函数使用不同的优化级别进行编译。但这不会影响顶层发生的事情,而命令行选项则会影响。

如果您确实必须做依赖顶级排序的可怕事情,请尝试 -fno-toplevel-reorder 选项。我怀疑将 __attribute__((noinline)) 也添加到相关函数中是个好主意。

This is happening even if I put a "#pragma GCC optimize 0" line in the source file, which is supposed to be the equivalent of a "g++ -O0" command line option.

I don't believe this is true: it is supposed to be the equivalent of attaching __attribute__((optimize(0))) to subsequently defined functions, which causes those functions to be compiled with a different optimisation level. But this does not affect what goes on at the top level, whereas the command line option does.

If you really must do horrible things that rely on top level ordering, try the -fno-toplevel-reorder option. And I suspect that it would be a good idea to add __attribute__((noinline)) to the functions in question as well.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文