VC教程
 

VC:WINDOWS 9x的后台进程

---- 1. 后 台 进 程 ----

在WINDOWS NT 中 有 一 个 功 能 强 大 的SERVICE 管 理 器, 它 管 理 着 一 部 分 实 现 重 要 功 能 的 后 台 进 程, 例 如FTP.HTTP.RAS. 网 络Message 等 等, 这 些 后 台 进 程 被 称 之 为Service, 他 们 可 以 在 系 统 启 动 时 就 加 载, 可 以 运 行 在 较 高 的 优 先 级, 可 以 说 是 非 常 靠 近 系 统 核 心 的 设 备 驱 动 程 序 中 的 一 种. 在WINDOWS95 下,Microsoft 没 有 提 供 这 样 一 个 高 度 集 中 化 了 的 管 理 器, 不 过 我 们 通 过VC 自 带 的PVIEW 可 以 看 到, 在 桌 面 背 后 同 样 有 秘 密 的 后 台 进 程 存 在, 例 如:SysTray, 电 源 管 理 等. 其 实, 这 些 就 是WINDOWS95 管 理 的 后 台 进 程,WINDOWS95 没 有 提 供SERVICE 管 理 器, 取 而 代 之 的 是 一 个 简 单 的 登 记 接 口, 可 以 类 似 的 称 之 为WINDOWS95 下 的Service( 不 过 严 格 的 讲,WINDOWS95 下 是 没 有Service 的), 同 样 的, 通 过 这 个 登 记 接 口, 我 们 可 以 使 自 己 的 程 序 随 系 统 启 动 而 最 先 运 行, 随 系 统 关 闭 而 最 后 停 止, 和 操 作 系 统 结 合 在 一 起, 实 现 许 多 独 特 的 功 能. 我 在 实 际 工 作 中, 仔 细 的 分 析 了 这 个Windows95 的 接 口, 并 且 测 试 后 发 现, 在WINDOWS97 和 最 新 的WINDOWS98 中 它 一 样 有 效. 并 通 过 这 个 机 制, 成 功 的 实 现 了WINDOWS95.98 下 的 无 人 职 守 监 控. 下 面 是 关 于 这 个 接 口 的 分 析 结 果 和 一 些 准 备 知 识. ---- 2. 进 程 数 据 库(PDB) 介 绍 ---- 在Windows 的 核 心 数 据 结 构 中, 有 一 个 重 要 的 进 程 管 理 结 构 叫 进 程 数 据 库, 它 位 于Kernel32 的 公 用 内 存 堆 中, 可 以 通 过GetCurrentProcessID(...) 得 到 指 向 该 结 构 的 指 针, 以 下 是 部 分PDB 的 组 成, 与 本 文 直 接 相 关 的 是PDB 偏 移21h 处 的Service 标 志 字 节, 通 过 后 面 的 伪 码 分 析, 我 们 可 以 清 楚 的 看 到 所 谓 登 记 为Windows95 或Windows98 下 的Service 进 程, 只 不 过 是 把 它 相 应 的PDB 中 该 标 志 字 节 置 为1 而 已. 偏移量长度 说明 ============================================ +00h DWORD Type // Kernel32对象的类型 +04h DWORD CReference //参考计数 +08h DWORD Un1 //未知 +0ch DWORD pSomeEvent //指向K32OBJ_EVENT指针 +10h DWORD TerminationStatus //活动标志或返回值 +14h DWORD Un2 //未知 ..... +21h BYTE Flags1 // Service标记, // "1"是Service进程, // "0"普通进程 ..... +24h DWORD pPSP // DOS PSP指针 ..... ============================================ ---- 3. 实 现 接 口 ---- (1) Windows95 中 提 供 的 简 单 的Service 接 口 是 一 个32 位 的API: RegisterServiceProcess, 由 于 在VC++ 的Online help 中 得 不 到 关 于 这 个API 的 确 切 解 释, 笔 者 不 得 不 针 对 此API 进 行 了 逆 向 分 析, 以 下 是 在Windows95 的Kernel32.dll 中 该API 的 伪 码. 我 们 可 以 清 楚 的 看 到Window95 内 部 到 底 是 怎 样 做 的, 其 实 处 理 的 非 常 简 单. BOOL RegisterServiceProcess ( DWORD dwProcessID, DWORD dwType ) { HANDLE dwPID; if( dwProcessID == NULL ) dwPID = dwCurrentProcessID; // Get global kernel32 variable else // Call some kernel functions if( ( dwPID = CheckPID( dwProcessID ) == NULL ) return FALSE; if( dwType == 1 ) { *(BYTE *)( dwPID + 0x21 ) | = 0x01; return TRUE; } if( dwType == 0 ) { *(BYTE *)( dwPID + 0x21 ) & = 0xFE; return TRUE; } return FALSE; } 以下为函数原形: BOOL RegisterServiceProcess( DWORD dwPID, DWORD dwType ) 参数: dwPID:进程ID, NULL代表当前进程 dwType: RSP_SIMPLE_SERVICE为登记 RSP_UNREGISTER_SERVICE为取消登记 返回值: TRUE: 调用成功 FALSE: 调用失败 ---- (2) 另 外, 为 了 让Service 进 程 有 机 会 在BOOT 后 就 启 动,Windows95 的Registry 中 提 供 了 加 载 方 法: 在KEY " MyComputer HKEY_LOCAL_MACHINESOFTWARE MicrosoftWindows CurrentVersion RunServices " 加 入 自 己 的 应 用 程 序 命 令 行, 即 可 实 现 开 机 自 动 加 载. 当 然, 如 果 你 得 机 器 中 没 有 这 个Key, 自 己 建 一 个 也 是 可 以 的. ---- 4. 例 程 ---- 下 面 是 实 现 例 程, 所 有 代 码 经 过 了WINDOWS95. WINDOWS98 BETA3 的 测 试, 可 以 方 便 的 加 入 到 自 己 的 项 目 文 件 中. ---- 头 文 件: // File: service.h // The head file of "service.cpp" // Note: 1. You must use C++ compiler // 2. The platform is WIN32 (WINNT & WIN95) #ifndef _SERVICE_H #define _SERVICE_H ///////////////////////////////////// ////////////// USED FOR WIN95 SERVICE // Micros #define RSP_SIMPLE_SERVICE 1 #define RSP_UNREGISTER_SERVICE 0 // Function types for GetProcAddress #define RegisterServiceProcess_PROFILE (DWORD (__stdcall *) (DWORD, DWORD)) // Service Fuctions in Win95 BOOL W95ServiceRegister(DWORD dwType); BOOL W95StartService( DWORD dwType ); #endif CPP 文 件: // File: service.cpp --- implement the service #include "service.h" ///////////////////////////////////////////////// // USED FOR WIN95 SERVICE登 记 为Service 子 程 序: ///////////////////////////////////////// //////////////////////////////////////// // Define: BOOL W95ServiceRegister(DWORD dwType) // Parameters: dwType --- Flag to register or unregister the service // RSP_SIMPLE_SERVICE means register // RSP_UNREGISTER_SERVICE means unregister // Return: TRUE --- call success; FALSE --- call failer BOOL W95ServiceRegister( DWORD dwType ) { // Function address defination DWORD (__stdcall * hookRegisterServiceProcess) ( DWORD dwProcessId, DWORD dwType ); // Get address of function hookRegisterServiceProcess = RegisterServiceProcess_PROFILE GetProcAddress(GetModuleHandle("KERNEL32"), TEXT("RegisterServiceProcess")); // Register the WIN95 service if(hookRegisterServiceProcess(NULL,dwType)==0) return FALSE; return TRUE; } ---- 加 入 注 册 表 子 程 序: #define SERVICE_NAME TEXT("SERVICE") // Define: BOOL W95StartService( DWORD dwType ) // Parameters: dwType --- Flag to register or unregister the service // RSP_SIMPLE_SERVICE means register // RSP_UNREGISTER_SERVICE means unregister // Return: TRUE --- call success; FALSE --- call failer BOOL W95StartService( DWORD dwType ) { // Local Variables TCHAR lpszBuff[256]; LPTSTR lpszStr = lpszBuff +128; LPTSTR lpszName = lpszBuff; HANDLE hKey = NULL; DWORD dwStrCb = 0; DWORD dwValueType = 0; // Get service name currently lpszName = GetCommandLine(); for( int i = _tcslen(lpszName)-1; I >=0; i-- ) { if( ( lpszName[i] != '"' )&&( lpszName[i]!=' ') ) break; else if( lpszName[i] == '"' ) lpszName[i] = '0'; } if( lpszName[0] == '"' ) lpszName = lpszName +1; // Registe as start up service if( RegOpenKeyEx (HKEY_LOCAL_MACHINE, TEXT( "SOFTWARE\Microsoft\Windows\ CurrentVersion\RunServices"), 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hKey ) != ERROR_SUCCESS ) { if( RegCreateKey( HKEY_LOCAL_MACHINE, TEXT( "SOFTWARE\Microsoft\ Windows\CurrentVersion\RunServices"), &hKey ) != ERROR_SUCCESS ) { //DebugOut( "RegCreateKey() error!"); return FALSE; } } dwValueType = REG_SZ; dwStrCb = 128; // Take value if( RegQueryValueEx(hKey, SERVICE_NAME, 0, &dwValueType, (LPBYTE)lpszStr, &dwStrCb ) == ERROR_SUCCESS ) { // Find this key value if( _tcscmp( lpszStr, lpszName )==0 ) { // Remove the service if( dwType == RSP_UNREGISTER_SERVICE ) { if(RegDeleteValue( hKey, SERVICE_NAME ) == ERROR_SUCCESS ) { RegCloseKey ( hKey ); return TRUE; } RegCloseKey( hKey ); return FALSE; } // Already exist service if( dwType == RSP_SIMPLE_SERVICE ) { //DebugOut("Already registed!"); RegCloseKey( hKey ); return TRUE; } } // Not find it } // No this value // Unregiste return if( dwType == RSP_UNREGISTER_SERVICE ) { RegCloseKey( hKey ); return TRUE; } // No this value then create it if( dwType == RSP_SIMPLE_SERVICE ) { dwStrCb = 128; // Set value if( RegSetValueEx(hKey,SERVICE_NAME,0,REG_SZ,(CONST BYTE *)lpszName, dwStrCb ) != ERROR_SUCCESS ) { //DebugOut("RegSetValueEx() error!"); RegCloseKey( hKey ); return FALSE; } RegCloseKey( hKey ); return TRUE; } // Unknow type RegCloseKey( hKey ); return FALSE; } ---- 主 程 序: // WinMain function is the entry of the this program int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { if( W95ServiceRegister( RSP_SIMPLE_SERVICE ) ) { W95StartService( RSP_SIMPLE_SERVICE ); } MessageBox(NULL, "Sample service", "SERVICE", MB_OK ); UNREFERENCED_PARAMETER( hInstance ); UNREFERENCED_PARAMETER( lpCmdLine ); UNREFERENCED_PARAMETER( nCmdShow ); UNREFERENCED_PARAMETER( hPrevInstance ); return 0; } ---- 运 行 这 个 程 序, 等 到MessageBox 弹 出 后, 从WINDOWS 中 退 出 到LOG ON 状 态, 你 会 看 见MessageBox 一 直 保 持 打 开 状 态 直 至 受 到 响 应 或 系 统 关 机. 所 以 要 做WINDOWS95 下 系 统 级 的 后 台 进 程, 并 不 一 定 非 要 去 编 写 容 易 引 起 系 统 混 乱 的VXD 程 序, 在 硬 件 部 分 允 许 的 情 况 下, 我 认 为 本 文 介 绍 的 方 法 更 加 方 便 有 效.