现在病毒泛滥,采用的技术也越来越邪恶,要么是全盘感染,要么是进程注入,一不小心中了,清除都要清除好久,稍不留意,又会死灰复燃。因此学会写病毒专杀,对付起来就会轻松多了!这篇文章将会从ring3层阐述病毒专杀攻略。
主要从三部分来阐述,分别是进程相关部分、注册表相关部分、文件相关部分。
进程相关部分
一、对抗多进程保护
为了使病毒程序能够在电脑中存活更久,现在的病毒都会采用相关的技术来保护自己,一旦病毒进程被结束掉,就会重新创建病毒进程。最常用的就是多进程保护,如双进程保护,三进程保护。一旦病毒进程被结束掉,另外的进程就会检测到并重新创建病毒进程,已达到生生不息的目的。
攻略:将进程挂起,然后逐个结束掉
代码:
typedef DWORD (WINAPI *PFSuspendProcess)(HANDLE hProcess);
PFSuspendProcess SuspendProcess; //挂起进程的API,在ntdlll.dll中
//函数功能:挂起进程 参数:进程ID
VOID SuspendProc(DWORD dwPID)
{
HMODULE hNtDllLib=LoadLibrary("ntdll.dll"); //加载ntdll.dll,获得dll句柄
SuspendProcess=(PFSuspendProcess)GetProcAddress(hNtDllLib,"ZwSuspendProcess");
//获取ZwSuspendProcess的地址
if (SuspendProcess)
{
HANDLE hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwPID);
//获取指定进程ID的句柄
SuspendProcess(hProcess); //挂起进程
}
FreeLibrary(hNtDllLib);//释放dll
}
VOID TerminateProc(DWORD dwPID) //函数功能:结束进程 参数:进程ID
{
HANDLE hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwPID);
TerminateProcess(hProcess,0);
}
//函数功能:枚举进程并挂起进程
VOID WINAPI EnumProcessAndSuspendProcess()
{
HANDLE hProcessSnap;
PROCESSENTRY32 pe32;
// Snapshot
hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
if( hProcessSnap == INVALID_HANDLE_VALUE )
{
printf( "CreateToolhelp32Snapshot (of processes) error!\n");
return ;
}
// 设置输入参数,结构的大小
pe32.dwSize = sizeof( PROCESSENTRY32 );
// 开始列举进程
if( !Process32First( hProcessSnap, &pe32 ) )
{
printf( "Process32First error!\n" ); // 出错信息
CloseHandle( hProcessSnap );
return ;
}
do
{
//枚举进程然后将病毒进程挂起
if (stricmp(pe32.szExeFile,"Global.exe")==0)
{
SuspendProc(pe32.th32ProcessID);
}
...
//在这里添加要结束的进程名
} while( Process32Next( hProcessSnap, &pe32 ) );
CloseHandle( hProcessSnap ); //关闭句柄
return ;
}
//函数功能:枚举进程并结束进程
VOID WINAPI EnumProcessAndTerminateProcess()
{
HANDLE hProcessSnap;
PROCESSENTRY32 pe32;
// Snapshot
hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
if( hProcessSnap == INVALID_HANDLE_VALUE )
{
printf( "CreateToolhelp32Snapshot (of processes) error!\n");
return ;
}
// 设置输入参数,结构的大小
pe32.dwSize = sizeof( PROCESSENTRY32 );
// 开始列举进程
if( !Process32First( hProcessSnap, &pe32 ) )
{
printf( "Process32First error!\n" ); // 出错信息
CloseHandle( hProcessSnap );
return ;
}
do
{ //枚举进程然后将病毒进程结束
if (stricmp(pe32.szExeFile,"Global.exe")==0)
{
TerminateProc(pe32.th32ProcessID);
}
...
//在这里添加要结束的进程名
} while( Process32Next( hProcessSnap, &pe32 ) );
CloseHandle( hProcessSnap ); //关闭句柄
return ;
}
然后在主程序里调用EnumProcessAndSuspendProcess()和EnumProcessAndTerminateProcess()就能将病毒程序结束掉。管它几个进程相互保护,都能轻松干掉!
二、对抗DLL进程注入
病毒进程除了会采用多进程保护之外,还会采用DLL注入来实现目的,这种方法相对来说比较隐蔽!必须通过监视工具(如Icesword)来监视程序结束后又被谁创建,如果进程是系统上的系统进程(如csrss.exe,svchost.exe),那就是系统进程被dll注入了,但是我们不能直接把系统进程也一起结束了吧,结束完就等着重启吧!那怎么办?
攻略:既然病毒能将dll注入到进程中,我们也能够将dll从进程中卸载掉。
代码:
说明:为了能够卸载掉注入的dll,首先要打开进程获取进程句柄,但是系统进程是不能访问的,因此要通过提升进程的权限至SE_DEBUG权限才能访问系统进程
//函数功能:提升权限
//参数:lpszPrivilege:权限名 bEnablePrivilege:是否允许
BOOL SetPrivilege(LPCTSTR lpszPrivilege,BOOL bEnablePrivilege)
{
TOKEN_PRIVILEGES tp;
LUID luid;
HANDLE hProcessToken=NULL;
if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ALL_ACCESS,&hProcessToken))
return -1;
if(!LookupPrivilegeValue(NULL,lpszPrivilege,&luid))
return FALSE;
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid=luid;
if(bEnablePrivilege)
tp.Privileges[0].Attributes =SE_PRIVILEGE_ENABLED;
else
tp.Privileges[0].Attributes =0;
//Enable the privilege or disable all privilege
AdjustTokenPrivileges(hProcessToken,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),(PTOKEN_PRIVILEGES)NULL,(PDWORD)NULL);
if(GetLastError()!=ERROR_SUCCESS)
return FALSE;
if(hProcessToken!=NULL)
CloseHandle(hProcessToken);
return TRUE;
}
提升完权限之后,就是打开所有运行进程,查看里面是否有我们要找的dll模块,如果存在,就要获得dll句柄,然后用FreeLibrary卸载掉。但是在windows系统中,各个进程是相互独立的,拥有独立的进程空间,彼此不能访问对方内存空间里的数据。因此在给远程进程创建线程时,无法将参数传递过去,只能将dll名写入到进程可以访问的空间,然后调用FreeLibrary卸载掉。
此处代码参考了《黑客防线2009黑客编程》中的一篇文章,在此表示感谢)
//函数功能:卸载掉注入的dll 参数;dll名
int KillDLL(char *DllName)
{
// 解除所有进程中某DLL模块的加载
HANDLE hProcess=NULL;
if(!SetPrivilege(SE_DEBUG_NAME,TRUE))
{
return -2;
}
DWORD aProcesses[1024],cbNeeded,cProcesses;
unsigned int i;
//计算目前有多少进程,aerocesses[]用来存放有效的进程PIDs
if(!EnumProcesses(aProcesses,sizeof(aProcesses),&cbNeeded))
return -11;
cProcesses=cbNeeded/sizeof(DWORD);
//按有效的PID遍历所有的进程
for(i= 0;i<cProcesses;i++)
{
if((hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,aProcesses[i]))==NULL)
{
continue;
}
// 由目标进程地址空间写入DLL名称
DWORD dwSize,dwWritten;
dwSize=strlen(DllName)+1;
LPVOID lpBuf=VirtualAllocEx(hProcess,NULL,dwSize,MEM_COMMIT,PAGE_READWRITE);
if(lpBuf=NULL)
{
CloseHandle(hProcess);
continue;
}
//向其中写入dll的名称
if(WriteProcessMemory(hProcess,lpBuf,(LPVOID)DllName,dwSize,&dwWritten))
{
// 若写入字节数与实际写入字节数不相等,仍属失败
if(dwWritten!=dwSize)
{
VirtualFreeEx(hProcess,lpBuf,dwSize,MEM_DECOMMIT);
CloseHandle(hProcess);
continue;
}
}
else
{
CloseHandle(hProcess);
continue;
}
//使目标进程调用GetModuleHandIe,获得DLL在进程中的句柄
DWORD dwHandle,dwID;
LPVOID pFunc= GetModuleHandleA;
HANDLE hThread = CreateRemoteThread(hProcess,NULL,0,(LPTHREAD_START_ROUTINE)pFunc,lpBuf,0,&dwID);
//等待GetModuleHandle运行完毕
WaitForSingleObject(hThread,INFINITE);
//获得GetModuleHandle的返回值
GetExitCodeThread(hThread,&dwHandle);
// 释放目标进程中申请的空间
VirtualFreeEx( hProcess,lpBuf,dwSize,MEM_DECOMMIT);
CloseHandle(hThread);
//使目标进程调用FreeLibrary,卸载DLL
pFunc=FreeLibrary;
hThread= CreateRemoteThread(hProcess,NULL,0,(LPTHREAD_START_ROUTINE)pFunc,(LPVOID)dwHandle,0,&dwID);
//等待FreeLibrary卸载完毕
WaitForSingleObject(hThread,INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);
}
if(hProcess!=NULL)
CloseHandle(hProcess);
return 0;
}
注册表相关部分
一、对抗自启动
系统中的注册表成了兵家必争之地,病毒通常修改注册表来达到自启动的目的。
攻略:删除掉相关的注册表项
代码:
VOID DeleteRunouceRegistry()
{
HKEY hTestKey;
CHAR szBuf[128];
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",0,KEY_READ|KEY_WRITE,&hTestKey)==ERROR_SUCCESS)
{
if(RegDeleteValue(hTestKey,"Runouce")!=ERROR_SUCCESS)
{
sprintf(szBuf,"%d",GetLastError());
MessageBox(NULL,szBuf,NULL,MB_OK);
}
}
}
这里只是给出一个自启动的例子,病毒自启动的方法相当多,只要将上面的注册表项改成病毒利用的注册表项,就能解决问题。
二、对抗映像劫持
可能有朋友遇到过这样的情况,一个正常的程序,无论把它放在哪个位置,或者是一个程序重新用安装盘修复过,都出现无法运行的情况,或是出错提示为“找不到文件”或者直接没有运行起来的反应,或者是比如运行程序A却成了执行B(可能是病毒),而改名后却可以正常运行的现象。 这就是映像劫持。病毒经常劫持注册表编辑器、任务管理器以及服务管理器等等用户常用的程序,来使病毒运行。
攻略:删除HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\下的相关注册表项。
代码:
VOID DeleteRunouceRegistry()//这里以任务管理器为例
{
HKEY hTestKey;
CHAR szBuf[128];
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\taskmgr",0,KEY_READ|KEY_WRITE,&hTestKey)==ERROR_SUCCESS)
{
if(RegDeleteValue(hTestKey,"Debugger")!=ERROR_SUCCESS)
{
sprintf(szBuf,"%d",GetLastError());
MessageBox(NULL,szBuf,NULL,MB_OK);
}
}
}
三、对抗文件隐藏
有时已经将文件夹选项下的“显示所有文件和文件夹”勾上和“隐藏受保护的系统文件”(去掉),但还是看不到文件,这是什么原因呢?原来是注册表中的一个注册表项在作怪。
攻略:将HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\ShowSuperHidden的值改为1。
由于上面的都是采用编程的方法来实现,现在换种更简单的方法来处理注册表的相关操作,采用批处理。
代码:
创建一个.bat文件,然后在里面添加要处理的注册表项,相关的格式可以参考网上的资料,
为了减少篇幅,不再叙述。
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v ShowSuperHidden /t reg_dword /d 00000001 /f
reg delete "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\taskmgr.exe" /v Debugger /f
reg delete "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\policies\Explorer\Run" /v sys /f
上面的批处理是将注册表项ShowSuperHidden的值改为1,删除掉任务管理器的映像劫持,删除掉sys项的自启动。
我们将它命名为kill.bat,将它和主程序放在同一个文件夹下,然后在主程序里调用执行一下,代码如下:
GetModuleFileName(NULL,szPath,MAX_PATH); //获取程序的路径
lstrcpy( _tcsrchr(szPath, _T('\\') ) + 1, _T("kill.bat") );//然后去掉程序名加上kill.bat
strcpy(szCmdLine,"cmd.exe /c start ");//WinExec的命令行
strcat(szCmdLine,szPath);
WinExec(szCmdLine,SW_SHOWNORMAL);
这样就很轻松的调用批处理,批处理写起来比C方便多了,只要一句就能实现C的四五句。
文件相关部分
一、对抗顽固文件
病毒会在运行时释放一些病毒文件,有的是病毒自身的复制,有的是Dll。为了使病毒能够更久得存活,病毒一般会对文件进行保护,以防止用户将其删除掉。
攻略:采用ring3下最强悍的ZwDeleteFile来删除病毒文件
代码:
HINSTANCE hNtDll;
ZWDELETEFILE ZwDeleteFile;
RTLINITUNICODESTRING RtlInitUnicodeString;
ZWCREATEFILE ZwCreateFile;
ZWWRITEFILE ZwWriteFile;
ZWCLOSE ZwClose;
hNtDll = LoadLibrary ("NTDLL");
if (!hNtDll)
return 0;
ZwDeleteFile = (ZWDELETEFILE)GetProcAddress (hNtDll,"ZwDeleteFile");
RtlInitUnicodeString = (RTLINITUNICODESTRING)GetProcAddress (hNtDll,"RtlInitUnicodeString");
ZwCreateFile = (ZWCREATEFILE)GetProcAddress (hNtDll,"ZwCreateFile");
ZwWriteFile = (ZWWRITEFILE)GetProcAddress (hNtDll,"ZwWriteFile");
ZwClose = (ZWCLOSE)GetProcAddress (hNtDll,"ZwClose");
UNICODE_STRING ObjectName;
RtlInitUnicodeString(&ObjectName,L"\\??\\E:\\autorun.inf");//记得这里要有\\??\\在前面的,文件名必须是符号链接或者设备名
OBJECT_ATTRIBUTES ObjectAttributes = {
sizeof(OBJECT_ATTRIBUTES), // Length
NULL, // RootDirectory
&ObjectName, // ObjectName
OBJ_CASE_INSENSITIVE, // Attributes
0, // SecurityDescriptor
NULL, // SecurityQualityOfService
};
HANDLE hFile;
PVOID content = "ForZwFileTest";
IO_STATUS_BLOCK IoStatusBlock;
ZwCreateFile(&hFile,
GENERIC_WRITE|SYNCHRONIZE|GENERIC_READ,
&ObjectAttributes,
&IoStatusBlock,
0,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_DELETE,
FILE_OPEN_IF,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
ZwWriteFile(hFile, 0, 0, 0, &IoStatusBlock, content, 12, NULL, NULL);
ZwClose(hFile);
ZwDeleteFile(&ObjectAttributes);
FreeLibrary (hNtDll);
总结:
这里只是在ring3层来阐述对抗病毒的攻略,但是现在的病毒也开始进入ring0层,利用底层技术来搞破坏,因此仅仅在ring3层讨论对抗病毒还是不够的,下次希望能够在ring0层讲下对抗病毒的攻略。
[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界