【文章标题】: PEiD中unUPX.dll(UPX unpacker)插件的逆向分析笔记
【文章作者】: the0crat
【作者邮箱】: the0crat.cn_at_gmail.com
【作者主页】: http://the0crat.spaces.live.com
【生产日期】: 20070821
【编写语言】: VC++ 6.0
【使用工具】: IDA + OD + IceSword
【作者声明】: 本文仅供研究学习,本人对因这篇文章而导致的一切后果,不承担任何法律责任。本文中的不足之处请各位多多指教
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
--------------------------------------------------------------------------------
【详细过程】

就是试试逆向,找了个10多KB的,不会太花时间也不会没劲.第一次搞逆向,没什么经验,也不知到底该做到什么程度,不足之处请见谅,多多指教.

Exports中有三个函数,
LoadDLL
DoMyJob
DllEntryPoint

其中LoadDLL是返回此DLL于PEiD中的名称,如下

代码:

char* __stdcall LoadDLL ()
{
  return "Unpacker for UPX";
}

DLLEntryPoint就不用说了,可以参考PEiD的插件编写资料,这里就不放于重点了,此文探查去UPX壳的过程


先附上要用到的两个函数,DoMyJob()中的,先提前放上来

代码:

////////////////////////////////////////////////////////
//
//  _IsFileExisting
//  return : TRUE  if File existing
//           FALSE if File not existing
//
////////////////////////////////////////////////////////

BOOL __stdcall _IsFileExisting (char *psFN)
{
  WIN32_FIND_DATA    WFD;
  if (FindFirstFile (psFN, &WFD) == INVALID_HANDLE_VALUE)
  {
    return FALSE;
  }
  return TRUE;
}

////////////////////////////////////////////////////////
//
//  _CalcAddrOffset
//  两次用到用来计算偏移量
//  return : Address (used by SetFilePointer)
//
////////////////////////////////////////////////////////
int __stdcall _CalcAddrOffset (  char*  pPartOfFileImage,
                int    nBaseAddr,
                int    word_404460)
{
  int*  pn  = 0;
  int    n  = 0;
  int    i  = 0;

  pn = (int*)pPartOfFileImage;
  n = nBaseAddr;
  pn += 3;
  for ( i = 0; i < word_404460; i++ )
  {
    if ( *pn <= n )
    {
      if ( (*pn + *(pn + 1)) > n )
      {
        n = (n - *pn) + *(pn + 2);
      }
    }
    pn += 0xA;
  }
  return n;
}
//


下面是DoMyJob()~~~



代码:

