一
研究背景
二
实现原理
bool Exception::InstallException(pfnExceptionHandlerApi p_exception_api)
{
DWORD old;//获取syscall函数地址
NtSetContextThread = (pfnNtSetContextThread)NtSetContextThreadProc;
::VirtualProtect((PVOID)((DWORD64)&NtSetContextThreadProc + 0x04), 4, PAGE_EXECUTE_READWRITE, &old);
*(DWORD*)((DWORD64)&NtSetContextThreadProc + 0x04) = (DWORD)GetSSDTIndexByName("NtSetContextThread");
::VirtualProtect((PVOID)((DWORD64)&NtSetContextThreadProc + 0x04), 4, old, NULL);NtSuspendThread = (pfnNtSuspendThread)NtSuspendThreadProc;
::VirtualProtect((PVOID)((DWORD64)&NtSuspendThreadProc + 0x04), 4, PAGE_EXECUTE_READWRITE, &old);
*(DWORD*)((DWORD64)&NtSuspendThreadProc + 0x04) = (DWORD)GetSSDTIndexByName("NtSuspendThread");
::VirtualProtect((PVOID)((DWORD64)&NtSuspendThreadProc + 0x04), 4, old, NULL);NtResumeThread = (pfnNtResumeThread)NtResumeThreadProc;
::VirtualProtect((PVOID)((DWORD64)&NtResumeThreadProc + 0x04), 4, PAGE_EXECUTE_READWRITE, &old);
*(DWORD*)((DWORD64)&NtResumeThreadProc + 0x04) = (DWORD)GetSSDTIndexByName("NtResumeThread");
::VirtualProtect((PVOID)((DWORD64)&NtResumeThreadProc + 0x04), 4, old, NULL);NtContinue = (pfnNtContinue)NtContinueProc;
::VirtualProtect((PVOID)((DWORD64)&NtContinueProc + 0x04), 4, PAGE_EXECUTE_READWRITE, &old);
*(DWORD*)((DWORD64)&NtContinueProc + 0x04) = (DWORD)GetSSDTIndexByName("NtContinue");
::VirtualProtect((PVOID)((DWORD64)&NtContinueProc + 0x04), 4, old, NULL);//保存函数指针
this->_self_exception_api = p_exception_api;HMODULE ntdll = ::GetModuleHandleA("ntdll.dll");
if (ntdll == NULL)
ntdll = ::LoadLibraryA("ntdll.dll");
//获取hook的返回地址
sysret_address = (DWORD64)::GetProcAddress(ntdll, "KiUserExceptionDispatcher");
if (sysret_address == NULL)
sysret_address = (DWORD64)::GetProcAddress(ntdll, "KiUserExceptionDispatcher");
rtl_restore_context_offset = this->GetOffset(sysret_address, 0x70, 0x10);
if (rtl_restore_context_offset <= 0)
::MessageBoxA(::GetActiveWindow(), "未找到函数偏移", "Error", MB_OK);PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION info;
info.Version = 0;
info.Reserved = 0;
info.Callback = MyCallbackEntry;
ULONG status = NtSetInformationProcess(GetCurrentProcess(), 0x28, &info, sizeof(info));
if (status)
return false;return true;
}
MyCallbackEntry PROC
mov gs:[2E0H], rsp ;Win10 TEB InstrumentationCallbackPreviousSp (保存的线程参数地址)
mov gs:[2D8H], r10 ;Win10 TEB InstrumentationCallbackPreviousPc (syscall 的返回地址)mov r10, rcx ;保存rcx
sub rsp, 4D0H ;Context结构大小
and rsp, -10H ;align rsp
mov rcx, rsp ;parameters are fun
call __imp_RtlCaptureContext ;保存线程Context上下文sub rsp, 20H ;开辟栈空间
call MyCallbackRoutine ;调用我们的函数int 3 ;不应该执行到这里
MyCallbackEntry ENDP
void MyCallbackRoutine(CONTEXT* context)
{
context->Rip = __readgsqword(0x02D8);//syscall 的返回地址
context->Rsp = __readgsqword(0x02E0);//context = rsp, ExceptionRecord = rsp + 0x4F0
context->Rcx = context->R10;if (context->Rip == sysret_address)
if (exception->_self_exception_api((PEXCEPTION_RECORD)(context->Rsp + 0x4F0), (PCONTEXT)context->Rsp) == EXCEPTION_CONTINUE_EXECUTION)
context->Rip = rtl_restore_context_offset;NtContinue(context, 0);
}
int Exception::SetHardWareBreakPoint(const wchar_t* main_modulename, DWORD64 dr7_statu, DWORD64 dr0, DWORD64 dr1, DWORD64 dr2, DWORD64 dr3)
{
this->_dr0 = dr0;
this->_dr1 = dr1;
this->_dr2 = dr2;
this->_dr3 = dr3;//遍历线程 通过openthread获取到线程环境后设置硬件断点
HANDLE hTool32 = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (hTool32 != INVALID_HANDLE_VALUE)
{
THREADENTRY32 thread_entry32; //线程环境结构体
thread_entry32.dwSize = sizeof(THREADENTRY32);
HANDLE h_hook_thread = NULL;
MODULEINFO module_info = { 0 }; //模块信息HANDLE target_modulehandle = GetModuleHandleW(main_modulename);
//从 ntdll.dll 中取出 ZwQueryInformationThread
(FARPROC&)ZwQueryInformationThread = ::GetProcAddress(GetModuleHandleA("ntdll"), "ZwQueryInformationThread");if (target_modulehandle != 0)
{
//获取模块结束地址
GetModuleInformation(GetCurrentProcess(), (HMODULE)target_modulehandle, &module_info, sizeof(MODULEINFO));
__int64 target_modulehandle_endaddress = ((__int64)module_info.lpBaseOfDll + module_info.SizeOfImage);
//遍历线程
if (Thread32First(hTool32, &thread_entry32))
{
do
{
//如果线程父进程ID为当前进程ID
if (thread_entry32.th32OwnerProcessID == GetCurrentProcessId())
{
h_hook_thread = OpenThread(THREAD_ALL_ACCESS, FALSE, thread_entry32.th32ThreadID);
// 获取线程入口地址
PVOID startaddr;//用来接收线程入口地址
ZwQueryInformationThread(h_hook_thread, (THREADINFOCLASS)ThreadQuerySetWin32StartAddress, &startaddr, sizeof(startaddr), NULL);
if (((__int64)startaddr >= (__int64)target_modulehandle) && ((__int64)startaddr <= target_modulehandle_endaddress))
{
//暂停线程
ULONG previous_count = NULL;
NtSuspendThread(h_hook_thread, &previous_count);//设置硬件断点
CONTEXT thread_context = { CONTEXT_DEBUG_REGISTERS };
thread_context.ContextFlags = CONTEXT_ALL;
//得到指定线程的环境(上下文)
if (!GetThreadContext(h_hook_thread, &thread_context))
return 3;
thread_context.Dr0 = dr0;
thread_context.Dr1 = dr1;
thread_context.Dr2 = dr2;
thread_context.Dr3 = dr3;
thread_context.Dr7 = dr7_statu;
if (NtSetContextThread(h_hook_thread, &thread_context) != NULL)
return 4;if (!GetThreadContext(h_hook_thread, &thread_context))
return 3;//恢复线程
NtResumeThread(h_hook_thread, &previous_count);
}
CloseHandle(h_hook_thread);
}
} while (Thread32Next(hTool32, &thread_entry32));
}
CloseHandle(hTool32);
return true;
}
else
return 2;//模块句柄获取失败
}
return 0;
}
LONG WINAPI ExceptionHandler(PEXCEPTION_RECORD exception_record, PCONTEXT context)
{
//hardware breakpoint
if (exception_record->ExceptionCode == EXCEPTION_SINGLE_STEP)
{
if (exception_record->ExceptionAddress == (PVOID64)exception->_dr0)
{
//ACE-Base64.dll + 815844 - 48 89 47 08 - mov[rdi + 08], rax //Hook点
//ACE-Base64.dll + 815848 - FF 53 20 - call qword ptr[rbx + 20] //跳过执行
//ACE-Base64.dll + 81584B - 48 8B 1B - mov rbx, [rbx]std::cout << "caller address: " << std::hex << *(DWORD64*)context->Rsi << std::endl;
std::cout << "callee address: " << std::hex << *(DWORD64*)(context->Rbx + 0x20) << std::endl;context->Rip = exception->_dr0 + 0x07;
return EXCEPTION_CONTINUE_EXECUTION;
}
else if (exception_record->ExceptionAddress == (PVOID64)exception->_dr1)
{
return EXCEPTION_CONTINUE_EXECUTION;
}
else if (exception_record->ExceptionAddress == (PVOID64)exception->_dr2)
{
return EXCEPTION_CONTINUE_EXECUTION;
}
else if (exception_record->ExceptionAddress == (PVOID64)exception->_dr3)
{
return EXCEPTION_CONTINUE_EXECUTION;
}
else
{
context->Dr0 = exception->_dr0;
context->Dr1 = exception->_dr1;
context->Dr2 = exception->_dr2;
context->Dr3 = exception->_dr3;
return EXCEPTION_CONTINUE_SEARCH;
}
}
//software breakpoint
else if (exception_record->ExceptionCode == EXCEPTION_BREAKPOINT)
{
}
return EXCEPTION_CONTINUE_SEARCH;
}
exception = std::make_shared<Exception>();
exception->InstallException(ExceptionHandler);DWORD64 ace_base_module = 0;
while (true)
{
ace_base_module = (DWORD64)::GetModuleHandleA("ACE-Base64.dll");
if (ace_base_module > 0x1000)
break;
}
auto value = exception->SetHardWareBreakPoint(L"crossfire.exe", 0x455, ace_base_module + 0x815844, 0x0, 0x0, 0x0);
printf("value:%d\n", value);
三
效果展示
四
总结
看雪ID:GN-顾念
https://bbs.kanxue.com/user-home-971710.htm
# 往期推荐
2、BFS Ekoparty 2022 Linux Kernel Exploitation Challenge
3、银狐样本分析
球分享
球点赞
球在看
点击阅读原文查看更多