⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unupxshell.cpp

📁 用来脱被upx加过壳的文件,包括被upxfix等修改过的文件,适用于几乎所有版本(不过特低的好像有些问题:( ) 欢迎指正!msn:phoenix8088@hotmail.com
💻 CPP
字号:
// UpxDecode.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <windows.h>
#include <winnt.h>

#define SIZE_OF_NT_SIGNATURE sizeof( DWORD ) // PE标志大小
#define NTSIGNATURE(a) (( LPVOID )(( BYTE* )a + \
						(( PIMAGE_DOS_HEADER )a )->e_lfanew  )) //定位到PE文件头部
#define PEFHDROFFSET(a) (( LPVOID )(( BYTE* )a + \
							(( PIMAGE_DOS_HEADER )a )->e_lfanew + SIZE_OF_NT_SIGNATURE )) //定位到IMAGE_FILE_HEADER结构处
#define OPTHDROFFSET(a) (( LPVOID )(( BYTE* )a + \
							(( PIMAGE_DOS_HEADER )a )->e_lfanew + SIZE_OF_NT_SIGNATURE + sizeof( IMAGE_FILE_HEADER ))) //定位到IMAGE_OPTIONAL_HEADER32结构处
#define SECHDROFFSET(a) (( LPVOID )(( BYTE* )a + \
							(( PIMAGE_DOS_HEADER )a )->e_lfanew + SIZE_OF_NT_SIGNATURE + sizeof( IMAGE_FILE_HEADER ) + sizeof ( IMAGE_OPTIONAL_HEADER ))) //定位到节表
//判断可执行文件是否是PE文件
DWORD WINAPI ImageFileType( LPVOID lpFile )
{
	//首先出现的是DOS文件标志
	if( *( USHORT* )lpFile == IMAGE_DOS_SIGNATURE )
	{
		//由DOS头部决定PE文件头部的位置
		if( LOWORD( *( DWORD* )NTSIGNATURE( lpFile ) ) == \
			IMAGE_OS2_SIGNATURE || 
			LOWORD( *( DWORD* )NTSIGNATURE( lpFile ) ) == \
			IMAGE_OS2_SIGNATURE_LE )
			return ( DWORD )LOWORD( *( DWORD * )NTSIGNATURE( lpFile ) );
		else if ( *( DWORD * )NTSIGNATURE( lpFile ) == 
			IMAGE_NT_SIGNATURE )
			return IMAGE_NT_SIGNATURE;
		else
			return IMAGE_DOS_SIGNATURE;
	}
	else
		//不明文件种类
		return 0;

}
//得到含有节的数目
int WINAPI NumberOfSections( LPVOID lpFile )
{
	return ( int )(( PIMAGE_FILE_HEADER )PEFHDROFFSET( lpFile ))->NumberOfSections;
}

//获得可执行映像的入口点
LPVOID WINAPI GetModuleEntryPoint( LPVOID lpFile )
{
	PIMAGE_OPTIONAL_HEADER pEntry;
	pEntry = ( PIMAGE_OPTIONAL_HEADER )OPTHDROFFSET( lpFile );
	if( pEntry != NULL )
		return ( LPVOID )pEntry->AddressOfEntryPoint;
	else
		return NULL;
}

//通过段名称来获得段头部信息
BOOL WINAPI GetSectionHdrByName( LPVOID lpFile, IMAGE_SECTION_HEADER *pSec, char *szSecName )
{	
	PIMAGE_SECTION_HEADER pShr;
	int nSections = NumberOfSections( lpFile );
	int i;
	if( ( pShr = ( PIMAGE_SECTION_HEADER )SECHDROFFSET( lpFile )) != NULL )
	{
		//由名称查找
		for( i = 0; i < nSections; i ++ )
		{
			if( !strcmp( ( char* )pShr->Name, szSecName ))
			{
				CopyMemory( ( LPVOID )pSec, ( LPVOID )pShr, sizeof( IMAGE_SECTION_HEADER ));
				return TRUE;
			}
			else
				pShr++;
		}
	}

	return FALSE;

}

