枚举服务的一种方法
Windows的服务枚举一般有使用函数EnumServicesStatus枚举和直接遍历注册表的方法.本文介绍另一种方法.
我们知道在服务管理中Services.Exe起了重要的作用.在该进程中存在一个双向的链表的结构,用来记录所有注册的服务的信息.
我们可以直接遍历这个链表以达到枚举服务的目的.
该链表的头部由ServiceDatabase符号来标明,在XPSP2下该符号的地址值为0x0101A098,在根据NT源代码(WIN2K源码没有服务相关的内容)我们知道
ServiceDatabase的类型为SERVICE_RECORD,我们根据NT源码,再结合反汇编XPSP2下的ScCreateServiceRecord函数和ScCreateImageRecord函数,
得出XPSP2下SERVICE_RECORD和IMAGE_RECORD的结构如下:
IMAGE_RECORED结构:(大小0x38:)
typedef struct _IMAGE_RECORD {
struct _IMAGE_RECORD *Prev; //+0 linked list
struct _IMAGE_RECORD *Next; //+4 linked list
LPWSTR ImageName; //+8 fully qualified .exe name
DWORD Pid; //+C Process ID ok.
DWORD ServiceCount; //+10 Num services running in process .
HANDLE PipeHandle; //+14 Handle to Service .
HANDLE ProcessHandle; //+18 Handle for process .
HANDLE ObjectWaitHandle; //+1C Handle for waiting on the process.
HANDLE TokenHandle; //+20 Logon token handle.
LUID Unknown1; //+24
HANDLE ProfileHandle; //+2c User profile handle
LPWSTR AccountName; //+30 Account process was started under !!!!!30
DWORD Unknown2; //+34
}IMAGE_RECORD, *PIMAGE_RECORD, *LPIMAGE_RECORD;
SERVICE_RECORD结构:(大小0x74)
typedef struct _SERVICE_RECORD {
struct _SERVICE_RECORD *Prev; // +0 linked list
struct _SERVICE_RECORD *Next; // +4 linked list
LPWSTR ServiceName; // +8 points to service name
LPWSTR DisplayName; // +C points to display name
DWORD ResumeNum; // +10 Ordered number for this rec
DWORD ServerAnnounce; // +14 Server announcement bit flags
DWORD Signature; // +18 Identifies this as a service record.
DWORD UseCount; // +1C How many open handles to service
DWORD StatusFlag; // +20 status(delete,update...)
union {
LPIMAGE_RECORD ImageRecord; // +24 Points to image record
LPWSTR ObjectName; // +24 Points to driver object name
};
SERVICE_STATUS ServiceStatus; // +28 see winsvc.h
DWORD StartType; // +44 AUTO, DEMAND, etc.
DWORD ErrorControl; // +48 NORMAL, SEVERE, etc.
DWORD Tag; // +4C DWORD Id for the service,0=none.
LPDEPEND_RECORD StartDepend; // +50
LPDEPEND_RECORD StopDepend; // +54
LPWSTR Dependencies; // +58
PSECURITY_DESCRIPTOR ServiceSd; // +5C
DWORD StartError; // +60
DWORD StartState; // +64
LPLOAD_ORDER_GROUP MemberOfGroup; // +68
LPLOAD_ORDER_GROUP RegistryGroup; // +6C
DWORD Unknown1; // +70
} SERVICE_RECORD, *PSERVICE_RECORD, *LPSERVICE_RECORD;
知道了这两个结构,我们使用ReadProcessMemory函数读取Services.exe的内存就可以枚举所有的服务了.
如果你想隐藏什么服务的话,只要将该服务的SERVICE_RECORD结构脱离掉链表就可以,此时所有的枚举方法都没有效果了.当然该服务也不接受SCP的控制管理了.
注意:上面的ServiceDatabase的位置以及IMAGE_RECORD/SERVICE_RECORD都是在XPSP2下的情况;若在其他系统,需要自己分析.
参考文献:
1.关于隐藏服务的讨论 by shadow3
2.Reverse Engineering the Service Control Manager(SCM)
3.hooking the service manager with hacker defender.