写了三天左右,思路什么的都很清晰,真正实现的时候就各种问题,蓝屏蓝到麻木了,幸好是虚拟机,半年前就打算看驱动了,因为各种原因耽搁了,现在什么都要重新来,这篇文章就当是开门贴吧。
主要功能:防止任务管理器结束进程。
主要原理:HOOK SSDT表中的NtOpenProcess,如果传入的是保护进程的PID,则返回无效句柄。
这个Windows进程保护器的主要界面如下:
利用此程序实现的禁止任务管理器中结束进程的效果图:
实现过程总结
应用程序层:
//为listcontrol添加右键菜单 #ifndef GET_X_LPARAM #define GET_X_LPARAM(lParam) ((int)(short)LOWORD(lParam)) #endif #ifndef GET_Y_LPARAM #define GET_Y_LPARAM(lParam) ((int)(short)HIWORD(lParam)) #endif case WM_CONTEXTMENU: { UINT xPos; UINT yPos; HWND hwndContext; hwndContext = (HWND)wParam; HWND hWndlist= GetDlgItem(hDlg, IDC_PROCESS_LIST); xPos = GET_X_LPARAM(lParam); yPos = GET_Y_LPARAM(lParam); // 来自 hWndlist 的消息 if(hwndContext == hWndlist) { // 非右键点击 if (xPos == -1 || yPos == -1) { break; } HMENU hMenu=LoadMenu(hIns,MAKEINTRESOURCE(IDR_MENU1)); HMENU hMenuTrackPopup=GetSubMenu(hMenu,0); TrackPopupMenu(hMenuTrackPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,xPos,yPos, 0, hDlg, NULL); DestroyMenu(hMenu); } // 做你自己的事 break; } TrackPopupMenu倒数第二个参数,要为当前对话框的句柄,否则无法响应菜单ID。 //初始化listcontrol VOID ListIni(HWND hDlg) { HWND hWndlist; LVCOLUMN ColInfo1 = {0}; LVCOLUMN ColInfo2 = {0}; LVCOLUMN ColInfo3 = {0}; LVCOLUMN ColInfo4 = {0}; LVCOLUMN ColInfo5 = {0}; hWndlist= GetDlgItem(hDlg, IDC_PROCESS_LIST); SendMessage(hWndlist, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP | LVS_EX_GRIDLINES); ColInfo1.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_FMT; ColInfo1.iSubItem = 0; ColInfo1.fmt = LVCFMT_CENTER; ColInfo1.cx = 100; ColInfo1.pszText = "进程名"; ColInfo1.cchTextMax = 50; ColInfo2.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_FMT; ColInfo2.iSubItem = 0; ColInfo2.fmt = LVCFMT_CENTER; ColInfo2.cx = 50; ColInfo2.pszText = "PID"; ColInfo2.cchTextMax = 50; ColInfo3.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_FMT; ColInfo3.iSubItem = 0; ColInfo3.fmt = LVCFMT_CENTER; ColInfo3.cx = 80; ColInfo3.pszText = "EPROCESS"; ColInfo3.cchTextMax = 50; ColInfo4.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_FMT; ColInfo4.iSubItem = 0; ColInfo4.fmt = LVCFMT_CENTER; ColInfo4.cx = 210; ColInfo4.pszText = "路径"; ColInfo2.cchTextMax = 50; ColInfo5.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_FMT; ColInfo5.iSubItem = 0; ColInfo5.fmt = LVCFMT_CENTER; ColInfo5.cx = 50; ColInfo5.pszText = "状态"; ColInfo5.cchTextMax = 50; ::SendMessage(hWndlist, LVM_INSERTCOLUMN, WPARAM(0), LPARAM(&ColInfo1)); ::SendMessage(hWndlist, LVM_INSERTCOLUMN, WPARAM(1), LPARAM(&ColInfo2)); ::SendMessage(hWndlist, LVM_INSERTCOLUMN, WPARAM(2), LPARAM(&ColInfo3)); ::SendMessage(hWndlist, LVM_INSERTCOLUMN, WPARAM(3), LPARAM(&ColInfo4)); ::SendMessage(hWndlist, LVM_INSERTCOLUMN, WPARAM(4), LPARAM(&ColInfo5)); } //与驱动间的通信 传入要保护的进程PID数组 bRet = DeviceIoControl(hDevice, IOCTL_PROTECTPROCESS_CONTROL, ProPid, sizeof(ULONG)*100, NULL,0,&dwOutput, NULL); //从驱动中获取当前进程列表 bRet = DeviceIoControl(hDevice, IOCTL_GETPROCESS_CONTROL,&de, sizeof(ULONG),ProcessList, sizeof(_ProcessList)*100,&dwOutput, NULL); 驱动层: #pragma PAGEDCODE struct _ProcessList { UCHAR ProcessName[30]; //进程名 ULONG PID;//PID ULONG Eprocess;//Eprocess ULONG ProCount; }ProcessList[100]; #pragma PAGEDCODE ULONG ProPid[100];
当时看的是Windows驱动开发详解,把变量换到分页内存中,害我蓝屏了30多次。
//获取进程列表 VOID EnumProcessList() { ULONG EProcess , FirstEProcess ; ULONG dwCount = 0 ; PLIST_ENTRY ActiveProcessLinks; ULONG dwPidOffset =0x84; ULONG dwPNameOffset = 0x174; ULONG dwPLinkOffset = 0x88; ULONG dwProcessId; PUCHAR pImageFileName; FirstEProcess = EProcess = ( ULONG ) PsGetCurrentProcess() ; while ( EProcess != 0 ) { dwProcessId = * ( (PULONG) ( EProcess + dwPidOffset ) ) ; pImageFileName = ( PUCHAR ) ( EProcess + dwPNameOffset ) ; if ( ( LONG ) dwProcessId >= 0 ) { //DbgPrint( "[Pid=%8d] EProcess=0x%08x %s\n" ,dwProcessId , EProcess , pImageFileName ) ; strcpy((char*)ProcessList[dwCount].ProcessName,(char*)pImageFileName); ProcessList[dwCount].PID=dwProcessId; ProcessList[dwCount].Eprocess=EProcess; ProcessList[dwCount].ProCount=0; dwCount ++ ; } ActiveProcessLinks = ( PLIST_ENTRY ) ( EProcess + dwPLinkOffset ) ; EProcess = ( ULONG ) ActiveProcessLinks->Flink - dwPLinkOffset ; if ( EProcess == FirstEProcess ) { break ; } } DbgPrint ( "ProcessNum = %d\n", dwCount ) ; ULONG i=0; ProcessList[0].ProCount=dwCount; DbgPrint ( "ProcessNum = %d\n", ProcessList[0].ProCount ) ; for (i=0;iMajorFunction) { case IRP_MJ_CREATE: DbgPrint("IRP_MJ_CREATE被调用\n"); break; case IRP_MJ_CLOSE: DbgPrint("IRP_MJ_CLOSE被调用\n"); break; case IRP_MJ_DEVICE_CONTROL: DbgPrint("IRP_MJ_DEVICE_CONTROL被调用\n"); IoControlCode=IrpStack->Parameters.DeviceIoControl.IoControlCode; switch(IoControlCode) { case IOCTL_PROTECTPROCESS_CONTROL: inSize=IrpStack->Parameters.DeviceIoControl.InputBufferLength; outSize=IrpStack->Parameters.DeviceIoControl.OutputBufferLength; inBuf=(long*)pIrp->AssociatedIrp.SystemBuffer; RtlCopyMemory(ProPid,inBuf,sizeof(ULONG)*100); break; case IOCTL_GETPROCESS_CONTROL: PVOID pInputBuffer, pOutputBuffer; ULONG outputLength, inputLength; DbgPrint("COMM_BufferedIo\r\n"); outputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength; inputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength; pInputBuffer = pIrp->AssociatedIrp.SystemBuffer; pOutputBuffer = pIrp->AssociatedIrp.SystemBuffer; DbgPrint("COMM_BufferedIo UserModeMessage = '%s'", pInputBuffer); for (int i=0;iIoStatus.Information = outputLength; break; default: break; } break; default: DbgPrint("未知请求包被调用\n"); break; } IoCompleteRequest( pIrp, IO_NO_INCREMENT ); KdPrint(("Leave HelloDDKDispatchRoutine\n")); return status; }