WINDOWS9x 的后台进程
【打印文章】
上海仙霞路山特公司软件中心 黄飞
----1.后台进程
----在WINDOWSNT中有一个功能强大的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_MACHINE\SOFTWARE \Microsoft\Windows \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中退出到LOGON状态,你会看见MessageBox一直保持打开状态直至受到响应或系统关机.所以要做WINDOWS95下系统级的后台进程,并不一定非要去编写容易引起系统混乱的VXD程序,在硬件部分允许的情况下,我认为本文介绍的方法更加方便有效.
----1.后台进程
----在WINDOWSNT中有一个功能强大的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_MACHINE\SOFTWARE \Microsoft\Windows \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中退出到LOGON状态,你会看见MessageBox一直保持打开状态直至受到响应或系统关机.所以要做WINDOWS95下系统级的后台进程,并不一定非要去编写容易引起系统混乱的VXD程序,在硬件部分允许的情况下,我认为本文介绍的方法更加方便有效.
本栏文章均来自于互联网,版权归原作者和各发布网站所有,本站收集这些文章仅供学习参考之用。任何人都不能将这些文章用于商业或者其他目的。( Pfan.cn )
【编程爱好者论坛】