查看: 3746|回复: 12
收起左侧

内存搜索对象..

[复制链接]
Sysnap
发表于 2009-5-31 19:54:02 | 显示全部楼层 |阅读模式
PS:  大多ARK的驱动检测好像老出现很多误报, 而且对某个驱动却找不到它的驱动对象..希望下面的代码可以用得上.....

//Time: 2009,5,31
//Author : Sysnap
//Link: http://hi.baidu.com/sysnap
前言:
Yas Kit的进程检测因为对对象的判断太过严格,搜索对象办法也不是很好,导致检测的效果不好,而驱动检测方面也不大理想, 使用了其他ARK,发现也有相干的问题,于是找点时间调整原来的搜索办法,过程记录下来与各位分享,也希望各位能提出问题,解决之[Sysnap]

1 一个对象生成时,一般都调用了ObCreateObject,每个对象都有不同的数据结构,在内存用一段空间表示,所谓的内存搜索对象,就是在内存里找出这些数据结构出来.当然你应该猜到ObCreateObject会调用ExAllocatePoolWithTag,这个函数的原形是
PVOID
  ExAllocatePoolWithTag(
    IN POOL_TYPE  PoolType,
    IN SIZE_T  NumberOfBytes,
    IN ULONG  Tag
    );
下面我们讲IN ULONG  Tag
2 效率
我们不能太暴力,尽量的获取相关信息来提高搜索的效率,其中Tag可以很好的利用. 对象管理器在分配一个对象时,根据不同的对象类型,ExAllocatePoolWithTag Tag也会不同,这给我们一个很好的搜索办法.就是在内存里找这些Tag,从而找到对象.
3搜索范围
一般对象数据结构的分配是在非分页内存的,系统有俩个非分页区,一般是在第一个分配,
这个非分页区的范围可以用俩个系统变量来标识.
MmNonPagedPoolStart和MmSizeOfPagedPoolInBytes,这俩个变量都是未导出,怎样定位呢?可以利用KPCR这个结构,
    __asm
    {
        mov eax, fs:[0x1C]  // SelfPCR   一般是0XFFDFF000
        mov eax, [eax+0x34] // KdVersionBlock
        mov KdVersionBlock, eax
    }
KdVersionBlock 就可以获取相关的变量了..
4还需要什么
先看
lkd> dd IoDriverObjectType
80561d60  85ea9040 85e60100 85ea9e70 85e602d0
80561d70  85e604a0 0000000a 00000000 00000000
lkd> dt _object_type 85ea9040
nt!_OBJECT_TYPE
   +0x000 Mutex            : _ERESOURCE
   +0x038 TypeList         : _LIST_ENTRY [ 0x85e5fc68 - 0x826c7f10 ]
   +0x040 Name             : _UNICODE_STRING ""
   +0x048 DefaultObject    : 0x80569c60
   +0x04c Index            : 0x1a
   +0x050 TotalNumberOfObjects : 0x81
   +0x054 TotalNumberOfHandles : 0
   +0x058 HighWaterNumberOfObjects : 0x81
   +0x05c HighWaterNumberOfHandles : 1
   +0x060 TypeInfo         : _OBJECT_TYPE_INITIALIZER
   +0x0ac Key              : 0x76697244
   +0x0b0 ObjectLocks      : [4] _ERESOURCE
