m3t*_*n0b 19 windows assembly exception-handling x86-64 sandbox
我目前正在研究如何实现一个沙盒(类似于谷歌的NaCl项目),在那里我可以运行不受信任的x86代码(受限制的指令集),这样它就不会损害我的其余进程.
与NaCl不同,不受信任的代码不会在单独的进程中运行,而是与主机应用程序运行相同的进程.因此,一个关键步骤是使Windows的结构化异常处理正确,以便捕获错误(如无效的内存访问或div为0),并在Windows杀死我的主机应用程序之前正常终止沙箱.(NaCl不会遇到这些问题.沙箱是一个单独的过程,如果出现错误就会被杀死.)
此外,沙盒代码不应使用宿主应用程序堆栈,而是在我自己分配的某个单独的"堆栈"上运行.
正是这种组合(存在自定义分配堆栈时的异常处理)扭曲了我的想法.我已经检查了Go和Factor的语言实现,它们做了类似的事情并且通过这个帮助得到了一些运行.
但仍有一些悬而未决的问题和不确定因素.所以我想我会利用Stack Overflow的神奇知识来获得一些意见:-)
以下是一个工作代码片段,内容涉及核心问题:
code.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);
}
Run Code Online (Sandbox Code Playgroud)
code.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
Run Code Online (Sandbox Code Playgroud)
运行它将打印"GEH FEH",然后正常退出代码42.
有没有人对这套StackBase & StackEnd"黑客" 有更深入的了解?我试图将堆栈限制缩小到:
mov gs:[008h], rsp
mov gs:[010h], rax ; rax is the address returned by malloc
Run Code Online (Sandbox Code Playgroud)
但它不起作用.它打印"GEH"然后由于未处理的异常而崩溃.
FrameExceptionHandler()将永远不会被执行.
我还尝试了更宽松的边界,包括"堆分配堆栈"以及Windows分配的堆栈.但它没有帮助.
另一个问题是,你是否知道我可能遇到的其他陷阱.例如,我注意到如果RSP不均匀,Windows不喜欢它(我想因为你不能通过在16字节对齐的堆栈指针上执行2/4/8字节的PUSH和POP来获得不均匀的RSP).
谢谢,乔纳斯
小智 0
您想要执行代码并检查其有效性。您可以使用自己的沙箱来完成此操作。请参阅 x86 处理器的虚拟盒实现。它可以提供帮助。但所有虚拟机都有价格:模拟处理器运行底层代码的速度比您的应用程序慢 5-10 倍。
如果您只需要错误检查并在核心CPU上运行应用程序,那么您需要在线程中运行它。当线程挂起时,应用程序保持不变。您可以向线程注入一些代码以查找其执行。但这种情况不太安全,因为恶意代码可能会破坏您的检查例程并利用它对您的系统进行后门/root。
所以,我的答案是:为了安全 - 使用你自己的虚拟机,为了速度 - 在另一个线程中执行。
最好的问候,祝你好运弗拉基米尔
| 归档时间: |
|
| 查看次数: |
922 次 |
| 最近记录: |