如题,sleep作为一个最经典的延迟执行反沙箱技术,但是现在的大多数沙箱一检测到 sleep 函数,会直接跳过,加速或不去执行 sleep,用来对抗我们的反沙箱技术
POC概念如下:
//定义函数指针
typedef void (NTAPI* pNtDelayExecution)(IN BOOLEAN Alertable,
IN PLARGE_INTEGER DelayInterval
);
//旧的
pNtDelayExecution pOldNtDelayExecution = (pNtDelayExecution)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtDelayExecution");
//新的
void NTAPI myNtDelayExecution(BOOLEAN Alertable, PLARGE_INTEGER DelayInterval
){
MessageBoxA(0,"检测到川哥想使用Sleep绕过沙箱","愚蠢的行为",0);
pOldNtDelayExecution(Alertable, 0); //使延迟为0,基本上睡眠无效
}
void setHook() {
if (MH_Initialize() == MB_OK)
{
MH_CreateHookApi(L"ntdll.dll", "NtDelayExecution", myNtDelayExecution, reinterpret_cast<void**>(&pOldNtDelayExecution));
MH_EnableHook(MH_ALL_HOOKS);
}
}
void UnHook()
{
if (MH_DisableHook(MH_ALL_HOOKS) == MB_OK)
{
MH_Uninitialize();
}
}
void main() {
//setHook();
Sleep(3000);
printf("hello laoxinsec.com");
}
有鉴于此。我们可以通过自封装一个"sleep"的手段进行bypass:
基本原理:
KUSER_SHARED_DATA 结构是一个系统内核和用户模式(当然是只读模式)共享的结构,其中包含 Windows 操作系统存储在内存地址中的各种系统参数,该地址自 Windows NT 以来在 Windows 版本中保持不变,位于内存地址(0x7ffe0000),我们可以从用户空间访问该地址。值得注意的是,可以在此结构中的 +0x14 偏移处检查系统时间。
在上面的屏幕截图中看到的那样,SystemTime 成员属于_KSYSTEM_TIME类型。我们可以dt此类型来了解我们需要做什么。
虽然可以读取_KSYSTEM_TIME结构的所有三个组件以实现系统时间的完整读取,但要开发MySleep,我们实际上只需要读取 LowPart 和 High1Time。
制作计时器
利用迄今为止获得的知识来制作一个概念验证
unsigned long long __get_timestamp()
{
const size_t TICKS_PER_SECOND = 10000000; // A tick is 100ns.
LARGE_INTEGER time;
time.LowPart = *(DWORD*)(KSHARE_DATA_ADDRESS + 0x14); // Read LowPart as unsigned long.
time.HighPart = *(long*)(KSHARE_DATA_ADDRESS + 0x1c); // Read High1Part as long.
return (unsigned long long)((time.QuadPart) / TICKS_PER_SECOND);
}
void main() {
printf("获取时间戳:%u\n", __get_timestamp());
}
执行代码,可以从KUser_Shared_Data结构中读取并观察到一个递增值,该值反映了每秒的时间变化
Ok,现在我们可以增加一些计时器逻辑让我们的程序进入睡眠状态,而无需调用任何 WinAPI 或 Native API!!!
unsigned long long __get_timestamp()
{
const size_t TICKS_PER_SECOND = 10000000; // A tick is 100ns.
LARGE_INTEGER time;
time.LowPart = *(DWORD*)(KSHARE_DATA_ADDRESS + 0x14); // Read LowPart as unsigned long.
time.HighPart = *(long*)(KSHARE_DATA_ADDRESS + 0x1c); // Read High1Part as long.
return (unsigned long long)((time.QuadPart) / TICKS_PER_SECOND);
}
void main() {
unsigned long long startTime = __get_timestamp();
unsigned long long sleeptime = 10; //休眠10秒
while (sleeptime > (__get_timestamp() - startTime)) {
}
//do something......such as payload()?
}
此外,KUser_Shared_Data结构包含一些更有趣的东西,可以用它们来获取系统信息,而无需与 Windows API 交互,将在https://www.laoxinsec.com/站点发布继续探讨。
参考链接:https://www.legacyy.xyz/defenseevasion/windows/2022/07/04/abusing-shareduserdata-for-defense-evasion-and-exploitation.html
https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm
https://www.vergiliusproject.com/kernels/x86/windows-10/22h2/_KUSER_SHARED_DATA
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/measure-command?view=powershell-7.4