能力值:
( LV2,RANK:10 )
|
-
-
29 楼
2013年干过这事, 当时是在windows xp上试的, 原理是把exe当成资源编译到你的程序中, 然后读到内在加载, 如果还不放心, 可以先把exe用upx加壳, 再放到资源中, 代码如下:
///////////////////////////////////////////////////
// date: 2013.08.15
// author: 刘立向
// email: llxxhm@126.com
// qq: 515311445
///////////////////////////////////////////////////
#include <windows.h>
#pragma pack(push, 1)
typedef struct
{
DWORD VirtualAddress;
DWORD SizeOfBlock;
} *PImageBaseRelocation;
#pragma pack(pop)
typedef IMAGE_SECTION_HEADER (*PIMAGE_SECTION_HEADERS)[1];
HANDLE MemExecute(VOID *MemBuffer, DWORD dwBufSize);
BOOL AlignPEToMem( VOID *MemBuffer, DWORD dwBufSize, PIMAGE_NT_HEADERS &peHead, PIMAGE_SECTION_HEADERS &peSecHead, VOID *&MemPtr, DWORD &ImageSize);
DWORD CalcTotalImageSize(PIMAGE_DOS_HEADER szMzHead, DWORD dwBufSize, PIMAGE_NT_HEADERS peHead, PIMAGE_SECTION_HEADERS peSecHead);
DWORD GetAlignedSize(DWORD Origin, DWORD Alignment);
HANDLE AttachPE(PIMAGE_NT_HEADERS peHead, VOID *MemPtr, DWORD ImageSize);
BOOL CreateMemProcess(CONTEXT &Context, HANDLE &hHandle, HANDLE &hThread, DWORD &BaseAddr, DWORD &ImageSize);
BOOL UnloadShell(HANDLE hProcess, DWORD BaseAddr);
BOOL HasRelocationTable(PIMAGE_NT_HEADERS peHead);
VOID DoRelocation(PIMAGE_NT_HEADERS peHead, VOID *OldBase, VOID *NewBase);
/* 运行资源中的EXE文件使用方法:
HRSRC hResource = FindResource(GetModuleHandle(NULL),MAKEINTRESOURCE(IDR_FILE_STC_ISP),TEXT("File"));
if(hResource)
{
HGLOBAL hg = LoadResource(GetModuleHandle(NULL),hResource);
if(hg)
{
LPVOID pData = LockResource(hg);
if(pData)
{
DWORD dwSize = SizeofResource(GetModuleHandle(NULL),hResource);
hProcess = MemExecute(pData,dwSize);
if(hProcess != INVALID_HANDLE_VALUE)
{
CloseHandle(CreateThread(NULL,0,WaitProcessExit,hWnd,NULL,0));
return TRUE;
}
}
}
}
*/
///////////////////////////////////////////////////
// date: 2013.08.15
// author: 刘立向
// email: llxxhm@126.com
// qq: 515311445
///////////////////////////////////////////////////
#include "PeApi.h"
HANDLE MemExecute(VOID *MemBuffer, DWORD dwBufSize)
{
DWORD ImageSize = 0;
VOID *MemPtr = NULL;
PIMAGE_NT_HEADERS peHead;
PIMAGE_SECTION_HEADERS peSecHead;
HANDLE hProcess = INVALID_HANDLE_VALUE;
if(AlignPEToMem(MemBuffer, dwBufSize, peHead, peSecHead, MemPtr, ImageSize))
{
hProcess = AttachPE(peHead, MemPtr, ImageSize);
VirtualFree(MemPtr, ImageSize, MEM_DECOMMIT);
}
return hProcess;
}
// 加载pe到内存并对齐所有节
BOOL AlignPEToMem( VOID *MemBuffer, DWORD dwBufSize, PIMAGE_NT_HEADERS &peHead, PIMAGE_SECTION_HEADERS &peSecHead, VOID *&MemPtr, DWORD &ImageSize)
{
PIMAGE_SECTION_HEADERS szPeSecHead;// 节表
PIMAGE_DOS_HEADER szMzHead = (PIMAGE_DOS_HEADER)MemBuffer; // DOS头
if( dwBufSize < sizeof(IMAGE_DOS_HEADER) )
return FALSE;
if( szMzHead->e_magic != IMAGE_DOS_SIGNATURE )
return FALSE;
if( dwBufSize < szMzHead->e_lfanew + (DWORD)sizeof(IMAGE_NT_HEADERS) )
return FALSE;
PIMAGE_NT_HEADERS SrcPeH = (PIMAGE_NT_HEADERS)((int)szMzHead + szMzHead->e_lfanew); //PE头
if( SrcPeH->Signature != IMAGE_NT_SIGNATURE )
return FALSE;
if( (SrcPeH->FileHeader.Characteristics & IMAGE_FILE_DLL)
|| (SrcPeH->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE == 0)
|| (SrcPeH->FileHeader.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER))
)
return FALSE;
szPeSecHead = (PIMAGE_SECTION_HEADERS)((int)SrcPeH + sizeof(IMAGE_NT_HEADERS));
ImageSize = CalcTotalImageSize( szMzHead, dwBufSize, SrcPeH, szPeSecHead);
if(ImageSize == 0)
return FALSE;
MemPtr = VirtualAlloc( NULL, ImageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); // 分配内存
if( MemPtr != NULL )
{
// 计算需要复制的PE头字节数
DWORD dwHeadSize = SrcPeH->OptionalHeader.SizeOfHeaders;
for( int i = 0; i < SrcPeH->FileHeader.NumberOfSections; ++i)
{
if( (szPeSecHead[i]->PointerToRawData) && (szPeSecHead[i]->PointerToRawData < dwHeadSize) )
{
dwHeadSize = szPeSecHead[i]->PointerToRawData;
}
}
memmove( MemPtr, szMzHead, dwHeadSize);
peHead = (PIMAGE_NT_HEADERS)((int)MemPtr + ((PIMAGE_DOS_HEADER)MemPtr)->e_lfanew);
peSecHead = (PIMAGE_SECTION_HEADERS)((int)peHead + sizeof(IMAGE_NT_HEADERS));
VOID *Pt = (VOID *)((DWORD)MemPtr + GetAlignedSize( peHead->OptionalHeader.SizeOfHeaders, peHead->OptionalHeader.SectionAlignment));
for( i = 0; i < peHead->FileHeader.NumberOfSections; ++i)
{
// 定位该节在内存中的位置
if(peSecHead[i]->VirtualAddress)
Pt = (VOID *)((DWORD)MemPtr + peSecHead[i]->VirtualAddress);
if(peSecHead[i]->SizeOfRawData)
{
// 复制数据到内存
memmove(Pt, (CONST VOID *)((DWORD)(szMzHead) + peSecHead[i]->PointerToRawData), peSecHead[i]->SizeOfRawData);
if(peSecHead[i]->Misc.VirtualSize < peSecHead[i]->SizeOfRawData)
Pt = (VOID *)((DWORD)Pt + GetAlignedSize(peSecHead[i]->SizeOfRawData, peHead->OptionalHeader.SectionAlignment));
else // pt 定位到下一节开始位置
Pt = (VOID *)((DWORD)Pt + GetAlignedSize(peSecHead[i]->Misc.VirtualSize, peHead->OptionalHeader.SectionAlignment));
}
else
{
Pt = (VOID *)((DWORD)Pt + GetAlignedSize(peSecHead[i]->Misc.VirtualSize, peHead->OptionalHeader.SectionAlignment));
}
}
}
return TRUE;
}
// 计算加载pe并对齐需要占用多少内存
// 未直接使用OptionalHeader.SizeOfImage作为结果是因为据说有的编译器生成的exe这个值会填0
DWORD CalcTotalImageSize(PIMAGE_DOS_HEADER szMzHead, DWORD dwBufSize, PIMAGE_NT_HEADERS peHead, PIMAGE_SECTION_HEADERS peSecHead)
{
DWORD ImageSize = GetAlignedSize( peHead->OptionalHeader.SizeOfHeaders, peHead->OptionalHeader.SectionAlignment);// 计算pe头的大小
// 计算所有节的大小
for( int i = 0; i < peHead->FileHeader.NumberOfSections; ++i)
{
// 超出文件范围
if(peSecHead[i]->PointerToRawData + peSecHead[i]->SizeOfRawData > dwBufSize)
{
return 0;
}
else if(peSecHead[i]->VirtualAddress)//计算对齐后某节的大小
{
if(peSecHead[i]->Misc.VirtualSize)
{
ImageSize = GetAlignedSize( peSecHead[i]->VirtualAddress + peSecHead[i]->Misc.VirtualSize, peHead->OptionalHeader.SectionAlignment);
}
else
{
ImageSize = GetAlignedSize( peSecHead[i]->VirtualAddress + peSecHead[i]->SizeOfRawData, peHead->OptionalHeader.SectionAlignment);
}
}
else if( peSecHead[i]->Misc.VirtualSize < peSecHead[i]->SizeOfRawData )
{
ImageSize += GetAlignedSize( peSecHead[i]->SizeOfRawData, peHead->OptionalHeader.SectionAlignment);
}
else
{
ImageSize += GetAlignedSize( peSecHead[i]->Misc.VirtualSize, peHead->OptionalHeader.SectionAlignment);
}
}
return ImageSize;
}
// 计算对齐后的大小
DWORD GetAlignedSize(DWORD Origin, DWORD Alignment)
{
return (Origin + Alignment - 1) / Alignment * Alignment;
}
// 创建外壳进程并用目标进程替换它然后执行
HANDLE AttachPE(PIMAGE_NT_HEADERS peHead, VOID *MemPtr, DWORD ImageSize)
{
CONTEXT Context;
DWORD BaseAddr = 0;
DWORD imageSize = 0;
HANDLE hProcess = INVALID_HANDLE_VALUE;
HANDLE hThread = INVALID_HANDLE_VALUE;
if(CreateMemProcess(Context, hProcess, hThread, BaseAddr, imageSize))
{
VOID *pBaseAddr = NULL;
DWORD OldProtect = 0;
if((peHead->OptionalHeader.ImageBase == BaseAddr) && (imageSize >= ImageSize))
{// 外壳进程可以容纳目标进程并且加载地址一致
pBaseAddr = (VOID *)BaseAddr;
VirtualProtectEx(hProcess, pBaseAddr, imageSize, PAGE_EXECUTE_READWRITE, &OldProtect);
}
else
{
if(UnloadShell(hProcess, BaseAddr))
{// 卸载外壳进程占有内存
pBaseAddr = VirtualAllocEx((VOID *)hProcess, (VOID *)peHead->OptionalHeader.ImageBase, ImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
}
if((pBaseAddr == NULL) && HasRelocationTable(peHead))
{// 分配内存失败并且目标进程支持重定向
pBaseAddr = VirtualAllocEx((VOID *)hProcess, NULL, ImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if(pBaseAddr) DoRelocation(peHead, MemPtr, pBaseAddr); // 重定向
}
}
if(pBaseAddr)
{
WriteProcessMemory(hProcess, (VOID *)(Context.Ebx+8), &pBaseAddr, sizeof(DWORD), &OldProtect); // 重置目标进程运行环境中的基址
peHead->OptionalHeader.ImageBase = (DWORD)pBaseAddr;
if(WriteProcessMemory(hProcess, pBaseAddr, MemPtr, ImageSize, &OldProtect))
{// 复制PE数据到目标进程
Context.ContextFlags = CONTEXT_FULL;
if((DWORD)pBaseAddr == BaseAddr)
Context.Eax = peHead->OptionalHeader.ImageBase + peHead->OptionalHeader.AddressOfEntryPoint; // 重置运行环境中的入口地址
else
Context.Eax = (DWORD)pBaseAddr + peHead->OptionalHeader.AddressOfEntryPoint;
SetThreadContext(hThread, &Context);// 更新运行环境
ResumeThread(hThread);// 执行
CloseHandle(hThread);
}
else
{// 加载失败,杀掉外壳进程
TerminateProcess(hProcess, 0);
CloseHandle(hThread);
hThread = INVALID_HANDLE_VALUE;
CloseHandle(hProcess);
hProcess = INVALID_HANDLE_VALUE;
}
}
else
{// 加载失败,杀掉外壳进程
TerminateProcess(hProcess, 0);
CloseHandle(hThread);
hThread = INVALID_HANDLE_VALUE;
CloseHandle(hProcess);
hProcess = INVALID_HANDLE_VALUE;
}
}
return hProcess;
}
// 创建外壳进程并获取其基址、大小和当前运行状态
BOOL CreateMemProcess(CONTEXT &Context, HANDLE &hProcess, HANDLE &hThread, DWORD &BaseAddr, DWORD &ImageSize)
{
STARTUPINFOA si;
DWORD dwReadSize = 0;
PROCESS_INFORMATION pi;
MEMORY_BASIC_INFORMATION MemInfo;
memset(&si, 0, sizeof(si));
memset(&pi, 0, sizeof(pi));
si.cb = sizeof(si);
char szCmd[MAX_PATH] = {0};
GetModuleFileName(0, szCmd, MAX_PATH);
if(CreateProcess(NULL, szCmd, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi))// 以挂起方式运行进程
{
hProcess = pi.hProcess;
hThread = pi.hThread;
// 获取外壳进程运行状态,[Context.Ebx+8]内存处存的是外壳进程的加载基址,Context.Eax存放有外壳进程的入口地址
Context.ContextFlags = CONTEXT_FULL;
GetThreadContext(hThread, &Context);
ReadProcessMemory(hProcess, (VOID *)(Context.Ebx+8), &BaseAddr, sizeof(DWORD), &dwReadSize); // 读取加载基址
VOID *pBaseAddr = (VOID *)BaseAddr;
// 计算外壳进程占有的内存
while(VirtualQueryEx(hProcess, pBaseAddr, &MemInfo, sizeof(MemInfo)))
{
if(MemInfo.State = MEM_FREE) break;
pBaseAddr = (VOID *)((DWORD)pBaseAddr + MemInfo.RegionSize);
}
ImageSize = (DWORD)pBaseAddr - (DWORD)BaseAddr;
return TRUE;
}
return FALSE;
}
// 卸载原外壳占用内存
BOOL UnloadShell(HANDLE hProcess, DWORD BaseAddr)
{
BOOL bRet = FALSE;
typedef DWORD (__stdcall *pfZwUnmapViewOfSection)(DWORD, DWORD);
pfZwUnmapViewOfSection ZwUnmapViewOfSection = NULL;
HMODULE hModel = LoadLibrary("ntdll.dll");
if(hModel)
{
ZwUnmapViewOfSection = (pfZwUnmapViewOfSection)GetProcAddress(hModel, "ZwUnmapViewOfSection");
if(ZwUnmapViewOfSection)
bRet = (ZwUnmapViewOfSection((DWORD)hProcess, BaseAddr) == 0);
FreeLibrary(hModel);
}
return bRet;
}
// 是否包含可重定向列表
BOOL HasRelocationTable(PIMAGE_NT_HEADERS peHead)
{
return (peHead->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress) && (peHead->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);
}
// 重定向PE用到的地址
VOID DoRelocation(PIMAGE_NT_HEADERS peHead, VOID *OldBase, VOID *NewBase)
{
DWORD Delta = (DWORD)NewBase - peHead->OptionalHeader.ImageBase;
PImageBaseRelocation pImageBaseRelocation = (PImageBaseRelocation)((DWORD)OldBase + peHead->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
while(pImageBaseRelocation->VirtualAddress + pImageBaseRelocation->SizeOfBlock)
{
DWORD *pImageBaseRelocationW = (DWORD *)((DWORD)pImageBaseRelocation + sizeof(*pImageBaseRelocation));
for(unsigned int i=1; i <= (pImageBaseRelocation->SizeOfBlock - sizeof(*pImageBaseRelocation)) / 2; ++i)
{
if((*pImageBaseRelocationW) & 0xF000 == 0x3000){
DWORD *t = (DWORD *)((DWORD)(OldBase) + pImageBaseRelocation->VirtualAddress + ((*pImageBaseRelocationW) & 0x0FFF));
*t += Delta;
}
++pImageBaseRelocationW;
}
pImageBaseRelocation = (PImageBaseRelocation)pImageBaseRelocationW;
}
}
|