加密壳

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/D_K_01/article/details/80806950

加密壳

控制台界面;
exe程序加壳;

功能

代码加密;
重定位;
IAT加密;
软件授权;
TLS模拟执行;
花指令;
混淆;
反调试;
反dump;
#编译环境
Win10 VS2015;

Github

https://github.com/dkni0/VPack

功能截图

主程序:

输入路径或拖入文件;
回车即可加壳;
主程序

加壳后程序截图:

代码段加密
代码段加密
支持重定位
重定位
IAT加密
未加密的IAT显示为函数地址
IAT加密
软件授权
通过机器码加密
软件授权
模拟执行TLS函数
TLS
花指令
花指令
代码混淆
混淆
反调试
多种反调试,总有一种适合你
支持x64和od,未检测到调试则显示ok
反调试1
反调试2

项目设计

架构图
程序分为加壳程序与stub壳代码部分;
加壳程序将宿主程序进行处理;
将stub部分植入宿主程序;
程序运行时由stub代码对宿主程序进行解密及修复;

项目经验

熟悉壳执行流程;
IAT加解密原理;
反调试原理;
加深对PE文件结构理解;

核心功能

###Hash获取函数
壳自身所用到的函数都通过Hash值来获取;


//获取API
void GetAPI()
{
	g_nTls;

	HMODULE hKernel;
	//获取模块基址
	__asm
	{
		push eax;				//保存寄存器
		mov eax, fs:[0x30];		//获取PEB
		mov eax, [eax + 0x0c];	//获取PEB_LDR
		mov eax, [eax + 0x1c];	//获取IninitalizationOrderModuleList链表
		mov eax, [eax];			//获取Kernel32.dll/Kerbase.dll
		mov eax, [eax + 0x08];	//获取模块基址
		mov hKernel, eax		//保存模块基址
		pop eax;				//恢复寄存器
	}

	//通过Hash获取地址
	pfnGetProcAddress = pGetProceAddress(FindFunByHash(hKernel, 0xbbafdf85));	//以下0xXXXXXXXX均为Hash值
	//获取LoadLibraryExA
	pfnLoadLibraryExA = (pLoadLibraryExA)(FindFunByHash(hKernel, 0xc0d83287));
	//获取VirtualProtectEx
	pfnVirtualProtect = (pVirtualProtect)(FindFunByHash(hKernel, 0xef64a41e));
	//获取GetModuleHandleA
	pfnGetModuleHandleA = (pGetModuleHandleA)(FindFunByHash(hKernel, 0xf4e2f2b2));
	//获取VirtualAlloc
	pfnVirtualAlloc = (pVirtualAlloc)(FindFunByHash(hKernel, 0x1ede5967));

	//获取基址
	g_hModule = (DWORD)pfnGetModuleHandleA(NULL);	
	pfnExitProcess = (pExitProcess)(FindFunByHash(hKernel, 0x4fd18963));
	pfnGetVolumeInformationA = (pGetVolumeInformationA)(FindFunByHash(hKernel, 0x7666caec));	
	pfnGetCurrentProcess = (pGetCurrentProcess)(FindFunByHash(hKernel, 0x3a2fe6bb));
	pfnGetCurrentThread=(pGetCurrentThread)(FindFunByHash(hKernel, 0x8ffb3b6e));
	pfnSetUnhandledExceptionFilter=(pSetUnhandledExceptionFilter)(FindFunByHash(hKernel, 0x4807d145));

	char strNtdll[10] = {0x4E, 0x74, 0x64, 0x6C, 0x6C, 0x2E, 0x64, 0x6C, 0x6C,0x00};

	HMODULE hNt = pfnLoadLibraryExA(strNtdll, 0, 0);
	pfnNtQueryInformationProcess = (pNtQueryInformationProcess)(FindFunByHash(hNt, 0x72aab605));
	pfnNtQuerySystemInformation = (pNtQuerySystemInformation)(FindFunByHash(hNt, 0xeffc1dbe));
	pfnNtQueryObject = (pNtQueryObject)(FindFunByHash(hNt, 0x0db59c8a));
	pfnZwSetInformationThread = (pZwSetInformationThread)(FindFunByHash(hNt, 0x3d83d869));	
	//定义字符串
	char strDllUser[11] = {0x55, 0x73, 0x65, 0x72, 0x33, 0x32, 0x2E, 0x64, 0x6C, 0x6C, 0x00};
	//载入User32
	HMODULE hUser = pfnLoadLibraryExA(strDllUser, 0, 0);
	//获取MessageBoxA
	pfnMessageBoxA = (pMessageBoxA)(FindFunByHash(hUser, 0x1e380a6a));
	pfnGetWindowThreadProcessId=(pGetWindowThreadProcessId)(FindFunByHash(hUser, 0xa0667fbe));
	//获取窗口相关函数
	pfnRegisterClassA= (pRegisterClassA)(FindFunByHash(hUser, 0x0bc05e32));
	pfnCreateWindowExA= (pCreateWindowExA)(FindFunByHash(hUser, 0x1fdaf55b));
	pfnShowWindow = (pShowWindow)(FindFunByHash(hUser, 0xdd8b5fb8));
	pfnGetMessageA = (pGetMessageA)(FindFunByHash(hUser, 0x6106044b));
	pfnFindWindowA=(pFindWindowA)(FindFunByHash(hUser, 0x3db19602));

	pfnTranslateMessage = (pTranslateMessage)(FindFunByHash(hUser, 0xe09980a2));	
	pfnDispatchMessageA = (pDispatchMessageA)(FindFunByHash(hUser, 0x7a1506c2));
	pfnGetDlgItemTextA = (pGetDlgItemTextA)(FindFunByHash(hUser, 0x1584c411));	
	pfnPostQuitMessage = (pPostQuitMessage)(FindFunByHash(hUser, 0xcaa94781));	
	pfnDefWindowProcA = (pDefWindowProcA)(FindFunByHash(hUser, 0x22e85ca4));		

	return;
}

