diff --git a/BranchTracerSys/BranchTracerSys.cpp b/BranchTracerSys/BranchTracerSys.cpp new file mode 100644 index 0000000..e594803 --- /dev/null +++ b/BranchTracerSys/BranchTracerSys.cpp @@ -0,0 +1,152 @@ +#include +#include +#include "asm/debug.h" +#include "bts/bts.h" +#include "kernel-hooks/Hooks.h" +#include "kernel-tools/KernelBase.h" + +#include "ioctls.h" + +NTSTATUS IoctlDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp); +NTSTATUS IoctlCreateClose(PDEVICE_OBJECT DeviceObject, PIRP Irp); + +PDEVICE_OBJECT DeviceObject; +UNICODE_STRING DeviceName; +UNICODE_STRING SymlinkName; + +VOID DriverUnload(PDRIVER_OBJECT DriverObject) +{ + UNREFERENCED_PARAMETER(DriverObject); + DbgPrint("Driver Unloading... \n"); + + IoDeleteSymbolicLink(&SymlinkName); + IoDeleteDevice(DriverObject->DeviceObject); + + // Reset BTS : ÊÍ·ÅDS_AreaÄÚ´æ. + ResetBTS(); + + // ¼à¿ØÆÚ¼ä»á²»¶Ï²úÉúTraceData. ½áÊøʱ±ØÐëÊÍ·ÅÕâЩÄÚ´æ¡£ + ClearThreadTraceData(); +} + +//StartMonitThread((HANDLE)THREADID); +//StopMonitThread((HANDLE)THREADID); + + +#define DEVICE_NAME L"\\Device\\Branch-Trace" +#define SYMLINK_NAME L"\\DosDevices\\Branch-Trace" +#define DRIVER_NAME L"\\Driver\\Branch-Trace" + +EXTERN_C NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING pRegistryPath) +{ + UNREFERENCED_PARAMETER(pRegistryPath); + + // ³õʼ»¯»·¾³ : ³õʼ»¯È«¾Ö±äÁ¿ + InitializeEnvironment(); + + // Setup + if (!NT_SUCCESS(SetupBTS())) { + return STATUS_UNSUCCESSFUL; + } + + + RtlInitUnicodeString(&DeviceName, DEVICE_NAME); + RtlInitUnicodeString(&SymlinkName, SYMLINK_NAME); + + + // ´´½¨É豸¶ÔÏó + IoCreateDevice(DriverObject, 0, &DeviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &DeviceObject); + + // ÉèÖÃͨѶ·½Ê½ + DeviceObject->Flags |= DO_BUFFERED_IO; + + IoCreateSymbolicLink(&SymlinkName, &DeviceName); + + + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IoctlDeviceControl; + DriverObject->MajorFunction[IRP_MJ_CREATE] = IoctlCreateClose; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = IoctlCreateClose; + DriverObject->DriverUnload = DriverUnload; + + DbgPrint("DriverEntry Completed!\n"); + return STATUS_SUCCESS; +} + + +NTSTATUS IoctlCreateClose(PDEVICE_OBJECT pDeviceObject, PIRP Irp) +{ + UNREFERENCED_PARAMETER(pDeviceObject); + UNREFERENCED_PARAMETER(Irp); + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; +} + +NTSTATUS IoctlDeviceControl(PDEVICE_OBJECT pDeviceObject, PIRP Irp) +{ + UNREFERENCED_PARAMETER(pDeviceObject); + UNREFERENCED_PARAMETER(Irp); + + NTSTATUS Status = STATUS_SUCCESS; + ULONG InfoSize = 0; + PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); + ULONG ControlCode = Stack->Parameters.DeviceIoControl.IoControlCode; + + + switch (ControlCode) { + case IOCTL_START_THREAD_TRACE: { + // ¿ªÊ¼¼à¿Ø + PSTART_THREAD_TRACE_PARAM Request = (PSTART_THREAD_TRACE_PARAM)Irp->AssociatedIrp.SystemBuffer; + if (Request->ThreadId == 0) { + Status = STATUS_UNSUCCESSFUL; + break; + } + + if (!StartMonitThread((HANDLE)Request->ThreadId)) { + DbgPrint("StartMonitThread Failed!\n"); + Status = STATUS_UNSUCCESSFUL; + break; + } + break; + } + + case IOCTL_STOP_THREAD_TRACE: + { + PSTOP_THREAD_TRACE_PARAM Request = (PSTOP_THREAD_TRACE_PARAM)Irp->AssociatedIrp.SystemBuffer; + StopMonitThread((HANDLE)Request->ThreadId); + + DbgBreakPoint(); + SIZE_T BufferSize = 0; + if (Request->Buffer != NULL) { + if (!ReadThreadTraceData((HANDLE)Request->ThreadId, Request->Buffer, + Request->BufferSize, Request->FilterStart, Request->FilterEnd, &BufferSize)) { + Status = STATUS_UNSUCCESSFUL; + break; + } + } + + // ÇåÀíÊý¾Ý + ClearThreadTraceData(); + Request->ReadSize = BufferSize; + InfoSize = sizeof(STOP_THREAD_TRACE_PARAM); + Status = STATUS_SUCCESS; + break; + + } + + + default: { + Status = STATUS_INVALID_DEVICE_REQUEST; + InfoSize = 0; + break; + } + } + + Irp->IoStatus.Status = Status; + Irp->IoStatus.Information = InfoSize; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; +} + diff --git a/BranchTracerSys/BranchTracerSys.vcxproj b/BranchTracerSys/BranchTracerSys.vcxproj new file mode 100644 index 0000000..f0c0dde --- /dev/null +++ b/BranchTracerSys/BranchTracerSys.vcxproj @@ -0,0 +1,142 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {D043300D-A14F-4E73-99A3-73C48E142404} + {dd38f7fc-d7bd-488b-9242-7d8754cde80d} + v4.5 + 12.0 + Debug + Win32 + BranchTracerSys + + + + Windows7 + true + WindowsKernelModeDriver10.0 + Driver + WDM + + + Windows7 + false + WindowsKernelModeDriver10.0 + Driver + WDM + + + Windows7 + true + WindowsKernelModeDriver10.0 + Driver + WDM + + + Windows7 + false + WindowsKernelModeDriver10.0 + Driver + WDM + + + + + + + + + + + DbgengKernelDebugger + + + DbgengKernelDebugger + + + DbgengKernelDebugger + $(ExcludePath) + + + DbgengKernelDebugger + $(ExcludePath) + + + + Level3 + + + + + Level3 + + + + + Level3 + + + + + Level3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + true + + + true + true + + + + + + \ No newline at end of file diff --git a/BranchTracerSys/BranchTracerSys.vcxproj.filters b/BranchTracerSys/BranchTracerSys.vcxproj.filters new file mode 100644 index 0000000..a0a6c31 --- /dev/null +++ b/BranchTracerSys/BranchTracerSys.vcxproj.filters @@ -0,0 +1,104 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;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 + + + {8E41214B-6785-4CFE-B992-037D68949A14} + inf;inv;inx;mof;mc; + + + {aead6267-5d84-45db-93fb-fffdf2f6343a} + + + {6c897276-9fe2-4ee8-b5d8-aef592f9ec56} + + + {1e45e513-6ea4-404a-8351-80b8d58a97a4} + + + {4d201744-e4c5-44ef-b184-a359e3015b45} + + + + + Source Files + + + Source Files\kernel-hooks + + + Source Files\kernel-hooks + + + Source Files\kernel-tools + + + Source Files\kernel-tools + + + Source Files\bts + + + + + Source Files\asm + + + + + Source Files\asm + + + Source Files\bts + + + Source Files\kernel-hooks + + + Source Files\kernel-hooks + + + Source Files\kernel-tools + + + Source Files\kernel-tools + + + Source Files\kernel-tools + + + Source Files\kernel-tools + + + Source Files\kernel-tools + + + Source Files\kernel-tools + + + Source Files\kernel-tools + + + Source Files + + + + + Source Files\asm + + + Source Files\asm + + + \ No newline at end of file diff --git a/BranchTracerSys/BranchTracerSys.vcxproj.user b/BranchTracerSys/BranchTracerSys.vcxproj.user new file mode 100644 index 0000000..6eb3bb7 --- /dev/null +++ b/BranchTracerSys/BranchTracerSys.vcxproj.user @@ -0,0 +1,19 @@ + + + + DbgengKernelDebugger + Thinkpad T460s + + + DbgengKernelDebugger + Thinkpad T460s + + + DbgengKernelDebugger + Thinkpad T460s + + + DbgengKernelDebugger + Thinkpad T460s + + \ No newline at end of file diff --git a/BranchTracerSys/asm/cpu.inc b/BranchTracerSys/asm/cpu.inc new file mode 100644 index 0000000..eaead4d --- /dev/null +++ b/BranchTracerSys/asm/cpu.inc @@ -0,0 +1,3 @@ +IA32_MISC_ENABLE EQU 1A0H +IA32_DS_AREA EQU 600H +IA32_DEBUGCTL EQU 1D9H diff --git a/BranchTracerSys/asm/debug.h b/BranchTracerSys/asm/debug.h new file mode 100644 index 0000000..ad2c1b9 --- /dev/null +++ b/BranchTracerSys/asm/debug.h @@ -0,0 +1,29 @@ +#pragma once + +EXTERN_C_START + +/* check support Debug Store*/ +BOOLEAN __stdcall CheckSupportDS(); + +/* check support 64bit Debug Store*/ +BOOLEAN __stdcall CheckSupportDS64(); + +/* check BTS is avaliable*/ +BOOLEAN __stdcall CheckAvaliableBTS(); + +/* check PEBS is avaliable*/ +BOOLEAN __stdcall CheckAvaliablePEBS(); + +/* Set IA32_DS_AREA*/ +BOOLEAN __stdcall SetDebugStoreArea(PVOID DebugStoreAreaBase); + +/*¿ªÆôBTS */ +BOOLEAN EnableBTS(); + +/*¹Ø±ÕBTS*/ +BOOLEAN DisableBTS(); + + +VOID TestJmp(); + +EXTERN_C_END \ No newline at end of file diff --git a/BranchTracerSys/asm/debug32.asm b/BranchTracerSys/asm/debug32.asm new file mode 100644 index 0000000..4c6997c --- /dev/null +++ b/BranchTracerSys/asm/debug32.asm @@ -0,0 +1,91 @@ +.686P +.model flat, stdcall +option casemap:none + +.code + +_asm_cpuid PROC uses edi ebx id:dword,pCpuinfo:dword + mov eax,id + cpuid + + ;Êä³ö²ÎÊý + mov edi ,pCpuinfo; + mov [edi+0],eax + mov [edi+04h],ecx + mov [edi+08h],edx + mov [edi+0ch],ebx + + mov eax, 1 + ret +_asm_cpuid ENDP + +_asm_vmxon PROC lowPart:dword,highPart:dword + sub esp,08h + mov eax, lowPart + mov [esp],eax + mov eax, highPart + mov [esp+4],eax + vmxon qword ptr [esp] + add esp,08h + ret +_asm_vmxon ENDP + +_asm_vmxoff PROC + vmxoff + ret +_asm_vmxoff ENDP + +_asm_vmlaunch PROC + vmlaunch + ret +_asm_vmlaunch ENDP + +_asm_vmresume PROC + vmresume + ret +_asm_vmresume ENDP + +_asm_vmcall PROC + vmcall + ret +_asm_vmcall ENDP + +_asm_vmclear PROC lowPart:dword, highPart:dword + sub esp,08h + mov eax, lowPart + mov [esp],eax + mov eax, highPart + mov [esp+4],eax + vmclear qword ptr [esp] + add esp,08h + ret +_asm_vmclear ENDP + +_asm_vmptrld PROC lowPart:dword, highPart:dword + sub esp,08h + + mov eax, lowPart + mov [esp],eax + mov eax, highPart + mov [esp+4],eax + vmptrld qword ptr [esp] + + add esp,08h + ret +_asm_vmptrld ENDP + +_asm_vmread PROC uses ecx filed:dword + mov eax,filed + vmread ecx,eax + mov eax, ecx + ret +_asm_vmread ENDP + +_asm_vmwrite PROC uses ecx filed:dword, value:dword + mov eax,filed + mov ecx,value + vmwrite eax,ecx + ret +_asm_vmwrite ENDP + +END \ No newline at end of file diff --git a/BranchTracerSys/asm/debug64.asm b/BranchTracerSys/asm/debug64.asm new file mode 100644 index 0000000..78ca052 --- /dev/null +++ b/BranchTracerSys/asm/debug64.asm @@ -0,0 +1,119 @@ +option casemap:none + +include cpu.inc + +.CODE +CheckSupportDS PROC uses rdx + mov eax,1 + cpuid + bt edx,21 ; ½«edx[21]¸´ÖƵ½CFλ + setc al ; ¸ù¾ÝCF±ê־λ set byte + movzx eax,al ; ÍØÕ¹alµ½eax + + ret +CheckSupportDS ENDP + +CheckSupportDS64 PROC + mov eax,1 + cpuid + bt ecx,2 ;ecx[2]:DEST64 + setc al + movzx eax,al + ret +CheckSupportDS64 ENDP + +CheckAvaliableBTS PROC + mov eax,1 + cpuid + bt edx,21 + jnc tag_end ; Ϊ0Ö±½ÓÌøתµ½·µ»Ø + + mov ecx,IA32_MISC_ENABLE ; IA32_MISC_ENABLE + rdmsr + bt eax,11 ;IA32_MISC_ENABLE[11] Ϊ0±íʾ¿ÉÓÃ. Ϊ1±íʾ²»¿ÉÓà + setnc al + +tag_end: + movzx eax,al ; ÍØÕ¹alµ½eax + ret +CheckAvaliableBTS ENDP + + +CheckAvaliablePEBS PROC + mov eax,1 + cpuid + bt edx,21 + jnc tag_end ; Ϊ0Ö±½ÓÌøתµ½·µ»Ø + + mov ecx,IA32_MISC_ENABLE ; IA32_MISC_ENABLE + rdmsr + bt eax,12 ;IA32_MISC_ENABLE[12] Ϊ0±íʾ¿ÉÓÃ. Ϊ1±íʾ²»¿ÉÓà + setnc al + +tag_end: + movzx eax,al ; ÍØÕ¹alµ½eax + ret +CheckAvaliablePEBS ENDP + + +; rcx = DebugStoreAreaBase +SetDebugStoreArea PROC uses rdx + + mov rax,rcx ; ½« DebugStoreAreaBase µÍλдÈëeax wrmsr»áºöÂÔrax¸ß32λ + mov rdx,rcx + shr rdx,32 ; ½« DebugStoreAreaBase ¸ß32λдÈëedx wrmsr»áºöÂÔrdx¸ß32λ + + mov ecx,IA32_DS_AREA + wrmsr ; write msr EDX:EAX -> msr + + ret +SetDebugStoreArea ENDP; + +EnableBTS PROC uses rcx rdx + mov ecx, IA32_DEBUGCTL + rdmsr ; read msr msr -> EDX:EAX + or eax,2C0h ; TR(bit6)=1, BTS(bit7)=1 BTS_OFF_OS(bit9) + wrmsr + ret +EnableBTS ENDP + +DisableBTS PROC uses rcx rdx + mov ecx, IA32_DEBUGCTL + rdmsr ; read msr msr -> EDX:EAX + and eax,0FFFFFF3Fh ; TR=0, BTS=0 + wrmsr + ret +DisableBTS ENDP + + + +TestJmp PROC + +lable1: + jmp lable2 +lable2: + jmp lable3 +lable3: + jmp lable4 +lable4: + jmp lable5 +lable5: + jmp lable6 +lable6: + jmp lable7 +lable7: + jmp lable8 +lable8: + jmp lable9 +lable9: + jmp lable10 +lable10: + jmp lable11 +lable11: + + ret +TestJmp ENDP + + + +END \ No newline at end of file diff --git a/BranchTracerSys/bts/bts.cpp b/BranchTracerSys/bts/bts.cpp new file mode 100644 index 0000000..739146f --- /dev/null +++ b/BranchTracerSys/bts/bts.cpp @@ -0,0 +1,377 @@ +#include "../kernel-tools/KernelBase.h" +#include "bts.h" +#include +#include "../asm/debug.h" +#include "../kernel-hooks/Hooks.h" + + +typedef struct _THREAD_TRACE_DATA +{ + LIST_ENTRY ListEntry; + HANDLE ThreadId; + HANDLE ProcessId; + PBTS_RECORD64 Start; + PBTS_RECORD64 End; +}THREAD_TRACE_DATA, * PTHREAD_TRACE_DATA; + + + + +typedef NTSTATUS(__stdcall* KeSetAffinityThread)(PKTHREAD thread, KAFFINITY affinity); + +PDS_AREA64 g_DSAreaArr[64] = { 0 }; +PBTS_RECORD64 g_BtsBufferArr[64] = { 0 }; +//PPEBS_RECORD64 g_PebsBufferArr[64] = { 0 }; + +ULONG ProcessorCount = 0; +KAFFINITY ActivedProcessors = 0; +KeSetAffinityThread KeSetAffinityThreadObj = NULL; +KAFFINITY AllayedProcessor = 0; + +#define MAX_CPU 64 + +INTERCEPT_INFO InterceptInfo; +UCHAR ProcessorFlag[MAX_CPU] = { 0 }; +LIST_ENTRY ThreadTraceDataHeaderArr[MAX_CPU]; +ULONG_PTR MonitThreadId = 0xFFFFFFFF; + + + + +VOID InitializeEnvironment() { + for (size_t i = 0; i < MAX_CPU; i++) + { + InitializeListHead(&ThreadTraceDataHeaderArr[i]); + } + + // »ñÈ¡KeSetAffinityThreadStr + UNICODE_STRING KeSetAffinityThreadStr = RTL_CONSTANT_STRING(L"KeSetAffinityThread"); + KeSetAffinityThreadObj = (KeSetAffinityThread)MmGetSystemRoutineAddress(&KeSetAffinityThreadStr); + + // CPUºËÐÄÊýÁ¿ + ProcessorCount = KeQueryActiveProcessorCount(&ActivedProcessors); +} + + + + +VOID ClearThreadTraceData() { + PETHREAD Thread = PsGetCurrentThread(); + for (size_t i = 0; i < MAX_CPU; i++) + { + PLIST_ENTRY header = &ThreadTraceDataHeaderArr[i]; + + // Çл»Ïß³ÌΪ¶ÔÓ¦µÄCPU + KAFFINITY CurrentAffinity = (KAFFINITY)1 << i; + if ((AllayedProcessor & CurrentAffinity) == 0) { + continue; + } + KeSetAffinityThreadObj(Thread, CurrentAffinity); + + while (!IsListEmpty(header)) { + THREAD_TRACE_DATA* s = CONTAINING_RECORD(RemoveTailList(header), THREAD_TRACE_DATA, ListEntry); + ExFreePool(s->Start); + ExFreePool(s); + } + + KeSetAffinityThreadObj(Thread, ActivedProcessors); + } +} + + +BOOLEAN ReadThreadTraceData(HANDLE ThreadId, PVOID Buffer, SIZE_T BufferSize, ULONG_PTR FilterStart, ULONG_PTR FilterEnd, OUT SIZE_T* lpReadSize) +{ + if (BufferSize < sizeof(BTS_RECORD64)) { + return FALSE; + } + + PBTS_RECORD64 pBuf = (PBTS_RECORD64)Buffer; + PBTS_RECORD64 end = (PBTS_RECORD64)((PUCHAR)Buffer + BufferSize - sizeof(BTS_RECORD64)); + + PETHREAD Thread = PsGetCurrentThread(); + // ±éÀúÿ¸öCPUºËÐÄ + for (size_t i = 0; i < MAX_CPU; i++) + { + PLIST_ENTRY header = &ThreadTraceDataHeaderArr[i]; + + // Çл»Ïß³ÌΪ¶ÔÓ¦µÄCPU + KAFFINITY CurrentAffinity = (KAFFINITY)1 << i; + if ((AllayedProcessor & CurrentAffinity) == 0) { + continue; + } + KeSetAffinityThreadObj(Thread, CurrentAffinity); + + // ÿ¸öCPU¶¼ÓÐÒ»´®Á´±í, Á´±íÖеÄÿһÏî¼Ç¼ÁËÏß³ÌÔÚÒ»¶Îʱ¼äƬÖеÄBranch + PLIST_ENTRY listEntry = header->Blink; + while (listEntry != header) + { + THREAD_TRACE_DATA* traceData = CONTAINING_RECORD(listEntry, THREAD_TRACE_DATA, ListEntry); + + if (traceData->ThreadId != ThreadId) { continue; } + if (traceData->End <= traceData->Start) { continue; } + + // ÄæÐò¸´ÖÆÊý¾Ý + PBTS_RECORD64 pData = traceData->End - 1; + while (pData >= traceData->Start) + { + if ( + (pData->from >= FilterStart && pData->from <= FilterEnd) + && (pData->to >= FilterStart && pData->to <= FilterEnd)) + { + //DbgPrint("p : %p data:%p\n", p, data); + RtlCopyMemory(pBuf, pData, sizeof(BTS_RECORD64)); + pBuf++; + } + if (pBuf >= end) { break; } + + pData--; + } + + listEntry = listEntry->Blink; + if (pBuf >= end) { break; } + } + + if (pBuf >= end) { break; } + + } + + KeSetAffinityThreadObj(Thread, ActivedProcessors); + if (lpReadSize) { + *lpReadSize = (ULONG_PTR)pBuf - (ULONG_PTR)Buffer; + } + + return TRUE; +} + + + +/* ¿ªÆôÕë¶ÔÏ̵߳ļà¿Ø */ +BOOLEAN StartMonitThread(HANDLE ThreadId) { + + PETHREAD Thread = NULL; + if (!NT_SUCCESS(PsLookupThreadByThreadId(ThreadId, &Thread))) { + return FALSE; + } + + if (MonitThreadId != 0xFFFFFFFF) { + StopMonitThread((HANDLE)MonitThreadId); + } + + MonitThreadId = (ULONG_PTR)ThreadId; + + KAFFINITY Affinity = (KAFFINITY)1; + KeSetAffinityThreadObj((PKTHREAD)Thread, Affinity); + ObDereferenceObject(Thread); + return TRUE; +} + +/* Í£Ö¹Õë¶ÔÏ̵߳ļà¿Ø */ +VOID StopMonitThread(HANDLE ThreadId) { + + if (ThreadId != NULL) { + + PETHREAD Thread = NULL; + if (NT_SUCCESS(PsLookupThreadByThreadId(ThreadId, &Thread))) { + KeSetAffinityThreadObj((PKTHREAD)Thread, ActivedProcessors); + ObDereferenceObject(Thread); + } + + } + + KdPrint(("Stop Monitor Thread!\n")); + + MonitThreadId = 0xFFFFFFFF; +} + + +VOID NTAPI SwapContextHandler(PREGISTER_CONTEXT Context) { + UNREFERENCED_PARAMETER(Context); + + ULONG CurrentProcessorIndex = KeGetCurrentProcessorIndex(); + + // µ±Ç°Thread + PETHREAD CurrentThread = (PETHREAD)Context->reg64.rdi; + HANDLE CurrentThreadId = PsGetThreadId(CurrentThread); + HANDLE CurrentProcessId = PsGetThreadProcessId(CurrentThread); + + // ´ýÇл»µÄThread + PETHREAD NextThread = (PETHREAD)Context->reg64.rsi; + HANDLE NextThreadId = PsGetThreadId(NextThread); + //HANDLE NextProcessId = PsGetThreadProcessId(NextThread); + + + // ÔÚÏß³ÌÇл»Ç° ½«BTSת´¢µ½Ä¿±ê¿Õ¼ä¡£ + if (ProcessorFlag[CurrentProcessorIndex] == TRUE) { + DisableBTS(); + ProcessorFlag[CurrentProcessorIndex] = FALSE; + + PDS_AREA64 DsArea = g_DSAreaArr[CurrentProcessorIndex]; + + if (DsArea->BTSIndex != DsArea->BTSBufferBase) { + + // ÁíÍâ·ÖÅäһƬ¿Õ¼ä ´æ·Å´úÂë + ULONG64 BufferSize = DsArea->BTSIndex - DsArea->BTSBufferBase; + PVOID allocate = ExAllocatePoolWithTag(NonPagedPool, (size_t)BufferSize, '.STB'); + + // !!!! ÕâÐдúÂëÔËÐÐʱ¼ä×£¬¿¨¶Ù»ù±¾¶¼ÊÇÒòΪÕâ¸öÔì³ÉµÄ¡£ + memcpy(allocate, (PVOID)DsArea->BTSBufferBase, (size_t)BufferSize); + + THREAD_TRACE_DATA* s = (THREAD_TRACE_DATA*)ExAllocatePoolWithTag(NonPagedPool, sizeof(THREAD_TRACE_DATA), '.STB'); + s->Start = (PBTS_RECORD64)allocate; + s->End = (PBTS_RECORD64)((PUCHAR)allocate + BufferSize); + s->ThreadId = CurrentThreadId; + s->ProcessId = CurrentProcessId; + InsertTailList(&ThreadTraceDataHeaderArr[CurrentProcessorIndex], &s->ListEntry); + + // ÖØÖà Index + DsArea->BTSIndex = DsArea->BTSBufferBase; + } + } + + + // ¸ù¾ÝÏß³ÌID¿ªÆô BTS + if ((ULONG_PTR)NextThreadId == MonitThreadId) { + EnableBTS(); + ProcessorFlag[CurrentProcessorIndex] = TRUE; + } + return; +} + + +NTSTATUS SetupBTS() { + + // ¼ì²éBTS + DbgPrint("Support DS: %s\n", CheckSupportDS() ? "yes" : "no"); + DbgPrint("Support DS64: %s\n", CheckSupportDS64() ? "yes" : "no"); + DbgPrint("Avaliable BTS: %s\n", CheckAvaliableBTS() ? "yes" : "no"); + DbgPrint("Avaliable PEBS: %s\n", CheckAvaliablePEBS() ? "yes" : "no"); + if (!CheckSupportDS() && !CheckSupportDS64() && !CheckAvaliableBTS() && !CheckAvaliablePEBS()) { + DbgPrint("BTS Not Support !\n"); + return STATUS_UNSUCCESSFUL; + } + + if (KeSetAffinityThreadObj == NULL) { + DbgPrint("Not found KeSetAffinityThread Routine!\n"); + return STATUS_UNSUCCESSFUL; + } + + + PKTHREAD Thread = KeGetCurrentThread(); + ObReferenceObjectByPointer(Thread, 0, *PsThreadType, KernelMode); + + UCHAR Flag = TRUE; + for (size_t i = 0; i < ProcessorCount; i++) + { + KAFFINITY CurrentAffinity = (KAFFINITY)1 << i; + if ((ActivedProcessors & CurrentAffinity) == 0) { + continue; + } + + PDS_AREA64 DebugStoreArea = NULL; + PBTS_RECORD64 BtsBuffer = NULL; + +#define BUFFER_SIZE 0x100000 + + // ·ÖÅäDebugStoreArea + DebugStoreArea = (PDS_AREA64)ExAllocatePoolWithTag(NonPagedPool, sizeof(DS_AREA64), 'STB.'); + if (DebugStoreArea == NULL) { goto _label_clear; } + memset(DebugStoreArea, 0, sizeof(DS_AREA64)); + + // ·ÖÅäBTS buffer + BtsBuffer = (PBTS_RECORD64)ExAllocatePoolWithTag(NonPagedPool, BUFFER_SIZE, 'STB.'); + if (BtsBuffer == NULL) { goto _label_clear; } + memset(BtsBuffer, 0, BUFFER_SIZE); + ULONG BtsRecordCount = BUFFER_SIZE / sizeof(BTS_RECORD64); + //ULONG BtsRecordCount = 10; + PBTS_RECORD64 BtsAbsoluteMaximum = BtsBuffer + BtsRecordCount; + PBTS_RECORD64 BtsInterruptThreshold = BtsBuffer + BtsRecordCount + 1; + + DebugStoreArea->BTSBufferBase = (ULONG64)BtsBuffer; + DebugStoreArea->BTSIndex = (ULONG64)BtsBuffer; + DebugStoreArea->BTSAbsoluteMaximum = (ULONG64)BtsAbsoluteMaximum; + DebugStoreArea->BTSInterruptThreshold = (ULONG64)BtsInterruptThreshold; + + DbgPrint("Processor[%d] Debug Store Area:%p\n", i, DebugStoreArea); + + // Çл»CPU + KeSetAffinityThreadObj(Thread, CurrentAffinity); + _disable(); + SetDebugStoreArea(DebugStoreArea); + _enable(); + KeSetAffinityThreadObj(Thread, ActivedProcessors); + + AllayedProcessor |= (KAFFINITY)1 << i; + g_DSAreaArr[i] = DebugStoreArea; + g_BtsBufferArr[i] = BtsBuffer; + continue; + + _label_clear: + if (DebugStoreArea) { ExFreePool(DebugStoreArea); } + if (BtsBuffer) { ExFreePool(BtsBuffer); } + Flag = FALSE; + break; + } + ObDereferenceObject(Thread); + + + + if (Flag) { + DbgPrint("SetupBTS Completed!\n"); + + // Hook SwapContext + PVOID KernelBase = GetKernelBase(NULL); + PVOID SourceCode = (PUCHAR)KernelBase + 0x153af0; + INTERCEPT_CREATE CreateInfo = { 0 }; + CreateInfo.patchType = PUSH_RET_14; + InsertIntercept64(SourceCode, SwapContextHandler, &CreateInfo, &InterceptInfo); + DbgPrint("Hook SwapContext Success!\n"); + + return STATUS_SUCCESS; + } + else { + DbgPrint("SetupBTS Failed!\n"); + ResetBTS(); + return STATUS_UNSUCCESSFUL; + } + + +} +VOID ResetBTS() { + PKTHREAD Thread = KeGetCurrentThread(); + ObReferenceObjectByPointer(Thread, 0, *PsThreadType, KernelMode); + for (size_t i = 0; i < ProcessorCount; i++) + { + + KAFFINITY CurrentAffinity = (KAFFINITY)1 << i; + if ((AllayedProcessor & CurrentAffinity) == 0) { + continue; + } + + // Çл»CPU + KeSetAffinityThreadObj(Thread, CurrentAffinity); + _disable(); + DisableBTS(); + SetDebugStoreArea(0); + _enable(); + KeSetAffinityThreadObj(Thread, ActivedProcessors); + + AllayedProcessor &= ~CurrentAffinity; + // ÊÍ·ÅÄÚ´æ + if (g_DSAreaArr[i]) { + ExFreePool(g_DSAreaArr[i]); + g_DSAreaArr[i] = NULL; + } + if (g_BtsBufferArr[i]) { + ExFreePool(g_BtsBufferArr[i]); + g_BtsBufferArr[i] = NULL; + } + + } + ObDereferenceObject(Thread); + + // Unhook + RemoveIntercept(&InterceptInfo); +} + + + diff --git a/BranchTracerSys/bts/bts.h b/BranchTracerSys/bts/bts.h new file mode 100644 index 0000000..003cba5 --- /dev/null +++ b/BranchTracerSys/bts/bts.h @@ -0,0 +1,103 @@ +#pragma once +#include + + +typedef struct _DS_AREA64 { + /*BTS*/ + ULONG64 BTSBufferBase; + ULONG64 BTSIndex; + ULONG64 BTSAbsoluteMaximum; + ULONG64 BTSInterruptThreshold; + + /*PEBS*/ + ULONG64 PEBSBufferBase; + ULONG64 PEBSIndex; + ULONG64 PEBSMaximum; + ULONG64 PEBSThreshold; + ULONG64 counter0; + ULONG64 counter1; + ULONG64 reserved; + +}DS_AREA64, * PDS_AREA64; + +typedef struct _DS_AREA32 { + /*BTS*/ + ULONG BTSBufferBase; + ULONG BTSIndex; + ULONG BTSMaximum; + ULONG BTSThreshold; + + /*PEBS*/ + ULONG PEBSBufferBase; + ULONG PEBSIndex; + ULONG PEBSMaximum; + ULONG PEBSThreshold; + ULONG counter0; + ULONG counter1; + ULONG counter2; + ULONG counter3; + ULONG reserved; + +}DS_AREA32, * PDS_AREA32; + + +typedef struct _BTS_RECORD64 +{ + ULONG64 from; // ¼Ç¼·ÖÖ§µÄÔ´µØÖ· + ULONG64 to; // ¼Ç¼·ÖÖ§µÄÄ¿±êµØÖ· + ULONG64 branchPredicted; +}BTS_RECORD64, * PBTS_RECORD64; + +//typedef struct _BTS_RECORD32 +//{ +// ULONG32 from; // ¼Ç¼·ÖÖ§µÄÔ´µØÖ· +// ULONG32 to; // ¼Ç¼·ÖÖ§µÄÄ¿±êµØÖ· +// ULONG32 branchPredicted; +//}BTS_RECORD32, * PBTS_RECORD32; + + +typedef struct _PEBS_RECORD64 +{ + ULONG64 rflags; + ULONG64 rip; + ULONG64 rax; + ULONG64 rbx; + ULONG64 rcx; + ULONG64 rdx; + ULONG64 rsi; + ULONG64 rdi; + ULONG64 rbp; + ULONG64 rsp; + ULONG64 r8; + ULONG64 r9; + ULONG64 r10; + ULONG64 r11; + ULONG64 r12; + ULONG64 r13; + ULONG64 r14; + ULONG64 r15; +}PEBS_RECORD64,*PPEBS_RECORD64; + +typedef struct _PEBS_RECORD32 +{ + ULONG eflags; + ULONG eip; + ULONG eax; + ULONG ebx; + ULONG ecx; + ULONG edx; + ULONG esi; + ULONG edi; + ULONG ebp; + ULONG esp; +}PEBS_RECORD32, * PPEBS_RECORD32; + + + +VOID InitializeEnvironment(); +VOID ClearThreadTraceData(); +BOOLEAN ReadThreadTraceData(HANDLE ThreadId, PVOID Buffer, SIZE_T BufferSize, ULONG_PTR FilterStart, ULONG_PTR FilterEnd, OUT SIZE_T* lpReadSize); +BOOLEAN StartMonitThread(HANDLE ThreadId); +VOID StopMonitThread(HANDLE ThreadId); +NTSTATUS SetupBTS(); +VOID ResetBTS(); diff --git a/BranchTracerSys/ioctls.h b/BranchTracerSys/ioctls.h new file mode 100644 index 0000000..d2837ab --- /dev/null +++ b/BranchTracerSys/ioctls.h @@ -0,0 +1,53 @@ +#pragma once + +#ifdef _WDMDDK_ +#include +#else +#include +#endif + +#define IOCTL_START_THREAD_TRACE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x808, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STOP_THREAD_TRACE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x809, METHOD_BUFFERED, FILE_ANY_ACCESS) + + +typedef struct _START_THREAD_TRACE_PARAM { + union + { + ULONG_PTR ThreadId; + ULONG64 ullThreadId; + }; +}START_THREAD_TRACE_PARAM, * PSTART_THREAD_TRACE_PARAM; + +typedef struct _STOP_THREAD_TRACE_PARAM { + union + { + ULONG_PTR ThreadId; + ULONG64 ullThreadId; + }; + + union { + ULONG_PTR FilterStart; + ULONG64 ullFilterStart; + }; + + union { + ULONG_PTR FilterEnd; + ULONG64 ullFilterStop; + }; + + union { + SIZE_T ReadSize; + ULONG64 ullReadSize; + }; + + union { + PVOID Buffer; + ULONG64 ullBuffer; + }; + union { + SIZE_T BufferSize; + ULONG64 ullBufferSize; + }; + + +}STOP_THREAD_TRACE_PARAM, * PSTOP_THREAD_TRACE_PARAM; diff --git a/BranchTracerSys/runsdvui.cmd b/BranchTracerSys/runsdvui.cmd new file mode 100644 index 0000000..1ea6e4a --- /dev/null +++ b/BranchTracerSys/runsdvui.cmd @@ -0,0 +1,2 @@ +cd /d "E:\Projects\windows-debugger-research\BranchTracer\BranchTracerSys" &msbuild "BranchTracerSys.vcxproj" /t:sdvViewer /p:configuration="Debug" /p:platform="x64" /p:SolutionDir="E:\Projects\windows-debugger-research" +exit %errorlevel% \ No newline at end of file