草庐IT

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

coder 2023-11-09 原文

我目前正在研究如何实现一个沙箱(类似于 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/

有关windows - 在 Windows 64 位上实现带有自定义堆栈的沙箱的更多相关文章

  1. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  2. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  3. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

  4. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  5. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  6. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  7. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

  8. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  9. ruby - 定义方法参数的条件 - 2

    我有一个只接受一个参数的方法:defmy_method(number)end如果使用number调用方法,我该如何引发错误??通常,我如何定义方法参数的条件?比如我想在调用的时候报错:my_method(1) 最佳答案 您可以添加guard在函数的开头,如果参数无效则引发异常。例如:defmy_method(number)failArgumentError,"Inputshouldbegreaterthanorequalto2"ifnumbereputse.messageend#=>Inputshouldbegreaterthano

  10. ruby - 如何在 Grape 中定义哈希数组? - 2

    我使用Ember作为我的前端和GrapeAPI来为我的API提供服务。前端发送类似:{"service"=>{"name"=>"Name","duration"=>"30","user"=>nil,"organization"=>"org","category"=>nil,"description"=>"description","disabled"=>true,"color"=>nil,"availabilities"=>[{"day"=>"Saturday","enabled"=>false,"timeSlots"=>[{"startAt"=>"09:00AM","endAt"=>

随机推荐