IAT加密

加壳程序加壳时将INT中的函数名称替换为Hash值;
修复宿主程序IAT也通过Hash获取函数;
均未使用GetProcAddress,增加脱壳难度


//修复IAT
void RecIAT()
{
	//判断是否存在导入表
	if (!g_Conf.dwImportRva)
	{
		return ;
	}

	//构造跳转代码
	BYTE bJmpByte[] = {
		0xe8, 0x01, 0x00, 0x00, 0x00, 0xe9, 0x58, 0xeb, 0x01, 0xe8, 0xb8, 0x11, 0x11, 0x11, 0x11, 0xeb,
		0x01, 0x15, 0x35, 0x16, 0x16, 0x16, 0x16, 0xeb, 0x01, 0xff, 0x50, 0xeb, 0x02, 0xff, 0x15, 0xc3 };

	//获取原INT地址
	PIMAGE_IMPORT_DESCRIPTOR pImport = (PIMAGE_IMPORT_DESCRIPTOR)(g_hModule + g_Conf.dwImportRva);

	//外层循环遍历模块
	while (pImport->Name)
	{
		//获取宿主INT
		PIMAGE_THUNK_DATA32 pThunkINT = (PIMAGE_THUNK_DATA32)(g_hModule+ pImport->OriginalFirstThunk);
		//获取宿主IAT
		PIMAGE_THUNK_DATA32 pThunkIAT = (PIMAGE_THUNK_DATA32)(g_hModule + pImport->FirstThunk);

		//获取DLL模块名称
		char *DllName = (CHAR*)(g_hModule + pImport->Name);

		//载入DLL模块
		HMODULE hDllModule = pfnLoadLibraryExA(DllName, 0, 0);

		//获取模块 EAT
		PIMAGE_NT_HEADERS pDLLNt = GetNtHeader((PBYTE)hDllModule);						 //NT头
		PIMAGE_EXPORT_DIRECTORY pDLLExport = (PIMAGE_EXPORT_DIRECTORY)
			((PBYTE)hDllModule + *(PDWORD)((PBYTE)pDLLNt + 0x78));						 //EXPORT	
		PDWORD pDLLEAT = (PDWORD)((PBYTE)hDllModule + pDLLExport->AddressOfFunctions);	 //EAT
		
		//修改内存属性
		DWORD dwOldProt = 0;
		pfnVirtualProtect(pThunkIAT, 1, PAGE_READWRITE, &dwOldProt);

		//内层循环遍历模块中的函数
		while (pThunkINT->u1.AddressOfData)
		{
			//检测是否序号
			bool IsOrdinal= (pThunkINT->u1.AddressOfData & 0xFFFF0000) == 0;
			DWORD dwFunAddress = 0;
			if (IsOrdinal)
			{
				//通过序号得到函数地址,需要加DLL基址
				dwFunAddress = (DWORD)(pDLLEAT[pThunkINT->u1.Ordinal] + (PBYTE)hDllModule);				
			}
			//名称命名
			else
			{
				//通过Hash获取函数地址
				dwFunAddress = FindFunByHash(hDllModule, pThunkINT->u1.AddressOfData);
			}

			//申请空间实现IAT跳转
			PBYTE pNewAddr= (PBYTE)pfnVirtualAlloc(0, sizeof(bJmpByte), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
			
			//计算秘钥
			DWORD dwIATKey = g_Conf.dwEncodeKey;
			IATKey(&dwIATKey);
			
			//替换秘钥
			PDWORD pKey = (PDWORD)&(bJmpByte[19]);
			*pKey = dwIATKey;

			//替换地址
			PDWORD pAddr = (PDWORD)&(bJmpByte[11]);
			*pAddr = dwFunAddress ^ dwIATKey;
			
			//拷贝代码
			memcpy(pNewAddr, bJmpByte, sizeof(bJmpByte));
			//存入IAT
			pThunkIAT->u1.AddressOfData = (DWORD)pNewAddr;

			//下一个INT			
			pThunkINT++;
			pThunkIAT++;		
		}

		//恢复内存属性
		pfnVirtualProtect(pThunkIAT, 1, dwOldProt, &dwOldProt);

		//下一个导入表
		pImport++;
	}

}

End

猜你喜欢

转载自blog.csdn.net/D_K_01/article/details/80806950
今日推荐