获取内核函数的原始地址

http://www.ant315.com/read.php?tid=580


本文以获取NtReadVirtualMemory讲述当该函数被HOOK后如何获取到正确的地址为例,解析获取原始内核函数地址的一种思路。思路虽然比较笨拙,但是也不失为一种解决办法。 


 
图片:1.bmp 
上图中NtReadVirtualMemory函数被hook了,如果我们从SSDT表获取函数的地址,则获取到的函数地址为0XA1277AFE而不是原始的函数地址0x805884F7,并且此函数并不是导出函数, 
无法通过MmGetSystemRoutineAddress这个函数来获取到正确的地址。如果你想恢复或者绕过某几p对这个函数的HOOK,你又获取到了一个错误的地址,那么结果当然只有两种,死机或者蓝屏。 
如此等等情况,我们写的pass某几p的代码中一种简单的解决方式是使用死地址(或称硬编码),但是存在的一个问题是你虚拟机上的地址跟你主机上的地址是不一样的,那么则必须要做实时的 
修改编译,区分在主机上使用的sys和在虚拟机上使用的sys,那么换台电脑又要再次修改。如此改来改去的真的是很麻烦。 
我们使用xuetr查看驱动模块发现对于内核而言里面表现出来的模块分两种情况一种ntoskrnl.exe,另外一种是ntkrnlpa.exe。这样一来我们就想到一个简单粗暴的方式是首先获得内核的入口地址 
和模块大小,然后通过特征码定位这个函数的地址。在windbg中输入命令 u nt!NtReadVirtualMemory回车后看到如下图 

 
图片:2.bmp 
考虑到前面几行有可能被某p或者其他程序inline hook 修改,例如某p将805aa792 这个地址修改为mov eax,xxxxxxxx  jmp eax  那么我们取特征的时候就要在稍微靠后一点去,这里我们就从805aa79e处取特征吧 
在windbg 中输入 db 805aa79e 得到如下图的数据 

 
图片:3.bmp 
我们取到805aa7ae处应该能确定下来了,也就是特征为 
64 a1 24 01 00 00 8b f8-8a 87 40 01 00 00 88 45 e0  
那么找到这个特征以后,得到的地址就是805aa79e要得到NtReadVirtualMemory函数的地址则将这个地址减去0xC就得到了NtReadVirtualMemory函数的地址了 
好了简单的分析完成那么接下来该是贴出代码的时候了,下面给出代码 
 
 
#include  
#include   
//模块结构的定义,这个好像有很多不同的定义这里先用这个 
typedef struct _SYSTEM_MODULE_INFORMATION {//Information Class 11 
HANDLE Section; 
PVOID MappedBase; 
PVOID Base; 
ULONG Size; 
ULONG Flags; 
USHORT LoadOrderIndex; 
USHORT InitOrderIndex; 
USHORT LoadCount; 
USHORT ModuleNameOffset; 
CHAR ImageName[256]; 
}SYSTEM_MODULE_INFORMATION,*PSYSTEM_MODULE_INFORMATION; 
//模块数组的定义 
typedef struct { 
DWORD    dwNumberOfModules; 
SYSTEM_MODULE_INFORMATION    smi[1]; 
} MODULES, *PMODULES; 
 
//ZwQuerySystemInformation函数的申明 
NTSYSAPI NTSTATUS ZwQuerySystemInformation( 
             IN  ULONG SystemInformationClass, 
             IN  OUT PVOID SystemInformation, 
             IN  ULONG SystemInformationLength, 
             OUT PULONG ReturnLength OPTIONAL 
          ); 
 
//这里是两个函数的定义 
PMODULES GetModuleList() //获取全部模块 

ULONG dwRet; 
PMODULES pmodule =(PMODULES)&pmodule; 
ZwQuerySystemInformation(11,pmodule,0,&dwRet); 
pmodule=(PMODULES)ExAllocatePoolWithTag(NonPagedPool,dwRet,'mod'); 
ZwQuerySystemInformation(11,pmodule,dwRet,NULL); 
return pmodule; 

VOID FreeModList(PMODULES pmodule) 

ExFreePoolWithTag(pmodule,'mod'); 

 
ULONG GetModBase(PCHAR szName) 

ULONG i=0; 
PMODULES pmodule = GetModuleList(); 
for (;i
dwNumberOfModules;i++) 

  if (0 == strcmp(szName,(CHAR*)((ULONG)pmodule->smi .ImageName + pmodule->smi.ModuleNameOffset))) 
  { 
   FreeModList(pmodule); 
   return (ULONG)pmodule->smi.Base; 
  } 

FreeModList(pmodule); 
return 0; 
}
 
ULONG GetModSize(PCHAR szName) 

ULONG i=0; 
ULONG ret=0; 
PMODULES pmodule = GetModuleList(); 
for (;i
dwNumberOfModules;i++) 

  if (0 == strcmp(szName,(CHAR*)((ULONG)pmodule->smi .ImageName + pmodule->smi.ModuleNameOffset))) 
  { 
   ret=(ULONG)pmodule->smi.Size; 
   FreeModList(pmodule); 
   return ret; 
  } 

FreeModList(pmodule); 
return 0; 
}
 
 
 
ULONG GetNtReadVirtualMemory() 

ULONG ModBaseAddr=0; 
ULONG ModSize=0; 
ULONG i=0; 
BYTE  *p; 
ModBaseAddr=GetModBase("ntoskrnl.exe"); 
if (ModBaseAddr==0)  

  ModBaseAddr=GetModBase("ntkrnlpa.exe"); 
  ModSize=GetModSize("ntkrnlpa.exe"); 

else 

  ModSize=GetModSize("ntoskrnl.exe"); 

//DbgPrint("ModBaseAddr=%x\n",ModBaseAddr); 
//DbgPrint("ModSize=%x\n",ModSize); 
if (ModBaseAddr==0) return 0; 
 
p = (BYTE*)ModBaseAddr + 20; //这个主要是设置一下跳过开始的几个地方少循环一些次数 
//64 a1 24 01 00 00 8b f8-8a 87 40 01 00 00 88 45 e0  
while (1) 

  if ((*p== 0x64) && 
   (*(p+1) == 0xa1) && 
            (*(p+2) == 0x24) && 
   (*(p+3) == 0x01) && 
   (*(p+4) == 0x00) && 
   (*(p+5) == 0x00) && 
   (*(p+6) == 0x8b) && 
   (*(p+7) == 0xf8) && 
   (*(p+8) == 0x8a) && 
   (*(p+9) == 0x87) && 
   (*(p+10) == 0x40) && 
   (*(p+11) == 0x01) && 
   (*(p+12) == 0x00) && 
   (*(p+13) == 0x00) && 
   (*(p+14) == 0x88) && 
   (*(p+15) == 0x45) && 
   (*(p+16) == 0xe0)) 
  { 
   DbgPrint("NtReadVirtualMemoryAddr=%x\n",(ULONG)p-0x0C); 
   return (ULONG)p-0x0C; 
  } 
  p++; 

 
return 0;  

 
void unload(PDRIVER_OBJECT pO) 

KdPrint(("unload\n")); 

NTSTATUS DriverEntry( PDRIVER_OBJECT pObj , PUNICODE_STRING path) 

pObj->DriverUnload = unload; 
GetNtReadVirtualMemory(); 
return STATUS_SUCCESS; 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值