在WINDOWS NT 中有一个功能强大的SERVICE 管理器, 它管理着一部分实现重要功能的后台进程, 例如FTP.HTTP.RAS. 网络Message 等等, 这些后台进程被称之为Service, 他们可以在系统启动时就加载, 可以运行在较高的优先级, 可以说是非常靠近系统核心的设备驱动程序中的一种. WINDOWS95 没有提供SERVICE 管理器, 取而代之的是一个简单的登记接口, 可以类似的称之为WINDOWS95 下的Service( 不过严格的讲,WINDOWS95 下是没有Service 的), 同样的, 通过这个登记接口, 我们可以使自己的程序随系统启动而最先运行, 随系统关闭而最后停止, 和操作系统结合在一起, 实现许多独特的功能. 首先我们可以先来看看一些相关的知识。
进程数据库(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 指针
...
============================================
实现接口
(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, 自己建一个也是可以的.
例程
---- 下面是实现例程, 所有代码经过了测试, 可以方便的加入到自己的项目文件中.
---- 头文件:
// 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 一直保持打开状态直至受到响应或系统关机.