首页
社区
课程
招聘
[原创]Win PE系列之一个简单的加密壳的实现
2021-10-15 11:43 25608

[原创]Win PE系列之一个简单的加密壳的实现

2021-10-15 11:43
25608

一.加壳原理

一共需要以下三个文件PE文件来实现本次实验。

  1. demo.exe代表是被加壳的源程序。

  2. Shell.exe代表的是壳子程序。

  3. Packed.exe代表的是加壳程序。

Packed.exe的作用是把demo.exe的内容保存到Shell.exe中,而Shell.exe则是把保存的demo.exe取出运行起来。

二.加壳过程

也就是Packed.exe的运行流程,过程如下:

  1. 将demo.exe读取出来进行异或加密

  2. 将加密后的内容为一个新增节追加到Shell.exe中

对应的源码如下

// Packed.cpp : 定义应用程序的入口点。
//

#include <Windows.h>
#include <cstdio>

#define SHELL_FILE_NAME "Shell.exe"	//壳子名
#define ORGIN_FILE_NAME "demo.exe"	//要被加壳的程序名称
#define TARGET_FILE_NAME "target.exe"	//生成的文件名


BOOL PackFile();	//将要加壳的程序加密以后加入壳子中
VOID EncpyptFile(PUCHAR pBaseAddr, DWORD dwFileSize);	//对文件内容进行加密
BOOL AddSection(PVOID pShellBase, PVOID pOrgBase, DWORD dwShellFileSize, DWORD dwOrgFileSize);	//将源文件加到壳子中
VOID ShowError(PCHAR msg);	//弹出错误信息
DWORD Align(DWORD dwSize, DWORD dwAlign);	//用于对齐,返回对齐以后的数字


int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
	if (PackFile())
	{
		MessageBox(NULL, TEXT("加壳成功"), TEXT("成功"), MB_OK);
	}

    return 0;
}

