吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 6203|回复: 7
收起左侧

[原创] 窥见ACPR1.32的ReplaceCode

[复制链接]
nick.coton 发表于 2009-10-24 15:48
【文章标题】: 窥见ACPR1.32的ReplaceCode
【文章作者】: nick
【作者主页】: www.begin09.com
【作者声明】: 成长的足迹~
--------------------------------------------------------------------------------
【详细过程】
  ACPR1.32的ReplaceCode,是将原程序中的5个字节的指令替换成CALL ReplaceCodeFun(call指令正好占用5字节),
  在ReplaceCodeFun中动态还原被替换的5个字节,同时参杂5个字节的垃圾指令,然后转去执行被还原的代码。
  被替换的5字节正常指令呈现出"2+3"或"3+2"的规律,即有2条正常的指令,一条是2字节,一条是3字节。
  被参杂的5字节垃圾指令,2字节的垃圾指令通常有2种,ADD REG1,REG2/SUB REG1,REG2垃圾指令对和XOR REG1/REG2垃圾指令对。
  
  在修复ReplaceCode的时候存在2张表:
  表一:被加密过的ReplaceCode的字节码表。该表10个字节为一项,正好对应解码出来的10字节指令(正常5字节+垃圾5字节)。
  表二:存放被ReplaceCode的代码的下一条指令的偏移地址(有点拗口),实际这个表中的项的值-5就是被ReplaceCode代码的起始偏移地址。
  
  
  壳区段.perplex作用:
  1 部分ReplaceCode将动态解码到壳的区段然后转去执行
  2 部分资源(图标,图标组)被抽取到了壳区段当中
  完美修复ReplaceCode所替换的代码后,还要将资源目录相关项修复,才能删除壳区段。
  
  示例中ReplaceCodeFun地址:00480416
  部分修复代码如下,完整代码和例子见附件
  //======================================================
  //    函数描述:搜索匹配的二字节垃圾代码的位置
  //    参数描述:pStart             搜索的起始位置
  //              nRelativeStartPos  返回时用于存放找到的垃圾代码相对于起始位置的位置
  //              cByte1             要搜索的垃圾代码的第一个字节
  //              cByte2             要搜索的垃圾代码的第二个字节
  //    返回值:  搜索成功 true / 搜索失败 false
  //======================================================
  bool Search2BytesOpCode( PVOID pStart, int& nRelativeStartPos, unsigned char cByte1, unsigned char cByte2 )
  {
          bool bRetCode = false;
          nRelativeStartPos = 0;
  
          while ( true )
          {
                  int nOpCodeSize = GetOpCodeSize( pStart );
  
                  if ( 1 == nOpCodeSize && 0xc3 == ((unsigned char*)pStart)[0] ) 
                  {
                          break;
                  }
                  else if ( 2 == nOpCodeSize 
                                  && cByte1 == ((unsigned char*)pStart)[0] 
                                  && cByte2 == ((unsigned char*)pStart)[1] )
                  {
                          bRetCode = true;
                          break;
                  }
                  //下一个起始搜索位置增加一个OpCodeSize
                  pStart = (char*)pStart + nOpCodeSize;
                  //记录当前位置距首次搜索起始位置的偏移
                  nRelativeStartPos += nOpCodeSize;
          }
          return bRetCode;
  }
  
  //主函数
  int main(int argc, char* argv[])
  {
      DWORD dwPos = 0;
      DWORD dwCount = 0;
      unsigned char szBuf[10] = { 0 };
      DWORD  dwBufPos = 0;
      int i = 0;
          int j = 0;
          int k = 0;
          int nOpCodeSize = 0;
          
          //将被加密的ReplaceCode循环解密
      for ( i = 0; i < nReplaceCodeItems * 10; i++ )
      {
                  *( ( (unsigned char *)CryptTable ) + i ) ^= CryptKey;
      }
  
      for ( i=0; i < nReplaceCodeItems; i++ )
      {
                  dwPos = 0;
                  dwBufPos = 0;
                  j = 0;
                  nOpCodeSize = 0;
                  memset( szBuf, 0x90, sizeof( szBuf ) );
  
                  while ( true )
                  {
                          nOpCodeSize = GetOpCodeSize( ( LPVOID )&CryptTable[i][j] );
  
                          //如果当前指令是retn指令,则退出本次修正
                          if ( 1 == nOpCodeSize && 0xc3 == CryptTable[i][j] )
                          {
                                  for ( ; j < 10; j++ )
                                  {
                                          CryptTable[i][j] = 0x90;
                                  }
                                  break;
                          }
                          //一个字节的指令全部是垃圾指令,直接nop
                          else if ( 1 == nOpCodeSize )
                          {
                                  CryptTable[i][j] = 0x90;
                          }
                          //2字节的指令继续判断是否是垃圾指令
                          else if ( 2 == nOpCodeSize )
                          {
                                  int nRelativeStartPos = 0;
                                  //搜索add/sub垃圾指令对并nop
                                  if ( 0x03 == CryptTable[i][j] || 0x2b == CryptTable[i][j] )
                                  {
                                          if ( Search2BytesOpCode( (LPVOID)&CryptTable[i][j+2], 
                                                                                           nRelativeStartPos, 
                                                                                           0x2e - CryptTable[i][j], 
                                                                                           CryptTable[i][j+1] ) )
                                          {
                                                  CryptTable[i][j] = 0x90;
                                                  CryptTable[i][j+1] = 0x90;
                                                  CryptTable[i][j+2+nRelativeStartPos] = 0x90;
                                                  CryptTable[i][j+3+nRelativeStartPos] = 0x90;
                                          }
                                  }
                                  //搜索xor垃圾指令并nop
                                  if ( 0x33 == CryptTable[i][j] )
                                  {
                                          if ( Search2BytesOpCode( (LPVOID)&CryptTable[i][j+2], 
                                                                                           nRelativeStartPos, 
                                                                                           CryptTable[i][j], 
                                                                                           CryptTable[i][j+1] ) )
                                          {
                                                  CryptTable[i][j] = 0x90;
                                                  CryptTable[i][j+1] = 0x90;
                                                  CryptTable[i][j+2+nRelativeStartPos] = 0x90;
                                                  CryptTable[i][j+3+nRelativeStartPos] = 0x90;
                                          }
                                  }
                          }
                          //调整下条指令的起始点
                          j += nOpCodeSize;
                  }
                  
                  j = 0;
                  int k = 0;
                  //循环拷贝正常指令到临时buffer
                  for ( ; j < sizeof(szBuf); j++ )
                  {
                          if ( 0x90 != CryptTable[i][j] )
                          {
                                  szBuf[k++] = CryptTable[i][j];
                          }
                  }
                  //将临时buffer的正常指令拷贝回原加密表
                  memcpy( (LPVOID)&CryptTable[i][0], szBuf, sizeof(szBuf) );                
      }
  
          //处理文件
          HANDLE hOrigFile = NULL;
          HANDLE hNewFile = NULL;
          HANDLE hMapFile = NULL;
          DWORD dwMappedAddr = 0;
          DWORD dwAddr = 0;
          DWORD dwFileSize = 0;
          char* pWriteBuf = NULL;
          DWORD dwTemp = 0;
  
          hOrigFile = CreateFile( strFileName,
                                                          GENERIC_READ | GENERIC_WRITE,
                                                          FILE_SHARE_READ,
                                                          NULL,
                                                          OPEN_EXISTING,
                                                          FILE_ATTRIBUTE_NORMAL,
                                                          NULL
                                                     );
          if ( INVALID_HANDLE_VALUE == hOrigFile )
          {
                  printf( "ErrCode:%d\n", GetLastError() );
                  goto Exit0;
          }
  
          hNewFile = CreateFile( strNewFileName,
                                                     GENERIC_READ | GENERIC_WRITE,
                                                     FILE_SHARE_READ,
                                                        NULL,
                                                     CREATE_ALWAYS,
                                                     FILE_ATTRIBUTE_NORMAL,
                                                     NULL
                                                  );
          if ( INVALID_HANDLE_VALUE == hNewFile )
          {
                  printf( "ErrCode:%d\n", GetLastError() );
                  goto Exit0;
          }        
          
          dwFileSize = GetFileSize( hOrigFile, 0 );
  
          pWriteBuf = new char[ dwFileSize ];
          if ( !pWriteBuf )
          {
                  goto Exit0;
          }
          memset( pWriteBuf, 0, dwFileSize );
  
          ReadFile( hOrigFile, pWriteBuf, dwFileSize, &dwTemp, 0 );
          if ( dwFileSize != dwTemp )
          {
                  goto Exit0;
          }
          //循环修改数据
          for ( i = 0; i < 1842; i++ )
          {
                  dwAddr = PatchOffset[i] + (unsigned long)(LPVOID)pWriteBuf - 5;
                  for ( j = 0; j < 5; j++ )
                  {
                          *( (char*)dwAddr + j ) = CryptTable[i][j];
                  }
          }
  
          WriteFile( hNewFile, pWriteBuf, dwFileSize, &dwTemp, 0 );
          if ( dwFileSize != dwTemp )
          {
                  goto Exit0;
          }
  
  Exit0:
          if ( hNewFile )
          {
                  CloseHandle( hNewFile );
          }
          if ( hMapFile )
          {
                  CloseHandle( hMapFile );
          }
          if ( hOrigFile )
          {
                  CloseHandle( hOrigFile );
          }
          system( "PAUSE" );
      return 0;
  }
  
  
