首页
论坛
课程
招聘
[原创]PEiD中unUPX.dll(UPX unpacker)插件的逆向分析笔记
2007-8-21 18:45 10404

[原创]PEiD中unUPX.dll(UPX unpacker)插件的逆向分析笔记

2007-8-21 18:45
10404
【文章标题】: 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

2022 KCTF春季赛【最佳人气奖】火热评选中!快来投票吧~

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (6)
雪    币: 3
活跃值: 活跃值 (15)
能力值: ( LV9,RANK:330 )
在线值:
发帖
回帖
粉丝
theOcrat 活跃值 8 2007-8-21 19:00
2
0
这个缩进~~~~~
雪    币: 1038
活跃值: 活跃值 (9862)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
kanxue 活跃值 8 2007-8-21 20:57
3
0
文章不错,感谢分享!
缩进这块论坛支持的还不很理想,以后再优化一下。
雪    币: 202
活跃值: 活跃值 (20)
能力值: ( LV13,RANK:1250 )
在线值:
发帖
回帖
粉丝
冲天剑 活跃值 31 2007-8-22 05:15
4
0
自文档化这一步做的稍欠完全,诸如word_404460、EBP_18此类的符号都是反汇编器产生的,人工反编译后要尽量避免再残留这些无意义的符号,否则,表示你对这个程序的功能理解得还不够完全。

全局数据要写在函数体之外,你那个DoMyJob函数体里写了很多的字符串常量,这是不对的。如果认为这是只在单个函数内被引用的全局数据,则要加static声明。

另外,VC或WinSDK中已经预定义的常数,能用符号表示就用符号表示。
譬如:MessageBox(...) == 6  这里的6应该写成ID_YES;
表示PE文件的DOS签名或者PE签名的常数0x5A4D或0x4550,应该分别写成
IMAGE_DOS_SIGNATURE和IMAGE_NT_SIGNATURE。
雪    币: 661
活跃值: 活跃值 (682)
能力值: ( LV9,RANK:190 )
在线值:
发帖
回帖
粉丝
qyc 活跃值 4 2007-8-22 10:00
5
0
感谢分享!
雪    币: 3
活跃值: 活跃值 (15)
能力值: ( LV9,RANK:330 )
在线值:
发帖
回帖
粉丝
theOcrat 活跃值 8 2007-8-22 13:57
6
0
万分感谢前辈的指点,代码已修改
雪    币: 538
活跃值: 活跃值 (20)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Saver 活跃值 2007-8-24 23:20
7
0
试试看看吧
游客
登录 | 注册 方可回帖
返回