4

現在、ネットワーク プロトコルのリバース エンジニアリングを行っており、小さな復号化プロトコルを作成しました。

以前は、パケットのバイトを符号なし文字配列に定義していました。次のようにします。

unsigned char buff[] = "\x00\xFF\x0A" etc.

プログラムをパケットごとに複数回再コンパイルしないようにするために、文字列から \xFF 表記でバイトを取得する小さな GUI ツールを作成しました。私はこれを次の方法で行いました:

int length = int(stencString.length());
unsigned char *buff = new unsigned char[length+1];
memcpy(buff, stencString.c_str(), length+1);

関数を呼び出すと、前の方法を使用してハードコーディングすると適切な復号化が行われますが、文字列から配列に memcpy すると、文字列の残りの部分がガベージになります。不気味な部分?どちらも同じ印刷出力です。

これが私がそれをどのように使用しているかです: http://pastie.org/private/kndfbaqgvmjiuwlounss9g

ここに kdxalgo.h があります (c) Luigi Auriemma: http://pastie.org/private/7dzemmwyyqtngiamlxy8tw

誰かが私を正しい方向に向けることができますか?

ありがとう!

4

2 に答える 2

2

ハードコーディングされたバージョンの buff に以下を使用するとどうなるかを確認してください。

unsigned char buff[] =
"\\xd3\\x8c\\x38\\x6b\\x82\\x4c\\xe1\\x1e"
"\\x6b\\x7a\\xff\\x4c\\x9d\\x73\\xbe\\xab"
"\\x38\\xc7\\xc5\\xb8\\x71\\x8f\\xd5\\xbb"
"\\xfa\\xb9\\xf3\\x7a\\x43\\xdd\\x12\\x41"
"\\x4b\\x01\\xa2\\x59\\x74\\x60\\x1e\\xe0"
"\\x6d\\x68\\x26\\xfa\\x0a\\x63\\xa3\\x88";

次のように入力すると、同じ出力が生成されるのではないかと思います\xd3\x8c\x38\x6b\x82\x4c\xe1\x1e\x6b\x7a\xff\x4c\x9d\x73\xbe\xab\x38\xc7\xc5\xb8\x71\x8f\xd5\xbb\xfa\xb9\xf3\x7a\x43\xdd\x12\x41\x4b\x01\xa2\x59\x74\x60\x1e\xe0\x6d\x68\x26\xfa\x0a\x63\xa3\x88

コンパイラは自動的に "\xd3" を取得し、予想される基になるバイナリ表現に変換します。文字のバックスラッシュ、x、d、3 を同じバイナリ表現に変換する方法が必要です。


適切にフォーマットされた入力を受け取ると確信している場合、答えはそれほど難しくありません。

unsigned char c2h(char ch)
{
    switch (ch)
    {
        case '0': return  0;
        case '1': return  1;
        case '2': return  2;
        case '3': return  3;
        case '4': return  4;
        case '5': return  5;
        case '6': return  6;
        case '7': return  7;
        case '8': return  8;
        case '9': return  9;
        case 'a': return 10;
        case 'b': return 11;
        case 'c': return 12;
        case 'd': return 13;
        case 'e': return 14;
        case 'f': return 15;
    }
}

std::string handle_hex(const std::string& str)
{
    std::string result;

    for (size_t index = 0; index < str.length(); index += 4) // skip to next hex digit
    {
        // str[index + 0] is '\\' and str[index + 1] is 'x'
        unsigned char ch = c2h(str[index+2]) * 16 + c2h(str[index+3]);
        result.append((char)ch);
    }

    return result;
}

ここでも完全なフォーマットを想定しているため、エラー処理はありません。これは最善の方法ではないため、この回答でいくつかのポイントを失うことはわかっていますが、アルゴリズムをできるだけ理解しやすくしたいと考えています。

于 2012-07-11T02:09:55.230 に答える
0

問題は、Jefferyが指摘しているように、コンパイラがを処理\xd3してその値の文字を生成することですが、文字列を読み取ると、実際\xd3には、、、およびの4文字\を読み取っています。xd3

文字列を読み取ってから、有効な内容に解析する必要があります。単純なアプローチの場合、入力が次のようにエンコードされた文字のスペースで区切られたシーケンスになるように形式を変更できます0xd3(これは解析が非常に簡単であるため)。

std::string buffer;
std::string input( "0xd3 0x8c 0x38" ); // this would be read
std::istringstream in( input );
in >> std::hex;
std::copy( std::istream_iterator<int>( in ),
           std::istream_iterator<int>(),
           std::back_inserter( buffer ) );

もちろん、フォーマットを変更する必要はなく、処理することができます。そのためには、一度に1文字だけ読む必要があります。に遭遇したとき\、次の文字を読み取りますx。次に、次の2文字(たとえばch1ch2)を読み取り、それらを整数値に変換します。

int value_of_hex( char ch ) {
   if (ch >= '0' && ch <= '9')
      return ch-'0';
   if (tolower(ch) >= 'a' && tolower(ch) <= 'f')
      return 10 + toupper(ch) - 'a';
   // error
   throw std::runtime_error( "Invalid input" );
}
value = value_of_hex( ch1 )*16 + value_of_hex( ch2 );
于 2012-07-11T03:04:37.273 に答える