首页
社区
课程
招聘
[求助]如何用API让被禁用的服务恢复为手动执行
发表于: 2008-10-6 20:08 6796

[求助]如何用API让被禁用的服务恢复为手动执行

2008-10-6 20:08
6796
收藏
免费 0
支持
分享
最新回复 (4)
雪    币: 431
活跃值: (442)
能力值: ( LV12,RANK:530 )
在线值:
发帖
回帖
粉丝
2
直接NET   START不行吗?非要用API?
2008-10-6 21:37
0
雪    币: 197
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
要用API实现
2008-10-6 22:14
0
雪    币: 247
活跃值: (10)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
4
我不太清楚具体的方法,

但是给ShellExcute函数传递参数"net start XXX"的方法还是可行的。
2008-10-7 08:46
0
雪    币: 451
活跃值: (78)
能力值: ( LV12,RANK:470 )
在线值:
发帖
回帖
粉丝
5
ChangeServiceConfig

原创 冷风 木马编程DIY之系统服务收藏
新一篇: 编程查杀ttdianying流氓软件 | 旧一篇: 明确的学习方向


注:本文于07/1月于黑客防线发表版权归黑客防线所有,转载请注明出处
木马编程DIY之系统服务
文/图冷风 [后方网络]
对系统服务的管理几乎是木马必不可少的功能了,比如神气儿,上兴远程控制等
要是能我们给自己的木马加上这个功能,看着也不赖。我们实现的效果如图3-4所示
图3
图4
好啦,现在开始干活

取得配置权限

在对服务进行管理设置前,需要以相应的权限打开服务,可通过下面两个API实现

SC_HANDLE OpenSCManager(
LPCTSTR lpMachineName, // pointer to machine name string
LPCTSTR lpDatabaseName, // pointer to database name string
DWORD dwDesiredAccess // type of access
);

SC_HANDLE OpenService(
SC_HANDLE hSCManager, // handle to service control manager
// database
LPCTSTR lpServiceName, // pointer to name of service to start
DWORD dwDesiredAccess // type of access to service
);

通常我们以完全权限打开,示例代码如下:

SC_HANDLE scm;
SC_HANDLE service;


if((scm=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS))==NULL)
{
Printf("OpenSCManager Error\n");
}

service=OpenService(scm,ServerName,SERVICE_ALL_ACCESS);

if(!service)
{
Printf("OpenService error!\n");
}


这样就可以通过service句柄对服务进行各种操作了



枚举基本服务信息

想要对服务进行设置就需要知道服务的当前信息,对我们有用的通常是以下几项
服务名称,显示名称,启动状态,启动方式,程序路径等。
这些信息我们可以通过API函数EnumServicesStatus来实现,它的原形如下:

BOOL EnumServicesStatus(
SC_HANDLE hSCManager, // handle to service control manager database
DWORD dwServiceType, // type of services to enumerate
DWORD dwServiceState, // state of services to enumerate
LPENUM_SERVICE_STATUS lpServices,
// pointer to service status buffer
DWORD cbBufSize, // size of service status buffer
LPDWORD pcbBytesNeeded, // pointer to variable for bytes needed
LPDWORD lpServicesReturned,
// pointer to variable for number returned
LPDWORD lpResumeHandle // pointer to variable for next entry
);


其中 LPENUM_SERVICE_STATUS lpServices是一个结构,它的原形如下:

typedef struct _ENUM_SERVICE_STATUS { // ess
LPTSTR lpServiceName;
LPTSTR lpDisplayName;
SERVICE_STATUS ServiceStatus;
} ENUM_SERVICE_STATUS, *LPENUM_SERVICE_STATUS;

结构中包含服务名称,显示名称,启动状态。虽然它所返回的信息是及为有限的,但它是一次枚举所有服务信息
在要求不高的情况下,用它还是相当方便的,下面的示例代码可以枚举系统中所有服务的基本信息,代码如下:

LPENUM_SERVICE_STATUS lpServices = NULL;
DWORD nSize = 0;
DWORD n;
DWORD nResumeHandle = 0;

