-
-
[原创] SandboxiePlus Service隔离代码分析
-
发表于: 2025-6-6 17:57 405
-
最近写Sandboxieplus劫持com请求方法的例子,RpcSs和DcomLaunch都是服务类型,需要详细了解SandboxiePlus如何实现服务隔离的。即本文剖析一个问题:SandboxiePlus如何管理一个服务的。
Windows服务对应的文件有两种类型:
一个Windows服务必须存在存在两个处理逻辑:ServiceMain函数和ServiceCtrlHandler函数。如果该服务是由svchost.exe进行托管的话,这个dll必须导出ServiceMain函数,函数名不可以改变。ServiceMain函数是服务的主要逻辑代码,ServiceCtrlHandler函数主要响应来自SCM(服务控制管理器)各种控制命令,比如:STOP和SHUTDOWN。下面将使用如下代码生成服务ServiceTest.exe文件研究SandboxiePlus如何实现服务的隔离。
执行sc create ServiceTest binPath= "D:\test\service_test_exe.exe" DisplayName= "Service Test" start= auto
命令来创建服务,注册表方面的修改如下:
主要逻辑:首先查看是否是沙盒化服务,如果是调用SbieDll_StartBoxedService,向SbieSvc进程发送MSGID_SERVICE_RUN请求;否则调用SbieDll_CallServer函数,向SbieSvc进程发送MSGID_SERVICE_START请求,启动服务。
SbieDll_StartBoxedService对应的源码如下:
Scm_StartBoxedService2函数对应的源码如下:
调用StartService之后,对应服务的注册表内容如下:
使用DebugView可以看到服务输出的内容,如下图:
启动的服务进程会被再次注入SbieDll,其对StartServiceCtrlDispatcher hook的代码如下:
对RegisterServiceCtrlHandler函数hook的源码主要设置Scm_Handler或Scm_HandlerEx,如下:
该函数可产生暂停、停止和恢复服务等效果,主要逻辑:设置服务的注册表SBIE_ControlCode键实现。上文中的Scm_StartServiceCtrlDispatcherX函数设置了hEvent来监听是否设置了SBIE_ControlCode,如果设置了就调用Scm_Handler或Scm_HandlerEx,通过这种方式实现了模拟SCM发送各种控制码给ServiceCtrlHandler函数的过程。
这些函数主要查询注册表中的信息,一些函数如下:
SubscribeServiceChangeNotifications和NotifyServiceStatusChange,这两个函数都是用于监控服务或SCM的状态改变。具体用法可以见微软的MSDN文档。这里举出两个使用情况:
对于SubscribeServiceChangeNotifications来说,SandboxiePlus对应的hook函数并没有实质的内容,目前是一个空函数,对应的代码如下:
对于NotifyServiceStatusChange来说,SandboxiePlus对应的hook函数主要逻辑:
对应的源码如下:
Scm_Notify_ThreadProc函数的源码如下:
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
SERVICE_STATUS g_ServiceStatus = { 0 };
SERVICE_STATUS_HANDLE
g_StatusHandle = NULL;
HANDLE
g_hStopEvent = NULL;
VOID
WINAPI ServiceMain(
DWORD
argc,
LPTSTR
* argv);
VOID
WINAPI ServiceCtrlHandler(
DWORD
);
DWORD
WINAPI ServiceWorkerThread(
LPVOID
lpParam);
#define SERVICE_NAME _T("SampleService")
int
main(
int
argc,
char
* argv[])
{
SERVICE_TABLE_ENTRY DispatchTable[] =
{
{ (
LPWSTR
)SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain },
{ NULL, NULL }
};
if
(!StartServiceCtrlDispatcher(DispatchTable))
{
return
GetLastError();
}
return
0;
}
VOID
WINAPI ServiceMain(
DWORD
argc,
LPTSTR
* argv)
{
DWORD
Status = E_FAIL;
HANDLE
hThread = INVALID_HANDLE_VALUE;
// Register our service control handler with the SCM
g_StatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler);
if
(g_StatusHandle == NULL)
{
goto
EXIT;
}
// Tell the service controller we are starting
ZeroMemory(&g_ServiceStatus,
sizeof
(g_ServiceStatus));
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwServiceSpecificExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
if
(!SetServiceStatus(g_StatusHandle, &g_ServiceStatus))
{
OutputDebugString(_T(
"MySampleService: ServiceMain: SetServiceStatus returned error"
));
}
// Create stop event to wait on later
g_hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if
(g_hStopEvent == NULL)
{
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = GetLastError();
g_ServiceStatus.dwCheckPoint = 1;
if
(!SetServiceStatus(g_StatusHandle, &g_ServiceStatus))
{
OutputDebugString(_T(
"MySampleService: ServiceMain: SetServiceStatus returned error"
));
}
goto
EXIT;
}
// Tell the service controller we are started
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
if
(!SetServiceStatus(g_StatusHandle, &g_ServiceStatus))
{
OutputDebugString(_T(
"MySampleService: ServiceMain: SetServiceStatus returned error"
));
}
// Start the thread that will perform the main task of the service
hThread = CreateThread(NULL, 0, ServiceWorkerThread, NULL, 0, NULL);
if
(hThread == NULL)
{
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = GetLastError();
g_ServiceStatus.dwCheckPoint = 1;
if
(!SetServiceStatus(g_StatusHandle, &g_ServiceStatus))
{
OutputDebugString(_T(
"MySampleService: ServiceMain: SetServiceStatus returned error"
));
}
goto
EXIT;
}
// Wait until our worker thread exits effectively signaling that the service needs to stop
WaitForSingleObject(hThread, INFINITE);
// Cleanup
CloseHandle(hThread);
CloseHandle(g_hStopEvent);
// Tell the service controller we are stopped
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 3;
if
(!SetServiceStatus(g_StatusHandle, &g_ServiceStatus))
{
OutputDebugString(_T(
"MySampleService: ServiceMain: SetServiceStatus returned error"
));
}
EXIT:
return
;
}
VOID
WINAPI ServiceCtrlHandler(
DWORD
Ctrl)
{
switch
(Ctrl)
{
case
SERVICE_CONTROL_STOP:
case
SERVICE_CONTROL_SHUTDOWN:
if
(g_ServiceStatus.dwCurrentState != SERVICE_RUNNING)
break
;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 4;
if
(!SetServiceStatus(g_StatusHandle, &g_ServiceStatus))
{
OutputDebugString(_T(
"MySampleService: ServiceCtrlHandler: SetServiceStatus returned error"
));
}
// This will signal the worker thread to start shutting down
SetEvent(g_hStopEvent);
break
;
default
:
break
;
}
}
DWORD
WINAPI ServiceWorkerThread(
LPVOID
lpParam)
{
// 主服务逻辑在此实现
// 这是一个示例,每10秒检查一次停止事件
while
(WaitForSingleObject(g_hStopEvent, 10000) != WAIT_OBJECT_0)
{
// 实现服务的核心功能
OutputDebugString(_T(
"MySampleService: Doing stuff..."
));
}
return
ERROR_SUCCESS;
}
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
SERVICE_STATUS g_ServiceStatus = { 0 };
SERVICE_STATUS_HANDLE
g_StatusHandle = NULL;
HANDLE
g_hStopEvent = NULL;
VOID
WINAPI ServiceMain(
DWORD
argc,
LPTSTR
* argv);
VOID
WINAPI ServiceCtrlHandler(
DWORD
);
DWORD
WINAPI ServiceWorkerThread(
LPVOID
lpParam);
#define SERVICE_NAME _T("SampleService")
int
main(
int
argc,
char
* argv[])
{
SERVICE_TABLE_ENTRY DispatchTable[] =
{
{ (
LPWSTR
)SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain },
{ NULL, NULL }
};
if
(!StartServiceCtrlDispatcher(DispatchTable))
{
return
GetLastError();
}
return
0;
}
VOID
WINAPI ServiceMain(
DWORD
argc,
LPTSTR
* argv)
{
DWORD
Status = E_FAIL;
HANDLE
hThread = INVALID_HANDLE_VALUE;
// Register our service control handler with the SCM
g_StatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler);
if
(g_StatusHandle == NULL)
{
goto
EXIT;
}
// Tell the service controller we are starting
ZeroMemory(&g_ServiceStatus,
sizeof
(g_ServiceStatus));
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwServiceSpecificExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
if
(!SetServiceStatus(g_StatusHandle, &g_ServiceStatus))
{
OutputDebugString(_T(
"MySampleService: ServiceMain: SetServiceStatus returned error"
));
}
// Create stop event to wait on later
g_hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if
(g_hStopEvent == NULL)
{
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = GetLastError();
g_ServiceStatus.dwCheckPoint = 1;
if
(!SetServiceStatus(g_StatusHandle, &g_ServiceStatus))
{
OutputDebugString(_T(
"MySampleService: ServiceMain: SetServiceStatus returned error"
));
}
goto
EXIT;
}
// Tell the service controller we are started
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
if
(!SetServiceStatus(g_StatusHandle, &g_ServiceStatus))
{
OutputDebugString(_T(
"MySampleService: ServiceMain: SetServiceStatus returned error"
));
}
// Start the thread that will perform the main task of the service
hThread = CreateThread(NULL, 0, ServiceWorkerThread, NULL, 0, NULL);
if
(hThread == NULL)
{
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = GetLastError();
g_ServiceStatus.dwCheckPoint = 1;
if
(!SetServiceStatus(g_StatusHandle, &g_ServiceStatus))
{
OutputDebugString(_T(
"MySampleService: ServiceMain: SetServiceStatus returned error"
));
}
goto
EXIT;
}
// Wait until our worker thread exits effectively signaling that the service needs to stop
WaitForSingleObject(hThread, INFINITE);
// Cleanup
CloseHandle(hThread);
CloseHandle(g_hStopEvent);
// Tell the service controller we are stopped
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 3;
if
(!SetServiceStatus(g_StatusHandle, &g_ServiceStatus))
{
OutputDebugString(_T(
"MySampleService: ServiceMain: SetServiceStatus returned error"
));
}
EXIT:
return
;
}
VOID
WINAPI ServiceCtrlHandler(
DWORD
Ctrl)
{
switch
(Ctrl)
{
case
SERVICE_CONTROL_STOP:
case
SERVICE_CONTROL_SHUTDOWN:
if
(g_ServiceStatus.dwCurrentState != SERVICE_RUNNING)
break
;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 4;
if
(!SetServiceStatus(g_StatusHandle, &g_ServiceStatus))
{
OutputDebugString(_T(
"MySampleService: ServiceCtrlHandler: SetServiceStatus returned error"
));
}
// This will signal the worker thread to start shutting down
SetEvent(g_hStopEvent);
break
;
default
:
break
;
}
}
DWORD
WINAPI ServiceWorkerThread(
LPVOID
lpParam)
{
// 主服务逻辑在此实现
// 这是一个示例,每10秒检查一次停止事件
while
(WaitForSingleObject(g_hStopEvent, 10000) != WAIT_OBJECT_0)
{
// 实现服务的核心功能
OutputDebugString(_T(
"MySampleService: Doing stuff..."
));
}
return
ERROR_SUCCESS;
}
_FX
SC_HANDLE
Scm_CreateServiceW(
SC_HANDLE
hSCManager,
WCHAR
*lpServiceName,
WCHAR
*lpDisplayName,
ULONG
dwDesiredAccess,
ULONG
dwServiceType,
ULONG
dwStartType,
ULONG
dwErrorControl,
WCHAR
*lpBinaryPathName,
WCHAR
*lpLoadOrderGroup,
WCHAR
*lpdwTagId,
WCHAR
*lpDependencies,
WCHAR
*lpServiceStartName,
WCHAR
*lpPassword)
{
NTSTATUS status;
SC_HANDLE
hService;
HANDLE
hkey;
UNICODE_STRING uni;
WCHAR
*name;
//
// verify the service does not exist (also verifies hSCManager,
// and that the service name is not NULL)
//
// 检查服务是否已经存在,沙盒中的hSCManager必须是HANDLE_SERVICE_MANAGER
hService = Scm_OpenServiceWImpl(
hSCManager, lpServiceName, SERVICE_QUERY_STATUS);
if
(hService) {
Scm_CloseServiceHandleImpl(hService);
SetLastError(ERROR_SERVICE_EXISTS);
return
NULL;
}
if
(GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
return
NULL;
//
// create a key for the new service
//
// 设置服务注册表内容,注册表位置HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lpServiceName
hkey = Scm_OpenKeyForService(lpServiceName, TRUE);
if
(! hkey) {
// SetLastError already called
return
NULL;
}
// Type => SERVICE_WIN32_OWN_PROCESS
RtlInitUnicodeString(&uni, L
"Type"
);
status = NtSetValueKey(
hkey, &uni, 0, REG_DWORD, &dwServiceType,
sizeof
(
ULONG
));
if
(! NT_SUCCESS(status))
goto
abort
;
// Start => auto
RtlInitUnicodeString(&uni, L
"Start"
);
status = NtSetValueKey(
hkey, &uni, 0, REG_DWORD, &dwStartType,
sizeof
(
ULONG
));
if
(! NT_SUCCESS(status))
goto
abort
;
// ErrorControl => 1,
RtlInitUnicodeString(&uni, L
"ErrorControl"
);
status = NtSetValueKey(
hkey, &uni, 0, REG_DWORD, &dwErrorControl,
sizeof
(
ULONG
));
if
(! NT_SUCCESS(status))
goto
abort
;
if
(lpDisplayName) {
// Service Test
RtlInitUnicodeString(&uni, L
"DisplayName"
);
status = NtSetValueKey(
hkey, &uni, 0, REG_SZ, lpDisplayName,
(wcslen(lpDisplayName) + 1) *
sizeof
(
WCHAR
));
if
(! NT_SUCCESS(status))
goto
abort
;
}
if
(lpBinaryPathName) {
// 可执行文件的路径 => D:\test\service_test_exe.exe
RtlInitUnicodeString(&uni, L
"ImagePath"
);
status = NtSetValueKey(
hkey, &uni, 0, REG_SZ, lpBinaryPathName,
(wcslen(lpBinaryPathName) + 1) *
sizeof
(
WCHAR
));
if
(! NT_SUCCESS(status))
goto
abort
;
}
if
(lpServiceStartName) {
RtlInitUnicodeString(&uni, L
"ObjectName"
);
status = NtSetValueKey(
hkey, &uni, 0, REG_SZ, lpServiceStartName,
(wcslen(lpServiceStartName) + 1) *
sizeof
(
WCHAR
));
if
(! NT_SUCCESS(status))
goto
abort
;
}
//
// add the service to SbieSvc list of sandboxed services
//
// 标记服务是一个沙盒化服务,将lpServiceName添加到HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SbieSvc的SandboxedServices中
status = Scm_AddBoxedService(lpServiceName);
if
(! NT_SUCCESS(status))
goto
abort
;
NtClose(hkey);
//
// allocate a 'handle' that points to the service name
//
name = Dll_Alloc(
sizeof
(
ULONG
) + (wcslen(lpServiceName) + 1) *
sizeof
(
WCHAR
));
*(
ULONG
*)name = tzuk;
wcscpy((
WCHAR
*)(((
ULONG
*)name) + 1), lpServiceName);
_wcslwr(name);
SetLastError(0);
return
(
SC_HANDLE
)name;
//
// failure: delete the key for the new service
//
abort
:
NtDeleteKey(hkey);
NtClose(hkey);
SetLastError(ERROR_INVALID_PARAMETER);
return
NULL;
}
_FX
SC_HANDLE
Scm_CreateServiceW(
SC_HANDLE
hSCManager,
WCHAR
*lpServiceName,
WCHAR
*lpDisplayName,
ULONG
dwDesiredAccess,
ULONG
dwServiceType,
ULONG
dwStartType,
ULONG
dwErrorControl,
WCHAR
*lpBinaryPathName,
WCHAR
*lpLoadOrderGroup,
WCHAR
*lpdwTagId,
WCHAR
*lpDependencies,
WCHAR
*lpServiceStartName,
WCHAR
*lpPassword)
{
NTSTATUS status;
SC_HANDLE
hService;
HANDLE
hkey;
UNICODE_STRING uni;
WCHAR
*name;
//
// verify the service does not exist (also verifies hSCManager,
// and that the service name is not NULL)
//
// 检查服务是否已经存在,沙盒中的hSCManager必须是HANDLE_SERVICE_MANAGER
hService = Scm_OpenServiceWImpl(
hSCManager, lpServiceName, SERVICE_QUERY_STATUS);
if
(hService) {
Scm_CloseServiceHandleImpl(hService);
SetLastError(ERROR_SERVICE_EXISTS);
return
NULL;
}
if
(GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
return
NULL;
//
// create a key for the new service
//
// 设置服务注册表内容,注册表位置HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lpServiceName
hkey = Scm_OpenKeyForService(lpServiceName, TRUE);
if
(! hkey) {
// SetLastError already called
return
NULL;
}
// Type => SERVICE_WIN32_OWN_PROCESS
RtlInitUnicodeString(&uni, L
"Type"
);
status = NtSetValueKey(
hkey, &uni, 0, REG_DWORD, &dwServiceType,
sizeof
(
ULONG
));
if
(! NT_SUCCESS(status))
goto
abort
;
// Start => auto
RtlInitUnicodeString(&uni, L
"Start"
);
status = NtSetValueKey(
hkey, &uni, 0, REG_DWORD, &dwStartType,
sizeof
(
ULONG
));
if
(! NT_SUCCESS(status))
goto
abort
;
// ErrorControl => 1,
RtlInitUnicodeString(&uni, L
"ErrorControl"
);
status = NtSetValueKey(
hkey, &uni, 0, REG_DWORD, &dwErrorControl,
sizeof
(
ULONG
));
if
(! NT_SUCCESS(status))
goto
abort
;
if
(lpDisplayName) {
// Service Test
RtlInitUnicodeString(&uni, L
"DisplayName"
);
status = NtSetValueKey(
hkey, &uni, 0, REG_SZ, lpDisplayName,
(wcslen(lpDisplayName) + 1) *
sizeof
(
WCHAR
));
if
(! NT_SUCCESS(status))
goto
abort
;
}
if
(lpBinaryPathName) {
// 可执行文件的路径 => D:\test\service_test_exe.exe
RtlInitUnicodeString(&uni, L
"ImagePath"
);
status = NtSetValueKey(
hkey, &uni, 0, REG_SZ, lpBinaryPathName,
(wcslen(lpBinaryPathName) + 1) *
sizeof
(
WCHAR
));
if
(! NT_SUCCESS(status))
goto
abort
;
}
if
(lpServiceStartName) {
RtlInitUnicodeString(&uni, L
"ObjectName"
);
status = NtSetValueKey(
hkey, &uni, 0, REG_SZ, lpServiceStartName,
(wcslen(lpServiceStartName) + 1) *
sizeof
(
WCHAR
));
if
(! NT_SUCCESS(status))
goto
abort
;
}
//
// add the service to SbieSvc list of sandboxed services
//
// 标记服务是一个沙盒化服务,将lpServiceName添加到HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SbieSvc的SandboxedServices中
status = Scm_AddBoxedService(lpServiceName);
if
(! NT_SUCCESS(status))
goto
abort
;
NtClose(hkey);
//
// allocate a 'handle' that points to the service name
//
name = Dll_Alloc(
sizeof
(
ULONG
) + (wcslen(lpServiceName) + 1) *
sizeof
(
WCHAR
));
*(
ULONG
*)name = tzuk;
wcscpy((
WCHAR
*)(((
ULONG
*)name) + 1), lpServiceName);
_wcslwr(name);
SetLastError(0);
return
(
SC_HANDLE
)name;
//
// failure: delete the key for the new service
//
abort
:
NtDeleteKey(hkey);
NtClose(hkey);
SetLastError(ERROR_INVALID_PARAMETER);
return
NULL;
}
_FX
SC_HANDLE
Scm_OpenServiceWImpl(
SC_HANDLE
hSCManager,
const
WCHAR
*lpServiceName,
DWORD
dwDesiredAccess)
{
WCHAR
*name;
BOOLEAN
ok = FALSE;
if
(hSCManager != HANDLE_SERVICE_MANAGER) {
SetLastError(ERROR_INVALID_HANDLE);
return
(
SC_HANDLE
)0;
}
if
((! lpServiceName) || (! *lpServiceName)) {
SetLastError(ERROR_INVALID_PARAMETER);
return
(
SC_HANDLE
)0;
}
//
// open the service if we know its name, first check in the sandbox,
// and if not found, outside the sandbox
//
Scm_DiscardKeyCache(lpServiceName);
if
(Scm_IsBoxedService(lpServiceName)) {
// 调用NtCreateKey 或 NtOpenKey打开对应的服务
HANDLE
hkey = Scm_OpenKeyForService(lpServiceName, FALSE);
if
(hkey) {
NtClose(hkey);
ok = TRUE;
}
}
else
{
// 调用SbieDll_CallServer向SbieSvc服务发送MSGID_SERVICE_QUERY类型请求
SERVICE_QUERY_RPL *rpl = (SERVICE_QUERY_RPL *)
Scm_QueryServiceByName(lpServiceName, FALSE, FALSE);
if
(rpl) {
Dll_Free(rpl);
ok = TRUE;
}
}
if
(! ok) {
// either Scm_OpenKeyForService or Scm_QueryServiceByName
// has already called SetLastError
return
(
SC_HANDLE
)0;
}
//
// allocate a 'handle' that points to the service name
//
name = Dll_Alloc(
sizeof
(
ULONG
) + (wcslen(lpServiceName) + 1) *
sizeof
(
WCHAR
));
*(
ULONG
*)name = tzuk;
wcscpy((
WCHAR
*)(((
ULONG
*)name) + 1), lpServiceName);
_wcslwr(name);
SetLastError(0);
return
(
SC_HANDLE
)name;
}
_FX
SC_HANDLE
Scm_OpenServiceWImpl(
SC_HANDLE
hSCManager,
const
WCHAR
*lpServiceName,
DWORD
dwDesiredAccess)
{
WCHAR
*name;
BOOLEAN
ok = FALSE;
if
(hSCManager != HANDLE_SERVICE_MANAGER) {
SetLastError(ERROR_INVALID_HANDLE);
return
(
SC_HANDLE
)0;
}
if
((! lpServiceName) || (! *lpServiceName)) {
SetLastError(ERROR_INVALID_PARAMETER);
return
(
SC_HANDLE
)0;
}
//
// open the service if we know its name, first check in the sandbox,
// and if not found, outside the sandbox
//
Scm_DiscardKeyCache(lpServiceName);
if
(Scm_IsBoxedService(lpServiceName)) {
// 调用NtCreateKey 或 NtOpenKey打开对应的服务
HANDLE
hkey = Scm_OpenKeyForService(lpServiceName, FALSE);
if
(hkey) {
NtClose(hkey);
ok = TRUE;
}
}
else
{
// 调用SbieDll_CallServer向SbieSvc服务发送MSGID_SERVICE_QUERY类型请求
SERVICE_QUERY_RPL *rpl = (SERVICE_QUERY_RPL *)
Scm_QueryServiceByName(lpServiceName, FALSE, FALSE);
if
(rpl) {
Dll_Free(rpl);
ok = TRUE;
}
}
if
(! ok) {
// either Scm_OpenKeyForService or Scm_QueryServiceByName
// has already called SetLastError
return
(
SC_HANDLE
)0;
}
//
// allocate a 'handle' that points to the service name
//
name = Dll_Alloc(
sizeof
(
ULONG
) + (wcslen(lpServiceName) + 1) *
sizeof
(
WCHAR
));
*(
ULONG
*)name = tzuk;
wcscpy((
WCHAR
*)(((
ULONG
*)name) + 1), lpServiceName);
_wcslwr(name);
SetLastError(0);
return
(
SC_HANDLE
)name;
}
_FX
BOOL
Scm_CloseServiceHandleImpl(
SC_HANDLE
hSCObject)
{
BOOL
ok = FALSE;
// 关闭Scm_OpenSCManagerW返回的结果HANDLE_SERVICE_MANAGER
if
(hSCObject == HANDLE_SERVICE_MANAGER)
ok = TRUE;
else
if
(Scm_GetHandleName(hSCObject)) {
// 删除Scm_Notify_Global中和hSCObject相关的element,和NotifyServiceStatusChange函数相关
Scm_Notify_CloseHandle(hSCObject);
Dll_Free(hSCObject);
ok = TRUE;
}
if
(ok)
SetLastError(0);
else
SetLastError(ERROR_INVALID_HANDLE);
return
ok;
}
_FX
BOOL
Scm_CloseServiceHandleImpl(
SC_HANDLE
hSCObject)
{
BOOL
ok = FALSE;
// 关闭Scm_OpenSCManagerW返回的结果HANDLE_SERVICE_MANAGER
if
(hSCObject == HANDLE_SERVICE_MANAGER)
ok = TRUE;
else
if
(Scm_GetHandleName(hSCObject)) {
// 删除Scm_Notify_Global中和hSCObject相关的element,和NotifyServiceStatusChange函数相关
Scm_Notify_CloseHandle(hSCObject);
Dll_Free(hSCObject);
ok = TRUE;
}
if
(ok)
SetLastError(0);
else
SetLastError(ERROR_INVALID_HANDLE);
return
ok;
}
_FX
BOOL
SbieDll_StartBoxedService(
const
WCHAR
*ServiceName,
BOOLEAN
WithAdd)
// WithAdd = False
{
HANDLE
hkey;
SERVICE_STATUS ss;
SERVICE_QUERY_RPL *rpl;
ULONG
retries, error;
WCHAR
text[130];
Sbie_snwprintf(text, 130, L
"StartBoxedService; name: '%s'"
, ServiceName);
SbieApi_MonitorPutMsg(MONITOR_SCM, text);
//
// when invoked from SandboxieRpcSs to handle StartProcess,
// specify WithAdd to add the service to the sandbox
//
if
(WithAdd)
Scm_AddBoxedService(ServiceName);
//
// get service parameters and check that the service can be started
//
rpl = Scm_QueryBoxedServiceByName(ServiceName, TRUE, -1);
if
(! rpl)
return
FALSE;
// 服务处于RUNNING状态,无需启动
if
(rpl->service_status.dwCurrentState != SERVICE_STOPPED &&
rpl->service_status.dwCurrentState != SERVICE_START_PENDING) {
Dll_Free(rpl);
SetLastError(ERROR_SERVICE_ALREADY_RUNNING);
return
FALSE;
}
// 启动的服务是个驱动,无法启动,报错。
if
(rpl->service_status.dwServiceType & SERVICE_DRIVER) {
SbieApi_Log(2103, L
"%S [%S] (StartService)"
, ServiceName, Dll_BoxName);
Dll_Free(rpl);
SetLastError(ERROR_ACCESS_DENIED);
return
FALSE;
}
// 如果启动的服务不是一个exe或dll,暂时不支持,报错。
if
(! (rpl->service_status.dwServiceType & SERVICE_WIN32)) {
Dll_Free(rpl);
SetLastError(ERROR_SERVICE_LOGON_FAILED);
return
FALSE;
}
//
// set service status - start pending
//
hkey = Scm_OpenKeyForService(ServiceName, TRUE);
if
(! hkey) {
error = GetLastError();
Dll_Free(rpl);
SetLastError(error);
return
FALSE;
}
//
// indicate the service is initializing
//
memzero(&ss,
sizeof
(SERVICE_STATUS));
ss.dwCurrentState = SERVICE_START_PENDING;
ss.dwControlsAccepted = SERVICE_ACCEPT_STOP;
ss.dwWaitHint = 5000;
// 设置该服务的状态,其实就是设置注册表键对应的值
Scm_SetServiceStatus_Internal(
hkey, HANDLE_SERVICE_STATUS, &ss, FALSE);
CloseHandle(hkey);
//
// launch the service
//
error = Scm_StartBoxedService2(ServiceName, rpl);
Dll_Free(rpl);
//
// wait for the service to indicate it has started
//
if
(! error) {
error = ERROR_SERVICE_LOGON_FAILED;
for
(retries = 0; retries < 40; ++retries) {
Sleep(500);
rpl = Scm_QueryBoxedServiceByName(ServiceName, TRUE, 0);
if
(! rpl)
return
FALSE;
// 查看服务是否启动成功
if
(rpl->service_status.dwCurrentState == SERVICE_RUNNING) {
error = 0;
break
;
}
Dll_Free(rpl);
}
}
......
SetLastError(0);
return
TRUE;
}
_FX
BOOL
SbieDll_StartBoxedService(
const
WCHAR
*ServiceName,
BOOLEAN
WithAdd)
// WithAdd = False
{
HANDLE
hkey;
SERVICE_STATUS ss;
SERVICE_QUERY_RPL *rpl;
ULONG
retries, error;
WCHAR
text[130];
Sbie_snwprintf(text, 130, L
"StartBoxedService; name: '%s'"
, ServiceName);
SbieApi_MonitorPutMsg(MONITOR_SCM, text);
//
// when invoked from SandboxieRpcSs to handle StartProcess,
// specify WithAdd to add the service to the sandbox
//
if
(WithAdd)
Scm_AddBoxedService(ServiceName);
//
// get service parameters and check that the service can be started
//
rpl = Scm_QueryBoxedServiceByName(ServiceName, TRUE, -1);
if
(! rpl)
return
FALSE;
// 服务处于RUNNING状态,无需启动
if
(rpl->service_status.dwCurrentState != SERVICE_STOPPED &&
rpl->service_status.dwCurrentState != SERVICE_START_PENDING) {
Dll_Free(rpl);
SetLastError(ERROR_SERVICE_ALREADY_RUNNING);
return
FALSE;
}
// 启动的服务是个驱动,无法启动,报错。
if
(rpl->service_status.dwServiceType & SERVICE_DRIVER) {
SbieApi_Log(2103, L
"%S [%S] (StartService)"
, ServiceName, Dll_BoxName);
Dll_Free(rpl);
SetLastError(ERROR_ACCESS_DENIED);
return
FALSE;
}
// 如果启动的服务不是一个exe或dll,暂时不支持,报错。
if
(! (rpl->service_status.dwServiceType & SERVICE_WIN32)) {
Dll_Free(rpl);
SetLastError(ERROR_SERVICE_LOGON_FAILED);
return
FALSE;
}
//
// set service status - start pending
//
hkey = Scm_OpenKeyForService(ServiceName, TRUE);
if
(! hkey) {
error = GetLastError();
Dll_Free(rpl);
SetLastError(error);
return
FALSE;
}
//
// indicate the service is initializing
//
memzero(&ss,
sizeof
(SERVICE_STATUS));
ss.dwCurrentState = SERVICE_START_PENDING;
ss.dwControlsAccepted = SERVICE_ACCEPT_STOP;
ss.dwWaitHint = 5000;
// 设置该服务的状态,其实就是设置注册表键对应的值
Scm_SetServiceStatus_Internal(
hkey, HANDLE_SERVICE_STATUS, &ss, FALSE);
CloseHandle(hkey);
//
// launch the service
//
error = Scm_StartBoxedService2(ServiceName, rpl);
Dll_Free(rpl);
//
// wait for the service to indicate it has started
//
if
(! error) {
error = ERROR_SERVICE_LOGON_FAILED;
for
(retries = 0; retries < 40; ++retries) {
Sleep(500);
rpl = Scm_QueryBoxedServiceByName(ServiceName, TRUE, 0);
if
(! rpl)
return
FALSE;
// 查看服务是否启动成功
if
(rpl->service_status.dwCurrentState == SERVICE_RUNNING) {
error = 0;
break
;
}
Dll_Free(rpl);
}
}
......
SetLastError(0);
return
TRUE;
}
_FX
ULONG
Scm_StartBoxedService2(
const
WCHAR
*name, SERVICE_QUERY_RPL *qrpl)
{
SERVICE_RUN_REQ *req;
MSG_HEADER *rpl;
ULONG
error, path_len, req_len;
WCHAR
*path;
BOOL
free_path;
//
// special handling for Sandboxie services:
// either run directly (for SandboxieCrypto)
// or build a path to the Sandboxie executable
//
free_path = FALSE;
// _bits -> 后台智能传输服务,_wuauserv -> Windows更新服务,Scm_CryptSvc -> 加密服务
// 这三个特殊服务特殊处理
if
(_wcsicmp(name, _bits) == 0 ||
_wcsicmp(name, _wuauserv) == 0 ||
_wcsicmp(name, Scm_CryptSvc) == 0) {
//PROCESS_INFORMATION pi;
STARTUPINFO si;
const
WCHAR
*ProcessName;
//BOOLEAN use_sbiesvc = TRUE;
if
(_wcsicmp(name, _bits) == 0) {
ProcessName = SandboxieBITS;
Scm_DeletePermissions(L
"69AD4AEE-51BE-439B-A92C-86AE490E8B30"
);
}
else
if
(_wcsicmp(name, _wuauserv) == 0) {
ProcessName = SandboxieWUAU;
Scm_DeletePermissions(L
"653C5148-4DCE-4905-9CFD-1B23662D3D9E"
);
}
else
if
(_wcsicmp(name, Scm_CryptSvc) == 0) {
ProcessName = SandboxieCrypto;
//use_sbiesvc = FALSE;
}
else
ProcessName = NULL;
si.lpReserved = NULL;
if
(SbieDll_RunFromHome(ProcessName, NULL, &si, NULL)) {
path = (
WCHAR
*)si.lpReserved;
if
(path)
free_path = TRUE;
}
}
if
(! free_path) {
path = Scm_GetServiceConfigString(qrpl,
'P'
);
}
//
// otherwise start service through SbieSvc
//
path_len = (wcslen(path) + 1) *
sizeof
(
WCHAR
);
req_len =
sizeof
(SERVICE_RUN_REQ) + path_len;
req = Dll_Alloc(req_len);
req->h.length = req_len;
req->h.msgid = MSGID_SERVICE_RUN;
req->type = qrpl->service_status.dwServiceType;
if
(_wcsicmp(name, L
"McAfee SiteAdvisor Service"
) == 0) {
//
// the McAfee SiteAdvisor Service is a WIN32_SHARE_PROCESS service
// when it is part of the Total Protection suite, so we need to
// make sure it will always be treated as SERVICE_WIN32_OWN_PROCESS
//
req->type = SERVICE_WIN32_OWN_PROCESS;
}
wcsncpy(req->name, name, 64);
req->name[63] = L
'\0'
;
req->devmap[0] = L
'\0'
;
File_GetSetDeviceMap(req->devmap);
req->path_len = path_len;
memcpy
(req->path, path, path_len);
// 向SbieSvc发送MSGID_SERVICE_RUN请求,创建进程
rpl = (MSG_HEADER *)SbieDll_CallServer(&req->h);
if
(! rpl)
error = ERROR_NOT_ENOUGH_MEMORY;
else
{
error = rpl->status;
Dll_Free(rpl);
}
//
// finish
//
if
(free_path)
HeapFree(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, path);
return
error;
}
_FX
ULONG
Scm_StartBoxedService2(
const
WCHAR
*name, SERVICE_QUERY_RPL *qrpl)
{
SERVICE_RUN_REQ *req;
MSG_HEADER *rpl;
ULONG
error, path_len, req_len;
WCHAR
*path;
BOOL
free_path;
//
// special handling for Sandboxie services:
// either run directly (for SandboxieCrypto)
// or build a path to the Sandboxie executable
//
free_path = FALSE;
// _bits -> 后台智能传输服务,_wuauserv -> Windows更新服务,Scm_CryptSvc -> 加密服务
// 这三个特殊服务特殊处理
if
(_wcsicmp(name, _bits) == 0 ||
_wcsicmp(name, _wuauserv) == 0 ||
_wcsicmp(name, Scm_CryptSvc) == 0) {
//PROCESS_INFORMATION pi;
STARTUPINFO si;
const
WCHAR
*ProcessName;
//BOOLEAN use_sbiesvc = TRUE;
if
(_wcsicmp(name, _bits) == 0) {
ProcessName = SandboxieBITS;
Scm_DeletePermissions(L
"69AD4AEE-51BE-439B-A92C-86AE490E8B30"
);
}
else
if
(_wcsicmp(name, _wuauserv) == 0) {
ProcessName = SandboxieWUAU;
Scm_DeletePermissions(L
"653C5148-4DCE-4905-9CFD-1B23662D3D9E"
);
}
else
if
(_wcsicmp(name, Scm_CryptSvc) == 0) {
ProcessName = SandboxieCrypto;
//use_sbiesvc = FALSE;
}
else
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课