4

我目前正在对网络协议进行逆向工程,并编写了一个小型解密协议。

我曾经将数据包的字节定义为无符号字符数组,如下所示:

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

为了不为每个数据包多次重新编译程序,我制作了一个小型 GUI 工具,它可以从字符串中获取 \xFF 表示法中的字节。我是通过以下方式做到的:

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 个字符:\x和.d3

您将需要读取字符串,然后将其解析为有效内容。对于一个简单的方法,您可以更改格式,以便输入是一个空格分隔的字符序列,编码为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 ) );

当然,不需要改变格式,你可以处理它。为此,您一次只需要读取一个字符。当你遇到 a\然后读取下一个字符,如果是x则读取接下来的两个字符(比如ch1and ch2)并将它们转换为整数值:

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 回答