lpServices = (LPENUM_SERVICE_STATUS) LocalAlloc(LPTR, 64 * 1024); //注意分配足够的空间
EnumServicesStatus(scm,SERVICE_WIN32,
SERVICE_STATE_ALL,
(LPENUM_SERVICE_STATUS)lpServices,
64 * 1024,
&nSize,
&n,
&nResumeHandle);
for ( i = 0; i < n; i++)
{
Printf("服务名称: %s",lpServices.lpServiceName);
Printf("显示名称: %s",lpServices.lpDisplayName);
if ( lpServices.ServiceStatus.dwCurrentState!=SERVICE_STOPPED)
{
Printf("启动状态: 已启动\n");
}
}


枚举详细服务信息

如果想得到更详细的服务信息,我们可以使用另一个API函数QueryServiceConfig
它的原形如下:

BOOL QueryServiceConfig(
SC_HANDLE hService, // handle of service
LPQUERY_SERVICE_CONFIG lpServiceConfig,
// address of service config. structure
DWORD cbBufSize, // size of service configuration buffer
LPDWORD pcbBytesNeeded // address of variable for bytes needed
);

LPQUERY_SERVICE_CONFIG lpServiceConfig是一个结构,它包含指定服务的详细资料,它的原形如下

typedef struct _QUERY_SERVICE_CONFIG { // qsc
DWORD dwServiceType;
DWORD dwStartType;
DWORD dwErrorControl;
LPTSTR lpBinaryPathName;
LPTSTR lpLoadOrderGroup;
DWORD dwTagId;
LPTSTR lpDependencies;
LPTSTR lpServiceStartName;
LPTSTR lpDisplayName;
} QUERY_SERVICE_CONFIG, LPQUERY_SERVICE_CONFIG;

很清楚了吧,服务类型,启动类型,程序路径,服务名称,显示名称尽在其中。
下面的示例代码可以得到程序路径,启动方式,其代码如下:

LPQUERY_SERVICE_CONFIG ServicesInfo = NULL;

for ( i = 0; i < n; i++)
{
SC_HANDLE service = NULL;
DWORD nResumeHandle = 0;

service=OpenService(scm,lpServices.lpServiceName,SERVICE_ALL_ACCESS);
ServicesInfo = (LPQUERY_SERVICE_CONFIG) LocalAlloc(LPTR, 64 * 1024); //注意分配足够的空间
QueryServiceConfig(service,ServicesInfo,64 * 1024,&nResumeHandle); //枚举各个服务信息

Printf("程序路径: %s",ServicesInfo->lpBinaryPathName);
if(2==ServicesInfo->dwStartType) //启动方式
{
Printf("自动\n");
}
if(3==ServicesInfo->dwStartType)
{
Printf("手动\n");
}
if(4==ServicesInfo->dwStartType)
{
Printf("禁止\n");
}

}

上面的代码稍加修改就可以用到你的程序中,现在对于服务信息的显示就完成了。


启动/停止服务


启动一个服务可以用StartService函数实现,不过在启动前先用QueryServiceStatus检查一下服务的运行状态,如下代码

SERVICE_STATUS status;
BOOL isSuccess=QueryServiceStatus(service,&status);
if (!isSuccess)
{
Printf("QueryServiceStatus error!\n");
}

if ( status.dwCurrentState==SERVICE_STOPPED )
{
isSuccess=StartService(service,NULL,NULL);

if (!isSuccess)
{
Printf("启动服务失败!");
}

}
下面是停止服务的实现代码:

if ( status.dwCurrentState!=SERVICE_STOPPED )
{
isSuccess=ControlService(service,SERVICE_CONTROL_STOP,&status);
if (!isSuccess )
{
Printf("停止服务失败!");
}
}


创建/删除服务


创建服务使用的API为CreateService,它的原形为:

SC_HANDLE CreateService(
SC_HANDLE hSCManager, // handle to service control manager
// database
LPCTSTR lpServiceName, // pointer to name of service to start
LPCTSTR lpDisplayName, // pointer to display name
DWORD dwDesiredAccess, // type of access to service
DWORD dwServiceType, // type of service
DWORD dwStartType, // when to start service
DWORD dwErrorControl, // severity if service fails to start
LPCTSTR lpBinaryPathName, // pointer to name of binary file
LPCTSTR lpLoadOrderGroup, // pointer to name of load ordering
// group
LPDWORD lpdwTagId, // pointer to variable to get tag identifier
LPCTSTR lpDependencies, // pointer to array of dependency names
LPCTSTR lpServiceStartName,
// pointer to account name of service
LPCTSTR lpPassword // pointer to password for service account
);

