萌动歌姬通信解密 (C++)

双草提供的 IDA 伪代码,找我修改为人眼可阅读的形式。

改了半天发现改出来的内容不对,于是连蒙带猜把算法补全了。

算法讲白了就是生成一个 xor key 的集合 (8 字节),然后依次对密文里的数字、字母进行 xor 操作,若结果也是数字、字母的话则保留,否则不进行更改。

每次进行更改,将 xor key 的索引 +1, 到达尾部的时候将每个 key 的值改为 k = ((k * 3) & 0x0F),继续循环。

相关代码参考下方代码:

#include <cstdlib>
#include <stdio.h>
#include <string.h>

/**
 * Convert a hex (0-F) to its representation.
 * @param c     Char ('0' ~ 'F')
 * @return      Char (0x0 ~ 0xF)
 */
inline char hexToChar(char c) {
  if (c >= '0' && c <= '9')
    return c - '0';

  if (c >= 'A' && c <= 'Z')
    return c - 'A' + 10;

  if (c >= 'a' && c <= 'z')
    return c - 'z' + 10;

  return c;
}

/**
 * Check if a char is valid (0-9, a-z, A-Z).
 * @param c  The char to check.
 * @return   true if valid, false otherwise.
 */
inline bool isAlphaOrDigit(char c) {
  return (c >= '0' && c <= '9')
          || (c >= 'A' && c <= 'Z')
          || (c >= 'a' && c <= 'z');
}

/**
 * Encode / Decode response from server.
 * @param lpKey       Communication key, constant.
 * @param keySize     Key size.
 * @param lpResponse  Response buffer to read and write.
 * @return            true if encode/decode successfully.
 */
bool encodeResponse(const char *lpKey, int keySize, char *lpResponse) {
  char *xorKeys;
  signed int dataLen;

  if (!(lpKey && keySize >= 1 && strlen(lpKey) >= keySize && lpResponse))
    return false;

  dataLen = strlen(lpResponse);
  if (dataLen < 1) {
    return false;
  }

  // Reverse search for char '}'.
  int jsonLength = 0;
  for (int i = dataLen - 1; i >= 0; i--) {
    if (lpResponse[i] == '}') {
      jsonLength = i;
      break;
    }
  }

  // Hex Char Representation to binary data.
  xorKeys = new char[keySize];
  if (keySize >= 1) {
    for (int i = 0; i < keySize; i++) {
      xorKeys[i] = hexToChar(lpKey[i]);
    }
  }

  for (int i = 0, k = 0; i < dataLen; i++) {
    if (i >= jsonLength) continue;

    char c = lpResponse[i];

    // check if c is a valid char.
    if (!isAlphaOrDigit(c)) continue;

    // xor with key
    c ^= xorKeys[k];

    // check if xored c is a valid char.
    if (!isAlphaOrDigit(c)) continue;
    
    // Store decrypted char.
    lpResponse[i] = c;
    
    // Check if key have been looped.
    k++;
    if (k == keySize) {
      for (int j = 0; j < keySize; j++) {
        // Limit xorKey from 0~F
        xorKeys[j] = (3 * xorKeys[j]) & 0x0F;
      }
      k = 0;
    }
  }

  delete[] xorKeys;
  return true;
}

bool getResponse(char *lpResponse) {
  if (lpResponse) {
    encodeResponse("EB1CEB1C", 8, lpResponse);
    return true;
  }

  return false;
}

char szTestData[] = "{\"rkxqcnsk_oaum\":{\"ktwlesjza_zlbin\":"
        "\"ojyzoRquo59NspWEMBR4rr2PLsF3cegoDmRz0DzC40vzaiaurXUnqzm"
        "Y64TQzQKSKh6jSOGJZZSI5YaRGvQyHR8\"},\"sxktuz_hknl\":940}";

int main(int argc, char** argv) {
  printf("encrypted: %s\n", szTestData);
  getResponse(szTestData);
  printf("decrypted: %s\n", szTestData);

  return 0;
}
encrypted: {"rkxqcnsk_oaum":{"ktwlesjza_zlbin":"ojyzoRquo59NspWEMBR4rr2PLsF3cegoDmRz0DzC40vzaiaurXUnqzmY64TQzQKSKh6jSOGJZZSI5YaRGvQyHR8"},"sxktuz_hknl":940}
decrypted: {"response_data":{"authorize_token":"aipveRxud13GxtYNLNR4rr2PBxG3ooflDiXz1GzG40xyheovrQYdxqiS64TXqUEXJd8aRCMKYZWC4ZeRIuXuFQ1"},"status_code":200}

-- Jixun.Moe 于火车

Jixun的头像

Jixun