BOOL PackFile()
{
	BOOL bRet = TRUE;
	HANDLE hOrgFile = NULL, hShellFile = NULL;
	DWORD dwOrgFileSize = 0, dwShellFileSize = 0, dwRet = 0, dwFileSize = 0;
	PVOID pOrgBase = NULL, pShellBase = NULL;

	hOrgFile = CreateFile(ORGIN_FILE_NAME, 
						  GENERIC_READ, 
		                  0, NULL, 
		                  OPEN_EXISTING, 
		                  FILE_ATTRIBUTE_NORMAL, NULL);

	if (hOrgFile == INVALID_HANDLE_VALUE)
	{
		ShowError("CreateFile OrigFile");
		bRet = FALSE;
		goto exit;
	}
	dwOrgFileSize = GetFileSize(hOrgFile, NULL);

	pOrgBase = VirtualAlloc(NULL, dwOrgFileSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
	if (!pOrgBase)
	{
		ShowError("VirtualAlloc pOrgBase");
		bRet = FALSE;
		goto exit;
	}

	ZeroMemory(pOrgBase, dwOrgFileSize);
	if (!ReadFile(hOrgFile, pOrgBase, dwOrgFileSize, &dwRet, NULL))
	{
		ShowError("ReadFile pOrgBase");
		bRet = FALSE;
		goto exit;
	}

	EncpyptFile((PUCHAR)pOrgBase, dwOrgFileSize);	//对源程序进行XOR加密

	hShellFile = CreateFile(SHELL_FILE_NAME,
				GENERIC_READ,
				0, NULL,
				OPEN_EXISTING,
				FILE_ATTRIBUTE_NORMAL, NULL);
	if (hShellFile == INVALID_HANDLE_VALUE)
	{
		ShowError("CreateFile ShellFile");
		bRet = FALSE;
		goto exit;
	}
	dwShellFileSize = GetFileSize(hShellFile, NULL);

	pShellBase = VirtualAlloc(NULL, dwShellFileSize + dwOrgFileSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
	if (!pShellBase)
	{
		ShowError("VirtualAlloc pShellBase");
		bRet = FALSE;
		goto exit;
	}

	ZeroMemory(pShellBase, dwShellFileSize + dwOrgFileSize);
	if (!ReadFile(hShellFile, pShellBase, dwShellFileSize, &dwRet, NULL))
	{
		ShowError("ReadFile pShellBase");
		bRet = FALSE;
		goto exit;
	}

	if (!AddSection(pShellBase, pOrgBase, dwShellFileSize, dwOrgFileSize))
	{
		bRet = FALSE;
		goto exit;
	}
exit:
	if (hOrgFile) CloseHandle(hOrgFile);
	if (hShellFile) CloseHandle(hShellFile);
	if (pOrgBase)
	{
		if (!VirtualFree(pOrgBase, 0, MEM_DECOMMIT))
		{
			ShowError("VirtualFree pOrgBase");
		}
	}

	if (pShellBase)
	{
		if (!VirtualFree(pShellBase, 0, MEM_DECOMMIT))
		{
			ShowError("VirtualFree pShellBase");
		}
	}
	return bRet;
}

BOOL AddSection(PVOID pShellBase, PVOID pOrgBase, DWORD dwShellFileSize, DWORD dwOrgFileSize)
{
	BOOL bRet = TRUE;
	DWORD dwRet = 0;
	HANDLE hFile = NULL;
	PIMAGE_DOS_HEADER pShellDosHead = (PIMAGE_DOS_HEADER)pShellBase;
	PIMAGE_FILE_HEADER pShellFileHead = (PIMAGE_FILE_HEADER)((DWORD)pShellBase + pShellDosHead->e_lfanew + 4);
	PIMAGE_OPTIONAL_HEADER32 pShellOptionHead = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pShellFileHead + IMAGE_SIZEOF_FILE_HEADER);
	PIMAGE_SECTION_HEADER pShellSectionHead = (PIMAGE_SECTION_HEADER)((DWORD)pShellOptionHead + pShellFileHead->SizeOfOptionalHeader);
	DWORD dwFileAlignment = pShellOptionHead->FileAlignment, dwSectionAlignment = pShellOptionHead->SectionAlignment;
	DWORD dwSize = 0;
	PVOID pResBase = NULL;

	if (pShellSectionHead[0].PointerToRawData - ((DWORD)&pShellSectionHead[pShellFileHead->NumberOfSections - 1] - (DWORD)pShellBase)
									< 2 * IMAGE_SIZEOF_SECTION_HEADER)
	{
		printf("壳子最后一个节表间隙不够\n");
		bRet = FALSE;
		goto exit;
	}
	
	dwSize = Align(dwOrgFileSize + dwShellFileSize, dwFileAlignment);	//dwFileAlignment整数倍
	pResBase = VirtualAlloc(NULL, dwSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
	if (!pResBase)
	{
		ShowError("VirtualAlloc pResBase");
		bRet = FALSE;
		goto exit;
	}

	ZeroMemory(pResBase, dwSize);
	memcpy((PVOID)pResBase, pShellBase, dwShellFileSize);	//将源文件复制到壳子中
	memcpy((PVOID)((DWORD)pResBase + dwShellFileSize), pOrgBase, dwOrgFileSize);	//将源文件复制到壳子中
	
	PIMAGE_DOS_HEADER pResDosHead = (PIMAGE_DOS_HEADER)pResBase;
	PIMAGE_FILE_HEADER pResFileHead = (PIMAGE_FILE_HEADER)((DWORD)pResBase + pResDosHead->e_lfanew + 4);
	PIMAGE_OPTIONAL_HEADER32 pResOptionHead = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pResFileHead + IMAGE_SIZEOF_FILE_HEADER);
	PIMAGE_SECTION_HEADER pResSectionHead = (PIMAGE_SECTION_HEADER)((DWORD)pResOptionHead + pResFileHead->SizeOfOptionalHeader);
	
	//增加节表
	ZeroMemory((PVOID)&pResSectionHead[pShellFileHead->NumberOfSections], IMAGE_SIZEOF_SECTION_HEADER);
	memcpy(pResSectionHead[pResFileHead->NumberOfSections].Name, ".1900", strlen(".1900"));
	pResSectionHead[pResFileHead->NumberOfSections].PointerToRawData = pResSectionHead[pShellFileHead->NumberOfSections - 1].PointerToRawData
																		   + Align(pShellSectionHead[pShellFileHead->NumberOfSections - 1].SizeOfRawData, dwFileAlignment);
	pResSectionHead[pResFileHead->NumberOfSections].SizeOfRawData = Align(dwOrgFileSize, dwFileAlignment);
	pResSectionHead[pResFileHead->NumberOfSections].VirtualAddress = pResSectionHead[pShellFileHead->NumberOfSections - 1].VirtualAddress
																			+ Align(pResSectionHead[pShellFileHead->NumberOfSections - 1].Misc.VirtualSize, dwSectionAlignment);
	pResSectionHead[pResFileHead->NumberOfSections].Misc.VirtualSize = dwOrgFileSize;
	pResSectionHead[pResFileHead->NumberOfSections].Characteristics |= IMAGE_SCN_MEM_READ;

	pResFileHead->NumberOfSections++;	//增加节数量
	pResOptionHead->SizeOfImage += Align(dwOrgFileSize, dwSectionAlignment);	//增加SizeOfImage

	hFile = CreateFile(TARGET_FILE_NAME,		//打开目标文件并保存
					   GENERIC_READ | GENERIC_WRITE,
					   0, NULL,
					   CREATE_ALWAYS,
					   FILE_ATTRIBUTE_NORMAL,
					   NULL);

	if (hFile == INVALID_HANDLE_VALUE)
	{
		ShowError("CreateFile");
		bRet = FALSE;
		goto exit;
	}

	if (!WriteFile(hFile, pResBase, dwSize, &dwRet, NULL))
	{
		ShowError("WriteFile");
		bRet = FALSE;
		goto exit;
	}

exit:
	if (hFile) CloseHandle(hFile);
	return bRet;
}

DWORD Align(DWORD dwSize, DWORD dwAlign)
{
	return dwSize % dwAlign ? dwSize + dwAlign - dwSize % dwAlign : dwSize;
}

VOID EncpyptFile(PUCHAR pBaseAddr, DWORD dwFileSize)
{
	DWORD i = 0;
	UCHAR uKey = 190;    //加密密钥

	for (i = 0; i < dwFileSize; i++)
	{
		if (pBaseAddr[i] && pBaseAddr[i] != uKey) pBaseAddr[i] ^= uKey;
	}
}

VOID ShowError(PCHAR msg)
{
	CHAR szError[105] = { 0 };

	sprintf(szError, "%s Error %d", msg, GetLastError());
	MessageBox(NULL, szError, TEXT("Error"), MB_OK);
}


三.脱壳过程

也就是Shell.exe的运行流程,过程如下:

  1. 从最后一个节中将节中的内容,也就是加密后的源程序取出来,并进行解密

  2. 根据文件对齐与节区对齐的大小获取PE文件装载到内存中的状态

  3. 修复IAT表

  4. 得到Shell.exe的文件路径,并以挂起的形式创建Shell.exe的新进程

  5. 通过ZwUnmapViewOfSection函数将得到的新进程中的内容卸载,以得到干净的进程空间

  6. 从新进程中申请足够容纳要运行的源程序的SizeOfImage大小的内存空间,并将修复IAT表之后的源文件内容写入空间中

  7. 获得新创建进程中的主线程状态

  8. 设置线程的入口点是在新进程申请的内存的初始地址和源程序入口偏移

  9. 设置新进程的ImageBase为在新进程申请的内存的初始地址

  10. 恢复线程

对应的源代码如下

// Shell.cpp : 定义应用程序的入口点。
//

#include <Windows.h>
#include <cstdio>

BOOL isPacked(PIMAGE_SECTION_HEADER pSectionHead);	//判断是否加壳
PVOID GetOrgFile(PIMAGE_SECTION_HEADER pSectionHead);	//将源文件从最后一个节中取出并解密
VOID Decrypt(PUCHAR pBaseAddr, DWORD dwSize);	//解密函数
PVOID GetOrgMemory(PVOID pBaseAddr);	//得到文件装载到内存中的状态
VOID RepairIAT(PVOID pBaseAddr);		//修复IAT表
BOOL UninstallShell(HANDLE hProcess, PVOID pBaseAddr);	//将启动的Shell进程空间中的内容卸载掉,得到一块干净进程空间
PVOID WriteMemoryToProcess(HANDLE hProcess, PVOID pSrcFile);	//从目标进程中申请内存
DWORD Min(DWORD x, DWORD y);	//返回较小值
VOID ShowError(PCHAR msg);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
	PIMAGE_DOS_HEADER pDosHead = (PIMAGE_DOS_HEADER)hInstance;
	PIMAGE_FILE_HEADER pFileHead = (PIMAGE_FILE_HEADER)((DWORD)pDosHead + pDosHead->e_lfanew + 4);
	PIMAGE_OPTIONAL_HEADER32 pOptionHead = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHead + IMAGE_SIZEOF_FILE_HEADER);
	PIMAGE_SECTION_HEADER pSectionHead = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHead + pFileHead->SizeOfOptionalHeader);
	PIMAGE_SECTION_HEADER pLastSectionHead = &pSectionHead[pFileHead->NumberOfSections - 1];
	PVOID pOrgFileAddr = NULL;	//保存源程序解密以后的内容的地址
	PVOID pMemoryAddr = NULL;	//保存源程序在内存中的状态的数据的地址
	PVOID pDestProcAddr = NULL;	//新进程中的申请的内存的地址
	STARTUPINFO si = { 0 };
	PROCESS_INFORMATION pi = { 0 };			//保存新进程状态
	CHAR szFileName[MAX_PATH] = { 0 };		//保存文件名
	CONTEXT cx;								//保存新进程的主线程状态	
	DWORD dwImageBase = 0;					//要写入新进程的ImageBase
	PIMAGE_DOS_HEADER pMemDosHeader = NULL;
	PIMAGE_OPTIONAL_HEADER32 pMemOptionHeader = NULL;

	if (!isPacked(pLastSectionHead))	//判断是否加壳了
	{
		MessageBox(NULL, TEXT("未加壳"), TEXT("失败"), MB_OK);
		goto exit;
	}

	
	pOrgFileAddr = GetOrgFile(pLastSectionHead);	//获取PE文件在磁盘中的状态
	if (!pOrgFileAddr)
	{
		MessageBox(NULL, TEXT("得到源文件失败"), TEXT("失败"), MB_OK);
		goto exit;
	}

	pMemoryAddr = GetOrgMemory(pOrgFileAddr);		//获取PE文件在内存中的状态
	if (!pMemoryAddr)
	{
		MessageBox(NULL, TEXT("得到源文件内存中状态失败"), TEXT("失败"), MB_OK);
		goto exit;
	}

	RepairIAT(pMemoryAddr);							//修复IAT表

	GetModuleFileName(hInstance, szFileName, MAX_PATH);		//获取程序路径

	//以挂起的形式创建进程
	si.cb = sizeof(STARTUPINFO);
	if (!CreateProcess(szFileName, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi))	
	{
		MessageBox(NULL, TEXT("创建进程失败"), TEXT("错误"), MB_OK);
		goto exit;
	}

	if (!UninstallShell(pi.hProcess, (PVOID)hInstance))	//卸载进程中的内容,以获得干净的进程空间
	{
		goto exit;
	}

	pDestProcAddr = WriteMemoryToProcess(pi.hProcess, pMemoryAddr);
	if (!pDestProcAddr)
	{
		goto exit;
	}

	pMemDosHeader = (PIMAGE_DOS_HEADER)pMemoryAddr;
	pMemOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pMemDosHeader + pMemDosHeader->e_lfanew + 4 + IMAGE_SIZEOF_FILE_HEADER);

	cx.ContextFlags = CONTEXT_FULL;
	if (!GetThreadContext(pi.hThread, &cx))
	{
		ShowError("GetThreadContext");
		goto exit;
	}

	cx.Eax = pMemOptionHeader->AddressOfEntryPoint + (DWORD)pDestProcAddr;	//eax保存的是ImageBase + EntryPoint
	dwImageBase = (DWORD)pDestProcAddr;
	// ebx保存的是PEB的地址,PEB+8的地址存放的是ImageBase
	if (!WriteProcessMemory(pi.hProcess, (PCHAR)cx.Ebx + 8, &dwImageBase, sizeof(dwImageBase), NULL))	
	{
		ShowError("WriteProcessMemory (PCHAR)cx.Ebx + 8");
		goto exit;
	}

	if (!SetThreadContext(pi.hThread, &cx))
	{
		ShowError("SetThreadContext");
		goto exit;
	}

	if (ResumeThread(pi.hThread) == -1)
	{
		ShowError("ResumeThread");
		goto exit;
	}
