首页
论坛
课程
招聘
[调试逆向] [求助]对HOOK的另一种实现
2009-3-4 21:05 5868

[调试逆向] [求助]对HOOK的另一种实现

2009-3-4 21:05
5868
在看雪了里,学到了不少大牛HOOK的技术,这里就不一一的感谢了。不过终究还是离不开这种模式:修改原函数头+N个字节处,实现跳转到自己A函数,在自己的A函数里加一些特别功能,再执行原函数被修改的代码,再跳到原修改处的下一句代码。

     我就想(我是菜鸟),既然到跳的A函数了,能不能永远不跳回原代码,就让它在A函数里直接就行,返回了事,这样可以,清除所有的其它 内联HOOK。

     思路:从源文件中,找到导出函数地址,把这个地址反汇编到自己的空间里的A函数里,修改源函数,使之跳转到A函数里。和以前不同的是不跳转回源函数。

     我在R0做了一试实验.代码如下:
#define EMPTP_ASM_32(x) __asm { __asm _emit x __asm _emit x __asm _emit x __asm _emit x __asm _emit x __asm _emit x __asm _emit x __asm _emit x }

#define CLR_WP() \
		__asm cli \
		__asm mov  eax,cr0 \
		__asm and  eax,not 10000h \
		__asm mov  cr0,eax 
			
#define SET_WP() \
		__asm mov  eax,cr0 \
		__asm or   eax,10000h \
		__asm mov  cr0,eax \
		__asm sti

//1K的空位
__declspec( naked )  IMP_NtOpenProcess(OUT PHANDLE ProcessHandle, IN ACCESS_MASK DesiredAccess,   IN POBJECT_ATTRIBUTES ObjectAttributes, IN PCLIENT_ID ClientId OPTIONAL )
{
EMPTP_ASM_32(0x90) EMPTP_ASM_32(0x90) EMPTP_ASM_32(0x90) EMPTP_ASM_32(0x90) EMPTP_ASM_32(0x90) EMPTP_ASM_32(0x90) EMPTP_ASM_32(0x90) EMPTP_ASM_32(0x90)
.....
EMPTP_ASM_32(0x90) EMPTP_ASM_32(0x90) EMPTP_ASM_32(0x90) EMPTP_ASM_32(0x90) EMPTP_ASM_32(0x90) EMPTP_ASM_32(0x90) EMPTP_ASM_32(0x90) EMPTP_ASM_32(0x90)
}

NTSTATUS  Skip_NtOpenProcess(OUT PHANDLE ProcessHandle, IN ACCESS_MASK DesiredAccess,   IN POBJECT_ATTRIBUTES ObjectAttributes, IN PCLIENT_ID ClientId OPTIONAL )
{
	DWORD   dwJmpFunAddr =  (DWORD)IMP_NtOpenProcess;
	DWORD   dwRunAdd;
        NTSTATUS rc;
	__asm
	{  
		mov   dwJmpFunAddr, offset _HX_EXIT_SIGN               
			push  ClientId
			push   ObjectAttributes
			push   DesiredAccess
			push   ThreadHandle        
			push  dwRunAdd   
			push  dwJmpFunAddr 		 
			ret
_HX_EXIT_SIGN:
	      	mov rc, eax 
				add esp, 10H		
				
	}
	return rc;
	
 }
//这个函数是抄的

ULONG GetKernelBaseAddress(OUT PCHAR lpszModule)
{
   NTSTATUS ntStatus;
   ULONG NeededSize, KernelAddr;//uLoop
   PMODULE_LIST pModuleList;
   
   KernelAddr = 0;

   ZwQuerySystemInformation( SystemModuleInformation, &NeededSize, 0, &NeededSize);
   pModuleList = ExAllocatePool( NonPagedPool, NeededSize );
   ntStatus = ZwQuerySystemInformation( SystemModuleInformation, pModuleList, NeededSize, NULL );
   if ( NT_SUCCESS(ntStatus) )
   {
      //ntoskrnl is always first there
      KernelAddr = (ULONG)pModuleList->SysModuleInfo[0].Base;
      strcpy( lpszModule, "\\SystemRoot\\System32\\" );
      strcat( lpszModule, pModuleList->SysModuleInfo[0].ModuleNameOffset
                          + pModuleList->SysModuleInfo[0].ImageName );
   }
   ExFreePool(pModuleList);
    
   return KernelAddr;
}
//这个函数是抄的