我们还需要 +0x0ac Key              : 0x76697244 和 TotalNumberOfObjects
其中 Key 用于搜索用, TotalNumberOfObjects用于对比用,比如我们内存搜索驱动对象一共搜索到120个,,但TotalNumberOfObjects的值是110,,说明其中有10已经无效了
而 Key 这个跟Tag有关, 比如 驱动类型的对象 Key              : 0x76697244
那么 驱动类型的 Tag是 0x76697244 | 0x80000000
其实就是'Driv' 你可以用 !poolfind Driv 命令来验证,,比如在我电脑输出
lkd>  !poolfind Driv
unable to get PoolTrackTable - pool tagging is likely disabled or you have the wrong symbols
unable to get large pool allocation table - either wrong symbols or pool tagging is disabled
Searching NonPaged pool (81da1000 : 85ec6000) for Tag: Driv
83f31000 size:  108 previous size:    0  (Allocated) Driv (Protected)
840d2380 size:  328 previous size:   20  (Free)      Dri.
8421c690 size:  108 previous size:   78  (Allocated) Driv (Protected)
84261cf0 size:  108 previous size:   40  (Allocated) Driv (Protected)
843bcd80 size:  108 previous size:   68  (Allocated) Driv (Protected)
843cb000 size:  108 previous size:    0  (Allocated) Driv (Protected)
84421320 size:  108 previous size:    8  (Allocated) Driv (Protected)
关于 84421320 , 843bcd80等是什么意义这个我不知道,但我发现这个地址在加上某个值时就是对象本身的地址....这个值怎么确定呢?比如对于驱动的,我们可以这样获取
下面其实就是逐渐验证方法,因为我不知道84421320代表的数据结构或者意义什么,也只能这么做了.
DWORD GetDriverOfNum()
{
DWORD dwI = 0;
OBJECT_TYPEINFO ObTypeInfo;
DWORD x = 0;

if(ObGetObjectTypeInfo(OBTYPE_DRIVER, &ObTypeInfo) == FALSE)
{
  return 0;
  
}

for(dwI = gNonPagePoolInfo.dwStart;  dwI < gNonPagePoolInfo.dwEnd ; dwI +=4)
{
  if (IsAddressSafe((PVOID)dwI) == TRUE)
  {
   if(*(DWORD*)dwI == ObTypeInfo.dwKey)
   {
    PDRIVER_OBJECT pTmpDriObject = NULL;
    for(x=0; x<0x150; x+=0x10)
    {
     pTmpDriObject = (PDRIVER_OBJECT)((dwI-4)+x);
     if(pTmpDriObject->Type == 4)
     {
      DbgPrint("--hi find x == 0x%x",x);
      return x;
      break;
     }
    }
   }
  }
}
return 0;
}
5开始搜索
这里以搜索驱动为例子
其实也比较简单,这里我们从几个地方获取名字.
pTmpDriObject->DriverExtension->ServiceKeyName.Buffer,
pDriverSection->BaseDllName.Buffer,
pTmpDriObject->DriverName.Buffer,
从检测的效果上看,很不错...
VOID ScanDriverObject()
{
DWORD dwI = 0;
DWORD dwCount = 1;
DWORD dwDriMagic = 0;
OBJECT_TYPEINFO ObTypeInfo;
ANSI_STRING asString;
NTSTATUS ntStatus;

if(ObGetObjectTypeInfo(OBTYPE_DRIVER, &ObTypeInfo))
{
  DbgPrint("--%x  %d",ObTypeInfo.dwKey,ObTypeInfo.dwTotalNumberOfObjects);
}
dwDriMagic = GetDriverOfNum();
for(dwI = gNonPagePoolInfo.dwStart;  dwI < gNonPagePoolInfo.dwEnd ; dwI +=4)
{
  if (IsAddressSafe((PVOID)dwI) == TRUE)
  {
   if(*(DWORD*)dwI == ObTypeInfo.dwKey)
   {
    PDRIVER_OBJECT pTmpDriObject = NULL;
    pTmpDriObject =(PDRIVER_OBJECT)((dwI-4)+dwDriMagic);
    if(pTmpDriObject->Type == 4)
    {
     PLDR_DATA_TABLE_ENTRY pDriverSection = (PLDR_DATA_TABLE_ENTRY)pTmpDriObject->DriverSection;
     //if (IsAddressSafe((PVOID)pDriverSection->FullDllName.Buffer) == TRUE)
     if(pDriverSection != 0)
     {
      
      ntStatus = RtlUnicodeStringToAnsiString(&asString,&pTmpDriObject->DriverName,TRUE);
      if(NT_SUCCESS(ntStatus))
      {
       if(asString.Buffer[0] != '\\')
      DbgPrint("%d %ws %ws %ws  0x%x 0x%x 0x%x %ws",dwCount,
       pTmpDriObject->DriverExtension->ServiceKeyName.Buffer,
       pDriverSection->BaseDllName.Buffer,
       pTmpDriObject->DriverName.Buffer,
       pTmpDriObject->DriverStart,
       pTmpDriObject->DriverSize,
       pTmpDriObject,
       pDriverSection->FullDllName.Buffer);
      }
      //判断也许不用了..没必要...
      //if(pTmpDriObject->DriverExtension->DriverObject == pTmpDriObject)
      
     }
     
     //DbgPrint("%d  %x",dwCount, ((dwI-4)+dwDriMagic));
     dwCount++;
    }
   }
  }
}
}

