序列化/编组/反向工程未知结构

时间:2009-08-15 15:58:02

标签: c# struct marshalling reverse-engineering serialization

当你不知道那个结构是什么时,有没有办法反序列化或编组或以某种方式将字节数组解析回结构?结构可能来自C ++。

一些背景:我有一个R / C飞机的飞行模拟器,我试图弄清楚我是否可以自动化它。没有API。我知道如何自动输入。我正试图获得该计划的输出。 (飞机的飞行动力学等)

模拟器具有多人游戏功能,因此我知道它必须通过网络传递我正在寻找的确切信息。它基于DirectX 9构建,并使用DirectPlay(不推荐的游戏网络协议)进行多玩家通信。我的 guess 是模拟器本身是用C ++编写的。

所以,我实际上可以连接到程序并获得一个13字节的消息。大。现在是什么。

一般来说,如何进行这样的逆向工程?

2 个答案:

答案 0 :(得分:4)

如果你可以访问结构的地址,你至少可以获取一个字节转储,以便开始。这是我制作的5分钟黑客攻击:

#include <stdio.h>

typedef struct {
    char c1;
    char c2;
    int i;
    float f;
    char *str;
} unknown;

void decode(unsigned char *address, int len) {
    unsigned char *p = address;
    for (; p < address + len ; p++) {
       printf("Byte offset: %p\tByte: 0x%02X\tAscii: %c\n", p - address, *p, *p);
    }
}

int main() {
    unknown x;
    int len = sizeof(unknown); /* or 13 like you've said the size is */

    /* this would happen in whatever software 
       you're using to generate the struct */
    x.c1 = 'h';
    x.c2 = 'i';
    x.i = 25;
    x.f = 3.14;
    x.str = "Hello";

    printf("first x:\n");
    decode((unsigned char*)(&x), len);

    x.c1 = 'o';
    x.c2 = 'l';
    x.i = 255;
    x.f = -9;
    x.str = "Goodbye";

    printf("second x:\n");
    decode((unsigned char*)(&x), len);

    return 0;
}

这是输出:

first x:
Byte offset: (nil)  Byte: 0x68  Ascii: h
Byte offset: 0x1    Byte: 0x69  Ascii: i
Byte offset: 0x2    Byte: 0xF3  Ascii: 
Byte offset: 0x3    Byte: 0xB7  Ascii: �
Byte offset: 0x4    Byte: 0x19  Ascii: 
Byte offset: 0x5    Byte: 0x00  Ascii: 
Byte offset: 0x6    Byte: 0x00  Ascii: 
Byte offset: 0x7    Byte: 0x00  Ascii: 
Byte offset: 0x8    Byte: 0xC3  Ascii: 
Byte offset: 0x9    Byte: 0xF5  Ascii: 
Byte offset: 0xa    Byte: 0x48  Ascii: H
Byte offset: 0xb    Byte: 0x40  Ascii: @
Byte offset: 0xc    Byte: 0xD8  Ascii: 
Byte offset: 0xd    Byte: 0x85  Ascii: �
Byte offset: 0xe    Byte: 0x04  Ascii: 
Byte offset: 0xf    Byte: 0x08  Ascii: 
second x:
Byte offset: (nil)  Byte: 0x6F  Ascii: o
Byte offset: 0x1    Byte: 0x6C  Ascii: l
Byte offset: 0x2    Byte: 0xF3  Ascii: 
Byte offset: 0x3    Byte: 0xB7  Ascii: �
Byte offset: 0x4    Byte: 0xFF  Ascii: �
Byte offset: 0x5    Byte: 0x00  Ascii: 
Byte offset: 0x6    Byte: 0x00  Ascii: 
Byte offset: 0x7    Byte: 0x00  Ascii: 
Byte offset: 0x8    Byte: 0x00  Ascii: 
Byte offset: 0x9    Byte: 0x00  Ascii: 
Byte offset: 0xa    Byte: 0x10  Ascii: 
Byte offset: 0xb    Byte: 0xC1  Ascii: 
Byte offset: 0xc    Byte: 0xE7  Ascii: 
Byte offset: 0xd    Byte: 0x85  Ascii: �
Byte offset: 0xe    Byte: 0x04  Ascii: 
Byte offset: 0xf    Byte: 0x08  Ascii: 

我正在使用的假设是你知道数据的输入是什么,你只是不知道布局是什么,或者不知道布局中包含的是什么。

即使我们知道那里有什么,这也很难。显然,char是最容易解码的。我们可以看到我们从一开始就从'hi'变为'ol'。

接下来是int,从25变为255.我们可以在偏移量0x4处看到0x19和0xff的两个值,但其余的字节在哪里?它是0x5-0x7(暗示int是“向后”存储的)?它可能是,并且可能偏移0x2-0x3只是填充我们使用的单字节字符(C结构根据字大小有一些对齐)。

然后有一个浮点数 - 我真的不知道浮点数是如何在内部编码的,所以我甚至不会尝试推断那里的区别。您可以查找IEEE标准。

最后,我们用指针关闭。如果该结构中有指针,那么您将不得不尝试查找这些内存地址而不会破坏您的程序。它们可能是指向其他结构的指针,在这种情况下,您将有幸重复此过程。

就像我说的那样,这是我花了5分钟的时间,我以前从未尝试过。主要是我第一次猜测你是怎么做的 - 从已知输入开始,然后一次改变一件事,直到你可以确定存储在结构中的数据类型和相应的字节偏移。

答案 1 :(得分:0)

首先,可能有大约20多种不同的消息,您需要模仿原始客户端/服务器。您可以在服务器和客户端之间编写代理,并捕获在这些服务器和客户端之间发送的所有合法数据包 其次,如果您想要反转这些东西,您可以反汇编您的模拟器,并尝试找到这些数据包的填充位置,那里可能会有一些提示。你可以做的另一件事是获得许多相同类型的数据包并对它们进行分析(可能当你的飞机改变了一些轴时,只有2或4个字节发生了变化,这表明这个字段负责改变这个轴 - 这个有点东西) 在你开始玩它之前,请考虑:
 你真的想进入这个,这并不容易  你确定,之前没有人这样做过,有些协议是由粉丝(或狂热分子?)发现并发布的。一个例子 - Ultima Online,可以找到大约10个仿真器,它们实现了大多数原始服务器功能,有很多关于如何实现协议的指南等。