diff --git a/ConsoleApplication1.sln b/ConsoleApplication1.sln new file mode 100644 index 0000000..b07b205 --- /dev/null +++ b/ConsoleApplication1.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31321.278 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ConsoleApplication1", "ConsoleApplication1\ConsoleApplication1.vcxproj", "{660016FD-E58A-49B0-97C6-5F87B4DED26B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {660016FD-E58A-49B0-97C6-5F87B4DED26B}.Debug|x64.ActiveCfg = Debug|x64 + {660016FD-E58A-49B0-97C6-5F87B4DED26B}.Debug|x64.Build.0 = Debug|x64 + {660016FD-E58A-49B0-97C6-5F87B4DED26B}.Debug|x86.ActiveCfg = Debug|Win32 + {660016FD-E58A-49B0-97C6-5F87B4DED26B}.Debug|x86.Build.0 = Debug|Win32 + {660016FD-E58A-49B0-97C6-5F87B4DED26B}.Release|x64.ActiveCfg = Release|x64 + {660016FD-E58A-49B0-97C6-5F87B4DED26B}.Release|x64.Build.0 = Release|x64 + {660016FD-E58A-49B0-97C6-5F87B4DED26B}.Release|x86.ActiveCfg = Release|Win32 + {660016FD-E58A-49B0-97C6-5F87B4DED26B}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E875AE0D-210A-415E-84AF-89F79335D220} + EndGlobalSection +EndGlobal diff --git a/ConsoleApplication1/ConsoleApplication1.cpp b/ConsoleApplication1/ConsoleApplication1.cpp new file mode 100644 index 0000000..61ea63c --- /dev/null +++ b/ConsoleApplication1/ConsoleApplication1.cpp @@ -0,0 +1,105 @@ +// ConsoleApplication1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 +// + +#include +#include +#include +#include +#include +extern "C" void asm_pg_KiErrata361Present(); +extern "C" bool asm_pg_single_step(); +/* +* https://revers.engineering/ +* https://revers.engineering/detecting-hypervisor-presence-on-windows-10/ +* https://key08.com/ +*/ +void write_to_file(std::string file_name, std::string file_context) { + std::ofstream out_file(file_name); + out_file << file_context; + out_file.close(); +} +struct _cpuid +{ + UINT data[4]; +}; +void check_by_time() +{ + unsigned __int64 old_priority = SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); + unsigned __int64 rdtsc_first = __rdtsc(); + Sleep(2000); + unsigned __int64 rdtsc_time_delta = __rdtsc() - rdtsc_first; + DWORD64 result_time = 0; + int cpuid_data[4] = { 0 }; + for (std::size_t count = 0; count < 0x6694; count++) + { + auto rdtsc_iter_time = __rdtsc(); + + __cpuid((int*)cpuid_data, 0); + + result_time += __rdtsc() - rdtsc_iter_time; + } + unsigned __int64 _time = 10000000 * result_time / rdtsc_time_delta / 0x65; + if (_time > 400 || _time < 10) + printf("rdtsc detected !\n"), + write_to_file("rdtsc.txt", "rdtsc detected!"); + else + printf("rdtsc pass! \n"); + printf("time: %d \n", _time); + SetThreadPriority(GetCurrentThread(), old_priority); +} + +void check_by_invalid_cpuid() +{ + unsigned int invalid_leaf = 0x13371337; + unsigned int valid_leaf = 0x40000000; + + auto fn_check = [](_cpuid a, _cpuid b)->bool { + return a.data[0] != b.data[0] || a.data[1] != b.data[1] || a.data[2] != b.data[2] || a.data[3] != b.data[3]; + }; + _cpuid cpuid_first = { 0 }; + _cpuid cpuid_sec = { 0 }; + + __cpuid((int*)&cpuid_first, invalid_leaf); + __cpuid((int*)&cpuid_sec, valid_leaf); + + if (fn_check(cpuid_first, cpuid_sec)) + { + printf("CPUID detected \n"); + write_to_file("cpuid.txt", "cpuid detected!"); + return; + } + printf("CPUID pass \n"); +} +void check_by_pg() { + printf("pg detecting... \n"); + write_to_file("start_pg_detect.txt", "start pg detect"); + asm_pg_KiErrata361Present(); + printf("pg detec pass \n"); + write_to_file("pg_detect_pass.txt", "pg detect pass"); +} +void check_by_single_step() { + + write_to_file("start_single_detect.txt", "start_single_detect"); + if (asm_pg_single_step()) { + printf("single_step pass \n"); + } + else { + printf("single_step detected \n"); + write_to_file("single_step.txt", "single_step detected"); + } + write_to_file("single_detect_end.txt", "single_detect_end"); +} +LONG CALLBACK veh_hanlde(struct _EXCEPTION_POINTERS* ExceptionInfo) +{ + return ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH; +} +int main() +{ + AddVectoredExceptionHandler(true, veh_hanlde); + check_by_pg(); + check_by_time(); + check_by_invalid_cpuid(); + check_by_single_step(); + system("pause"); + return 0; +} diff --git a/ConsoleApplication1/ConsoleApplication1.vcxproj b/ConsoleApplication1/ConsoleApplication1.vcxproj new file mode 100644 index 0000000..1ffdaf6 --- /dev/null +++ b/ConsoleApplication1/ConsoleApplication1.vcxproj @@ -0,0 +1,156 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {660016fd-e58a-49b0-97c6-5f87b4ded26b} + ConsoleApplication1 + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + + + false + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + + + Console + true + true + true + + + + + + + + Document + + + + + + + \ No newline at end of file diff --git a/ConsoleApplication1/ConsoleApplication1.vcxproj.filters b/ConsoleApplication1/ConsoleApplication1.vcxproj.filters new file mode 100644 index 0000000..65cbec2 --- /dev/null +++ b/ConsoleApplication1/ConsoleApplication1.vcxproj.filters @@ -0,0 +1,27 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + 源文件 + + + + + 源文件 + + + \ No newline at end of file diff --git a/ConsoleApplication1/ConsoleApplication1.vcxproj.user b/ConsoleApplication1/ConsoleApplication1.vcxproj.user new file mode 100644 index 0000000..88a5509 --- /dev/null +++ b/ConsoleApplication1/ConsoleApplication1.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/ConsoleApplication1/duck.asm b/ConsoleApplication1/duck.asm new file mode 100644 index 0000000..95e390d --- /dev/null +++ b/ConsoleApplication1/duck.asm @@ -0,0 +1,26 @@ +.code + +asm_pg_single_step proc + pushfq + mov rax,0 + or dword ptr [rsp], 0100h + mov eax, 0FFFFFFFFh + popfq + mov rax,1 ;,仰Ǵ˵ + nop + ret +asm_pg_single_step endp + +asm_pg_KiErrata361Present proc + mov ax,ss + pushfq + or qword ptr[rsp],100h + popfq + mov ss,ax + db 0f1h ;icebp + pushfq + and qword ptr[rsp],0FFFFFEFFh + popfq + ret +asm_pg_KiErrata361Present endp +end \ No newline at end of file diff --git a/README.md b/README.md index 9248950..02c0eca 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,55 @@ # DuckSandboxDetect 沙箱测试,用于测评国内常见沙箱的代码 + +# 本次测评分别测评如下性能: +1. icebp指令模拟 +https://key08.com/index.php/2021/05/13/1086.html: +> mov ss会产生一个异常,但是这个异常会在下一个指令执行的时候再抛出.因此 他首先mov ss了,这样下一个指令才会执行异常, 到icebp的时候, mov ss造成的异常就应该被抛出了。但是同时icebp也会造成一个异常,而且异常优先级哎比mov ss的高,你说巧不巧.这样CPU就会处理icebp的异常而不处理mov ss的异常,但是mov ss的异常是必须要求dr6的single_instruction bit位(也就叫做DR6.BS位)为1的,要不然就炸。很遗憾的是icebp的异常他不会设置这个bs位,导致直接炸虚拟机.很多时候虚拟机在2004跑起来了结果一阵子就虚拟机guest机异常了就是这个毛病 + +2. 时间延迟检测 +> 由于经过虚拟化的vmexit阶段,沙箱的退出时间会比真实的早 + +3. cpuid检测 +https://secret.club/2020/04/13/how-anti-cheats-detect-system-emulation.html +> 一种类似于保留 MSR 地址范围的快速方法是检查保留CPUID响应与它们通常的值。例如,40000000h是由架构标记为保留的 CPUID 叶子,最常用于 VMM 的报告功能。有两个选项可以检查无效的eax或返回相同数据的eax。 + +4.单步检测 +https://howtohypervise.blogspot.com/2019/01/a-common-missight-in-most-hypervisors.html + +# 检测结果: + +腾讯哈勃 +https://habo.qq.com/file/showdetail?pk=ADcGYF1vB24IOFs8U2s%3D + +奇安信: +https://sandbox.ti.qianxin.com/sandbox/page/detail?type=file&id=AXprRYp1qO1C-f6P9JVe&env=&time=&sha1=0666775c8eb67fbd87c99a54cb7968084573c709 + +freebuf: +https://sandbox.freebuf.com/reportDetail?fileSha1=0666775c8eb67fbd87c99a54cb7968084573c709 + +微步在线: +https://s.threatbook.cn/report/file/6d244d4978f8b8b67aa338ee3fef23e30198fc554a3ed225fea734efa118ea59/?env=win7_sp1_enx64_office2013 + +virustotal: +https://www.virustotal.com/gui/file/fbdbf6716b19de8607064abaf69fb5f157be34b328dd62cbbf0d6f874d9e04d3/behavior/Microsoft%20Sysinternals%20Sysmon + +其中,freebuf和微步在线的沙箱均无法分析出icebp指令之后的内容(可能是不支持这个指令),因此我多次测试了几次, +https://s.threatbook.cn/report/file/18fc971fd8b097331322c0fc815bfba26f8427a15ffb16f34ee869065d3cabc4/?env=win7_sp1_enx64_office2013 + +https://sandbox.freebuf.com/reportDetail?fileSha1=529fc26cc6e8c9ff4158a9b45755279502afdc9b +均崩溃或者无法继续执行: +![](https://key08.com/usr/uploads/2021/07/2918362663.png) + +![](https://key08.com/usr/uploads/2021/07/315797688.png) + +奇安信与VT的沙箱对于cpuid和rdtsc模拟不够好,但没有在icebp指令崩溃: +![](https://key08.com/usr/uploads/2021/07/1932825589.png) + +![](https://key08.com/usr/uploads/2021/07/1626874842.png) + +腾讯哈勃表现最好,只有rdtsc指令模拟不够好,其他的均不错 +![](https://key08.com/usr/uploads/2021/07/2370001926.png) + +# 暂时测试的结论: +freebuf = 微步在线 < 奇安信 = VirtusTotal < 腾讯哈勃 +**仅仅代表本次测试结果,不排除测试不严谨导致的问题** \ No newline at end of file diff --git a/images/1.png b/images/1.png new file mode 100644 index 0000000..80a95e8 Binary files /dev/null and b/images/1.png differ diff --git a/images/2.png b/images/2.png new file mode 100644 index 0000000..2e9ab90 Binary files /dev/null and b/images/2.png differ diff --git a/images/3.png b/images/3.png new file mode 100644 index 0000000..11ea4d8 Binary files /dev/null and b/images/3.png differ diff --git a/images/4.png b/images/4.png new file mode 100644 index 0000000..b28e1ba Binary files /dev/null and b/images/4.png differ diff --git a/images/5.png b/images/5.png new file mode 100644 index 0000000..9896862 Binary files /dev/null and b/images/5.png differ