其中 DWORD dwStartType是指动方式,有三种方式

SERVICE_AUTO_START //自动
SERVICE_DEMAND_START //手动
SERVICE_DISABLED //禁用

此函数的参比较多但我们通常只用其中的一部分,如
SC_HANDLE hSCManager, //用OpenSCManager打开的句柄
LPCTSTR lpServiceName, // 服务名称
LPCTSTR lpDisplayName, // 显示名称
DWORD dwStartType, // 启动方式
LPCTSTR lpBinaryPathName, // 程序路径

其它直接赋0或NULL就可以了
例如下面的代码可以创建一个名为 LengFeng 路径为C:\LengFeng.EXE的自启动服务

void CreateServer()
{
SC_HANDLE scm=NULL;
SC_HANDLE service=NULL;

if((scm=OpenSCManager(NULL,NULL,SC_MANAGER_CREATE_SERVICE))==NULL)
{
Printf("OpenSCManager Error");
}
service=CreateService(
scm,"LengFeng" ,"LengFeng" ,
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
"C:\LengFeng.EXE", 0, 0, 0, 0, 0 );
if(!service)
Printf("服务创建失败");

CloseServiceHandle(service);
CloseServiceHandle(scm);
}

删除服务更容易些,可以用DeleteService来实现

BOOL DeleteService( SC_HANDLE hService);

SC_HANDLE hService是我们以前用OpenService打开的服务句柄,在删除前注意先用,启动/停止服务中介绍的方法
停止正在运行的服务。


配置启动方式



有时候我们需要对服务的启动方式进行更改,比如TELNET改为自动运行,对以存在的服务进行配置
可以用ChangeServiceConfig来实现,它的原形如下:

BOOL ChangeServiceConfig(
SC_HANDLE hService // handle to service
DWORD dwServiceType, // type of service
DWORD dwStartType, // when to start service
DWORD dwErrorControl, // severity if service fails to start
LPCTSTR lpBinaryPathName, // pointer to service binary file name
LPCTSTR lpLoadOrderGroup, // pointer to load ordering group name
LPDWORD lpdwTagId, // pointer to variable to get tag identifier
LPCTSTR lpDependencies, // pointer to array of dependency names
LPCTSTR lpServiceStartName,
// pointer to account name of service
LPCTSTR lpPassword, // pointer to password for service account
LPCTSTR lpDisplayName // pointer to display name
);

揉揉眼睛仔细看一下,是不是有点面熟?嘿它的参数跟创建服务的CreateService就是一样的嘛!这样就好办了
我们把需要的地方改掉,不需要的就放个NULL或SERVICE_NO_CHANGE就行了。
为了安全更新配置信息,微软要求在执行ChangeServiceConfig之前需要用LockServiceDatabase来锁定服务数据
偶测试了一下,有时候会锁定失败,但仍然可以实现对服务配置的更改。
下面的示例代码,可以把上面创建的LengFeng服务的启动方式改为 禁止
其代码如下:

SC_LOCK sclLock;
sclLock = LockServiceDatabase(scm);
if (sclLock == NULL)
{

if (GetLastError() != ERROR_SERVICE_DATABASE_LOCKED)
Printf("LockServiceDatabase error\n");

}
if (! ChangeServiceConfig(
service, // handle of service
SERVICE_NO_CHANGE, // service type: no change
SERVICE_DISABLED, // 这里做了更改
SERVICE_NO_CHANGE, // error control: no change
NULL, // binary path: no change
NULL, // load order group: no change
NULL, // tag ID: no change
NULL, // dependencies: no change
NULL, // account name: no change
NULL, // password: no change
NULL)) //displayname
{
Printf("ChangeServiceConfig error!\n");
}
UnlockServiceDatabase(sclLock);

伸个懒腰,与服务相关的操作,我们也搞个六七八九不离十啦,想把它加到自己的木马中时,只要设计一个便于网络传输的结构,然后把代码拷进去就差不多了。在写这个小程序时遇到的相关问题写在了blog.csdn.net/chinafe有兴趣可以跟我讨论。
2008-10-7 11:43
0
游客
登录 | 注册 方可回帖
返回
//