用于解密功能的 IDA Pro C 转储

逆向工程 C 艾达
2021-06-26 02:44:57

我一直在与这种感染作斗争,这种感染将我的文件加密为 512 字节块。我们已经设法从支付解密器费用的用户那里找到了我们认为在 IDA 中的解密函数(代码被严重混淆)。下面是加密函数的C转储:

int __stdcall sub_40C78E(int a1, int a2, int a3, int a4)
{
  int result;
  char v5; 
  int v6; 
  int v7; 
  int v8; 

  v7 = a1;
  v6 = a2;
  v5 = 0;
  result = 0;
  if ( a2 )
  {
    v8 = a3;
    do
    {
      LOBYTE(v8) = v5 + v8;
      *(_BYTE *)v7 ^= v8;
      v5 = *(_BYTE *)v7++;
      v8 = __ROL__(a4 + v8, 8);
      --v6;
    }
    while ( v6 );
    result = v8;
  }
  return result;
}

我的朋友试图简化它或理解它,这就是他想出的:

int __stdcall sub_40C78E((_BYTE *)buffer, int nonce1, int nonce2)
{
  char v5; 
  int n; 
  int v8; 

  n = 0x400;    // It is a little bit confusing, because the length of block is 0x200 (rest of buffer is filled by 0).
                        // Only first 0x200 bytes are saved to a file for block CT0A.
  v5 = 0;
  v8 = nonce1;

  do
  {
      LOBYTE(v8) = v5 + LOBYTE(v8);
      *buffer ^= LOBYTE(v8);
      v5 = *buffer;
      buffer++;
      v8 = __ROL__(nonce2 + v8, 8);
      --n;
  }
  while ( n );

return v8;       
}

假设 nonce1 和 nonce2 代表某种键。

我们在这种感染中发现,如果您将密文的第一个字节与纯文本进行异或,您将获得一个关键字节,您可以使用它来获取每个文件的第一个字节。这个函数是有意义的,因为第一次在循环中键被添加到 0,这意味着它只是键。但是后来这个人使用了某种奇怪的 CFB 类型的异或加密,它使用前一个异或字节和下一个密钥。

我只是不太了解这个功能,我希望这里的某个地方可以为我简化或解释它。如果有人知道如何用这些语言解释函数,我也知道 C# 和 VB。

1个回答

正如您所料,它正在执行一个非常简单的 XOR。等效代码如下所示:

int mystery(char *buff, int bufsize, int nonce1, int nonce2)
{
  int result = 0;
  // ch is the next byte (character) in the buffer
  char ch = 0; 
  int count = bufsize; 
  char *ptr = buff; 
  int x;

  for (x = nonce1; count; --count)
  {
      // this bit of trickery just replaces the low 8 bits
      // of x with the low 8 bits of (x+ch) neglecting carry, if any
      x = (x & ~0xff) | ((x+ch) & 0xff);
      // XOR the buffer with the calculated x value
      *ptr ^= x;
      // read in the next character into ch
      ch = *ptr++;
      // obfuscate by adding nonce2 
      x += nonce2;
      // if x = 0x12345678, this would make it 0x34567812
      // for 32-bit ints.  Just a rotate left of 8 bits.
      x = (x<<8) | ((x >>((sizeof(int)-1)*8) ) & 0xff);  
  }
  result = x;
  // return the last calculated x which may be used to chain all
  // of the blocks together.  That is, the return value x is 
  // probably passed as nonce1 to encode the next block.
  return result;
}