首页
社区
课程
招聘
[旧帖] [分享]单EXE注入傀儡进程 0.00雪花
发表于: 2014-1-20 23:01 2805

[旧帖] [分享]单EXE注入傀儡进程 0.00雪花

2014-1-20 23:01
2805
关于单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期)

收藏
免费 0
支持
分享
最新回复 (1)
雪    币: 3496
活跃值: (749)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
赞一个!!有个问题是,注入后能否孑类化呢?
2014-2-4 18:28
0
游客
登录 | 注册 方可回帖
返回
//