PUCHAR GetExportFunFormBase(PCHAR ImageBase, PCSTR Name)
{
   PIMAGE_DOS_HEADER		DosHeader;
	 PIMAGE_NT_HEADERS		PeHeader;
	 PIMAGE_DATA_DIRECTORY	ImageExportDirectoryEntry;
	 ULONG					  ExportDirectorySize, ExportDirectoryOffset, i;
	 PIMAGE_EXPORT_DIRECTORY	ExportDirectory;
	 PULONG					ExportAddressTable;
	 PSHORT					ExportOrdinalTable;
	 PULONG					ExportNameTable;

	 if ( (DosHeader = (PIMAGE_DOS_HEADER)ImageBase) == NULL)
	 	  return NULL;

	 if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE)
		  return NULL;

	 if (DosHeader->e_lfanew > 1024*1024)
		  return NULL;

	 if ( (PeHeader = (PIMAGE_NT_HEADERS) (ImageBase + DosHeader->e_lfanew)) == NULL)
		  return NULL;

	 //if (PeHeader->Signature != IMAGE_PE_SIGNATURE)
	 if (PeHeader->Signature != IMAGE_NT_SIGNATURE)
		  return NULL;

	 if ( (ImageExportDirectoryEntry = PeHeader->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_EXPORT) == NULL)
		  return NULL;

	 ExportDirectorySize = ImageExportDirectoryEntry->Size;
	 ExportDirectoryOffset = ImageExportDirectoryEntry->VirtualAddress;

	 if ( (ExportDirectory = (PIMAGE_EXPORT_DIRECTORY) (ImageBase + ExportDirectoryOffset)) == NULL)
		  return NULL;

	 ExportAddressTable = (PULONG)(ImageBase + ExportDirectory->AddressOfFunctions);
	 ExportOrdinalTable = (PSHORT)(ImageBase + ExportDirectory->AddressOfNameOrdinals);
	 ExportNameTable =    (PULONG)(ImageBase + ExportDirectory->AddressOfNames);

	 for (i = 0; i < ExportDirectory->NumberOfNames; i++)
	 {
		  ULONG ord = ExportOrdinalTable[i];

		  if ( ExportAddressTable[ord] < ExportDirectoryOffset ||
			     ExportAddressTable[ord] >= ExportDirectoryOffset + ExportDirectorySize)
		  {
			   if (strcmp(ImageBase + ExportNameTable[i], Name) == 0)
			   {
				    return ImageBase + ExportAddressTable[ord];
			   }
		  }
	 }
	 return NULL;
}

