NetRoc's Blog

N-Tech

 

进程中dll模块的隐藏

 

cc682/NetRoc

 http://netroc682.spaces.live.com/

        为了避免自己的某个dll模块被别人检测出来,有时候希望在自己加载一个dll之后,或者将dll注入到他人进程之后避免被检查出来。这就需要想办法抹掉这个dll的模块信息,使得Toolhelppsapi等枚举模块的API无法枚举它。

        我们可以先简单看看Windows枚举进程内模块的办法吧:

        首先是BOOL EnumProcessModules( HANDLE hProcess, HMODULE* lphModule, DWORD cb, LPDWORD lpcbNeeded);

        EnumProcessModules实际调用EnumProcessModulesInternal进行枚举。下面是vistapsapi的代码片断:

.text:514024B8                 push    ebx

.text:514024B9                 push    18h

.text:514024BB                 lea     eax, [ebp+stProcessBasicInfo]

.text:514024BE                 push    eax

.text:514024BF                 push    ebx      ;ebx=0

.text:514024C0                 push    [ebp+hProcess]

.text:514024C3                 call    ds:__imp__NtQueryInformationProcess@20 ; NtQueryInformationProcess(x,x,x,x,x)

.text:514024C9                 cmp     eax, ebx

.text:514024CB                 jge     short loc_514024E0

        调用NtQueryInformationProcess获得ProcessBasicInformation,在PROCESS_BASIC_INFORMATION结构中取得PEB地址。然后读取指定进程PEB中的数据

text:514024E0 loc_514024E0:                           ; CODE XREF: EnumProcessModulesInternal(x,x,x,x,x)+24j

.text:514024E0                 mov     eax, [ebp+stProcessBasicInfo.PebBaseAddress]

.text:514024E3                 cmp     eax, ebx

.text:514024E5                 jnz     short loc_514024EE

.text:514024E7                 push    8000000Dh

.text:514024EC                 jmp     short loc_514024CE

.text:514024EE ; ---------------------------------------------------------------------------

.text:514024EE

.text:514024EE loc_514024EE:                           ; CODE XREF: EnumProcessModulesInternal(x,x,x,x,x)+3Ej

.text:514024EE                 push    ebx             ; lpNumberOfBytesRead

.text:514024EF                 push    4               ; nSize

.text:514024F1                 lea     ecx, [ebp+Ldr]

.text:514024F4                 push    ecx             ; lpBuffer

.text:514024F5                 add     eax, 0Ch

.text:514024F8                 push    eax             ; lpBaseAddress

.text:514024F9                 push    [ebp+hProcess] ; hProcess

.text:514024FC                 mov     edi, ds:__imp__ReadProcessMemory@20 ; ReadProcessMemory(x,x,x,x,x)

.text:51402502                 call    edi ; ReadProcessMemory(x,x,x,x,x) ; ReadProcessMemory(x,x,x,x,x)

这里读取的是PEB地址+0C处的四个字节。

通过WinDbg我们可以看看nt!_PEB的结构

0: kd> dt nt!_PEB

   +0x000 InheritedAddressSpace : UChar

   +0x001 ReadImageFileExecOptions : UChar

   +0x002 BeingDebugged    : UChar

   +0x003 SpareBool        : UChar

   +0x004 Mutant           : Ptr32 Void

   +0x008 ImageBaseAddress : Ptr32 Void

   +0x00c Ldr              : Ptr32 _PEB_LDR_DATA

  +0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS

……

+0C处是一个_PEB_LDR_DATA结构指针,里面包含了和LDR相关的一些数据,进程的模块链表就保存在Ldr中。下面是_PEB_LDR_DATA的结构:

0: kd> dt nt!_PEB_LDR_DATA

   +0x000 Length           : Uint4B

   +0x004 Initialized      : UChar

   +0x008 SsHandle         : Ptr32 Void

   +0x00c InLoadOrderModuleList : _LIST_ENTRY

   +0x014 InMemoryOrderModuleList : _LIST_ENTRY

   +0x01c InInitializationOrderModuleList : _LIST_ENTRY

   +0x024 EntryInProgress : Ptr32 Void

其中,InLoadOrderModuleListInMemoryOrderModuleListInInitializationOrderModuleList就是进程当前已加载模块的链表,只是按照不同的方式排序。EnumProcessModules是通过InMemoryOrderModuleList链表枚举的,而根据Win2k代码,ToolHelp32函数是通过InLoadOrderModuleList枚举。这三个_LIST_ENTRY都是在一个RTL_PROCESS_MODULE_INFORMATION结构中的成员。这个结构在2k代码中有引用,不过没有确切的定义,下面是ReactOS中的定义,不过看起来我的vista PSAPI中使用的结构已经有所变化了,这里只作参考。

//

// Loader Data Table Entry

//

typedef struct _LDR_DATA_TABLE_ENTRY

