mirror of
https://github.com/donnaskiez/ac.git
synced 2024-11-21 22:24:08 +01:00
simple exception hooking detection
This commit is contained in:
parent
08b059bee9
commit
0b729a6fa0
4 changed files with 63 additions and 20 deletions
|
@ -9,6 +9,8 @@ open source anti cheat (lol) which I made for fun.
|
||||||
- NMI stackwalking via isr iretq
|
- NMI stackwalking via isr iretq
|
||||||
- APC stackwalking via RtlCaptureStackBackTrace
|
- APC stackwalking via RtlCaptureStackBackTrace
|
||||||
- DPC stackwalking via RtlCaptureStackBackTrace
|
- DPC stackwalking via RtlCaptureStackBackTrace
|
||||||
|
- Return address exception hooking detection
|
||||||
|
- Chained .data pointer detection (iffy)
|
||||||
- Handle stripping via obj callbacks
|
- Handle stripping via obj callbacks
|
||||||
- Process handle table enumeration
|
- Process handle table enumeration
|
||||||
- System module device object verification
|
- System module device object verification
|
||||||
|
@ -27,7 +29,7 @@ open source anti cheat (lol) which I made for fun.
|
||||||
|
|
||||||
# architecuture
|
# architecuture
|
||||||
|
|
||||||
For an overview of the architecture, see architecture.md.
|
- todo!
|
||||||
|
|
||||||
# planned features
|
# planned features
|
||||||
|
|
||||||
|
|
|
@ -260,7 +260,7 @@ IrpQueueAllocateDeferredPacket(_In_ PVOID Buffer, _In_ UINT32 BufferSize)
|
||||||
return report;
|
return report;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MAX_DEFERRED_REPORTS_COUNT 100
|
#define MAX_DEFERRED_REPORTS_COUNT 256
|
||||||
|
|
||||||
STATIC
|
STATIC
|
||||||
VOID
|
VOID
|
||||||
|
|
|
@ -497,6 +497,14 @@ end:
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FORCEINLINE
|
||||||
|
STATIC
|
||||||
|
BOOLEAN
|
||||||
|
IsUserModeAddress(_In_ UINT64 Rip)
|
||||||
|
{
|
||||||
|
return Rip <= WINDOWS_USERMODE_MAX_ADDRESS ? TRUE : FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
HandleValidateDriversIOCTL()
|
HandleValidateDriversIOCTL()
|
||||||
{
|
{
|
||||||
|
@ -638,7 +646,8 @@ ReportMissingCidTableEntry(_In_ PNMI_CONTEXT Context)
|
||||||
|
|
||||||
STATIC
|
STATIC
|
||||||
VOID
|
VOID
|
||||||
ReportInvalidRipFoundDuringNmi(_In_ PNMI_CONTEXT Context)
|
ReportInvalidRipFoundDuringNmi(_In_ PNMI_CONTEXT Context,
|
||||||
|
_In_ UINT32 ReportSubCode)
|
||||||
{
|
{
|
||||||
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
||||||
UINT32 packet_size =
|
UINT32 packet_size =
|
||||||
|
@ -650,7 +659,7 @@ ReportInvalidRipFoundDuringNmi(_In_ PNMI_CONTEXT Context)
|
||||||
if (!report)
|
if (!report)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
INIT_REPORT_PACKET(report, REPORT_NMI_CALLBACK_FAILURE, 0);
|
INIT_REPORT_PACKET(report, REPORT_NMI_CALLBACK_FAILURE, ReportSubCode);
|
||||||
|
|
||||||
report->kthread_address = Context->kthread;
|
report->kthread_address = Context->kthread;
|
||||||
report->invalid_rip = Context->interrupted_rip;
|
report->invalid_rip = Context->interrupted_rip;
|
||||||
|
@ -667,6 +676,34 @@ ReportInvalidRipFoundDuringNmi(_In_ PNMI_CONTEXT Context)
|
||||||
IrpQueueSchedulePacket(report, packet_size);
|
IrpQueueSchedulePacket(report, packet_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define INSTRUCTION_UD2_BYTE_1 0x0F
|
||||||
|
#define INSTRUCTION_UD2_BYTE_2 0x0B
|
||||||
|
#define INSTRUCTION_INT3_BYTE_1 0xCC
|
||||||
|
|
||||||
|
STATIC
|
||||||
|
BOOLEAN
|
||||||
|
DoesRetInstructionCauseException(_In_ UINT64 ReturnAddress)
|
||||||
|
{
|
||||||
|
/* UD2 instruction is 2 bytes*/
|
||||||
|
UCHAR opcodes[2] = {0};
|
||||||
|
|
||||||
|
/* we deal with um later */
|
||||||
|
if (IsUserModeAddress(ReturnAddress))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
RtlCopyMemory(&opcodes, ReturnAddress, sizeof(opcodes));
|
||||||
|
|
||||||
|
if (opcodes[0] == INSTRUCTION_UD2_BYTE_1 &&
|
||||||
|
opcodes[1] == INSTRUCTION_UD2_BYTE_2)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (opcodes[0] == INSTRUCTION_INT3_BYTE_1)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
DEBUG_VERBOSE("Ret address instruction doesnt throw exception");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* todo: i think we should split this function up into each analysis i.e one for
|
* todo: i think we should split this function up into each analysis i.e one for
|
||||||
* the interrupted rip, one for the cid etc.
|
* the interrupted rip, one for the cid etc.
|
||||||
|
@ -718,16 +755,19 @@ AnalyseNmiData(_In_ PNMI_CONTEXT NmiContext, _In_ PSYSTEM_MODULES SystemModules)
|
||||||
* PsGetNextProcess ?
|
* PsGetNextProcess ?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!DoesThreadHaveValidCidEntry(NmiContext[core].kthread)) {
|
if (!DoesThreadHaveValidCidEntry(NmiContext[core].kthread))
|
||||||
ReportMissingCidTableEntry(&NmiContext[core]);
|
ReportMissingCidTableEntry(&NmiContext[core]);
|
||||||
}
|
|
||||||
|
|
||||||
if (NmiContext[core].user_thread)
|
if (NmiContext[core].user_thread)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (DoesRetInstructionCauseException(NmiContext[core].interrupted_rip))
|
||||||
|
ReportInvalidRipFoundDuringNmi(
|
||||||
|
&NmiContext[core], REPORT_SUBTYPE_EXCEPTION_THROWING_RET);
|
||||||
|
|
||||||
if (IsInstructionPointerInInvalidRegion(
|
if (IsInstructionPointerInInvalidRegion(
|
||||||
NmiContext[core].interrupted_rip, SystemModules))
|
NmiContext[core].interrupted_rip, SystemModules))
|
||||||
ReportInvalidRipFoundDuringNmi(&NmiContext[core]);
|
ReportInvalidRipFoundDuringNmi(&NmiContext[core], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
|
@ -749,14 +789,6 @@ GetIsrMachineFrame(_In_ TASK_STATE_SEGMENT_64* TaskStateSegment)
|
||||||
return TaskStateSegment->Ist3 - sizeof(MACHINE_FRAME);
|
return TaskStateSegment->Ist3 - sizeof(MACHINE_FRAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCEINLINE
|
|
||||||
STATIC
|
|
||||||
BOOLEAN
|
|
||||||
IsUserModeAddress(_In_ UINT64 Rip)
|
|
||||||
{
|
|
||||||
return Rip <= WINDOWS_USERMODE_MAX_ADDRESS ? TRUE : FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
STATIC BOOLEAN
|
STATIC BOOLEAN
|
||||||
NmiCallback(_Inout_opt_ PVOID Context, _In_ BOOLEAN Handled)
|
NmiCallback(_Inout_opt_ PVOID Context, _In_ BOOLEAN Handled)
|
||||||
{
|
{
|
||||||
|
@ -1266,7 +1298,9 @@ CheckForDpcCompletion(_In_ PDPC_CONTEXT Context)
|
||||||
|
|
||||||
STATIC
|
STATIC
|
||||||
VOID
|
VOID
|
||||||
ReportDpcStackwalkViolation(_In_ PDPC_CONTEXT Context, _In_ UINT64 Frame)
|
ReportDpcStackwalkViolation(_In_ PDPC_CONTEXT Context,
|
||||||
|
_In_ UINT64 Frame,
|
||||||
|
_In_ UINT32 ReportSubtype)
|
||||||
{
|
{
|
||||||
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
||||||
UINT32 packet_size =
|
UINT32 packet_size =
|
||||||
|
@ -1278,7 +1312,7 @@ ReportDpcStackwalkViolation(_In_ PDPC_CONTEXT Context, _In_ UINT64 Frame)
|
||||||
if (!report)
|
if (!report)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
INIT_REPORT_PACKET(report, REPORT_DPC_STACKWALK, 0);
|
INIT_REPORT_PACKET(report, REPORT_DPC_STACKWALK, ReportSubtype);
|
||||||
|
|
||||||
report->kthread_address = PsGetCurrentThread();
|
report->kthread_address = PsGetCurrentThread();
|
||||||
report->invalid_rip = Frame;
|
report->invalid_rip = Frame;
|
||||||
|
@ -1306,11 +1340,17 @@ ValidateDpcStackFrame(_In_ PDPC_CONTEXT Context, _In_ PSYSTEM_MODULES Modules)
|
||||||
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
||||||
BOOLEAN flag = FALSE;
|
BOOLEAN flag = FALSE;
|
||||||
|
|
||||||
|
/* With regards to this, lets only check the interrupted rip */
|
||||||
|
if (DoesRetInstructionCauseException(Context->stack_frame[0]))
|
||||||
|
ReportDpcStackwalkViolation(Context,
|
||||||
|
Context->stack_frame[0],
|
||||||
|
REPORT_SUBTYPE_EXCEPTION_THROWING_RET);
|
||||||
|
|
||||||
for (UINT32 frame = 0; frame < Context->frames_captured; frame++) {
|
for (UINT32 frame = 0; frame < Context->frames_captured; frame++) {
|
||||||
UINT64 rip = Context->stack_frame[frame];
|
UINT64 rip = Context->stack_frame[frame];
|
||||||
|
|
||||||
if (IsInstructionPointerInInvalidRegion(rip, Modules))
|
if (IsInstructionPointerInInvalidRegion(rip, Modules))
|
||||||
ReportDpcStackwalkViolation(Context, rip);
|
ReportDpcStackwalkViolation(Context, rip, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,9 @@
|
||||||
#define REPORT_SELF_DRIVER_PATCHED 160
|
#define REPORT_SELF_DRIVER_PATCHED 160
|
||||||
#define REPORT_BLACKLISTED_PCIE_DEVICE 170
|
#define REPORT_BLACKLISTED_PCIE_DEVICE 170
|
||||||
|
|
||||||
#define REPORT_SUBTYPE_NO_BACKING_MODULE 0x0
|
#define REPORT_SUBTYPE_NO_BACKING_MODULE 0x0
|
||||||
#define REPORT_SUBTYPE_INVALID_DISPATCH 0x1
|
#define REPORT_SUBTYPE_INVALID_DISPATCH 0x1
|
||||||
|
#define REPORT_SUBTYPE_EXCEPTION_THROWING_RET 0x2
|
||||||
|
|
||||||
#define PACKET_TYPE_REPORT 0x0
|
#define PACKET_TYPE_REPORT 0x0
|
||||||
#define PACKET_TYPE_HEARTBEAT 0x1
|
#define PACKET_TYPE_HEARTBEAT 0x1
|
||||||
|
|
Loading…
Reference in a new issue