2

我在内存中有一个结构,但并非所有成员都是已知的(这个结构是逆向工程的)。我想要做的是在内存中有这样的表示:

struct Name {
    long Id;
    byte unknown[32];
    float X;
};

但我希望它byte unknown[32]是不可见的,所以当我使用某种类型的东西时,Name我只能看到 2 个变量 Id 和 X。我认为它类似于:

struct Name {
    long Id;
    byte : 32*8; // So this doesn't appear
    float X;
};

但这不起作用 1. 因为我被限制为每行 8 个字节,所以它必须看起来像:

struct Name {
    long Id;
    long long : 64;
    long long : 64;
    long long : 64;
    long long : 64;
    float X;
};

其次,当我实际尝试这样做时,它并没有按预期工作(访问 X 并不是指结构的偏移量 0x24)。

4

2 回答 2

2

你走在正确的轨道上,但你只是把细节弄错了。编译器将对齐填充插入到您的Name. 该程序可能会执行您想要的操作:

#include <cstddef>
#include <iostream>
#include <cassert>

struct Name {
    long Id;  // offset 0x00
    int : 32; // offset 0x04
    long long : 64;  // 0x08
    long long : 64;  // 0x10
    long long : 64;  // 0x18
    int : 32; // offset 0x20
    float X;  // offset 0x24
};

int main () {
  assert(sizeof(int) == 4);
  assert(sizeof(long) == 4);
  assert(sizeof(float) == 4);
  assert(sizeof(long long) == 8);
  assert(offsetof(Name, Id) == 0);
  assert(offsetof(Name, X) == 0x24);
}

或者,您可以调查#pragma pack.

注意:您的问题没有可移植的、标准认可的解决方案。编译器可以自由地(几乎)插入填充字节,无论它们选择如何。但是可能有非可移植的、编译器认可的解决方案,例如上面的两个。

于 2012-05-22T17:44:46.993 回答
1

如果您正在寻找任何未知结构的通用解决方案,请查看此代码

template <size_t SIZE> class UnknownStruct
{
public:
    enum {size = SIZE};
    explicit UnknownStruct(unsigned char* data)
    {
        memcpy(m_data, data, SIZE);
    }
    template <size_t OFFSET, typename TYPE> TYPE* read()
    {
        if(OFFSET + sizeof(TYPE) <= SIZE)
            return reinterpret_cast<TYPE*>(m_data + OFFSET);
        return NULL;
    }
private:
    unsigned char m_data[SIZE];
};

UnknownStructure 是您可以使用该read函数访问的一团原始字节(计数大小)。这是如何将其用于您的问题的示例

class Name : public UnknownStruct<sizeof(long) + 32 + sizeof(float)>
{
public:
    explicit Name(unsigned char* data) : UnknownStruct<size>(data){}
    long& ID()
    {
        return *read<0, long>();
    }
    float& X()
    {
        return *read<sizeof(long) + 32, float>();
    }
};

调用代码看起来像这样

unsigned char foodata[100] = {0};
Name fooreader(foodata);
fooreader.ID() = 57;
long id = fooreader.ID();

当您发现更多关于结构的信息时,您可以向 Name 类添加更多函数,这些函数将从适当的偏移量读取类型

此代码的优点是它可以用于任何未知结构。可能有其他库可以提供此解决方案,但这很短且易于使用

于 2012-05-22T20:24:25.093 回答