6对象的有效性,这个不同的对象判断办法不同,也比较难弄全.比如进程我们可以判断EXITTME,但总不太完美
下面是一个搜索进程的例子,加了简单的对象有效判断.
/////////////////////////////////////////////////////////////////////////////////////
/////
////////////////////////////////////////////////////////////////////////////////////
DWORD GetProcessOfNum()
{
DWORD dwI = 0;
OBJECT_TYPEINFO ObTypeInfo;
DWORD x = 0;
if(ObGetObjectTypeInfo(OBTYPE_PROCESS, &ObTypeInfo) == FALSE)
{
  return -1;
  
}

for(dwI = gNonPagePoolInfo.dwStart;  dwI < gNonPagePoolInfo.dwEnd ; dwI +=4)
{
  if (IsAddressSafe((PVOID)dwI) == TRUE)
  {
   if(*(DWORD*)dwI == ObTypeInfo.dwKey)
   {
    PVOID pTmpObject = NULL;
    for(x=0; x<0x150; x+=0x10)
    {
     pTmpObject = (PVOID)((dwI-4)+x);
     if(pTmpObject == (PVOID)PsGetCurrentProcess())
     {
      DbgPrint("--hi find x == 0x%x",x);
      return x;
      break;
     }
    }
   }
  }
}
return -1;
}

DWORD ExitTimeOffset()
{
DWORD dw_i=0;
CHAR* cFuncAddress =0;
UNICODE_STRING uniFuncName;

RtlInitUnicodeString(&uniFuncName,L"PsGetProcessExitTime");
cFuncAddress =  (CHAR*)MmGetSystemRoutineAddress(&uniFuncName);

//DbgPrint("-xx -%x",cFuncAddress);
//if(dwFuncAddress ! = 0)
{
  for(dw_i =0; dw_i < 16; dw_i++)
  {
   //DbgPrint("-xx -%x %x",cFuncAddress[dw_i]&0xff,cFuncAddress[dw_i+1]&0xff);
   if( (cFuncAddress[dw_i]&0xff)==0x8b && (cFuncAddress[dw_i+1]&0xff)==0x41)
   {
    //DbgPrint("eeetttttttttttttttttt--");
    return (DWORD)cFuncAddress[dw_i+2];
   }
  }
}
return 0;
/*  /// XP SP3
lkd> u PsGetProcessExitTime
nt!PsGetProcessExitTime:
805e2dab 64a124010000    mov     eax,dword ptr fs:[00000124h]
805e2db1 8b4844          mov     ecx,dword ptr [eax+44h]
805e2db4 8b4178          mov     eax,dword ptr [ecx+78h]
805e2db7 8b517c          mov     edx,dword ptr [ecx+7Ch]
805e2dba c3              ret
*/
}

