PG2 BYPASS源码阅读 学习x64解密定时器、特征码定位

来源:互联网 发布:电子地图数据规范 编辑:程序博客网 时间:2024/04/29 10:37

以前没有接触过x64内核编程,借这份代码来学习一下,源码 http://www.codeproject.com/Articles/28318/Bypassing-PatchGuard-3


之前说到过PG3的一些机制,下面根据源码回顾一下


PG可能会queue一些dpc来触发syscheck,其中dpc context传入的是非传统地址,从而触发异常,转到异常处理去执行PG。

所以要判断dpc context

BOOLEAN CheckSubValue(ULONGLONG InValue){ULONGi;ULONGResult;UCHAR*Chars = (UCHAR*)&InValue;// random values will have a result around 120...Result = 0;for(i = 0; i < 8; i++){Result += ((Chars[i] & 0xF0) >> 4) + (Chars[i] & 0x0F);}// the maximum value is 240, so this should be safe...if(Result < 70)return TRUE;return FALSE;}BOOLEAN PgIsPatchGuardContext(void* Ptr){ULONGLONGValue = (ULONGLONG)Ptr;UCHAR*Chars = (UCHAR*)&Value;LONGi;// this is a requirement for a canonical pointer...//合法地址if((Value & 0xFFFF000000000000) == 0xFFFF000000000000)return FALSE;//0 也不是非法的if((Value & 0xFFFF000000000000) == 0)return FALSE;// sieve out other common values...//检测随机数?if(CheckSubValue(Value) || CheckSubValue(~Value))return FALSE;if(Ptr == NULL)return FALSE;//This must be the last check and filters latin-char UTF16 strings...//检测字符串for(i = 7; i >= 0; i -= 2){if(Chars[i] != 0)return TRUE;}// this should only return true if the pointer is a unicode string!!!return FALSE;}

这个检测还是考虑了不少情况,接下来是获得dpc加密key的方法


NTSTATUS PgInitialize(){void*SymbolArray[MAX_SYMBOL_COUNT];void*ValidationArray[MAX_SYMBOL_COUNT];void*IntersectionArray[MAX_SYMBOL_COUNT];ULONGiSymbol;ULONGIndex;ULONGMatchCount;KTIMERTestTimer;KDPCTestTimerDpc;LARGE_INTEGERTimerDueTime = {0};ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);/*Extract and validate methods...搜索同步用的未导出api,还是很谨慎的,用KeCancelTimer和KeSetTimerEx对比进行定位*/if(!ExtractSymbolAddresses((void*)KeCancelTimer, FALSE, 0xE8, OUT SymbolArray) ||!ExtractSymbolAddresses((void*)KeSetTimerEx, FALSE, 0xE8, OUT ValidationArray))return STATUS_NOT_SUPPORTED;if(IntersectSymbolAddresses(SymbolArray, ValidationArray, OUT IntersectionArray) != 5)return STATUS_NOT_SUPPORTED;KiAcquireDispatcherLockRaiseToSynch = IntersectionArray[0];KeAcquireQueuedSpinLockAtDpcLevel = IntersectionArray[1];KeReleaseQueuedSpinLockFromDpcLevel = IntersectionArray[2];KiReleaseDispatcherLockFromSynchLevel = IntersectionArray[3];KiExitDispatcher = IntersectionArray[4];/*Extract KiTimerTableListHead...*/if(!ExtractSymbolAddresses((void*)KeCancelTimer, TRUE, 0x8D48, OUT SymbolArray))return STATUS_NOT_SUPPORTED;if(!ExtractSymbolAddresses((void*)KeSetTimerEx, TRUE, 0x8D48, OUT ValidationArray))return STATUS_NOT_SUPPORTED;MatchCount = IntersectSymbolAddresses(SymbolArray, ValidationArray, OUT IntersectionArray);for(iSymbol = 0; iSymbol < MatchCount; iSymbol++){if(ValidateTimerTable(IntersectionArray[iSymbol])){// check if we found ambiguous symbol referencesKiTimerTableListHead = IntersectionArray[iSymbol];break;}}if(KiTimerTableListHead == NULL)return STATUS_NOT_SUPPORTED;/*Create test timer...We use a well known, probably unique DeferredContext for later identification...*/KeInitializeTimer(&TestTimer);KeInitializeDpc(&TestTimerDpc, OnTestTimerInvokation, (void*)PgInitialize);__try{KeSetTimerEx(&TestTimer, TimerDueTime, 10000, &TestTimerDpc);/*Extract KiWaitAlways and KiWaitNever一个特征码找到这两个值,然后验证*/if(!ExtractSymbolAddresses((void*)KeSetTimerEx, TRUE, 0x8B48, OUT SymbolArray))return STATUS_NOT_SUPPORTED;for(iSymbol = 0; iSymbol < MAX_SYMBOL_COUNT; iSymbol++){if(SymbolArray[iSymbol] == NULL)break;for(Index = 0; Index < MAX_SYMBOL_COUNT; Index++){if(SymbolArray[Index] == NULL)break;if(iSymbol == Index)continue;if(!ProbeAndSetKeys(&TestTimer,(ULONGLONG*)SymbolArray[iSymbol],(ULONGLONG*)SymbolArray[Index]))continue;return STATUS_SUCCESS;}}return STATUS_NOT_SUPPORTED;}__finally{// cleanup resourcesKeCancelTimer(&TestTimer);}}

PG2非常简单,直接摘掉dpc了事


BOOLEAN PgDisablePatchGuard(PDEVICE_OBJECT InDevice){KIRQLOldIrql;ULONGIndex;PKSPIN_LOCK_QUEUELockQueue;PKTIMER_TABLE_ENTRYTimerListHead;PLIST_ENTRYTimerList;PKTIMERTimer;PKDPCTimerDpc;/*Lock the dispatcher database and loop through the timer list...We will cancel all timers that have a non-canonical DeferredContext.*/OldIrql = KiAcquireDispatcherLockRaiseToSynch();for(Index = 0; Index < TIMER_TABLE_SIZE; Index++){LockQueue = KeTimerIndexToLockQueue((UCHAR)(Index & 0xFF));KeAcquireQueuedSpinLockAtDpcLevel(LockQueue);// now we can work with the timer list...TimerListHead = &KiTimerTableListHead[Index];TimerList = TimerListHead->Entry.Flink;while(TimerList != (PLIST_ENTRY)TimerListHead){// is DPC patched?Timer = CONTAINING_RECORD(TimerList, KTIMER, TimerListEntry);TimerList = TimerList->Flink;TimerDpc = PgDeobfuscateTimerDpc(Timer);if(TimerDpc == NULL)continue;if(PgIsPatchGuardContext(TimerDpc->DeferredContext) && KeContainsSymbol(TimerDpc->DeferredRoutine)){// this will cancel the timer...Timer->Header.Inserted = FALSE;if(RemoveEntryList(&Timer->TimerListEntry))TimerListHead->Time.HighPart = 0xFFFFFFFF;}}KeReleaseQueuedSpinLockFromDpcLevel(LockQueue);}KiReleaseDispatcherLockFromSynchLevel();KiExitDispatcher(OldIrql);return TRUE;}

原创粉丝点击