2009-08-15 6 views
0

처음 구조가 무엇인지 모를 때 역 직렬화하거나 마샬링하거나 구조체로 바이트 배열을 구문 분석하는 방법이 있습니까? 구조는 아마 C++에서 왔습니다.알 수없는 구조 직렬화/마샬링/리버스 엔지니어링

일부 배경 : R/C 비행기 용 비행 시뮬레이터가 있는데 자동화가 가능한지 알아 내려고하고 있습니다. API가 없습니다. 나는 입력을 자동화하는 방법을 안다. 나는 프로그램의 결과를 얻으려고 노력하고있다. (비행기의 비행 역학 등)

시뮬레이터에는 멀티 플레이어 기능이있어서 네트워크를 통해 원하는 정확한 정보를 전달해야한다는 것을 알고 있습니다. DirectX 9를 기반으로하며 멀티 플레이어 통신을 위해 DirectPlay (더 이상 사용되지 않는 게임 네트워크 프로토콜)를 사용합니다. 내 추측는 시뮬레이터 자체가 C++로 작성되었습니다.

그래서 저는 실제로 프로그램에 연결할 수 있으며 13 바이트의 메시지를 받았습니다. 큰. 이제 뭐.

일반적으로 이러한 리버스 엔지니어링 방법은 무엇입니까?

+0

나는 그것에 총을 맞았고, 좋지 않다. 타임 스탬프처럼 보이는 8 바이트가 있습니다. 그들은 실제로 C 시간 구조를 따르지 않습니다. 다른 데이터 형식으로 deserialized했습니다 있지만 값 사이의 간격을 일렬로 것 같습니다. 해시 결과 또는 체크섬 일 수 있다고 생각하기 시작했습니다. 이 경우 잊어 버려. 글쎄, 그것은 총 손실 아니에요. DirectX, 메모리의 구조 레이아웃 및 비 직렬화에 대해 배웠습니다. – Patrick

+0

얼마 동안 이것을 선반에 얹은 후에, 나는 최근에 더 많은 성공을 거두었습니다. 이전에 프로그램간에 전송 된 첫 번째 패킷 만보고 실수를 저질렀습니다. 이번에는 MS NetMon을 설정하고 몇 분의 데이터를 캡처했습니다. NetMon API를 사용하여 데이터를 눈으로 볼 필요없이 프로그래밍 방식으로 패턴을 찾습니다. 또한 BitConverter 클래스를 사용하여 전체 내용을 비 직렬화하는 대신 바이트 배열에서 개별 필드를 뽑았습니다. 나는 지금 찾고있는 분야의 절반 정도를 가지고있다. C#의 샘플 NetMon API 코드 : [Top Users] (http://nmtopusers.codeplex.com) – Patrick

답변

0

우선 20 가지 이상의 다양한 메시지가있을 수 있으며 원본 클라이언트/서버를 모방해야합니다. 당신은 서버와 클라이언트 사이에 프록시를 작성하고 그 사이에 전송되는 모든 합법적 인 패킷을 잡을 수 있습니다.
두 번째로 이러한 것들을 뒤집으려면 시뮬레이터를 해체하고 패킷이 어디에 있는지 찾아보십시오 채워지면 몇 가지 힌트가있을 수 있습니다. 당신이 할 수있는 또 다른 일은 같은 종류의 많은 패킷을 얻고 분석하는 것입니다 (아마 비행기가 일부 축을 변경했을 때 2 ~ 4 바이트 만 변경되었을 것입니다, 이것은이 필드가이 축을 변경하는 책임이 있음을 나타냅니다). 물건의 종류).
그리고 그걸 가지고 놀기 전에 다음과 같이 생각하십시오.
1. 정말 들어가기를 원하십니까? 쉽지 않을 것입니다.
2. 누구도 전에 이것을 한 적이 없으며 일부 프로토콜은 팬 (또는 광신자)이 발견하여 게시 했습니까? 예를 들어, Ultima Online은 원래의 서버 기능 대부분을 구현하는 약 10 개의 에뮬레이터를 찾을 수 있습니다. 프로토콜 구현 방법에 대한 많은 가이드가 있습니다.

+0

동일한 생각을하고 있습니다. 테스트 비행을하고 패킷 스니퍼로 데이터를 캡처합니다. – Patrick

4

구조체 주소에 액세스 할 수 있으면 적어도 시작을 위해 거기에있는 것의 바이트 덤프. '

 
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: 

내가 사용 가정하면 입력 데이터로 무엇을 알고, 당신은 단지 돈 : 여기에 내가 만든 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; 
} 

는 그리고 여기에 출력의 레이아웃이 무엇인지, 또는 레이아웃에 무엇이 포함되어 있는지를 안다.

우리는 거기에 무엇이 있는지를 알기조차 어렵습니다. char은 해독하기가 가장 쉽습니다. 우리는 처음에는 '안녕'에서 '올'로 바뀌 었음을 알 수 있습니다.

다음은 int이며, 25에서 255로 변경됩니다. 오프셋 0x4에서 0x19와 0xff의 두 값을 볼 수 있지만 나머지 바이트는 어디에 있습니까? 0x5-0x7입니까? (int가 "거꾸로"저장되어 있다고 제안 하시겠습니까?) 아마 0x2-0x3 오프셋은 우리가 사용한 1 바이트 문자 (C 구조체는 워드 크기에 따라 정렬 됨)를 채우기위한 것일뿐입니다.

그렇다면 float가 있습니다. 실제로 플로트가 내부적으로 어떻게 인코딩되는지 모르므로 차이점을 추론하려고하지는 않습니다. 아마도 IEEE 표준을 찾아 볼 수 있습니다.

마지막으로 포인터로 닫습니다. 해당 구조체에 포인터가 있으면 프로그램을 segfault하지 않고 해당 메모리 주소를 찾아 봐야합니다. 그것들은 다른 구조체에 대한 포인터 일 수 있습니다.이 경우이 프로세스를 반복하는 기쁨을 누릴 수 있습니다.

내가 말했듯이, 이것은 내 5 분 걸릴 것이고, 실제로 전에 이것을 시도한 적이 없습니다. 이것은 여러분이 이것에 대해 어떻게 생각하는지에 대한 첫 번째 추측이었습니다. 알려진 입력으로 시작한 다음 구조체에 저장된 데이터 형식과 해당 바이트 오프셋을 확인할 때까지 한 번에 한 가지만 변경하십시오.

+0

매우 도움이됩니다. 고맙습니다. – Patrick