gpt4 book ai didi

windows - 在 Windows 64 位上实现带有自定义堆栈的沙箱

转载 作者:可可西里 更新时间:2023-11-01 12:17:53 25 4
gpt4 key购买 nike

我目前正在研究如何实现一个沙箱(类似于 Google's NaCl project),我可以在其中运行不受信任的 x86 代码(受限指令集),而不会损害我的其余进程。

与 NaCl 不同,不受信任的代码不会在单独的进程中运行,而是在与主机应用程序相同的进程中运行。因此,一个关键步骤是让 Windows 的结构化异常处理正确,以便捕获错误(如无效内存访问或 div by 0)并在 Windows 杀死我的主机应用程序之前优雅地终止沙箱。 (NaCl 不会面临这些问题。沙箱是一个单独的进程,一旦出现错误就会被杀死。)

此外,沙盒代码不应使用主机应用程序堆栈,而应在我自己分配的一些单独的“堆栈”上运行。

正是这种组合(存在自定义分配堆栈的异常处理)让我感到困惑。我检查了 Go 的语言实现和 Factor它做类似的事情,并在这种帮助下运行了一些东西。

但仍然存在一些悬而未决的问题和不确定性。所以我想我会利用 Stack Overflow 的奇妙知识来获得一些意见 :-)

以下是针对核心问题的工作代码片段:

代码.cpp

#include <Windows.h>
extern "C" void Sandbox();

// just a low level helper to print "msg"
extern "C" void Write(const char* msg)
{
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),
msg, (DWORD)strlen(msg), NULL, NULL);
}

// should be called first on error and continue exception handling
LONG __stdcall GlobalExceptionHandler(_EXCEPTION_POINTERS*)
{
Write("GEH ");
return EXCEPTION_CONTINUE_SEARCH;
}

// should be called afterwards on error and terminate the process
// of course this is just a stub to simplify the issue
// in real world it would just terminate the sandbox
extern "C" EXCEPTION_DISPOSITION __stdcall FrameExceptionHandler(
PEXCEPTION_RECORD, ULONG64, PCONTEXT, PVOID)
{
Write("FEH ");
ExitProcess(42);
}

void main()
{
AddVectoredExceptionHandler(1, GlobalExceptionHandler);
Sandbox();
// never reach this...
ExitProcess(23);
}

代码.asm

EXTERN FrameExceptionHandler:PROC
EXTERN malloc:PROC

.code

Handler:
jmp FrameExceptionHandler

Sandbox PROC FRAME : Handler
; function prologue compliant with Windows x86_64 calling conventions
; saves rsp to the "frame-pointer" r15
push r15
.PUSHREG r15
sub rsp, 20h
.ALLOCSTACK(20h)
mov r15, rsp
.SETFRAME r15, 0h
.ENDPROLOG

; set rsp to the top of a "heap allocated stack" of size 0x10000 bytes
mov rcx, 10000h
call malloc
lea rsp, [rax+10000h]

; got this from implementation of the Go language runtime:
; while unwinding the stack, Windows sanity checks the values of
; RSP to be within stack-bounds. Of course RSP is set to our
; "heap allocated stack" and not within the bounds of what Windows
; thinks should be the stack.
; Fix this by adjusting StackBase and StackEnd in the TIB (thread
; information block), so that basically the stack is unbounded:
; StackBase = 0xffffffffffffffff, StackEnd = 0x0000000000000000
mov rcx, 0FFFFFFFFFFFFFFFFh
mov gs:[008h], rcx
mov rcx, 0
mov gs:[010h], rcx


; trigger an access error by reading invalid memory
mov rax, 0DEADBEEFh
mov rax, [rax]

; function epilogue - will never get here
mov rax, 0
add rsp, 28h
ret
Sandbox ENDP

end

运行此命令将打印“GEH FEH”,然后以代码 42 正常退出。

有没有人对这组 StackBase & StackEnd “hack”有更深入的了解?我试图将堆栈限制缩小到类似的范围:

    mov gs:[008h], rsp
mov gs:[010h], rax ; rax is the address returned by malloc

但它不起作用。它打印“GEH”,然后由于未处理的异常而崩溃。FrameExceptionHandler() 永远不会被执行。

我还尝试了更宽松的边界,包括“堆分配堆栈”以及 Windows 分配的堆栈。但这没有帮助。

另一个问题是,您是否知道我可能遇到的任何其他陷阱。例如,我注意到 Windows 不喜欢 RSP 不均匀(我猜是因为您永远无法通过在 16 字节对齐的堆栈指针上执行 2/4/8 字节 PUSH 和 POP 来获得不均匀的 RSP)。

谢谢,乔纳斯

最佳答案

在同一进程中运行不受信任的第 3 方代码是自找麻烦。该代码可以通过多种方式终止您的进程。例如。它可以在失败时调用 exit(),请求大量内存,或写入线程分配的内存。

更安全但不那么困难的解决方案是在不同的进程中运行此代码,类似于 Chrome 所做的。每个 Chrome 扩展程序都在不同的进程中运行,并且数据在进程之间传递。

您的应用程序可以启动一个单独的进程并通过管道、Windows 消息、共享内存(内存映射文件)共享大数据等与其通信。

插件(通常)实现一个接口(interface),因此您需要编写一个代理对象来抽象插件驻留在另一个进程中的事实,并隐藏多进程应用程序带来的 IPC 复杂性。 gSoap就是这样一个框架,还有其他的。

关于windows - 在 Windows 64 位上实现带有自定义堆栈的沙箱,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14244667/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com