--------------------------------------------------------------------------------
【版权声明】: 本文原创于天草软件安全培训论坛, 转载请注明作者并保持文章的完整, 谢谢!

                                                       2009年10月24日 15:11:25
示例.rar (251.9 KB, 下载次数: 6)
RepairAcprRC修复.rar (26.72 KB, 下载次数: 4)

免费评分

参与人数 1威望 +1 收起 理由
wgz001 + 1 感谢发布原创作品,[吾爱破解]因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

wangkui 发表于 2009-10-24 16:26
沙发支持下
小糊涂虫 发表于 2009-10-24 17:02
疾风之翼 发表于 2009-10-25 11:15
josong 发表于 2009-10-25 12:14
本帖最后由 josong 于 2009-10-25 12:16 编辑

完全看不懂...
ReplaceCode这词最近常见, ..到底他是什么..
跟一些文章讲的"被偷代码"有什么不一样呢?
请高人指点..
 楼主| nick.coton 发表于 2009-10-25 13:33
5# josong

下载我提供的实例,参照文章中给出的ReplaceCoceFunc的地址,自己跟进去看看,你就知道ReplaceCode长相是啥样子了
ZeNiX 发表于 2009-10-26 13:45
很直接的分析,
很精彩的代碼.
datochan 发表于 2009-11-1 17:19
还是这个论坛排版比较好,比begin09的代码舒服多了。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-5-9 22:58

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表