是否有符合标准的方法在C ++中指定字段偏移?

时间:2014-04-21 15:29:47

标签: c++ memory reverse-engineering

我有一块由外部代码填充的内存,我试图进行逆向工程。我不知道这个内存的完整结构,但我知道一些字段(例如,块开始时使用名为' foo'的int32,并且在偏移0xC处有一个双重调用'杆&#39)。我想定义一个结构,并基本上将一个指向这个内存块的指针重新解释为该结构,然后将它排成一行。我不确定这种技术是否有更传统的名称,但我将其称为创建“覆盖类型”。

这是我希望能够做到的草图:

START_OVERLAY_TYPE(my_type, 0xFF) // struct named my_type, size 0xFF
    FIELD(0x00, int32_t foo);     // field int32_t foo at 0x00
    FIELD(0x0C, double bar);      // field double bar at 0x0C
END_OVERLAY_TYPE

不必使用宏将是一个加分,但我没有看到他们周围的好方法。

使用我当前的实现,我将其扩展为(类似):

__pragma(pack(push, 1))
template<size_t p> struct padding_t { unsigned char pad[p]; };
template<> struct padding_t<0> {};
struct my_type
{
    union
    {
        struct : padding_t<0xFF> {}; // ensure total size is 0xFF
        struct : padding_t<0x00> { int32_t foo; }; // field at 0x00
        struct : padding_t<0x0C> { double bar; }; // field at 0x0C
    };
};
__pragma(pack(pop))

这编译并且工作得很好,至少在我尝试过的clang,gcc和VC ++版本中(对pragma进行了适当的更改)。不幸的是,由于匿名结构的非标准使用,警告比比皆是。

在保持标准的同时,有没有办法达到同样的效果?要求是声明(就像当前的宏一样)相当简单,而对于消费者来说,使用是无法区分的

struct my_type { int32_t foo; double bar; }

至少对于不经意的观察者来说。

目前的代码可以用于我的目的,我只是好奇我是否有更好的方法。

1 个答案:

答案 0 :(得分:2)

您可以尝试使用隐式类型转换和包含该值的内部结构的赋值运算符。这种方式不是使用未命名的结构,而是带有名称,但内部通过运算符重载成为未命名的部分。

我尝试了一些客户端代码(传递给函数,获取/设置值),一切似乎都很好。我当然可能在某个地方错过了一个场景。

__pragma(pack(push, 1))
template<size_t p, typename t>
struct padding_t
{
    unsigned char pad[p];
    t             val;
    operator t  () const {return val;}
    operator t& ()       {return val;}
    padding_t<p, t>& operator= (const t& rhs) {val = rhs; return *this;}
};
template<typename t> struct padding_t<0, t>
{
    t             val;
    operator t  () const {return val;}
    operator t& ()       {return val;}
    padding_t<0, t>& operator= (const t& rhs) {val = rhs; return *this;}
};
template<size_t p>
struct sizing_t
{
    unsigned char pad[p];
};
struct my_type
{
    union
    {
        sizing_t<0xFF>           size; // ensure total size is 0xFF
        padding_t<0x00, int32_t> foo;  // field at 0x00
        padding_t<0x0C, double>  bar;  // field at 0x0C
    };
};
__pragma(pack(pop))