BOOLEAN MmScanProcessObject()
{
OBJECT_TYPEINFO ObTypeInfo;
DWORD dwPsMagic = 0;
DWORD dwI = 0;
DWORD dwCount =1;
DWORD dwExitTimeOffset = 0;
NTSTATUS ntStatus;
HANDLE hProcess;
dwPsMagic = GetProcessOfNum();
if((ObGetObjectTypeInfo(OBTYPE_PROCESS, &ObTypeInfo)==FALSE) || (dwPsMagic == -1))
{
  return FALSE;
}

dwExitTimeOffset = ExitTimeOffset();
DbgPrint("TRUE OBJECT COUNT %d",ObTypeInfo.dwTotalNumberOfObjects);
for(dwI = gNonPagePoolInfo.dwStart;  dwI < gNonPagePoolInfo.dwEnd ; dwI +=4)
{
  if (IsAddressSafe((PVOID)dwI) == TRUE)
  {
   if(*(DWORD*)dwI == ObTypeInfo.dwKey)
   {
    PVOID pTmpObject = NULL;
    pTmpObject =(PVOID)((dwI-4)+dwPsMagic);
    if(*(UCHAR*)pTmpObject == 0x03)  //xp sp3???
    {
     PLARGE_INTEGER ExitTime;
     ExitTime = (PLARGE_INTEGER)((DWORD)pTmpObject + dwExitTimeOffset);  
     if(ExitTime->QuadPart == 0) //已经结束的进程的ExitTime为非零
     
     DbgPrint("%08x %8d%s ",pTmpObject, PsGetProcessId(pTmpObject),
     PsGetProcessImageFileName(pTmpObject));
     //DbgPrint("%d EPROCESS 0x%x",dwCount,pTmpObject);
     dwCount++;
    }
   }
  }
}
return TRUE;
}
具体的代码见附件.

YasFindObject代码.rar

10.6 KB, 下载次数: 72

评分

参与人数 6经验 +20 人气 +7 收起 理由
wolfwalk888 + 1 精品文章
yangdw + 1 感谢开源分享!
Deker + 3 正面临这种问题
backway + 20 感谢提供分享:-D
dl123100 + 1 学习

查看全部评分

jefffire
头像被屏蔽
发表于 2009-5-31 20:08:16 | 显示全部楼层
技术贴啊,对我这种只懂C皮毛的人实在复杂了点。。
wuzhewujian
发表于 2009-5-31 20:15:10 | 显示全部楼层
谢谢对我来说这是天书
jefffire
头像被屏蔽
发表于 2009-5-31 20:15:19 | 显示全部楼层

回复 1楼 Sysnap 的帖子

有个问题  SYSNAP为何老是被各种杀软报毒?
tawny2008
发表于 2009-5-31 20:52:24 | 显示全部楼层
这是用来搜索已经驻留的内存驱动的代码吗?
jefffire
头像被屏蔽
发表于 2009-5-31 20:56:47 | 显示全部楼层

回复 5楼 tawny2008 的帖子

应该是的~
olly
发表于 2009-6-1 01:12:54 | 显示全部楼层
MARK。
大少爷
发表于 2009-6-1 07:41:33 | 显示全部楼层
kafan真是藏龙卧虎。
palmerlee
发表于 2009-6-1 09:26:58 | 显示全部楼层
第一页支持一下
左手
发表于 2009-6-1 10:53:22 | 显示全部楼层
头晕了~

飘过~~~·····

只看懂几行~
您需要登录后才可以回帖 登录 | 快速注册

本版积分规则

手机版|杀毒软件|软件论坛| 卡饭论坛

Copyright © KaFan  KaFan.cn All Rights Reserved.

Powered by Discuz! X3.4( 沪ICP备2020031077号-2 ) GMT+8, 2025-1-7 05:47 , Processed in 0.131094 second(s), 20 queries .

卡饭网所发布的一切软件、样本、工具、文章等仅限用于学习和研究,不得将上述内容用于商业或者其他非法用途,否则产生的一切后果自负,本站信息来自网络,版权争议问题与本站无关,您必须在下载后的24小时之内从您的电脑中彻底删除上述信息,如有问题请通过邮件与我们联系。

快速回复 客服 返回顶部 返回列表