BOOL HookNtOpenProcessFunction(PUCHAR jmpFun,OUT PUCHAR sotreFun/*输出反汇编代码*/)
{
    //取ntoskrnl ImageBase 略过,
     PUCHAR pOrgiAddr=GetExportFunFormBase(ImageBase,"NtOpenProcess");
     PUCHAR pCurrAddr=(PUCHAR)NtOpenProcess;
     PUCHAR pOutAddr= sotreFun;
     UCHAR jmp_hook_code[]={ 0xe9, 0x00, 0x00, 0x00, 0x00,
						    0x90,0x90,0x90,0x90,0x90,0x90};	
    
    UINT nJmpHookCodeLen = sizeof(jmp_hook_code)-6; //跳转代码长度
     UINT nNextLen=0,i=0;
     UINT bIsOK=FALSE;

    while(TRUE) //复制代码
		{    
                        //反汇编 见附件              
			nNextLen=getNextInstruction(pOrgiAddr,1,pOutAddr,10);
			i+=nNextLen;
			pOutAddr+=nNextLen;
			pOrgiAddr+=nNextLen;

			if(!bIsOk && i>=nJmpHookCodeLen ) //保证是完整指令替换
			{
				nJmpHookCodeLen=i;
				bIsOk=TRUE;
			}
                         
                        //是否到函数的结尾
			if( (pOrgiAddr[0]==0x90 && pOrgiAddr[1]==0x90 && pOrgiAddr[2]==0x90 && pOrgiAddr[3]==0x90 ) ||
				(pOrgiAddr[0]==0xCC && pOrgiAddr[1]==0xCC && pOrgiAddr[2]==0xCC && pOrgiAddr[3]==0xCC )	)
			{
				nNextLen=4;
				IsJmpBack=FALSE;
				RtlCopyMemory(pOutAddr,pOrgiAddr,nNextLen);
				i+=nNextLen;
				pOutAddr+=nNextLen;
				pOrgiAddr+=nNextLen;
				break;
			}

	
		}
                if(i>0)
               {
                        *((ULONG*)(jmp_orig_code + 1) )=(ULONG)jmpFun;
                        CLR_WP();
			RtlCopyMemory(originalCode,jmp_hook_code,nJmpHookCodeLen);
			SET_WP();
                        return TRUE;
               }
              return FALSE;
}



void InitHook()
{
    
    PUCHAR addr1=(PUCHAR)Skip_NtOpenProcess;
    PUCHAR addr2=(PUCHAR)IMP_NtOpenProcess;//
    HookNtOpenProcessFunction(addr1,addr2);/*从ntoskrnl.exe 文件中,读NtOpenProcess真实地址,,并对NtOpenProcess从文件进行反汇编输出*/
}



以上为代码,不过这段代码老是出问题,开始会成功,后面就挂了。

《0day安全 软件漏洞分析技术(第二版)》第三次再版印刷预售开始!

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (9)
雪    币: 141
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
XSJS 活跃值 2009-3-4 21:08
2
0
我是来抢沙发的
雪    币: 215
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
veninson 活跃值 2009-3-4 21:24
3
0
应该需要什么重定位吧,如果把整个干净的内核复制一份,不知道有没有用
雪    币: 41
活跃值: 活跃值 (22)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wenboly 活跃值 2009-3-4 21:29
4
0
这个,是通过附件里的反汇编引擎,反汇编后复制的,对反汇编引擎作了些短跳转的修改,有兴趣的朋友可以看看,并不是
把整个干净的内核复制一份
雪    币: 80
活跃值: 活跃值 (39)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
uvbs 活跃值 2009-3-4 23:45
5
0
我是来下楼主的代码的
雪    币: 213
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
sooaoo 活跃值 2009-3-5 17:34
6
0
改他的入口进你的函数?不跑回去怎么执行他的过程?
雪    币: 519
活跃值: 活跃值 (47)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
笨笨雄 活跃值 14 2009-3-5 17:45
7
0
据说ICESWORD就是这么做的
雪    币: 209
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ybpcn 活跃值 2009-3-11 21:25
8
0
我测试过了。这种思路没有问题,问题出现在反汇编上面。我看了下反汇编引擎,这个反汇编没有对了0F80-0F8F\EB\E3指令,进行正确的处理。
雪    币: 765
活跃值: 活跃值 (59)
能力值: (RANK:730 )
在线值:
发帖
回帖
粉丝
海风月影 活跃值 17 2009-3-11 21:52
9
0
内核里面的函数不一定是地址线性增长的
雪    币: 7400
活跃值: 活跃值 (84)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
achillis 活跃值 15 2009-3-12 15:01
10
0
不跑回去执行当然是可以的,只是那样搞就需要多做些工作,比如重定位,麻烦了一点,所以大家都偷懒不用啦~
游客
登录 | 注册 方可回帖
返回