exit:
	if (pi.hProcess) CloseHandle(pi.hProcess);
	return 0;
}

PVOID WriteMemoryToProcess(HANDLE hProcess, PVOID pSrcFile)
{
	PIMAGE_DOS_HEADER pDosHead = (PIMAGE_DOS_HEADER)pSrcFile;
	PIMAGE_FILE_HEADER pFileHead = (PIMAGE_FILE_HEADER)((DWORD)pDosHead + pDosHead->e_lfanew + 4);
	PIMAGE_OPTIONAL_HEADER32 pOptionHead = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHead + IMAGE_SIZEOF_FILE_HEADER);
	PVOID pBaseAddr = NULL;
	DWORD dwImageBase = pOptionHead->ImageBase, dwSizeOfBlock = 0, dwGap = 0;
	PIMAGE_BASE_RELOCATION pBaseRelocation = NULL;
	DWORD dwNum = 0, i = 0;
	PWORD pOffset = NULL;
	PDWORD pTargetAddr = NULL;

	pBaseAddr = VirtualAllocEx(hProcess, (PVOID)dwImageBase, pOptionHead->SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
	if (!pBaseAddr)
	{
		if (!pOptionHead->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)
		{
			MessageBox(NULL, TEXT("脱壳失败"), TEXT("失败"), MB_OK);
			goto fail;
		}

		while (!pBaseAddr)
		{
			pBaseAddr = VirtualAllocEx(hProcess, (PVOID)dwImageBase, pOptionHead->SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
			dwImageBase += 0x100000;
		}

		//修复重定位表
		dwGap = dwImageBase - pOptionHead->ImageBase;
		pBaseRelocation = (PIMAGE_BASE_RELOCATION)((DWORD)pDosHead + pOptionHead->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
		while (pBaseRelocation->VirtualAddress != 0 || pBaseRelocation->SizeOfBlock != 0)
		{
			dwSizeOfBlock = pBaseRelocation->SizeOfBlock;
			dwNum = (dwSizeOfBlock - 2 * sizeof(DWORD)) / 2;
			pOffset = (PWORD)((DWORD)pBaseRelocation + 2 * sizeof(DWORD));
			for (i = 0; i < dwNum; i++)
			{
				if (pOffset[i] & 0x3000)
				{
					pTargetAddr = (PDWORD)((DWORD)pDosHead + pBaseRelocation->VirtualAddress + (pOffset[i] & ~0x3000));
					*pTargetAddr += dwGap;
				}
			}
			pBaseRelocation = (PIMAGE_BASE_RELOCATION)((DWORD)pBaseRelocation + dwSizeOfBlock);
		}
	}

	//将内容写入到新进程
	if (!WriteProcessMemory(hProcess, pBaseAddr, pSrcFile, pOptionHead->SizeOfImage, NULL))
	{
		ShowError("WriteProcessMemory pBaseAddr");
		goto fail;
	}

	goto exit;
fail:
	if (pBaseAddr)
	{
		if (!VirtualFree(pBaseAddr, 0, MEM_DECOMMIT))
		{
			ShowError("VirtualFree pBaseAddr");
		}
		pBaseAddr = NULL;
	}
exit:
	return pBaseAddr;
}

BOOL UninstallShell(HANDLE hProcess, PVOID pBaseAddr)
{
	typedef NTSTATUS(*pFnZwUnmapViewOfSection)(HANDLE, PVOID);
	BOOL bRet = TRUE;
	HMODULE hModule = NULL;
	pFnZwUnmapViewOfSection pfnZwUnmapViewOfSection = NULL;

	hModule = LoadLibrary("ntdll.dll");
	if (hModule == NULL)
	{
		bRet = FALSE;
		ShowError("LoadLibrary");
		goto exit;
	}

	pfnZwUnmapViewOfSection = (pFnZwUnmapViewOfSection)GetProcAddress(hModule, "ZwUnmapViewOfSection");
	if (pfnZwUnmapViewOfSection == NULL)
	{
		bRet = FALSE;
		ShowError("GetProcAddress");
		goto exit;
	}

	if (pfnZwUnmapViewOfSection(hProcess, pBaseAddr) != 0)	//卸载新进程中的内容,以得到干净的进程空间
	{
		bRet = FALSE;
		ShowError("pfnZwUnmapViewOfSection");
		goto exit;
	}
exit:
	if (hModule) FreeLibrary(hModule);

	return bRet;
}

VOID RepairIAT(PVOID pBaseAddr)
{
	PIMAGE_DOS_HEADER pDosHead = (PIMAGE_DOS_HEADER)pBaseAddr;
	PIMAGE_FILE_HEADER pFileHead = (PIMAGE_FILE_HEADER)((DWORD)pBaseAddr + pDosHead->e_lfanew + 4);
	PIMAGE_OPTIONAL_HEADER32 pOptionHead = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHead + IMAGE_SIZEOF_FILE_HEADER);
	PIMAGE_IMPORT_DESCRIPTOR pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pBaseAddr + pOptionHead->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
	PDWORD pINT = NULL, pIAT = NULL;
	PCHAR pDllName = NULL;
	PIMAGE_IMPORT_BY_NAME pFunName = NULL;
	DWORD dwFuncAddr = 0, dwOrder = 0;
	HMODULE hModule = NULL;

	if ((DWORD)pImportTable == (DWORD)pBaseAddr)
	{
		MessageBox(NULL, TEXT("没有导入表"), TEXT("结果"), MB_OK);
		goto exit;
	}

	while (pImportTable->OriginalFirstThunk != 0 || pImportTable->FirstThunk != 0)
	{
		pDllName = (PCHAR)pBaseAddr + pImportTable->Name;	//获得dll名地址
		hModule = LoadLibrary(pDllName);

		if (!hModule)
		{
			ShowError("LoadLibrary");
			goto exit;
		}

		pINT = (PDWORD)((DWORD)pBaseAddr + pImportTable->OriginalFirstThunk);
		pIAT = (PDWORD)((DWORD)pBaseAddr + pImportTable->FirstThunk);
		while (*pINT)
		{
			dwFuncAddr = 0;
			if (IMAGE_SNAP_BY_ORDINAL32(*pINT)) //the highest bit is 1?
			{
				dwOrder = *pINT & ~IMAGE_ORDINAL_FLAG32;	//clear highest bit
				dwFuncAddr = (DWORD)GetProcAddress(hModule, MAKEINTRESOURCE(dwOrder));	//以序号的方式获取函数地址
			}
			else
			{
				pFunName = (PIMAGE_IMPORT_BY_NAME)((DWORD)pBaseAddr + *pINT);
				dwFuncAddr = (DWORD)GetProcAddress(hModule, (PCHAR)pFunName->Name);      //以名字的方式获取函数地址
			}
			*pIAT = dwFuncAddr;
			pINT++;
			pIAT++;
		}
		pImportTable++;
	}
exit:;
}

PVOID GetOrgMemory(PVOID pBaseAddr)
{
	PIMAGE_DOS_HEADER pDosHead = (PIMAGE_DOS_HEADER)pBaseAddr;
	PIMAGE_FILE_HEADER pFileHead = (PIMAGE_FILE_HEADER)((DWORD)pDosHead + pDosHead->e_lfanew + 4);
	PIMAGE_OPTIONAL_HEADER32 pOptionHead = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHead + IMAGE_SIZEOF_FILE_HEADER);
	PIMAGE_SECTION_HEADER pSectionHead = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHead + pFileHead->SizeOfOptionalHeader);
	DWORD i = 0, dwSecNum = pFileHead->NumberOfSections;
	PVOID pMemoryAddr = NULL;

	pMemoryAddr = VirtualAlloc(NULL, pOptionHead->SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
	if (!pMemoryAddr)
	{
		ShowError("VirtualAlloc pMemoryAddr");
		goto exit;
	}
	ZeroMemory(pMemoryAddr, pOptionHead->SizeOfImage);
	memcpy(pMemoryAddr, pBaseAddr, pOptionHead->SizeOfHeaders);

	for (i = 0; i < dwSecNum; i++)
	{
		memcpy((PVOID)((DWORD)pMemoryAddr + pSectionHead[i].VirtualAddress), (PVOID)((DWORD)pBaseAddr + pSectionHead[i].PointerToRawData), Min(pSectionHead[i].Misc.VirtualSize, pSectionHead[i].SizeOfRawData));
	}
exit:
	return pMemoryAddr;
}

