0

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

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

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

所以,我实际上可以连接到程序并收到一条 13 个字节的消息。伟大的。怎么办。

一般来说,一个逆向工程会如何做这样的事情?

4

2 回答 2

4

如果您可以访问该结构的地址,您至少可以获取其中内容的字节转储作为开始。这是我制作的 5 分钟 hack:

#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;
}

这是输出:

第一个 x:
字节偏移量:(nil) 字节:0x68 Ascii:h
字节偏移:0x1 字节:0x69 Ascii:i
字节偏移:0x2 字节:0xF3 Ascii:
字节偏移:0x3 字节:0xB7 Ascii:�
字节偏移:0x4 字节:0x19 Ascii:
字节偏移:0x5 字节:0x00 Ascii:
字节偏移:0x6 字节:0x00 Ascii:
字节偏移:0x7 字节:0x00 Ascii:
字节偏移:0x8 字节:0xC3 Ascii:
字节偏移:0x9 字节:0xF5 Ascii:
字节偏移:0xa 字节:0x48 Ascii:H
字节偏移:0xb 字节:0x40 Ascii:@
字节偏移:0xc 字节:0xD8 Ascii:
字节偏移:0xd 字节:0x85 Ascii:�
字节偏移:0xe 字节:0x04 Ascii:
字节偏移:0xf 字节:0x08 Ascii:
第二个x:
字节偏移:(无)字节:0x6F Ascii:o
字节偏移:0x1 字节:0x6C Ascii:l
字节偏移:0x2 字节:0xF3 Ascii:
字节偏移:0x3 字节:0xB7 Ascii:�
字节偏移:0x4 字节:0xFF Ascii:�
字节偏移:0x5 字节:0x00 Ascii:
字节偏移:0x6 字节:0x00 Ascii:
字节偏移:0x7 字节:0x00 Ascii:
字节偏移:0x8 字节:0x00 Ascii:
字节偏移:0x9 字节:0x00 Ascii:
字节偏移:0xa 字节:0x10 Ascii:
字节偏移:0xb 字节:0xC1 Ascii:
字节偏移:0xc 字节:0xE7 Ascii:
字节偏移:0xd 字节:0x85 Ascii:�
字节偏移:0xe 字节:0x04 Ascii:
字节偏移:0xf 字节:0x08 Ascii:

我使用的假设是您知道数据的输入是什么,您只是不知道布局是什么,或者不一定知道其中包含什么。

即使我们知道里面有什么,这也很困难。显然,chars 是最容易解码的。我们可以看到我们一开始就从“hi”变成了“ol”。

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

然后是一个浮点数——我真的不知道浮点数是如何在内部编码的,所以我什至不会尝试在那里推断差异。您可能可以为此查找 IEEE 标准。

最后,我们用指针结束。如果该结构中有指针,那么您将不得不尝试查找这些内存地址,而不会使您的程序出现段错误。它们可能是指向其他结构的指针,在这种情况下,您将乐于重复此过程。

就像我说的,这是我 5 分钟的尝试,我之前从未真正尝试过。这主要是我对如何进行此操作的第一次猜测——从已知输入开始,然后一次更改一件事,直到您可以确定存储在结构中的数据类型和相应的字节偏移量。

于 2009-08-15T16:30:53.247 回答
0

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

于 2009-08-15T16:09:52.090 回答