//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