sandboxie没有生态,除了大佬多数和我一样是新手。
开源后业余时间断续学习,啃别人代码,理解他人思路属实不易,源码笔记有点乱序,后经过整理才有这篇文章,分享学习过程中遇到问题和思路。
本篇文章并不是轻量级沙盘实现原理,关注者可以直接略过该文。
共37页,部分内容可能不严谨,但是会随着学习的深入不断完善和改正错误。
预计分为4篇:
1. 进程篇
2. 监控篇
3. toB(正在研究的阶段)
4. 原理机制Ps:多少参杂了一些逆向,LPC通信Handler处理用windbg附加SbieSvc服务,利用Start.exe挂调试,IDA定位分析/源码辅助学习,调试过程有些问题拿捏不准,感谢前辈的帮助。
SandBoxie循序渐进耳(进程篇)
关于沙箱,工作之外断断续续学习走过不少坑,去年部署Cuckoo用来个人学习优化Monitor。也尝试过开发轻量级沙盘,逆向Sandboxie连皮毛都没学到,幸好今年SandBoxie开源给学习者带来了更多的思路。
作者推荐了代码审计重点,个人喜欢从界面开始熟悉,交互是响应各功能模块第一步,相对比较友好,较快的理解软件流程的来龙去脉。
推荐一个活跃的sandboxie生态论坛分支,也许你会找到想要的答案:
https://www.wilderssecurity.com/forums/sandboxing-virtualization.98/
1. 如果系统已有wdk7600环境,vs2015配置7600,请参考下述文章:
https://www.cnblogs.com/iBinary/p/8290595.html
2. 解决error LNK2001: 无法解析的外部符号 _memcmp/_wcsnicmp等被引用原因:这个过程浪费了大量的业余时间,引入各类函数lib无济于事,修复skd环境,大量的obj报错最终参考msdn文档解决,在Sandboxie的论坛上也发现了解决方案。
https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features?view=vs-2019
https://community.sophos.com/products/sandboxie/f/forum/119641/important-sandboxie-open-source-code-is-available-for-download
3. 解决MinFilter编译被引用,属性-->链接器-->输入-->附加依赖项目:fltMgr.lib
4. 编译成功,不错的开端(vs2017同样编译成功,v141)。
这个步骤该阶段不太重要,不影响源码学习。Install/ReadMe按照步骤来做,NSIS已经更新到了v3,按照步骤安装和替换文件。Sandbox.sln同级目录下创建tools/iconv,解压拷贝,这些工作一次性便适用,不需要重复工。
DavidXanatos推出了SandBoxie-Plush,使用了QT,如果不加入其它操作系统分析引擎(可移植),Win下面向界面便捷开发更倾向于使用Libuidk实现(基于MFC商用框架已开源-国外人可能也不知道),容易重构。
https://github.com/sandboxie-plus/Sandboxie
可以下载发行版Sandboxie安装到主机,如果熟悉MFC这将是好的开端,能快速定位代码,控件响应和功能模块,代码重在理解和应用,汲取自己需要的知识。
创建沙盘(r3)
Create New SandBox找到对应的类
1. 输入沙盘名称做规则检测,如下所示:
// 1. 长度小于等于32 if (len <= 32) { // 2. 字符串是否合规 for (; i < len; ++i) { if (name[i] >= L'0' && name[i] <= L'9') continue; if (name[i] >= L'A' && name[i] <= L'Z') continue; if (name[i] >= L'a' && name[i] <= L'z') continue; if (name[i] == L'_') continue; break; } } // 3. 如果违规失败 if (i == 0 || i != len) errmsg = MSG_3667;
2.调用SbieApi_IsBoxEnabled()判断沙盘名称是否已创建,发送API_SBIEDRV_CTLCODEDLL查询,封装了两个重要的参数:
1. API_IS_BOX_ENABLED(Driver API Codes)
2. Name_Address
3. Drv驱动 --> api.c(370行开始),对分发进行校验和处理:
3. 校验API_SBIEDRV_CTLCODEDLL
4. 分发api,回调查询code-->API_IS_BOX_ENABLED
__try { ProbeForRead( buf, sizeof(ULONG64) * API_NUM_ARGS, sizeof(ULONG64)); // 1. 拷贝r3传递过来的数据user_args memzero(user_args, sizeof(ULONG64) * API_NUM_ARGS); memcpy(user_args, buf, buf_len); func_code = (ULONG)user_args[0]; // 2. 这里对DerviceCode做校验 if (func_code > API_FIRST && func_code < API_LAST) // 3. 获取功能函数指针 func_ptr = Api_Functions[func_code - API_FIRST - 1]; if (func_ptr) { // 4. 返回执行状态 status = func_ptr(proc, user_args); } else status = STATUS_INVALID_DEVICE_REQUEST; } __except (EXCEPTION_EXECUTE_HANDLER) {
Api_functions通过SetFunction初始化(conf_user.c-->106行),初始化分发函数.
Api_SetFunction(API_IS_BOX_ENABLED, Conf_Api_IsBoxEnabled)回调函数处理,如果不存在添加到链中,返回状态码标识是否成功,详细请见代码。
1. 选中沙盘点击运行,也可以直接拖到Dlg中,如下所示:
2. 思路有很多种,最简单直接的办法搜索函数,这里拖拽文件响应使用OnDropFiles,该工程也只有这一处拖拽使用,如下所示:
void CMyFrame::OnDropFiles(HDROP hDrop) { WCHAR path[512]; // 1. 响应拖拽消息 if (! DragQueryFile(hDrop, 0, path, sizeof(path) / sizeof(WCHAR) - 1)) path[0] = L'\0'; if (path[0]) { CString QuotedPath = L"\"" + CString(path) + L"\""; // 2. 进入处理函数 CMyApp::RunStartExe(QuotedPath, CString()); } } void CMyApp::RunStartExe( const CString &cmd, const CString &box, BOOL wait, BOOL inherit) { // 3. 再次封装调用 Common_RunStartExe(cmd, box, wait, inherit); }
3. 沙盘如何将可执行文件加载,这是一个漫长的过程,RunStartExe.cpp --> 35行Common_RunStartExe,如下所示:
//--------------------------------------------------------------------------- // Common_RunStartExe //--------------------------------------------------------------------------- // 1. 拼接指令 "/box:__ask__ fileName wcscpy(cmdline, L"/box:"); if (box.IsEmpty()) wcscat(cmdline, L"__ask__"); else wcscat(cmdline, box); wcscat(cmdline, L" "); wcscat(cmdline, cmd); // 2. 重点:SbieDll_RunFromHome Start.exe加载执行文件 if (! SbieDll_RunFromHome(START_EXE, cmdline, &si, &pi));
4. SbieDll_RunFromHome被定义在了proc.c进程模块,最终会通过CreateProcessW来启动文件,如下所示:
// 1. 拼接执行命令格式 if (si->lpReserved) { inherit = TRUE; si->lpReserved = NULL; } else inherit = FALSE; if (si->dwXCountChars == tzuk && si->dwYCountChars == tzuk) { creation_flags = ABOVE_NORMAL_PRIORITY_CLASS; si->dwXCountChars = si->dwYCountChars = 0; } else creation_flags = 0; memzero(pi, sizeof(PROCESS_INFORMATION)); // 2. 创建进程 ok = CreateProcess(NULL, path, NULL, NULL, inherit, creation_flags, NULL, NULL, si, pi)
参数:"E:\Program Files\Sandboxie\Start.exe" /box:__ask__ "C:\Users\Administrator\Downloads\powershell.txt"
5. Start.exe,可以选择x64跟踪,也可以选择参数带入源码,解析格式box和_,查询进程信息,box:__ask__,如下所示:
if (_wcsnicmp(cmd, L"box:", 4) == 0) { if (*tmp == L'-' && (! SbieApi_QueryProcessInfo( (HANDLE)(ULONG_PTR)GetCurrentProcessId(), 0))) {
针对一些指令会进行处理,Parse_Command_Line()返回执行文件路径。
Validate_Box_Name选择使用沙盘,代码如下:
if (! disable_force_on_this_program) { // 1. 判断标识 if (_wcsicmp(BoxName, L"__ask__") == 0 || _wcsicmp(BoxName, L"current") == 0) { if (auto_select_default_box) { wcscpy(BoxName, L"DefaultBox"); if (SbieApi_IsBoxEnabled(BoxName) != STATUS_SUCCESS) auto_select_default_box = FALSE; } if (! auto_select_default_box) // 2. DoBoxDialog选择使用沙盘,记录沙盘名称 wcscpy(BoxName, DoBoxDialog()); if (! BoxName[0]) { if (disable_force_on_this_program) { // might be set by DoBoxDialog return FALSE; } return die(EXIT_FAILURE); } } // 3. 判断沙盘是否开启,获取当前状态 if (SbieApi_IsBoxEnabled(BoxName) != STATUS_SUCCESS) { if (run_silent) ExitProcess(ERROR_UNKNOWN_PROPERTY); SetLastError(0); Show_Error(SbieDll_FormatMessage1(MSG_3204, BoxName)); return die(EXIT_FAILURE); } }
6. 通过return die(RestartInSandbox())完成进程启动,RestartInSandbox函数:
dir = (WCHAR *)MyHeapAlloc(1024 * sizeof(WCHAR)); GetCurrentDirectory(1020, dir); cmd = (WCHAR *)MyHeapAlloc(16384 * sizeof(WCHAR)); cmd[0] = L'\"'; GetModuleFileName(NULL, cmd + 1, MAX_PATH); ptr = cmd + wcslen(cmd); wcscpy(ptr, L"\" /env:00000000_" SBIE L"_CURRENT_DIRECTORY=\""); wcscat(ptr, dir); wcscat(ptr, L"\" /env:=Refresh "); ptr += wcslen(ptr); if (run_elevated_2) { wcscpy(ptr, L"/elevate "); ptr = cmd + wcslen(cmd); } if (wait_for_process) { wcscpy(ptr, L"/wait "); ptr = cmd + wcslen(cmd); } wcscpy(ptr, ChildCmdLine);
7. 调用Callsvc.c(dll模块)处理req,req结构体下文会介绍,数据如下:
rpl = ( PROCESS_RUN_SANDBOXED_RPL *)SbieDll_CallServer(&req->h);
SandBoxie-LPC通信
LPC参考:https://bbs.pediy.com/thread-144492.htm
8. 本地通信模块需要熟悉LPC,推荐如下:
https://bbs.pediy.com/thread-144492.htm
https://bbs.pediy.com/thread-162365.htm
Client-Server调试方式,每个人都有自己的学习习惯,文章使用的第二种方式:
1. vs执行start源码,vs执行SbieSvc源码,编译好全部工程,输出目录同一个文件夹下,安装驱动,然后进行调试。(未尝试,理论可行)
2. vs执行start源码,windbg附加SbieSvc服务,IDA+源码辅助学习。
Client:
SbieDll_RunSandboxed()
负责tagPROCESS_RUN_SANDBOXED_REQ结构数据填充,前8bit数据MSG_HEADER结构体。
// msgid是0x1205,沙盘运行进程 req->h.msgid = MSGID_PROCESS_RUN_SANDBOXED; wcscpy(req->boxname, box_name); req->si_flags = si->dwFlags; req->si_show_window = si->wShowWindow; req->creation_flags = creation_flags; ptr = (WCHAR *)((ULONG_PTR)req + sizeof(PROCESS_RUN_SANDBOXED_REQ)); // 拷贝执行的命令 req->cmd_ofs = (ULONG)((ULONG_PTR)ptr - (ULONG_PTR)req); req->cmd_len = cmd_len; if (cmd_len) { wmemcpy(ptr, cmd, cmd_len); ptr += cmd_len; } *ptr = L'\0'; ++ptr; // 拷贝dir req->dir_ofs = (ULONG)((ULONG_PTR)ptr - (ULONG_PTR)req); req->dir_len = dir_len; if (dir_len) { wmemcpy(ptr, dir, dir_len); ptr += dir_len; } *ptr = L'\0'; ++ptr; // 拷贝环境变量(字符巨多) req->env_ofs = (ULONG)((ULONG_PTR)ptr - (ULONG_PTR)req); req->env_len = env_len; if (env_len) { wmemcpy(ptr, env, env_len); ptr += env_len; } rpl = (PROCESS_RUN_SANDBOXED_RPL *)SbieDll_CallServer(&req->h);
tagPROCESS_RUN_SANDBOXED_REQ结构,后面尾随的是消息块包括执行cmd和dir,env环境,内存数据如下所示:
SbieDll_CallServer()
负责将客户端结构数据分发至服务端处理。
_FX MSG_HEADER *SbieDll_CallServer(MSG_HEADER *req) { static volatile ULONG last_sequence = 0; UCHAR curr_sequence; THREAD_DATA *data = Dll_GetTlsData(NULL); UCHAR spaceReq[MAX_PORTMSG_LENGTH], spaceRpl[MAX_PORTMSG_LENGTH]; NTSTATUS status; PORT_MESSAGE *msg; UCHAR *buf, *msg_data; ULONG buf_len, send_len; MSG_HEADER *rpl; if (! data->PortHandle) { BOOLEAN Silent = (req->msgid == MSGID_SBIE_INI_GET_VERSION || req->msgid == MSGID_SBIE_INI_GET_USER || req->msgid == MSGID_PROCESS_CHECK_INIT_COMPLETE); // 1. 连接\\RPC Control\\SbieSvcPort if (! SbieDll_ConnectPort(Silent)) return NULL; } // 连接成功,循环Dispatch curr_sequence = (UCHAR) InterlockedIncrement(&last_sequence); buf = (UCHAR *)req; buf_len = req->length; while (buf_len) { msg = (PORT_MESSAGE *)spaceReq; memzero(msg, data->SizeofPortMsg); msg_data = (UCHAR *)msg + data->SizeofPortMsg; if (buf_len > data->MaxDataLen) send_len = data->MaxDataLen; else send_len = buf_len; msg->u1.s1.DataLength = (USHORT)send_len; msg->u1.s1.TotalLength = (USHORT)(data->SizeofPortMsg + send_len); memcpy(msg_data, buf, send_len); if (buf == (UCHAR *)req) { msg_data[3] = curr_sequence; } buf += send_len; buf_len -= send_len; // 发送至server,等待回复 status = NtRequestWaitReplyPort(data->PortHandle, (PORT_MESSAGE *)spaceReq, (PORT_MESSAGE *)spaceRpl); if (! NT_SUCCESS(status)) break; msg = (PORT_MESSAGE *)spaceRpl; if (buf_len && msg->u1.s1.DataLength) { SbieApi_Log(2203, L"early reply"); return NULL; } }
Service:
Sandboxie客户端循环发送MSG消息到服Svc.Pipserver.cpp(SbieSvcPort),服务端由NtReplyWaitReceivePort循环等待客户端数据,源码中封装如下:
NtReplyWaitReceivePort():
void PipeServer::Thread() { NTSTATUS status; UCHAR space[MAX_PORTMSG_LENGTH], spaceReply[MAX_PORTMSG_LENGTH]; PORT_MESSAGE *msg = (PORT_MESSAGE *)space; HANDLE hReplyPort; PORT_MESSAGE *ReplyMsg; hReplyPort = m_hServerPort; ReplyMsg = NULL; while (1) { if (ReplyMsg) { memcpy(spaceReply, ReplyMsg, ReplyMsg->u1.s1.TotalLength); ReplyMsg = (PORT_MESSAGE *)spaceReply; } status = NtReplyWaitReceivePort(hReplyPort, NULL, ReplyMsg, msg); if (! m_hServerPort) // service is shutting down break; if (ReplyMsg) { hReplyPort = m_hServerPort; ReplyMsg = NULL; if (! NT_SUCCESS(status)) continue; // ignore errors on client port } else if (! NT_SUCCESS(status)) { if (status == STATUS_UNSUCCESSFUL) { // can be considered a warning rather than an error continue; } break; // abort on errors on server port } if (msg->u2.s2.Type == LPC_CONNECTION_REQUEST) { PortConnect(msg); } else if (msg->u2.s2.Type == LPC_REQUEST) { // 查找客户端client CLIENT_THREAD *client = (CLIENT_THREAD *)PortFindClient(msg); if (! client) continue; if (! client->replying) PortRequest(client->hPort, msg, client); msg->u2.ZeroInit = 0; if (client->replying) PortReply(msg, client); else { msg->u1.s1.DataLength = (USHORT) 0; msg->u1.s1.TotalLength = sizeof(PORT_MESSAGE); } hReplyPort = client->hPort; ReplyMsg = msg; client->in_use = FALSE; } else if (msg->u2.s2.Type == LPC_PORT_CLOSED || msg->u2.s2.Type == LPC_CLIENT_DIED) { PortDisconnect(msg); } } }
构造PORT_MESSAGE数据包,data->MaxDataLen数值是288bit,TotalLength总大小是328bit,包含结构体本身大小,LPC传输超过256bit进行内存共享传输。
msg = (PORT_MESSAGE *)spaceReq; memzero(msg, data->SizeofPortMsg); msg_data = (UCHAR *)msg + data->SizeofPortMsg; if (buf_len > data->MaxDataLen) send_len = data->MaxDataLen; else send_len = buf_len; msg->u1.s1.DataLength = (USHORT)send_len; msg->u1.s1.TotalLength = (USHORT)(data->SizeofPortMsg + send_len); memcpy(msg_data, buf, send_len); ....... // buf_len <= 0时候意味着客户端传输完成 buf += send_len; buf_len -= send_len;
windbg下断SbieSvc.exe-->NtReplyWaitReceivePort,客户端发送MSG至服务端消息队列,也可以直接审计源码,如下所示:
Sbiesvc.exe拖入ida,定位代码段:
LPC处理LPC_CONNECTION_REQUEST,LPC_REQUEST,LPC_PORT_CLOSED,LPC_CLIENT_DIED类型。
客户端client->replying标志,客户端在循环传输过程中调用PortRequest。
if (! client->replying) PortRequest(client->hPort, msg, client);
PortRequest():
if (! client->buf_hdr) { ULONG *msg_Data = (ULONG *)msg->Data; ULONG msgid = msg_Data[1]; client->sequence = ((UCHAR *)msg_Data)[3]; ((UCHAR *)msg_Data)[3] = 0; buf_len = msg_Data[0]; if (msgid && buf_len && buf_len < MAX_REQUEST_LENGTH && buf_len >= sizeof(MSG_HEADER) && buf_len >= msg->u1.s1.DataLength) { // 申请内存 client->buf_hdr = AllocMsg(buf_len);
client->buf_ptr = (UCHAR *)client->buf_hdr; } if (! client->buf_hdr) { client->sequence = 0; goto finish; } // 拷贝客户端发来的消息 memcpy(client->buf_ptr, msg->Data, msg->u1.s1.DataLength); client->buf_ptr += msg->u1.s1.DataLength; buf_len += msg->u1.s1.DataLength; // MSG_HEADER msgid client->buf_hdr = (MSG_HEADER *)buf_ptr; client->buf_ptr = (UCHAR *)buf_ptr client->replying = TRUE; // 判断是否接收数据完毕 if (buf_len < client->buf_hdr->length) return; // 接收完毕,LPC handler功能分发处理 buf_ptr = CallTarget(client->buf_hdr, PortHandle, msg);
CallTarget():
负责LPC Handler函数分发,LPC Handler根据Msgid执行功能函数。
定位分发函数,断点0x1205观察,通过搜索定位函数代码,如下所示:
*ProcessServer::Handler()
IDA-Windbg对比源码无误,下断g运行,如下所示:
运行后会触发LPC回调分发,MSGID_PROCESS_RUN_SANDBOXED调用号断下1205,ProcessServer.cpp(line:428),启动新进程主模块。
*ProcessServer::RunSandboxedHandler()
MSG_HEADER *ProcessServer::RunSandboxedHandler(MSG_HEADER *msg)
获取cmd,dir,env数据
WCHAR *cmd = RunSandboxedCopyString(&req->h, req->cmd_ofs, req->cmd_len); WCHAR *dir = RunSandboxedCopyString(&req->h, req->dir_ofs, req->dir_len); WCHAR *env = RunSandboxedCopyString(&req->h, req->env_ofs, req->env_len);
*cmd参数如下:
如果调用方是沙盒,pid号将确定API_START_PROCESS调用的BoxNameOrModel Pid参数,如果是沙箱外部的呼叫者则指定了一个框名。
SbieApi_QueryProcessInfo()
复制和初始化,调用Ioctl来进行数据初始化
__declspec(align(8)) ULONG64 ResultValue; __declspec(align(8)) ULONG64 parms[API_NUM_ARGS]; API_QUERY_PROCESS_INFO_ARGS *args = (API_QUERY_PROCESS_INFO_ARGS *)parms; memzero(parms, sizeof(parms)); args->func_code = API_QUERY_PROCESS_INFO; args->process_id.val64 = (ULONG64)(ULONG_PTR)ProcessId; args->info_type.val64 = (ULONG64)(ULONG_PTR)info_type; args->info_data.val64 = (ULONG64)(ULONG_PTR)&ResultValue;
SbieApi_Ioctl()
1. 初始化 "\\Device\\" SANDBOXIE L"DriverApi"对象
2. NtOpenFile-->DriverApi
3. 发送API_SBIEDRV_CTLCODE控制码
RunSandboxedGetToken()
如果指定了SYSTEM/THREAD权限,将会对应的权限处理
ok = OpenProcessToken( CallerProcessHandle, TOKEN_RIGHTS, &OldTokenHandle);
打开权限,建一个新的访问主令牌来复制一个已经存在的标记
ok = DuplicateTokenEx(OldTokenHandle, TOKEN_RIGHTS, NULL, SecurityIdentification, TokenPrimary, &NewTokenHandle);
获取SessionId会话,设置
ULONG SessionId = PipeServer::GetCallerSessionId(); ok = SetTokenInformation(NewTokenHandle, TokenSessionId, &SessionId, sizeof(ULONG));
通知驱动程序并启动新进程,然后将句柄复制:
if (RunSandboxedStartProcess( PrimaryTokenHandle, BoxNameOrModelPid, CallerPid, cmd, dir, env, &req->creation_flags, &si, &pi)) { if (RunSandboxedDupAndCloseHandles( CallerProcessHandle, req->creation_flags, &pi, &piReply)) { err = 0; lvl = 0; } else { err = GetLastError(); lvl = 0x55; } } else { err = GetLastError(); lvl = 0x44; }
RunSandboxedStartProcess():
设置相关的会话权限和si结构体拷贝,利用CreateProCessAsUser启动特定的子进程
// create new process ok = CreateProcessAsUser( PrimaryTokenHandle, NULL, cmd, NULL, NULL, FALSE, crflags2, env, dir, si, pi);
如果启动成功,需要通知驱动,明确进程pid
LONG rc = SbieApi_CallTwo(API_START_PROCESS, BoxNameOrModelPid, pi->dwProcessId);
执行RunSandBoxedStartProcess之后并非直接进程启动,还需要历经一些分发函数处理.
Msgid = Rax = 0x1e01 = MSGID_QUEUE_CREATE *QueueServer::Handler() *QueueServer::CreateHandler()
请求检测是否再沙盘内,如果成功查找请求对象。
QUEUE_OBJ *QueueObj = (QUEUE_OBJ *)FindQueueObj(QueueName); if (QueueObj) { status = STATUS_OBJECT_NAME_COLLISION; goto finish; }
获取进程时间相关信息。
PortReply():
负责拷贝Msg消息,代码如下所示:
msg->u2.ZeroInit = 0; if (client->replying) PortReply(msg, client); else { msg->u1.s1.DataLength = (USHORT) 0; msg->u1.s1.TotalLength = sizeof(PORT_MESSAGE); }
PortDisconnect():
关闭释放连接
NotifyTargets():
这部分笔记只是一些msgid调用记录通信完成后关闭,回调处理一些msgid=xxff的消息,windbg调用流程简单梳理了一下关闭连接后调用的回调函数顺序如下。
TARGET *target = (TARGET *)List_Head(&m_targets); while (target) { msg.msgid = target->serverId | 0xFF; (*target->handler)(target->context, &msg); target = (TARGET *)List_Next(target); }
*ProcessServer::Handler()
第一次循环IRP Handler进入到Handler函数,msgids.h定义消息宏如下:
eax = 0x12ff,Handler函数没有对该消息号有处理,线性执行代码返回。
#define MSGID_PROCESS 0x1200 #define MSGID_PROCESS_CHECK_INIT_COMPLETE 0x1201 #define MSGID_PROCESS_GET_WORK_DEPRECATED 0x1202 #define MSGID_PROCESS_KILL_ONE 0x1203 #define MSGID_PROCESS_KILL_ALL 0x1204 #define MSGID_PROCESS_RUN_SANDBOXED 0x1205 #define MSGID_PROCESS_SET_DEVICE_MAP 0x1206 #define MSGID_PROCESS_OPEN_DEVICE_MAP 0x1207
*SbieIniServer::Handler()
第二次循环eax =0x18ff,进入到SbieIniServer回调中,Windbg偏移+IDA定位对比源码无误,如下所示:
SbieIniServer *pThis = (SbieIniServer *)_this; EnterCriticalSection(&pThis->m_critsec); pThis->m_text = NULL; pThis->m_text_base = NULL; pThis->m_text_max_len = 0; pThis->m_insertbom = FALSE; // 内部调用Handler2,用来请求判断,处理获取数据和验证参数。 MSG_HEADER *rpl = pThis->Handler2(msg);
同样eax=0x18ff不在Handler处理范围之内,线性执行,回到主循环。
if (pThis->m_text) HeapFree(GetProcessHeap(), 0, pThis->m_text_base); pThis->m_text = NULL; pThis->m_text_base = NULL; pThis->m_text_max_len = 0; LeaveCriticalSection(&pThis->m_critsec);
*ServiceServer::Handler()
处理宏消息如下:
#define MSGID_SERVICE 0x1300
#define MSGID_SERVICE_START 0x1301
#define MSGID_SERVICE_QUERY 0x1302
#define MSGID_SERVICE_LIST 0x1303
#define MSGID_SERVICE_RUN 0x1304
#define MSGID_SERVICE_UAC 0x1305
Eax= 0x13ff,仍然只是进入了ServiceServer回调,调用了TlsGetValue()函数,不做宏处理分发,用到时候再来分析该函数。
*PStoreServer::Handler()
Eax=0x11ff,不做分发处理
*TerminalServer::Handler()
#define MSGID_TERMINAL 0x1400 #define MSGID_TERMINAL_QUERY_INFO 0x1411 #define MSGID_TERMINAL_CHECK_TYPE 0x1412 #define MSGID_TERMINAL_GET_NAME 0x1413 #define MSGID_TERMINAL_GET_PROPERTY 0x1414 #define MSGID_TERMINAL_DISCONNECT 0x1415
Eax= 0x14ff,不做分发处理.
*NamedPipeServer::Handler()
#define MSGID_NAMED_PIPE 0x1500 #define MSGID_NAMED_PIPE_OPEN 0x1501 #define MSGID_NAMED_PIPE_CLOSE 0x1502 #define MSGID_NAMED_PIPE_SET 0x1503 #define MSGID_NAMED_PIPE_READ 0x1504 #define MSGID_NAMED_PIPE_WRITE 0x1505 #define MSGID_NAMED_PIPE_LPC_CONNECT 0x1506 #define MSGID_NAMED_PIPE_LPC_REQUEST 0x1507 #define MSGID_NAMED_PIPE_ALPC_REQUEST 0x1508 #define MSGID_NAMED_PIPE_NOTIFICATION 0x15FF
Eax= 15ff,分发处理
NamedPipeServer *pThis = (NamedPipeServer *)_this; HANDLE idProcess = (HANDLE)(ULONG_PTR)PipeServer::GetCallerProcessId(); if (msg->msgid == MSGID_NAMED_PIPE_NOTIFICATION) { pThis->NotifyHandler(idProcess); return NULL; }
*FileServer::Handler()
#define MSGID_FILE 0x1700 #define MSGID_FILE_SET_ATTRIBUTES 0x1701 #define MSGID_FILE_SET_SHORT_NAME 0x1702 #define MSGID_FILE_LOAD_KEY 0x1703 #define MSGID_FILE_GET_ALL_HANDLES 0x1704 #define MSGID_FILE_IMPERSONATION_REQUESTS 0x1780 #define MSGID_FILE_SET_REPARSE_POINT 0x1781 #define MSGID_FILE_OPEN_WOW64_KEY 0x1782 #define MSGID_FILE_CHECK_KEY_EXISTS 0x1783 FileServer *pThis = (FileServer *)_this; HANDLE idProcess = (HANDLE)(ULONG_PTR)PipeServer::GetCallerProcessId(); if (0 != SbieApi_QueryProcess(idProcess, NULL, NULL, NULL, NULL)) return SHORT_REPLY(STATUS_ACCESS_DENIED); SbieApi_QueryProcess(){ return SbieApi_QueryProcessEx2( ProcessId, 96, out_box_name_wchar34, out_image_name_wchar96, out_sid_wchar96, out_session_id, NULL); }
SbieApi_QueryProcessEx2负责参数的校验和数据配置
NTSTATUS status; // 定义结构 __declspec(align(8)) UNICODE_STRING64 BoxName; __declspec(align(8)) UNICODE_STRING64 ImageName; __declspec(align(8)) UNICODE_STRING64 SidString; __declspec(align(8)) ULONG64 parms[API_NUM_ARGS]; API_QUERY_PROCESS_ARGS *args = (API_QUERY_PROCESS_ARGS *)parms; memzero(parms, sizeof(parms)); args->func_code = API_QUERY_PROCESS;
args->process_id.val64 = (ULONG64)(ULONG_PTR)ProcessId;
status = SbieApi_Ioctl(parms);重置参数设置。
*ComServer::Handler()
Eax= 0x1bff,分发处理:
ComServer *pThis = (ComServer *)_this; HANDLE idProcess = (HANDLE)(ULONG_PTR)PipeServer::GetCallerProcessId(); if (msg->msgid == MSGID_COM_NOTIFICATION) { pThis->NotifyAllSlaves(idProcess); return NULL; } NotifyAllSlaves()函数用于创建一个线程发送同通知 ULONG64 *ThreadData = (ULONG64 *) HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG64) * 2); if (! ThreadData) return; ThreadData[0] = (ULONG64)this; ThreadData[1] = (ULONG64)(ULONG_PTR)idProcess; hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)NotifyAllSlaves2, ThreadData, 0, &idThread); NotifyAllSlaves2()线程回调,ThreadData堆内存 ComServer *pThis = (ComServer *)ThreadData[0]; ULONG_PTR idProcess = (ULONG)ThreadData[1]; HeapFree(GetProcessHeap(), 0, ThreadData); pThis->NotifyAllSlaves3((HANDLE)idProcess);
NotifyAllSlaves3()这一块理解有些偏差,后续深入后再填充
*IpHlpServer::Handler()
#define MSGID_IPHLP 0x1C00 #define MSGID_IPHLP_CREATE_FILE 0x1C01 #define MSGID_IPHLP_CLOSE_HANDLE 0x1C02 #define MSGID_IPHLP_SEND_ECHO 0x1C03 #define MSGID_IPHLP_NOTIFICATION 0x1CFF
Eax=0x1cff,分发处理
IpHlpServer *pThis = (IpHlpServer *)_this; HANDLE idProcess = (HANDLE)(ULONG_PTR)PipeServer::GetCallerProcessId(); if (msg->msgid == MSGID_IPHLP_NOTIFICATION) { pThis->NotifyHandler(idProcess); return NULL; }
NotifyHandler()
m_ProxyHandle->ReleaseProcess(idProcess); if (proxy->refcount == 0) { m_close_callback(m_context_for_callback, &proxy->data); List_Remove(&m_list, proxy); HeapFree(m_heap, 0, proxy); }
再次循环仍会进入lpHipServer:Handler(),eax = 0x1cff
loc_140014400
.text:0000000140014400 cmp dword ptr [rdx+4], 1A01h ; cmp dword ptr [rdx+4],1A01h ds:0000005f`387ffb84=00001aff .text:0000000140014407 jz sub_140014650 .text:000000014001440D xor eax, eax .text:000000014001440F retn #define MSGID_NETAPI 0x1A00 #define MSGID_NETAPI_USE_ADD 0x1A01 //#define MSGID_NETAPI_WKSTA_GET_INFO 0x1A01 //#define MSGID_NETAPI_SERVER_GET_INFO 0x1A02
清除eax标志
*QueueServer::Handler()
#define MSGID_QUEUE 0x1E00 #define MSGID_QUEUE_CREATE 0x1E01 #define MSGID_QUEUE_GETREQ 0x1E02 #define MSGID_QUEUE_PUTRPL 0x1E03 #define MSGID_QUEUE_PUTREQ 0x1E04 #define MSGID_QUEUE_GETRPL 0x1E05 #define MSGID_QUEUE_NOTIFICATION 0x1EFF
Eax=0x1eff,处理分发
QueueServer *pThis = (QueueServer *)_this; HANDLE idProcess = (HANDLE)(ULONG_PTR)PipeServer::GetCallerProcessId(); if (msg->msgid == MSGID_QUEUE_NOTIFICATION) { pThis->NotifyHandler(idProcess); return NULL; }
QueueServer::NotifyHandler()删除进程对象
*EpMapperServer::Handler()
#define MSGID_EPMAPPER 0x1F00 #define MSGID_EPMAPPER_GET_PORT_NAME 0x1F01 EpMapperServer *pThis = (EpMapperServer *)_this; if (msg->msgid == MSGID_EPMAPPER_GET_PORT_NAME) return pThis->EpmapperGetPortNameHandler(msg); return NULL;
windows/linux/安卓/iot沙箱思维是相通的,当然监控元数据都不一样,检测矩阵不一样。国内外关于演讲沙箱设计都会经过多个维度升华,如应用层到内核层监,内核到虚拟化,针对恶意行为设置关卡层层把控,添加漏洞元数据等。在企业中常见如沙箱-att&ck落地,也可以是攻防拦截,如elf/pe注入,窗口/进程/线程等隐藏手法,ProcessHollwing,安卓边信道劫持等不乏多个维度。
上述观点存在很多偏差,仅个人的一些理解。
[公告]看雪论坛2020激励机制上线了!发帖不减雪币了!如何获得积分快速升级?
最后于 29分钟前 被一半人生编辑 ,原因: