一、沙箱限制主要是依赖windows提供的四个保护机制:
1、一个限制令牌
2、Windows 作业对象
更多参考:SetInformationJobObject 函数 (jobapi2.h) - Win32 apps | Microsoft Learn
3、Windows desktop对象
4、限于Vista:完整性级别 (xp以下无)
实现原理更多参考官网介绍:
https://chromium.googlesource.com/chromium/src/+/HEAD/docs/design/sandbox.md
沙箱主要是依赖hook方式实现:
二、沙箱作用主要是为了限制新创建子进程权限,具体如下:
1、token和IntegrityLevel,
2、作业(JobLevel) ,
3、环境变量 (Environment),
4、Files 【hook文件操作】,
5、Named pipes【hook 命令管道,mojom消息使用命名管道实现】,
6、 Process creation 【进程创建】
7、Registry【hook注册表操作】 ,
8、Synchronization objects 【同步对象等】
三、沙箱启动子进程过程分析:
核心逻辑在sandbox\win\src\broker_services.cc
BrokerServicesBase::SpawnTarget()函数里
1、设置tokenlevel:
policy_base->MakeTokens(initial_token, lockdown_token);
2、更新桌面Integrity
result = UpdateDesktopIntegrity(config_base->desktop(),config_base->integrity_level());
3、初始化作业限制
result = policy_base->InitJob(); //限制或禁用访问剪切板桌面等等资源。
【sandbox\win\src\sandbox_policy_base.cc】
4、将以上初始化的token 桌面 job 环境变量信息存储到StartupInformationHelper对象里面。
5、调用TargetProcess::Create
6、在TargetProcess::Create 函数里面会判定是否需要环境变量过滤
if (startup_info_helper->IsEnvironmentFiltered()) {wchar_t* old_environment = ::GetEnvironmentStringsW();if (!old_environment) {return SBOX_ERROR_CANNOT_OBTAIN_ENVIRONMENT;}// Only copy a limited list of variables to the target from the broker's// environment. These are// * "Path", "SystemDrive", "SystemRoot", "TEMP", "TMP": Needed for normal// operation and tests.// * "LOCALAPPDATA": Needed for App Container processes.// * "CHROME_CRASHPAD_PIPE_NAME": Needed for crashpad.static constexpr std::wstring_view to_keep[] = {L"Path",L"SystemDrive",L"SystemRoot",L"TEMP",L"TMP",L"LOCALAPPDATA",L"CHROME_CRASHPAD_PIPE_NAME"};new_env = FilterEnvironment(old_environment, to_keep);::FreeEnvironmentStringsW(old_environment);}
7、最后根据StartupInformationHelper信息 调用CreateProcessAsUserW创建子进程。
bool inherit_handles = startup_info_helper->ShouldInheritHandles();PROCESS_INFORMATION temp_process_info = {};if (!::CreateProcessAsUserW(lockdown_token_.get(), exe_path, cmd_line.get(),nullptr, // No security attribute.nullptr, // No thread attribute.inherit_handles, flags,new_env.empty() ? nullptr : std::data(new_env),nullptr, // Use current directory of the caller.startup_info->startup_info(),&temp_process_info)) {*win_error = ::GetLastError();return SBOX_ERROR_CREATE_PROCESS;}
附
CreateProcessAsUserW函数定义:
BOOL CreateProcessAsUserW([in, optional] HANDLE hToken,[in, optional] LPCWSTR lpApplicationName,[in, out, optional] LPWSTR lpCommandLine,[in, optional] LPSECURITY_ATTRIBUTES lpProcessAttributes,[in, optional] LPSECURITY_ATTRIBUTES lpThreadAttributes,[in] BOOL bInheritHandles,[in] DWORD dwCreationFlags,[in, optional] LPVOID lpEnvironment,[in, optional] LPCWSTR lpCurrentDirectory,[in] LPSTARTUPINFOW lpStartupInfo,[out] LPPROCESS_INFORMATION lpProcessInformation
);
CreateProcessAsUserW 函数 (processthreadsapi.h) - Win32 apps | Microsoft Learn
四:概念介绍:
以下信息可以用procexp64.exe进行查看
1、integrity level
// List of all the integrity levels supported in the sandbox.
// The integrity level of the sandboxed process can't be set to a level higher
// than the broker process.
//
// Note: These levels map to SIDs under the hood.
// INTEGRITY_LEVEL_SYSTEM: "S-1-16-16384" System Mandatory Level
// INTEGRITY_LEVEL_HIGH: "S-1-16-12288" High Mandatory Level
// INTEGRITY_LEVEL_MEDIUM: "S-1-16-8192" Medium Mandatory Level
// INTEGRITY_LEVEL_MEDIUM_LOW: "S-1-16-6144"
// INTEGRITY_LEVEL_LOW: "S-1-16-4096" Low Mandatory Level
// INTEGRITY_LEVEL_BELOW_LOW: "S-1-16-2048"
// INTEGRITY_LEVEL_UNTRUSTED: "S-1-16-0" Untrusted Mandatory Level
//
// Not defined: "S-1-16-20480" Protected Process Mandatory Level
// Not defined: "S-1-16-28672" Secure Process Mandatory Level
enum IntegrityLevel {INTEGRITY_LEVEL_SYSTEM,INTEGRITY_LEVEL_HIGH,INTEGRITY_LEVEL_MEDIUM,INTEGRITY_LEVEL_MEDIUM_LOW,INTEGRITY_LEVEL_LOW,INTEGRITY_LEVEL_BELOW_LOW,INTEGRITY_LEVEL_UNTRUSTED,INTEGRITY_LEVEL_LAST
};
对应如图:
2、Token level
// The Token level specifies a set of security profiles designed to
// provide the bulk of the security of sandbox.
//
// TokenLevel |Restricting |Deny Only |Privileges|
// |Sids |Sids | |
// ----------------------------|--------------|----------------|----------|
// USER_LOCKDOWN | Null Sid | All | None |
// ----------------------------|--------------|----------------|----------|
// USER_LIMITED | Users | All except: | Traverse |
// | Everyone | Users | |
// | RESTRICTED | Everyone | |
// | | Interactive | |
// ----------------------------|--------------|----------------|----------|
// USER_INTERACTIVE | Users | All except: | Traverse |
// | Everyone | Users | |
// | RESTRICTED | Everyone | |
// | Owner | Interactive | |
// | | Local | |
// | | Authent-users | |
// | | User | |
// ----------------------------|--------------|----------------|----------|
// USER_RESTRICTED_NON_ADMIN | Users | All except: | Traverse |
// | Everyone | Users | |
// | Interactive | Everyone | |
// | Local | Interactive | |
// | Authent-users| Local | |
// | User | Authent-users | |
// | | User | |
// ----------------------------|--------------|----------------|----------|
// USER_RESTRICTED_SAME_ACCESS | All | None | All |
// ----------------------------|--------------|----------------|----------|
// USER_UNPROTECTED | None | None | All |
// ----------------------------|--------------|----------------|----------|
//
// The above restrictions are actually a transformation that is applied to
// the existing broker process token. The resulting token that will be
// applied to the target process depends both on the token level selected
// and on the broker token itself.
//
// The LOCKDOWN level is designed to allow access to almost nothing that has
// security associated with and they are the recommended levels to run sandboxed
// code specially if there is a chance that the broker is process might be
// started by a user that belongs to the Admins or power users groups.
enum TokenLevel {USER_LOCKDOWN = 0,USER_LIMITED,USER_INTERACTIVE,USER_RESTRICTED_NON_ADMIN,USER_RESTRICTED_SAME_ACCESS,USER_UNPROTECTED,USER_LAST
};
对应如图:
3、 Job level
// The Job level specifies a set of decreasing security profiles for the
// Job object that the target process will be placed into.
// This table summarizes the security associated with each level:
//
// JobLevel |General |Quota |
// |restrictions |restrictions |
// -----------------|---------------------------------- |--------------------|
// kUnprotected | None | *Kill on Job close.|
// -----------------|---------------------------------- |--------------------|
// kInteractive | *Forbid system-wide changes using | |
// | SystemParametersInfo(). | *Kill on Job close.|
// | *Forbid the creation/switch of | |
// | Desktops. | |
// | *Forbids calls to ExitWindows(). | |
// -----------------|---------------------------------- |--------------------|
// kLimitedUser | Same as kInteractive plus: | *One active process|
// | *Forbid changes to the display | limit. |
// | settings. | *Kill on Job close.|
// -----------------|---------------------------------- |--------------------|
// kLockdown | Same as kLimitedUser plus: | *One active process|
// | * No read/write to the clipboard. | limit. |
// | * No access to User Handles that | *Kill on Job close.|
// | belong to other processes. | *Kill on unhandled |
// | * Forbid message broadcasts. | exception. |
// | * Forbid setting global hooks. | |
// | * No access to the global atoms | |
// | table. | |
// -----------------|-----------------------------------|--------------------|
//
// In the context of the above table, 'user handles' refers to the handles of
// windows, bitmaps, menus, etc. Files, treads and registry handles are kernel
// handles and are not affected by the job level settings.
enum class JobLevel { kLockdown = 0, kLimitedUser, kInteractive, kUnprotected };
对应如图:
4、Environment【环境变量】
五、总结:
其实最核心的就是利用CreateProcessAsUserW函数 指定用户token, 桌面, 环境变量和job,然后来限制子进程的权限。