【文章标题】: 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中的名称,如下
DLLEntryPoint就不用说了,可以参考PEiD的插件编写资料,这里就不放于重点了,此文探查去UPX壳的过程代码:char* __stdcall LoadDLL ()
{
return "Unpacker for 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()~~~
附件中是经注释的IDA database代码: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完成,但是还需要修复一下输入表
}
----------
END