//定位数据目录
LPVOID WINAPI ImageDirectoryOffset( LPVOID lpFile, DWORD dwImage_Directory )
{
	PIMAGE_OPTIONAL_HEADER poh;
	PIMAGE_SECTION_HEADER psh;
	int nSections = NumberOfSections( lpFile );
	int i = 0;
	LPVOID VAImageDir;
	//获得可选头部和段头部的偏移量
	poh = ( PIMAGE_OPTIONAL_HEADER )OPTHDROFFSET( lpFile );
	psh = ( PIMAGE_SECTION_HEADER )SECHDROFFSET( lpFile );
	
	//必须在0和NumberOfRawAndSizes-1之间
	if( dwImage_Directory >= poh->NumberOfRvaAndSizes )
		return NULL;
	//定位映像目录的相对虚拟地址
	VAImageDir = ( LPVOID )poh->DataDirectory[dwImage_Directory].VirtualAddress;
	//定位包含映像目录的段
	while( i++ < nSections )
	{
		if( psh->VirtualAddress <= ( DWORD )VAImageDir && \
			psh->VirtualAddress + psh->SizeOfRawData > ( DWORD )VAImageDir )
			break;
		psh++;
	}
	if( i > nSections )
		return NULL;
	//返回映像导入目录的文件偏移量
	return ( LPVOID )( ( int )lpFile + ( int )VAImageDir - ( int )psh->VirtualAddress + ( int )psh->PointerToRawData );



}
//
//将虚拟地址转换成文件地址
LPVOID WINAPI RVAToOffset( LPVOID lpFile, DWORD dwRVA )
{
	PIMAGE_OPTIONAL_HEADER poh;
	PIMAGE_SECTION_HEADER psh;
	int nSections = NumberOfSections( lpFile );
	int i = 0;

	poh = ( PIMAGE_OPTIONAL_HEADER )OPTHDROFFSET( lpFile );
	psh = ( PIMAGE_SECTION_HEADER )SECHDROFFSET( lpFile );
	while( i++ < nSections )
	{
		if( psh->VirtualAddress <= dwRVA && \
			psh->VirtualAddress + psh->SizeOfRawData > dwRVA )
			break;
		psh++;
	}
	if( i > nSections )
		return NULL;
	
	//返回文件偏移量
	return ( LPVOID )(( int )lpFile + ( int )dwRVA - ( int )psh->VirtualAddress + ( int )psh->PointerToRawData );

		
}

//得到虚拟地址所在节的名称
PCHAR WINAPI GetRVASectionName( LPVOID lpFile, DWORD dwRVA )
{
	PIMAGE_SECTION_HEADER psh;
	int nSections = NumberOfSections( lpFile );
	int i = 0;

	psh = ( PIMAGE_SECTION_HEADER )SECHDROFFSET( lpFile );
	while( i++ < nSections )
	{
		if( psh->VirtualAddress <= dwRVA && \
			psh->VirtualAddress + psh->SizeOfRawData > dwRVA )
			break;
		psh++;
	}
	if( i > nSections )
		return NULL;
	return ( PCHAR )(( int )lpFile + ( int )psh->PointerToRawData );
}

