0

そもそもその構造が何であったかわからない場合に、バイト配列を構造に逆シリアル化またはマーシャリングまたは何らかの方法で解析する方法はありますか? 構造はおそらく C++ から来ています。

いくつかの背景: R/C 飛行機用のフライト シミュレータがあり、それを自動化できるかどうかを調べています。API はありません。入力を自動化する方法を知っています。プログラムの出力を取得しようとしています。(飛行機の飛行力学など)

シミュレーターにはマルチプレイヤー機能があるため、探している正確な情報をネットワーク経由で渡す必要があることはわかっています。DirectX 9 に基づいて構築されており、マルチプレイヤー通信に DirectPlay (非推奨のゲーム ネットワーク プロトコル) を使用します。私の推測では、シミュレータ自体は C++ で書かれています。

それで、実際にプログラムに接続して、13 バイトのメッセージを取得できました。偉大な。それで。

一般に、このようなものをどのようにリバース エンジニアリングするのでしょうか?

4

2 に答える 2

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

出力は次のとおりです。

最初の x:
バイト オフセット: (nil) バイト: 0x68 アスキー: h
バイト オフセット: 0x1 バイト: 0x69 アスキー: i
バイト オフセット: 0x2 バイト: 0xF3 アスキー:
バイト オフセット: 0x3 バイト: 0xB7 アスキー: �
バイト オフセット: 0x4 バイト: 0x19 アスキー:
バイト オフセット: 0x5 バイト: 0x00 アスキー:
バイト オフセット: 0x6 バイト: 0x00 アスキー:
バイト オフセット: 0x7 バイト: 0x00 アスキー:
バイト オフセット: 0x8 バイト: 0xC3 アスキー:
バイト オフセット: 0x9 バイト: 0xF5 アスキー:
バイト オフセット: 0xa バイト: 0x48 アスキー: H
バイト オフセット: 0xb バイト: 0x40 アスキー: @
バイト オフセット: 0xc バイト: 0xD8 アスキー:
バイト オフセット: 0xd バイト: 0x85 アスキー: �
バイト オフセット: 0xe バイト: 0x04 アスキー:
バイト オフセット: 0xf バイト: 0x08 アスキー:
2 番目の x:
バイト オフセット: (nil) バイト: 0x6F Ascii: o
バイト オフセット: 0x1 バイト: 0x6C アスキー: l
バイト オフセット: 0x2 バイト: 0xF3 アスキー:
バイト オフセット: 0x3 バイト: 0xB7 アスキー: �
バイト オフセット: 0x4 バイト: 0xFF アスキー: �
バイト オフセット: 0x5 バイト: 0x00 アスキー:
バイト オフセット: 0x6 バイト: 0x00 アスキー:
バイト オフセット: 0x7 バイト: 0x00 アスキー:
バイト オフセット: 0x8 バイト: 0x00 アスキー:
バイト オフセット: 0x9 バイト: 0x00 アスキー:
バイト オフセット: 0xa バイト: 0x10 アスキー:
バイト オフセット: 0xb バイト: 0xC1 アスキー:
バイト オフセット: 0xc バイト: 0xE7 アスキー:
バイト オフセット: 0xd バイト: 0x85 アスキー: �
バイト オフセット: 0xe バイト: 0x04 アスキー:
バイト オフセット: 0xf バイト: 0x08 アスキー:

私が使用している仮定は、データへの入力が何であるかを知っているということですが、レイアウトが何であるか、または必然的にそこに何が含まれているかを知らないだけです。

そこに何が入っているかを知っていても、これはかなり難しいです。明らかに、s は最もchar簡単にデコードできます。最初に「hi」から「ol」に変わったことがわかります。

次は int で、25 から 255 に変化します。オフセット 0x4 に 0x19 と 0xff の 2 つの値がありますが、残りのバイトはどこにあるのでしょうか? 0x5-0x7 ですか (int が「後方」に格納されていることを示唆しています)? そうかもしれませんし、おそらくオフセット 0x2-0x3 は、使用した 1 バイト文字の単なるパディングです (C 構造体には、ワード サイズに応じたアライメントがあります)。

それから浮動小数点数があります。浮動小数点数が内部でどのようにエンコードされているかは本当にわかりません。そのため、その違いを推測するつもりさえありません。おそらくIEEE標準を調べることができます。

最後に、ポインターで閉じます。その構造体にポインターがある場合は、プログラムをセグメンテーション フォールトせずに、それらのメモリ アドレスを調べて調べる必要があります。それらは他の構造体へのポインターである可能性があり、その場合、このプロセスを繰り返す喜びがあります。

私が言ったように、これは私の5分間のテイクであり、実際にこれを試したことはありません. これは主に私の最初の推測でした。既知の入力から始めて、構造体に格納されているデータ型と対応するバイト オフセットを特定できるまで、一度に 1 つずつ変更します。

于 2009-08-15T16:30:53.247 に答える
0

まず、おそらく 20 以上のさまざまなメッセージがあり、元のクライアント/サーバーを模倣する必要があります。サーバーとクライアントの間にプロキシを作成し、それらの間で送信されるすべての正当なパケットをキャッチする
ことができます。そこに何かヒントがあるかもしれません。あなたができるもう1つのことは、同じタイプの多くのパケットを取得して分析することです(おそらく、飛行機がいくつかの軸を変更したときに、2または4バイトだけが変更されたことを示します。これは、このフィールドがこの軸の変更を担当していることを示します-これ種類のもの)。
そして、それをいじる前に次のことを考えて
みてください。
2. これまで誰もこれを行っていないことを確信していますか? 一部のプロトコルは、ファン (または狂信者?) によって発見され、公開されています。例 - Ultima Online、オリジナルのサーバー機能のほとんどを実装する約 10 のエミュレーターを見つけることができます。プロトコルの実装方法などに関する多くのガイドがあります。

于 2009-08-15T16:09:52.090 に答える