BOOL __stdcall DoMyJob (int    UnknownArg1,
            HWND  hWnd,
            char  *pFileName
            )
{
  unsigned long  sBuffer[2]      = {0};
  unsigned long  *lpBuffer      = &sBuffer[0];
  unsigned long  ulOffset      = 0;  //PE文件偏移0x3C处的值,频繁用来计算其他偏移值
  unsigned long  ulBuff        = 0;  //EBP_14,临时变量,存储读取的数据
  int        nFileSize      = 0;  //文件大小
  int        nUPXSign      = 0;  //EBP_28    ulOffset + _CalcAddrOffset    UPX的标识
  int        nStr1AddrInFile    = 0;  //EBP_2C    输出的文件中将写入Str1[0x31]的地址
  int        nStr1FullSize    = 0;  //EBP_30    sizeof (Str1 + 填补的0)
  int        nPEHeaderAddr    = 0;  //EBP_18    ulOffset + 0x34    0x00400000
  int        nHeapSize      = 0;  //EBP_1C    ulOffset + 0x50    输出文件的完整内存映像大小
  int        nBaseAddr      = 0;  //EBP_10
  int        i          = 0;  //temp var
  int        n          = 0;  //temp var
  int        *pn          = 0;  //temp var
  int        nPatch        = 0xFEEB;  //用来改写程序内存的一个值
  const  int    nCounter      = 3;  //循环次数
  HANDLE      hMemBlock      = 0;
  HANDLE      hFile        = 0;
  char      *lpCaption      = 0;
  char      sPartOfFileImage[150]  = {0};  //压缩文件的内存映像
  char      *pPartOfFileImage  = &sPartOfFileImage[0];
  char      *p          = 0;  //temp var
  unsigned long  lNumberOfBytesRead  = 0;
  LPDWORD      lpNumberOfBytesRead  = &lNumberOfBytesRead;
  STARTUPINFO          SI    = {0};  //EBP_78
  PROCESS_INFORMATION      PI    = {0};  //EBP_88
  CONTEXT            CT    = {0};
  static  char  sNewFileName[]    = "unpacked.exe";
  static  char  sExistingFileName[]  = "unpacked_.exe";

  //一些用来改写的值
  static  char  sChar1[]      =  "\xE0\x00\x00\xE0";
  static  char  sChar2[]      =  "\x40\x00\x00\xC0";
  static  char  sCharunpacked[]    =  "unpacked";
  static  char  sCharpusher[]    =  "_pusher_";
  static  char  Str1[0x31]      =  "\x00\x8D\x40\x00\x5F\x70\x75\x73\x68\x65\x72\x5F\x00\x8D\x40\x00"
                      "\x34\x41\x2B\x01\x58\x44\x2B\x01\x88\x30\x2B\x01\x90\x30\x2B\x01"
                      "\x5C\x44\x2B\x01\x60\x44\x2B\x01\x94\x30\x2B\x01\x54\x44\x2B\x01";



  if ( pFileName == NULL )
  {
    MessageBox ( hWnd, "no file ?", lpCaption, MB_OK|MB_APPLMODAL );
    return FALSE;
  }

  hFile = CreateFile ( pFileName,
             GENERIC_READ,
             FILE_SHARE_READ,
             NULL,
             OPEN_EXISTING,
             FILE_ATTRIBUTE_NORMAL,
             NULL
             );
  
  if ( hFile == INVALID_HANDLE_VALUE )
  {
    MessageBox ( hWnd, "FAILED (can't open file)", lpCaption, MB_OK|MB_APPLMODAL );
    return FALSE;
  }
  //_OpenFile

  if (( nFileSize = GetFileSize ( hFile, NULL )) <= 0x258 )
  {
    MessageBox ( hWnd, "FAILED (file size too small)", lpCaption, MB_OK|MB_APPLMODAL );
    return FALSE;
  }
  //_IsFileSizeRight

  ReadFile ( hFile, lpBuffer, 2, lpNumberOfBytesRead, NULL );
  if ( *lpBuffer != IMAGE_DOS_SIGNATURE)
  {
    MessageBox ( hWnd, "FAILED (invalid EXE)", lpCaption, MB_OK|MB_APPLMODAL );
    return FALSE;
  }
  //_IsFileWin32

  SetFilePointer  ( hFile, 0x3C, NULL, FILE_BEGIN );
  ReadFile    ( hFile, &ulOffset, 4, lpNumberOfBytesRead, NULL );
  SetFilePointer  ( hFile, ulOffset, NULL, FILE_BEGIN );
  ReadFile    ( hFile, &ulBuff, 4, lpNumberOfBytesRead, NULL );
  if ( ulBuff != IMAGE_NT_SIGNATURE )
  {
    MessageBox ( hWnd, "FAILED (invalid PE)", lpCaption, MB_OK|MB_APPLMODAL );
    return FALSE;
  }
  //_IsFileValidPE

  SetFilePointer  ( hFile, ulOffset + 0x16, NULL, FILE_BEGIN );
  ReadFile    ( hFile, &ulBuff, 2, lpNumberOfBytesRead, NULL );
  if (( ulBuff &= 0x2000 ) == 0x2000 )
  {
    MessageBox ( hWnd, "I'm sorry but this unpacker won't work with .dll files", lpCaption, MB_OK|MB_APPLMODAL );
    return FALSE;
  }
  //_IsFileNotDLL

  /*
  if ( nFileSize > ulOffset )
  {
    return FALSE;
  }
  */
  //loc_402376

  SetFilePointer  ( hFile, ulOffset + 6, NULL, FILE_BEGIN );
  ReadFile    ( hFile, &ulBuff, 2, lpNumberOfBytesRead, NULL );

  //
  SetFilePointer  ( hFile, ulOffset +0xF8, NULL, FILE_BEGIN );
  ReadFile    ( hFile, pPartOfFileImage, 0x28 * 3, lpNumberOfBytesRead, NULL );
  //_ReadPartOfFileIntoMem

  pn      = (int*)&sPartOfFileImage[0];
  nStr1AddrInFile  = int (( ulBuff << 3 ) * 5 + ulOffset + 0xF8);
  nStr1FullSize  = (*(pn + 0x5) - 0x1D) - nStr1AddrInFile + 1;

  SetFilePointer  ( hFile, ulOffset + 0x34, NULL, FILE_BEGIN );
  ReadFile    ( hFile, &nPEHeaderAddr, 4, lpNumberOfBytesRead, NULL );

  SetFilePointer  ( hFile, ulOffset + 0x50, NULL, FILE_BEGIN );
  ReadFile    ( hFile, &nHeapSize, 4, lpNumberOfBytesRead, NULL );

  SetFilePointer  ( hFile, ulOffset +0x28, NULL, FILE_BEGIN );
  ReadFile    ( hFile, &nBaseAddr, 4, lpNumberOfBytesRead, NULL );

  n = _CalcAddrOffset ( pPartOfFileImage, nBaseAddr, nCounter);

  SetFilePointer  (hFile, n, NULL, FILE_BEGIN);
  ReadFile    (hFile, &nUPXSign, 2, lpNumberOfBytesRead, NULL);
  CloseHandle    (hFile);

  // UPX的标识:
  if ((nUPXSign -= 0xE8) == 0)
  {
  }
  else if ((nUPXSign -= 0x60A8) == 0)
  {
  }
  else if ((nUPXSign -= 0x5CD0) == 0)
  {
  }
  else if ((nUPXSign -= 0x2A00) == 0)
  {
  }
  else
  {
    MessageBox (hWnd, "No UPX signature were found...", lpCaption, MB_OK|MB_APPLMODAL);
    if ( MessageBox (hWnd, "Still wanna try to unpack it ?", "(if you are sure its UPX)", MB_YESNO|MB_ICONQUESTION|MB_APPLMODAL) == IDNO)
    {
      return FALSE;
    }
  }

  GetStartupInfo (&SI);
  if (CreateProcess (  pFileName,
            NULL,
            NULL,
            NULL,
            FALSE,
            CREATE_SUSPENDED,
            NULL,
            NULL,
            &SI,
            &PI
            ) == 0 )
  {
    MessageBox (hWnd, "Failed to run program", lpCaption, MB_OK|MB_APPLMODAL);
    return FALSE;
  }

  // 找OEP:
  p = (char*) nBaseAddr + nPEHeaderAddr + 0x14E;
  for (i = 0; i < 0x50; i++)
  {
    ReadProcessMemory (PI.hProcess, p, &ulBuff, 2, lpNumberOfBytesRead);
    if (ulBuff == 0xE961)
    {
      break;
    }
    else if (ulBuff == 0xE9CC)
    {
      break;
    }
    else if (ulBuff == 0xE960)
    {
      break;
    }
    p++;
    if(i == 0x4F) //循环结束还没有找到OEP
    {
      MessageBox (hWnd, "were unable to find OEP, could be a modified version.", "closing down...", MB_OK|MB_APPLMODAL);
      TerminateProcess (PI.hProcess, 0);
      return FALSE;
    }
  }

  //loc_402605:
  p += 2;
  ReadProcessMemory (PI.hProcess, p, &ulBuff, 4, lpNumberOfBytesRead);
  ulBuff = ulBuff + (unsigned long)p + 4 - nPEHeaderAddr;
  p--;
  WriteProcessMemory (PI.hProcess, p, &nPatch, 2, lpNumberOfBytesRead);
  CT.ContextFlags = CONTEXT_FULL;

  do{
    ResumeThread (PI.hThread);
    Sleep (1);
    SuspendThread (PI.hThread);
    GetThreadContext (PI.hThread, &CT);
  } while ((DWORD)p != CT.Eip );

  if (_IsFileExisting (pFileName) == 1)
  {
    if (MessageBox (hWnd, "A file called unpacked.exe already exists, do you want to overwrite it ?", "Overwrite ?", MB_YESNO|MB_ICONQUESTION|MB_APPLMODAL) != IDYES)
    {
      MessageBox (hWnd, "Terminating Process...", lpCaption, MB_OK|MB_APPLMODAL);
      TerminateProcess (PI.hProcess, 0);
      return FALSE;
    }
    DeleteFile (&sNewFileName[0]);
  }

  //_WriteUnpackedFile:
  if (nHeapSize != 0)
  {
    hMemBlock = HeapAlloc (GetProcessHeap(), 0, nHeapSize);
    if (hMemBlock == 0)
    {
      MessageBox ( hWnd, "HeapAlloc() failed", "", MB_OK);
    }
  }

  ReadProcessMemory (PI.hProcess, (char*)nPEHeaderAddr, hMemBlock, nHeapSize, lpNumberOfBytesRead);
  hFile = CreateFile (&sNewFileName[0], 0xC0000000, 3, 0, 2, 0x80, 0);
  WriteFile (hFile, hMemBlock, nHeapSize, lpNumberOfBytesRead, 0);
  if (hMemBlock != 0)
  {
    if ( !HeapFree (GetProcessHeap(), 1, hMemBlock) )
    {
      MessageBox (hWnd, "HeapFree() failed", "", MB_OK);
    }
  }
  SetFilePointer  (hFile, ulOffset + 0x28, 0, FILE_BEGIN);
  WriteFile    (hFile, &ulBuff, 4, lpNumberOfBytesRead, 0);

  p = pPartOfFileImage;
  if (nCounter != 0)
  {
    n = 1;
    for (i = 0; i < nCounter; i++)  //nCounter = 3
    {
      strncpy (p,  &sCharunpacked[0], 8);
      *(p + 0x10) = *(p + 0x8);
      *(p + 0x11) = *(p + 0x9);
      *(p + 0x12) = *(p + 0xA);
      *(p + 0x13) = *(p + 0xB);
      *(p + 0x14) = *(p + 0xC);
      *(p + 0x15) = *(p + 0xD);
      *(p + 0x16) = *(p + 0xE);
      *(p + 0x17) = *(p + 0xF);
      if (n == 1)
      {
        *(p + 0x24) = sChar1[0];
        *(p + 0x25) = sChar1[1];
        *(p + 0x26) = sChar1[2];
        *(p + 0x27) = sChar1[3];
      }
      else
      {
        *(p + 0x24) = sChar2[0];
        *(p + 0x25) = sChar2[1];
        *(p + 0x26) = sChar2[2];
        *(p + 0x27) = sChar2[3];
      }
      n++;
      p += 0x28;
    }
  }

  SetFilePointer (hFile, ulOffset + 0xF8, 0, FILE_BEGIN);
  p = pPartOfFileImage;
  if (nCounter > 0)
  {
    for (i = 0; i< nCounter; i++)
    {
      WriteFile ( hFile, p, 0x28, lpNumberOfBytesRead, 0);
      p += 0x28;
    }
  }

  //loc_4027C1:
  GetFileSize    (hFile, 0);
  SetFilePointer  (hFile, ulOffset + 8, 0, FILE_BEGIN);
  WriteFile    (hFile, &sCharpusher, 8, lpNumberOfBytesRead, 0);
  SetFilePointer  (hFile, nStr1AddrInFile, 0, FILE_BEGIN);

  if (nStr1FullSize > 0x30)
  {
    for (i = 0; i < 0x30; i++)
    {
      WriteFile (hFile, &Str1, 1, lpNumberOfBytesRead, 0);
    }
    SetFilePointer (hFile, nStr1AddrInFile + 0x30, 0, FILE_BEGIN);
    for (i = 0; i < (nStr1FullSize - 0x30); i++)
    {
      WriteFile (hFile, "\x00", 1, lpNumberOfBytesRead, 0);
    }
  }

  n = _CalcAddrOffset ( pPartOfFileImage, nBaseAddr, nCounter);

  SetFilePointer  (hFile, n, 0, FILE_BEGIN);

  //loc_40284B:
  for (i = 0; i < 0x30; i++)
  {
    WriteFile (hFile, &Str1, 1, lpNumberOfBytesRead, 0);
  }

  CloseHandle (hFile);
  /*
  //  BOOL __stdcall _RebuildImport (HWND  hWnd,
                     int  EBP_80,
                     int  EBP_14,
                     char  *sFN,
                     int  i,
                     int  j
                     )
  //  通过ImpREC.dll修复输入表,就不弄它了

  if (_RebuildImport ( &sNewFileName, 0xA, 0) != 0 )
  {
    DeleteFile (&sNewFileName);
    MoveFile (&sExistingFileName, &sNewFileName);
    MessageBox (hWnd, "Unpacking Done (unpacked.exe)", lpCaption , MB_OK|MB_APPLMODAL);
  }
  */
  TerminateProcess (PI.hProcess, 0);
  return TRUE;
  //dump完成,但是还需要修复一下输入表
}

附件中是经注释的IDA database


----------
END