DWORD Min(DWORD x, DWORD y)
{
	return x < y ? x : y;
}

PVOID GetOrgFile(PIMAGE_SECTION_HEADER pSectionHead)
{
	DWORD dwFileSize = pSectionHead->SizeOfRawData;
	PVOID pOrigFileAddr = NULL;
	PVOID pDestMemoryAddr = (PVOID)((DWORD)GetModuleHandle(NULL) + pSectionHead->VirtualAddress);

	pOrigFileAddr = VirtualAlloc(NULL, dwFileSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
	if (pOrigFileAddr == NULL)
	{
		ShowError("VirtualAlloc pOrigFileAddr");
		goto exit;
	}
	ZeroMemory(pOrigFileAddr, dwFileSize);
	memcpy(pOrigFileAddr, pDestMemoryAddr, dwFileSize);

	Decrypt((PUCHAR)pOrigFileAddr, dwFileSize);
exit:
	return pOrigFileAddr;
}

VOID Decrypt(PUCHAR pBaseAddr, DWORD dwSize)
{
	UCHAR uKey = 190;
	DWORD i = 0;

	for (i = 0; i < dwSize; i++)
	{
		if (pBaseAddr[i] && pBaseAddr[i] != uKey) pBaseAddr[i] ^= uKey;
	}
}

BOOL isPacked(PIMAGE_SECTION_HEADER pSectionHead)
{
	return strcmp((PCHAR)pSectionHead->Name, ".1900") == 0;	//新增的节的名称是.1900,所以判断最后一个节的名称来判断是否加壳
}

VOID ShowError(PCHAR msg)
{
	CHAR szError[105] = { 0 };

	sprintf(szError, "%s Error %d", msg, GetLastError());
	MessageBox(NULL, szError, TEXT("错误"), MB_OK);
}


四.程序运行结果

    运行Pack.exe以后会生成target.exe。

查看target.exe的PE节表信息,可以看到demo.exe已经被成功加入

点击以后发现可以成功运行demo.exe

    


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2021-12-27 17:13 被1900编辑 ,原因:
收藏
点赞10
打赏
分享
打赏 + 5.00雪花
打赏次数 1 雪花 + 5.00
 
赞赏  sloanyyc   +5.00 2023/02/06 问一下,X64里, GetThreadContext 的 Rax 和 Rbx 都为0,为啥, Rcx,Rdx不为0,正好和 x86里相反
最新回复 (2)
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
sloanyyc 2023-2-6 23:56
2
0
谢谢,已经搞定. x64 加壳成功!  Eax, Ebx 和 Rcx, Rdx 有对应关系, 另外 +8 改成 +16
雪    币: 251
活跃值: (620)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
mb_maiyudos 2023-11-4 00:43
3
0
这不是和滴水的加密壳思路一样吗?怎么就原创了
游客
登录 | 注册 方可回帖
返回