怎样让自己的程序进程不让别人强行关闭掉
Posted 潘祖记
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了怎样让自己的程序进程不让别人强行关闭掉相关的知识,希望对你有一定的参考价值。
作者:潘枫 技术交流QQ:598432467
完整源代码:http://download.csdn.net/source/196884
今天刚注册了CSDN用户,前面在这里学到了很多东西,一直也想自己写点什么,可注册了好多次居然不成功。呵,其它的题外话就不说了,我们今天要谈论的话题是“怎样让自己的程序进程不让别人强行关闭掉”。昨天公司让我写了一个软件,并且不能让别人结束这个程序的进程。前面看到我过一些相关的文章,有创建一个线程不停检测进程名(通过枚举进程列表)的方法,但我觉得这种方法可能有些占资源。还有将自己进程提升为系统进程的,这种我也没有试过,如果谁有这种方法的实现代码给我一份将不甚感激,我今天用到是另外一种方法,拦截API函数,有两种方法:
1.在强行关闭一个进程时系统调用的是
BOOL WINAPI TerminateProcess(
HANDLE hProcess,
UINT uExitCode
);
我们如果利用钩子拦截TerminateProcess这个API函数,在系统调用这个函数是先判断是不是我们不让关闭进程的句柄就行了。
2.在调用BOOL WINAPI TerminateProcess(
HANDLE hProcess,
UINT uExitCode
);之前系统必须要先用
HANDLE WINAPI OpenProcess(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwProcessId
);在开进程的句柄,如果我们发现第一参数是PROCESS_TERMINATE方式,说明是要强行结束此进程,我们可以这以这种方打开的调用进程分析,看进程ID是不是我们不让关闭的进程的ID,下面我们着重来讲一下这种方法:
因为要用到钩子,所以们先来创建一个DLL工程,创建的过程我在这里就不说了。在这里我使用了windows核心编程里面的APIHOOK类,将这个类拷贝到工程目录下,加入自己的工程。
在DLL工程里加入一个WH_SHELL的钩子,它的作用是进程创建时将DLL文件插入到每一个进程里面,从而达到拦截API函数的目的。
下面是钩子实现部分代码:
#pragma data_seg(".SHARED")
HHOOK glhHook = NULL; // 安装勾子句柄
#pragma data_seg()
#pragma comment( linker, "/section:shared,rws" )
HINSTANCE glhInstance = NULL; // DLL实例句柄
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
... {
glhInstance = (HINSTANCE)hModule;
return TRUE;
}
static LRESULT WINAPI ShellHookProc( int code, WPARAM wParam, LPARAM lParam)
... {
return ::CallNextHookEx(glhHook, code, wParam, lParam);
}
extern " C " __declspec(dllexport) BOOL StartHook(DWORD pid)
... {
BOOL bResult=FALSE;
if(!glhHook)
...{
glhHook = SetWindowsHookEx(WH_SHELL,ShellHookProc,glhInstance, 0);
if(glhHook!=NULL)
...{
bResult=TRUE;
}
}
return bResult;
}
extern " C " __declspec(dllexport) BOOL StopHook()
... {
BOOL bResult=FALSE;
if(glhHook)
...{
bResult= UnhookWindowsHookEx(glhHook);
if(bResult)
...{
glhHook=NULL;
}
}
return bResult;
}
DLL文件插入其它进程里了,下面的工作就是替换OpenProcess函数了,
typedef HANDLE (WINAPI * PFNOPENPROCESS)(DWORD,BOOL,DWORD);
extern CAPIHook g_OpenProcess;
// 自定义OpenProcess函数
HANDLE WINAPI Hook_OpenProcess(DWORD dwDesiredAccess,BOOL bInheritHandle,DWORD dwProcessId);
// .............................................................................................../*
HANDLE WINAPI Hook_OpenProcess(DWORD dwDesiredAccess,BOOL bInheritHandle,DWORD dwProcessId)
... {
if(dwDesiredAccess == PROCESS_TERMINATE && dwProcessId == dwProcessId == lpData->dwProcessId/**//*这个值是不让关闭进程的ID*/)
...{
char sz[2048];
wsprintf(sz, "%d,%d,%d",dwDesiredAccess,dwProcessId,lpData->dwProcessId);
MessageBox(NULL,sz,"d",MB_OK);
return NULL;
}
return ((PFNOPENPROCESS)(PROC)g_OpenProcess)(dwDesiredAccess,bInheritHandle,dwProcessId);
}
// 挂钩OpenProcess函数
CAPIHook g_OpenProcess("kernel32.dll", "OpenProcess",(PROC)Hook_OpenProcess,TRUE);
把上面这代码加入到刚才创建的DLL里就行了。
刚才大家在查看上面代码时看到了lpData->dwProcessId这个参数,这就是我不让关闭的进程ID,那么这个值怎么得到呢。当然方法很多,可以通过窗口名获取窗口句柄
DWORD hpid; // 进程ID
GetWindowThreadProcessId( hwnd , & hpid );
但如果你的进程没有窗口应该怎么办呢?那么就只能在进程运行时用::GetCurrentProcessId(); 取得,然后通过内存映射的方式传给DLL文件。如下面的代码
DWORD dwProcessId;
char szModuleFileName[MAX_PATH];
} SHWP_STRUCT, * LPSHWP_STRUCT;
// 全局变量定义
HANDLE hMapping; // 内存映射名柄
LPSHWP_STRUCT lpData; // 共享内存
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
... {
//创建内存共享
hMapping=CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE,0,0x100,"PCMONITOR.");
if(hMapping != NULL)
...{
lpData=(LPSHWP_STRUCT)MapViewOfFile(hMapping,FILE_MAP_ALL_ACCESS,0,0,0);
}
lpData->dwProcessId = ::GetCurrentProcessId(); //当前进程ID
...............................其它代码
}DLL里面的内存映射部分代码
HANDLE hMapping; // 内存映射名柄
LPSHWP_STRUCT lpData; // 共享内存
// ........................................................................../*
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
... {
//创建内存共享
hMapping=CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE,0,0x100,"PCMONITOR.");
if(hMapping != NULL)
...{
lpData=(LPSHWP_STRUCT)MapViewOfFile(hMapping,FILE_MAP_ALL_ACCESS,0,0,0);
}
return TRUE;
}
这样我们的进程在运行时它的进程ID通过lpData->dwProcessId = ::GetCurrentProcessId(); 得到并以内存映射的方式传给DLL文件。
DLL里面拦截了OpenProcess函数里面的DWORD dwProcessId参数,如果这个数据是我们自己进程的ID就直接反回一个NULL值,也就是打开我们进程失败,这样系统就没有办法掉用TerminateProcess强行关闭我们的进程了。如果我们直接拦截TerminateProcess函数,然后不管哪个函数掉用它直接返回TRUE值,那完了,你就永远没想在你机子上强行关闭任何程序,呵,我说的是强行,发送WM_CLOSE消息关了不算哟。
拦截TerminateProcess函数部分代码:
typedef BOOL (WINAPI * PFNTERMINATEPROCESS)(HANDLE, UINT);
extern CAPIHook g_TerminateProcess;
BOOL WINAPI Hook_TerminateProcess(HANDLE hProcess, UINT uExitCode); // 自定义TerminateProcess函数
// .............................................................................................../*
// 自定义TerminateProcess函数
BOOL WINAPI Hook_TerminateProcess(HANDLE hProcess, UINT uExitCode)
... {
// 取得主模块的文件名称
char szPathName[MAX_PATH];
::GetModuleFileName(NULL, szPathName, MAX_PATH);
// 构建发送给主窗口的字符串
char sz[2048];
wsprintf(sz, " 进程:(%d)%s 进程句柄:%X 退出代码:%d (%x)",::GetCurrentProcessId(), szPathName, hProcess, uExitCode,lpData->dwProcessId);
MessageBox(NULL,sz,"d",MB_OK);
return ((PFNTERMINATEPROCESS)(PROC)g_TerminateProcess)(hProcess, uExitCode);
}
// 挂钩TerminateProcess函数
CAPIHook g_TerminateProcess( " kernel32.dll " , " TerminateProcess " ,(PROC)Hook_TerminateProcess,TRUE);
以上是关于怎样让自己的程序进程不让别人强行关闭掉的主要内容,如果未能解决你的问题,请参考以下文章