欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]ShadowWalker内存伪装详细过程,附完整测试源码

[原创]ShadowWalker内存伪装详细过程,附完整测试源码

ShadowWalker内存伪装详细过程
一。准备
提问http://bbs.pediy.com/showthread.php?t=183520
ShadowWalker原理,部分代码参照这里http://bbs.pediy.com/showthread.php?t=56689
内存分页机制http://bbs.pediy.com/showthread.php?t=135274
内存分页机制http://bbs.pediy.com/showthread.php?t=181016
二。目的
这是需要伪装的代码,需要用新的code_seg进行伪装

#pragma code_seg(".target") 
#pragma optimize( "", off )
VOID target()
{
	int sum=0x77;
	if(sum==0)
	{
		_asm _emit(0xc3)//返回指令Retn
	}
	_asm
	{
		mov eax,0x88
			mov sum,eax
	}
	DbgPrint("sum=%x g_iTimes=%d g_iTimes1=%d g_iTimes2=%d g_iTimes3=%d\n",sum,g_iTimes,g_iTimes1,g_iTimes2,g_iTimes3);
}
#pragma optimize( "", on ) 
#pragma code_seg() 


//每十秒调用执行target
VOID OnTimer(
	IN PDEVICE_OBJECT DeviceObject,
	IN PVOID Context)
{
	if(g_iTimes%10==9)
	{
		target();
	}
	g_iTimes++;
}

//可以读取target的内存
NTSTATUS HelloDDKDispatchRoutin(IN PDEVICE_OBJECT pDevObj,
	IN PIRP pIrp) 
{
	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
	UCHAR type = stack->MajorFunction;
	IoCompleteRequest( pIrp, IO_NO_INCREMENT );
	if(type==IRP_MJ_READ)
	{
		BYTE buf[5]={0};
		memcpy(buf,(PBYTE)g_pExecutePage+0x14,5);
		DbgPrint("buf %x %x %x %x %x\n",buf[0],buf[1],buf[2],buf[3],buf[4]);
	}
	return STATUS_SUCCESS;
}


在没有内存伪装时是正常输出

我的目的是
让汇编执行时是mov eax,0x88 对应内存B8 88 00 00 00
但是HelloDDKDispatchRoutin查看时是mov eax,0x99999999 对应内存 B8 99 99 99 99

三。ShadowWalker
首先进行中断0X0EHook,并修改内存页为不存在
DWORD nSetThreadRVA=GetAPIAddr((PVOID)g_pNtKernelBaseAddr,"KeSetAffinityThread");
	g_pFunKeSetAffinityThread=(DWORD)g_pNtKernelBaseAddr+nSetThreadRVA;
	DbgPrint("GsDriverEntry NumberOfProcessors=%d pFunSetThread=0x%x \n",KeNumberProcessors,g_pFunKeSetAffinityThread);
	//Hook IDT
	int i=1;
	for(i=1;i<=KeNumberProcessors;i++)
	{
		((KeSetAffinityThread)((PVOID)g_pFunKeSetAffinityThread))( KeGetCurrentThread(), i);//绑定CPU
		HookTrap0E();
	}
	PBYTE pHookAddr=(PBYTE)target;
	if(MmIsAddressValid(pHookAddr))
	{
		PVOID pReadWriteView = AllocateViewOfPage( (PBYTE)pHookAddr);
		if(pReadWriteView)
		{
			HookMemoryPage(  (PBYTE)pHookAddr, pReadWriteView, (PBYTE)target+0x13); 
		}
		int i=1;
		for(i=1;i<=KeNumberProcessors;i++)
		{
			((KeSetAffinityThread)((PVOID)g_pFunKeSetAffinityThread))( KeGetCurrentThread(), i);//绑定CPU
			__asm invlpg g_pExecutePage
		}
	}

这里是生成读操作时,需要伪装的内存
PVOID AllocateViewOfPage( PVOID VirtualAddress)
{
	if(g_pMDL || g_pNewPage)
	{
		return NULL;
	}
	PVOID pPage = RoundDownToPageBoundary( VirtualAddress );
	DWORD offset=(DWORD)VirtualAddress-(DWORD)pPage+0x14;
	if( IsInLargePage( VirtualAddress ) )
	{
		PHYSICAL_ADDRESS HighestAddress = { HIGHEST_ADDRESS_IN_LARGE_PAGE_RANGE, 0 }; 
		g_pNewPage = ExAllocatePoolWithTag( PagedPool, 2*LARGE_PAGE_SIZE, 'SWHK');
		if( g_pNewPage != NULL)	
		{
			g_pNewPage = RoundUpToPageBoundary( g_pNewPage );
			RtlCopyMemory( g_pNewPage, pPage, LARGE_PAGE_SIZE ); //copy the contents of the page containing VirtualAddress to the new page
			RtlCopyMemory( (PVOID)((DWORD)g_pNewPage+offset), "\xB8\x99\x99\x99\x99", 5 );//把内存修改为\xB8\x99\x99\x99\x99
		}
		return g_pNewPage;
	}//end if
	else
	{
		g_pNewPage = ExAllocatePoolWithTag( PagedPool, PAGE_SIZE, 'SWHK');
		g_pMDL = IoAllocateMdl( g_pNewPage, PAGE_SIZE, FALSE, FALSE, NULL);
		MmProbeAndLockPages( g_pMDL, KernelMode, IoReadAccess);
		if( g_pNewPage != NULL)	
		{
			RtlCopyMemory( g_pNewPage, pPage, PAGE_SIZE ); //copy the contents of the page containing VirtualAddress to the new page
			RtlCopyMemory( (PVOID)((DWORD)g_pNewPage+offset), "\xB8\x99\x99\x99\x99", 5 ); //把内存修改为\xB8\x99\x99\x99\x99
		}
		return g_pNewPage;
	}//end else
}//end AllocateReadWriteViewOfPage

