首页
社区
课程
招聘
[原创]内存搜索对象
发表于: 2009-5-31 19:47 17423

[原创]内存搜索对象

2009-5-31 19:47
17423

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

具体的代码见附件.


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 7
支持
分享
最新回复 (17)
雪    币: 220
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
先占块地,学习。。。
2009-5-31 19:48
0
雪    币: 564
活跃值: (42)
能力值: ( LV12,RANK:230 )
在线值:
发帖
回帖
粉丝
3
不错的说.......
2009-6-1 16:10
0
雪    币: 137
活跃值: (435)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
占地学习....
2009-6-2 18:23
0
雪    币: 1450
活跃值: (35)
能力值: (RANK:680 )
在线值:
发帖
回帖
粉丝
5
Support.
好东西, mark一下.
2009-6-3 18:51
0
雪    币: 112
活跃值: (51)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
Mark
谢谢LZ
2009-6-4 09:27
0
雪    币: 209
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
占地学习....
2009-6-5 15:26
0
雪    币: 218
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
学习楼主牛人
2009-6-17 16:23
0
雪    币: 267
活跃值: (438)
能力值: ( LV9,RANK:190 )
在线值:
发帖
回帖
粉丝
9
我在我用的xp系统测试了:
PKDDEBUGGER_DATA64 pKdData64 = KdGetDebuggerDataBlock();
gNonPagePoolInfo.dwStart = *(DWORD*)pKdData64->MmNonPagedPoolStart;
gNonPagePoolInfo.dwEnd = *(DWORD*)pKdData64->MmSizeOfPagedPoolInBytes + gNonPagePoolInfo.dwStart;

*(DWORD*)pKdData64->MmNonPagedPoolStart的值是:0x81300000
*(DWORD*)pKdData64->MmSizeOfPagedPoolInBytes的值是:0x0A800000
而我加载的驱动:PDRIVER_OBJECT pDriverObject的值却是:0xFAEC6688
请问Sysnap,我这是矛盾了吗?我的pDriverObject的值有可能是:0xFAEC6688吗?KdGetDebuggerDataBlock有没有错误了啊?(0x81300000+0x0A800000)小于0xFAEC6688啊!我的pDriverObject不在指定搜索的非分页内存范围,怎么回事啊?
2009-6-22 18:28
0
雪    币: 95
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
虚心来学习下 谢谢分享 特地来支持楼主
2009-6-22 20:25
0
雪    币: 267
活跃值: (438)
能力值: ( LV9,RANK:190 )
在线值:
发帖
回帖
粉丝
11
我用devicetree察看了驱动对象,发现驱动对象不只分布在:0x81300000到(0x81300000+0x0A800000)的内存区域,还有很多是分布在:0xFA596548到0xFFBE0000的内存区域,我又发现:*(DWORD*)pKdData64->MmNonPagedPoolEnd的值是:0xFFBE0000   。师傅可以说说以0xFFBE0000
结束的非分页内存的大小在pKdData64的哪个成员给出啊?
2009-6-30 21:07
0
雪    币: 231
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
12
for(x=0; x<0x150; x+=0x10)
{
        pTmpDriObject = (PDRIVER_OBJECT)((dwI-4)+x);---------这里为什么要dwI-4?????谁能告诉我吗
        if(pTmpDriObject->Type == 4)
        {
          DbgPrint("--hi find x == 0x%x",x);
          return x;
          break;
        }
}
2009-7-2 23:26
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
13
暂时没法测试,但是从代码来看,找不到我的HideDriver~~
2009-7-3 10:12
0
雪    币: 581
活跃值: (149)
能力值: ( LV12,RANK:600 )
在线值:
发帖
回帖
粉丝
14
呵呵...这个你要测试下才知道...

现在隐藏驱动应该是
断掉 \DRIVER自己的对象
断掉 PsLoadedModuleList
修改 DRIVER_OBJECT,去掉其中的名字或者路径
插除 PE文件的一些特征..比如 'PE' 'MS' 'PDB' 等
绕过 TypeList的检测等等...

这样就可以绕过大部ARK的模块检测了..
2009-7-3 10:19
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
15
恩,说的不错,我做的工作比你说的多了一点,所以理论上你还是检测不到。编译你的检测代码时有点问题,没时间弄了,可以的话,直接把bin发到我的邮箱achillis@126.com,我试一下你的检测效果
2009-7-3 17:02
0
雪    币: 269
活跃值: (25)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
16
同问~~~应该找MmNonPagedPoolEnd吧~~
2009-12-28 22:26
0
雪    币: 269
活跃值: (25)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
17
经过实践到0x90000000之后就没了。。。
2009-12-29 11:41
0
雪    币: 274
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
mark,谢谢分享
2010-12-21 15:12
0
游客
登录 | 注册 方可回帖
返回
//