我一直在与这种感染作斗争,这种感染与朋友用512字节块加密了我的文件。我们设法在IDA中找到了我们认为来自付费解密者的用户的Decryption函数(代码被严重混淆)。下面是加密函数的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类型xor加密,它使用了先前的xor'ed字节和next键。也许可以为我进一步简化或解释它。我也知道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;
}


评论


非常感谢您的回答。我几乎放弃了希望。但是,如果您不介意的话,我还有另一个问题。起初,我对此功能感到困惑。如果它是在循环中调用的函数,或者它本身进行了循环加密。基本上,每个解密器中都有一个20字节的密钥,其中4个字节用于生成标头,其他字节用于加密。在上面的函数中,您认为Nonce1和nonce2的长度是否超过1个字节(如完整键),还是大于1个字节(距键一个字节)。而且您认为这种加密方案像XOR一样是可暴力破解/可破解的吗?非常感谢。

–user3546043
2014年5月2日在15:28

它应该很容易反转。实际上,除了更改ch = * ptr ++行之外,几乎可以使用完全相同的代码。到ch = * ptr ++ ^ x;并使用相同的现时值调用它,这将有效地对先前已加扰的缓冲区进行加扰。至于您的其他问题,请作为一个单独的问题提出,我认为评论太短而无法解释。

–爱德华
2014年5月2日在16:23

至于破解,随机数是从密钥生成的,我不知道,因为该代码来自另一个受害者解密器。那么,您是否会在不知道密钥的情况下立即出现(现在)?

–user3546043
2014年5月2日在17:03

至于第一个问题,我想知道您是否可以从函数中判断传递给函数的随机数是一个字节还是一个字节以上?我想我说的没错。顺便说一句,再次感谢

–user3546043
2014年5月2日在17:04

@ user3546043:每个随机数都声明为int,所以我认为这是您计算机上的32位。至于另一个问题,我会考虑的,但这绝对是另一个问题。

–爱德华
2014年5月2日在17:59