{

    LIST_ENTRY InLoadOrderLinks;

    LIST_ENTRY InMemoryOrderModuleList;

    LIST_ENTRY InInitializationOrderModuleList;

    PVOID DllBase;

    PVOID EntryPoint;

    ULONG SizeOfImage;

    UNICODE_STRING FullDllName;

    UNICODE_STRING BaseDllName;

    ULONG Flags;

    USHORT LoadCount;

    USHORT TlsIndex;

    union

    {

        LIST_ENTRY HashLinks;

        PVOID SectionPointer;

    };

    ULONG CheckSum;

    union

    {

        ULONG TimeDateStamp;

        PVOID LoadedImports;

    };

    PVOID EntryPointActivationContext;

    PVOID PatchInformation;

} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;

到这里,隐藏模块的方法就已经明了了:通过PEB取得Ldr数据,拿到三个模块链表,并将要隐藏的模块断链即可。下面是主要代码实现:

BOOL HideMyself()

{

     HMODULE hMod = GetModuleHandle( _T( "ntdll.dll"));

     HMODULE hModMyself = GetModuleHandle( _T("dll.dll"));

     pfnNtQueryInformationProcess p = (pfnNtQueryInformationProcess)::GetProcAddress( hMod, "NtQueryInformationProcess");

 

     PROCESS_BASIC_INFORMATION stInfo = {0};

     DWORD dwRetnLen = 0;

     DWORD dw = p( GetCurrentProcess(), 0, &stInfo, sizeof(stInfo), &dwRetnLen);

 

     PPEB pPeb = stInfo.PebBaseAddress;

     PLIST_ENTRY ListHead, Current;

     PLDR_DATA_TABLE_ENTRY pstEntry = NULL;

 

     ListHead = &( stInfo.PebBaseAddress->Ldr->InLoadOrderModuleList);

     Current = ListHead->Flink;

     while ( Current != ListHead)

     {

         pstEntry = CONTAINING_RECORD( Current, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);

         //DebugOutW( L"Module:%s, base:0x%X\r\n", pstEntry->FullDllName.Buffer, pstEntry->EntryPoint);

         if ( pstEntry->DllBase == hModMyself)

         {

              pstEntry->InLoadOrderLinks.Flink->Blink = pstEntry->InLoadOrderLinks.Blink;

              pstEntry->InLoadOrderLinks.Blink->Flink = pstEntry->InLoadOrderLinks.Flink;

              DebugOut( _T( "Hide injected dll."));

              break;

         }

         Current = pstEntry->InLoadOrderLinks.Flink;

     }

 

     ListHead = &( stInfo.PebBaseAddress->Ldr->InMemoryOrderModuleList);

     Current = ListHead->Flink;

     while ( Current != ListHead)

     {

         pstEntry = CONTAINING_RECORD( Current, LDR_DATA_TABLE_ENTRY, InMemoryOrderModuleList);

         DebugOutW( L"Module:%s, base:0x%X\r\n", pstEntry->FullDllName.Buffer, pstEntry->EntryPoint);

         if ( pstEntry->DllBase == hModMyself)

         {

              pstEntry->InMemoryOrderModuleList.Flink->Blink = pstEntry->InMemoryOrderModuleList.Blink;

              pstEntry->InMemoryOrderModuleList.Blink->Flink = pstEntry->InMemoryOrderModuleList.Flink;

              DebugOut( _T( "Hide injected dll."));

              break;

         }

         Current = pstEntry->InMemoryOrderModuleList.Flink;

     }

     DebugOutW( L"\r\n");

 

     ListHead = &( stInfo.PebBaseAddress->Ldr->InInitializationOrderModuleList);

     Current = ListHead->Flink;

     while ( Current != ListHead)

     {

         pstEntry = CONTAINING_RECORD( Current, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);

         DebugOutW( L"Module:%s, base:0x%X\r\n", pstEntry->FullDllName.Buffer, pstEntry->EntryPoint);

         if ( pstEntry->DllBase == hModMyself)

         {

              pstEntry->InInitializationOrderModuleList.Flink->Blink = pstEntry->InInitializationOrderModuleList.Blink;

              pstEntry->InInitializationOrderModuleList.Blink->Flink = pstEntry->InInitializationOrderModuleList.Flink;

              DebugOut( _T( "Hide injected dll."));

              break;

         }

         Current = pstEntry->InInitializationOrderModuleList.Flink;

     }

     //DebugOut( _T("Out HideMyself\r\n"));

     return TRUE;

}

        这样处理之后,通过常规的枚举进程方式已经枚举不到隐藏模块,ProcessExplorer也无法枚举。但是,通过枚举进程内存空间等非常规方法,仍然是可以找到的。关于PSAPIToolhelp函数枚举模块的原理,可以逆向Windows代码,或者查找网上的代码看看就明白了。

posted on 2008-05-04 14:59 NetRoc 阅读(1659) 评论(1)  编辑 收藏 引用 所属分类: 内核技术Rootkit

评论

# re: 进程中dll模块的隐藏 2008-08-07 22:11 iWind

需要加什么头文件?  回复  更多评论   

只有注册用户登录后才能发表评论。

导航

统计

常用链接

留言簿(6)

随笔档案(99)

文章分类(35)

文章档案(32)

Friends

Mirror

搜索

最新评论

阅读排行榜

评论排行榜