最主要部分,挂钩内存缺页处理函数
#pragma LOCKEDCODE
void __declspec (naked) my_interrupt_hook(void)
{
	//__asm      jmp old_ISR_pointer
	__asm                                                   
	{        
		pushad      
		mov eax,cr2
		push eax
		mov edx, dword ptr [esp+0x24] //PageFault.ErrorCode
		test edx, 1  //不是缺页错误
			jne PassDown
			mov eax,cr2     //faulting virtual address 
			////////////////////////////////////////
			//判断是否是Hook掉的page
			/////////////////////////////////////////
			mov ebx, g_pExecutePage
 			and  ebx, 0xFFFFF000
 			and  eax, 0xFFFFF000
			cmp eax, ebx
			mov eax, cr2  
			jnz PassDown  //不是,传下去
			///////////////////////////////////////         
			//下面处理Hook掉的页面了 
			/////////////////////////////////////           
			mov eax, cr2                                                                  
			push eax
			//*************************GetPteAddress***********************************************
			//push eax
			//call GetPteAddress
			//
			mov edx, eax
			cli			//disable interrupts
			mov esi, PROCESS_PAGE_DIR_BASE
			shr eax, 22
			lea eax, [esi + eax*4]  //pointer to page directory entry (PDE)
			test [eax], 0x80
			jnz Done	//it's a large page
			mov esi, PROCESS_PAGE_TABLE_BASE
			shr edx, 12
			lea eax, [esi + edx*4]  //pointer to page table entry (PTE)
			//NOTE: There is not a page table for large pages because the PTE's are contained in the page directory.
Done:
			sti		//reenable interrupts
			//*************************GetPteAddress***********************************************
			mov ebx, eax  //ebx = pPte
 			pop eax           
 			mov cr2,eax               
			cmp [esp+0x28], eax     //判断是执行出错还是读写时出错?
			je LoadITLB  
			//判断是否是Hook的那些字节        
			cmp eax, g_pExecutePage
			jb  LoadDTLB
			sub eax, g_pExecutePage
			//cmp eax, g_ulHookCodeLen		
			cmp eax, 50		
			jg  LoadDTLB
			jmp LoadFakeFrame
LoadITLB:
		////////////////////////////////                
		//是一次执行操作,所以Load ITLB
		///////////////////////////////                 
		cli                       
			or dword ptr [ebx], 0x01         //标志页面为存在
			call g_pfnCallIntoHookedPage //通过调用一下那个页面内的代码,装载ITLB
			and dword ptr [ebx], 0xFFFFFFFE  //重新标记为不存在
			push eax
			mov eax,g_iTimes1
			add eax,1
			mov g_iTimes1,eax
			pop eax
			//sti                                             
			jmp ReturnWithoutPassdown                       
			////////////////////////////////                
			// 这是读写造成的异常,并且不在我们要隐藏的代码范围内,Load DTLB
			///////////////////////////////                  
LoadDTLB: 
		cli    
			mov eax,cr2
			or dword ptr [ebx], 0x01           //mark the page present
			mov eax, dword ptr [eax]           //load the DTLB    
			and dword ptr [ebx], 0xFFFFFFFE  //重新标记为不存在
			push eax
			mov eax,g_iTimes2
			add eax,1
			mov g_iTimes2,eax
			pop eax
			//sti                                             
			jmp ReturnWithoutPassdown                       
			/////////////////////////////////               
			//需要隐藏这段代码,所以Load伪装的页面 
			/////////////////////////////////   
LoadFakeFrame:     
		mov eax, cr2
			mov esi, g_pReadWritePTE
			mov ecx, dword ptr [esi]            //ecx = PTE of the    
		//read / write page   
		//把页面替换为假的 
		mov edi, [ebx]                                  
		and edi, 0x00000FFF //preserve the lower 12 bits of the   
			//faulting page's PTE                 
			and ecx, 0xFFFFF000 //isolate the physical address in     
			//the "fake" page's PTE               
			or ecx, edi                                     
			mov edx, [ebx]     //save the old PTE so we can replace it
		cli       
			mov [ebx], ecx    //replace the faulting page's phys frame
			//address w/ the fake one 
			//load DTLB 
			or dword ptr [ebx], 0x01   //标志为存在
			mov eax, cr2               //faulting virtual address     
			mov eax, dword ptr[eax]    //访问一次页面的数据,Load DTLB
			and dword ptr [ebx], 0xFFFFFFFE  //重新标记为不存在
			push eax
			mov eax,g_iTimes3
			add eax,1
			mov g_iTimes3,eax
			pop eax
			//Finally, restore the original PTE 
			mov [ebx], edx                                  
			//sti                                             
ReturnWithoutPassDown: 
		sti         
		pop eax
		mov cr2,eax
		popad                                           
		add esp,4 
		iretd                                           
PassDown:     
		pop eax
		mov cr2,eax
		popad                                           
			jmp g_old_ISR_pointer
	}//end asm                          
}  

四。结果

内存已经伪装成功了
五。注意
1.测试只能用于intel CPU,虚拟机好像不行,我试过N次,都蓝屏,vmware好像不支持tlbs
2.只能用于R0的伪装,R3的好像不行,大神说的,我自己也试过

有没有办法让R3也能用ShadowWalker啊??求解
我自己试过在R3下,能短时间的伪装,很快就蓝屏了
六。完整测试代码
应该可以直接用的

上传的附件 pseudo.jpg
target.jpg
NoShadowWalker.jpg
ShadowWalker.jpg
原理.jpg
cvcvxk.jpg
ShadowWalker.zip

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功