//解密函数
void UnUpxShell( LPVOID lpFile ,const char *lpFileName )
{
	PIMAGE_SECTION_HEADER psh;
	BYTE  *pEntry;
	DWORD dwFileSize, dwDLL, dwEDI, dwEntry, dwPackEntry,  dwImageBase, dwESI, dwCount = 0;
	DWORD dwVoffset_UPX0, dwOffset, dwSize, dwEAX, dwEncryptData;
	FILE *fp;
	BYTE *lpSection, *lpOldSection, *lpImageOfUpx1, *lpAsciiName;
	DWORD *lpIID;
	DWORD dwEBX;
	long dwVOffset;
	
	dwImageBase = (( PIMAGE_OPTIONAL_HEADER )OPTHDROFFSET( lpFile ))->ImageBase;
	dwFileSize = 0;
	psh = ( PIMAGE_SECTION_HEADER )SECHDROFFSET( lpFile );
	for( int i = 0; i < NumberOfSections( lpFile ); i++ )
		dwFileSize += ( psh + i )->Misc.VirtualSize; //获得所有节的内存映像大小

	dwVOffset = dwFileSize - ( psh + NumberOfSections( lpFile ) - 1 )->Misc.VirtualSize;
	lpOldSection = ( BYTE* )calloc( dwFileSize + 4096 * 2, 1 );
	dwVOffset = ( DWORD )lpOldSection + dwVOffset;//最后一个节的在内存中的位置
	dwVOffset = ( psh + NumberOfSections( lpFile ) - 1 )->VirtualAddress - dwVOffset;
	lpSection = lpOldSection;
	
	for( int i = 1; i< NumberOfSections( lpFile ); i++ )//模拟PEloader装载各个节
	{
		lpSection += ( psh + i - 1 )->Misc.VirtualSize;	
		dwOffset = ( psh + i )->PointerToRawData;
		dwSize = ( psh + i )->SizeOfRawData;
		memcpy( ( PVOID )lpSection, ( PVOID )(( int )lpFile + ( int )dwOffset ), dwSize );

	}

	dwVoffset_UPX0 = psh->VirtualAddress; //UPX0在内存中的偏移	
	lpImageOfUpx1 = ( BYTE* )(( int )lpOldSection + ( int )psh->Misc.VirtualSize );//指向upx1的内存映象	
	
	dwPackEntry = ( DWORD )GetModuleEntryPoint( lpFile );
	pEntry = ( BYTE* )RVAToOffset( lpFile, dwPackEntry );
	dwVoffset_UPX0 += dwImageBase;

	dwEncryptData = *(( DWORD* )( pEntry + 2 ));//加密数据的内存地址
	dwEncryptData -= dwImageBase;
	dwEncryptData -= ( psh + 1 )->VirtualAddress;
	dwEncryptData += ( DWORD )lpImageOfUpx1;

	for( int i = 0; i < 400; i++ )
	{
		if( *( DWORD* )( pEntry + i ) == 0xbe8dd9e2 )
			break;		
	}
	if( i >= 400 )
	{
		printf( "Unpack failed: LOOP/LEA not found\n" );
		goto end;
	}
	dwEDI = *( DWORD* )( pEntry + i + 4 ); //dwEDI + esi

	*( pEntry + i + 2 ) = 0xc3;//ret

	for( ; i < 400; i++ )
	{
		if( *( DWORD* )( pEntry + i ) == 0x30848d04 )
			break;
	}
	if( i >= 400 )
	{
		printf( "Unpack failed: MOV/LEA not found\n" );
		goto end;
	}
	dwDLL = *( DWORD* )( pEntry + i + 4 );

	for( ; i < 400; i++ )
	{
		if( *( WORD* )( pEntry + i ) == 0xe961 )
			break;
	}
	if( i > 400 )
	{
		printf( " Unpack failed : POPAD/JMP not found\n" );
		goto end;
	}
	dwEntry = *( DWORD* )( pEntry + i + 2 ); //跳转的位移量
	dwPackEntry = dwPackEntry + i + 1; 
	dwEntry = dwEntry + dwPackEntry + 5;
	
	//开始解码
	pEntry += 12;
	_asm
	{
		pushad
		push	ebp
		mov		esi,dwEncryptData
		mov		edi,lpOldSection
		call 	pEntry	
		pop		ebp
		mov		edi,dwEDI
		add		edi,esi
		mov		dwEDI,edi
		mov		dwESI,esi
		popad
	}
	
	
	lpAsciiName = lpOldSection + dwFileSize + 1024;
	lpIID = ( PDWORD )( lpOldSection + dwFileSize );
	for(  ; ( dwEAX = *(( PDWORD )dwEDI )) != 0;  )
	{
			dwCount++;
			dwEBX = *(( PDWORD )dwEDI + 1 );
			dwEAX = dwESI + dwEAX + dwDLL;//指向dll名字字符串
			( ( int )lpAsciiName % 2 ) != 0 ? lpAsciiName++ : lpAsciiName;//函数名或dll名开始地址按偶数对齐
			
			memcpy( lpAsciiName, ( PVOID )dwEAX, strlen( ( PCHAR )dwEAX ));
			*( lpIID + 3 ) = ( DWORD )lpAsciiName + dwVOffset;
			lpAsciiName += strlen( ( PCHAR )lpAsciiName );
			lpAsciiName++;		
			dwEBX += dwESI;
			*( lpIID + 4 ) = dwEBX + dwVOffset;//IAT
			*( lpIID ) = dwEBX + dwVOffset;//目前先和FirstThunk指向同一数组
			lpIID += 5;
			dwEDI += 8;
			
			
			while( *(( PBYTE )dwEDI++ ) != 0 )
			{
				//char c1 = *(( PBYTE )dwEDI );
				char c2 = *(( PBYTE )dwEDI + 1 );

				if( !isprint( c2 ) )//可能会出现问题
				{
					*(( PDWORD )dwEBX ) = IMAGE_ORDINAL_FLAG32 | *(( PWORD )dwEDI );
					dwEBX += 4;
					dwEDI += 2;
					continue;

				}

				( ( int )lpAsciiName  % 2 ) != 0 ? lpAsciiName++ : lpAsciiName;//函数名或dll地址按偶数对齐
				*(( PDWORD )dwEBX ) = ( DWORD )lpAsciiName + dwVOffset;
				dwEBX += 4;
				lpAsciiName += 2;//留两个字节放函数序号
				memcpy( lpAsciiName, ( LPVOID )dwEDI,strlen( ( PCHAR )dwEDI ));
				lpAsciiName += strlen( ( PCHAR )dwEDI );
				lpAsciiName++;
				dwEDI += strlen( ( PCHAR )dwEDI );
				dwEDI++;
				

			}

	}

	//PE头中需要修改的字段	
	(( PIMAGE_OPTIONAL_HEADER )OPTHDROFFSET( lpFile ))->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = \
		( DWORD )( lpOldSection + dwFileSize + dwVOffset );	
	(( PIMAGE_OPTIONAL_HEADER )OPTHDROFFSET( lpFile ))->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = \
		dwCount * 20;		
	(( PIMAGE_OPTIONAL_HEADER )OPTHDROFFSET( lpFile ))->AddressOfEntryPoint = dwEntry;
	(( PIMAGE_OPTIONAL_HEADER )OPTHDROFFSET( lpFile ))->SizeOfImage += ( 4096 * 2 );


	//节表中需要修改的字段
	for( int i = 0; i < NumberOfSections( lpFile ) - 1; i++ )
	{
		( psh + i )->SizeOfRawData = ( psh + i )->Misc.VirtualSize;
		( psh + i )->PointerToRawData = ( psh + i )->VirtualAddress;

	}

	//最后一个节的节头需要特殊处理
	( psh + i )->Misc.VirtualSize += ( 4096 *2 );
	( psh + i )->SizeOfRawData = ( psh + i )->Misc.VirtualSize;
	( psh + i )->PointerToRawData = ( psh + i )->VirtualAddress;
	strcpy( ( char* )( psh + i )->Name," KV " );

	fp = fopen( lpFileName, "wb" );
	fwrite( lpFile, 1, (( PIMAGE_OPTIONAL_HEADER )OPTHDROFFSET( lpFile ))->SizeOfHeaders, fp );
	fwrite( lpOldSection, 1, dwFileSize + 4096 * 2, fp );
	fclose( fp );
end:
	free( lpFile );
	free( lpOldSection );


}
int _tmain(int argc, _TCHAR* argv[])
{
	FILE *fp;
	DWORD dwFileType;
	LONG dwPos;
	LPVOID pHead;
	BYTE *pCheckUpx;

	if( argc != 3 ){
		printf( "Usage: UpxDecode FileUpx Unpack\n" );
		exit( EXIT_FAILURE );
	}

	fp = fopen( argv[1], "rb" );	
	if( fp == NULL )
	{
		perror( argv[1] );
		exit( EXIT_FAILURE );
	}

	fseek( fp, 0L, SEEK_END );
	dwPos = ftell( fp );
	fseek( fp, 0L, SEEK_SET );
	pHead = malloc( dwPos );	
	fread( pHead, 1, dwPos , fp );
	fclose( fp );	

	//判断是否是PE文件
	dwFileType = ImageFileType( pHead );
	if( dwFileType != IMAGE_NT_SIGNATURE )
	{
		printf( "Not PE file!\n" );
		exit( EXIT_FAILURE );
	}
	//根据字节流判断是否被upx压缩过
	pCheckUpx = ( BYTE* )GetModuleEntryPoint( pHead );
	pCheckUpx =( BYTE* ) RVAToOffset( pHead, ( DWORD )pCheckUpx );
	pCheckUpx++; //跳过pushad
	if( *pCheckUpx != 0xbe || *( pCheckUpx + 5 ) !=  0x8d || \
		*( pCheckUpx + 11 ) != 0x57 || *( PDWORD )( pCheckUpx + 12 ) != 0xebffcd83 )
	{
		printf( "This file not packed by UPX!\n" );
		exit( EXIT_FAILURE );
	}
	UnUpxShell( pHead, argv[2] );
}






⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -