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

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


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


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

所以要判断dpc context

BOOLEAN CheckSubValue(ULONGLONG InValue)
{
	ULONG			i;
	ULONG			Result;
	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)
{
	ULONGLONG		Value = (ULONGLONG)Ptr;
	UCHAR*			Chars = (UCHAR*)&Value;
	LONG			i;

	// 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];
	ULONG				iSymbol;
	ULONG				Index;
	ULONG				MatchCount;
	KTIMER				TestTimer;
	KDPC				TestTimerDpc;
	LARGE_INTEGER		TimerDueTime = {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 references
			KiTimerTableListHead = 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 resources
		KeCancelTimer(&TestTimer);
	}
}

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


BOOLEAN PgDisablePatchGuard(PDEVICE_OBJECT InDevice)
{
	KIRQL					OldIrql;
	ULONG					Index;
	PKSPIN_LOCK_QUEUE		LockQueue;
	PKTIMER_TABLE_ENTRY		TimerListHead;
	PLIST_ENTRY				TimerList;
	PKTIMER					Timer;
	PKDPC					TimerDpc;

	/*
		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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值