Author:   Polymorphours
Email:   Polymorphours@whitecell.org
Homepage:http://www.whitecell.org
Date:     2005-11-17


/*++
         Author: Polymorphours

Date: 2005/1/10

通过对 NtReadVirtualMemory 挂钩,防止其他进程对保护的模块进行扫描,
如果发现其他进程读被保护模块的内存,则返回0

--*/


typedef struct _LDR_DATA_TABLE_ENTRY {

LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;


/*
+0x034 Flags             : Uint4B
+0x038 LoadCount         : Uint2B
+0x03a TlsIndex          : Uint2B
+0x03c HashLinks         : _LIST_ENTRY
+0x03c SectionPointer    : Ptr32 Void
+0x040 CheckSum          : Uint4B
+0x044 TimeDateStamp     : Uint4B
+0x044 LoadedImports     : Ptr32 Void
+0x048 EntryPointActivationContext : Ptr32 Void
+0x04c PatchInformation : Ptr32 Void
*/
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;

/*++

函数名: MyNtReadVirtualMemory

参数:
   IN HANDLE ProcessHandle,
   IN PVOID BaseAddress,
   OUT PVOID Buffer,
   IN ULONG BufferLength,
   OUT PULONG ReturnLength OPTIONAL
  
功能:
   隐藏保护模块的内存,如果发现有内存扫描到这块内存,则返回加密后的数据扰乱扫描过程
  
返回:
   NTSTATUS
  
--*/


NTSTATUS
MyNtReadVirtualMemory(
IN HANDLE ProcessHandle,
IN PVOID BaseAddress,
OUT PVOID Buffer,
IN ULONG BufferLength,
OUT PULONG ReturnLength OPTIONAL
)
{
NTSTATUS status;
PEPROCESS eProcess;
PVOID   Peb;

PPEB_LDR_DATA PebLdrData;
PLDR_DATA_TABLE_ENTRY LdrDataTableHeadList;
PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;

PLIST_ENTRY    Blink;
PPROTECT_NODE   FileNode = NULL;
BOOLEAN     bHideFlag = FALSE;
ULONG     ImageMaxAddress = 0;

/*
#ifdef _DEBUG
DbgPrint( "Call Process: %s, BaseAddress: %08x\n", PsGetProcessImageFileName( PsGetCurrentProcess() ), BaseAddress );
#endif
*/

status =ObReferenceObjectByHandle(
     ProcessHandle,
     FILE_READ_DATA,
     PsProcessType,
     KernelMode,
     (PVOID)&eProcess,
     NULL
     );
if ( NT_SUCCESS(status) ) {
  
   //
   // 得到PEB的地址
   //
  
   Peb = (PVOID)(*(PULONG)((PCHAR)eProcess + PebOffset));
  
   //
   // 切换到目标进程空间
   //
  
  
   KeAttachProcess( eProcess );
  
   //
   // 判断PEB是否有效,如果有效,那么准备利用PEB结构遍历进程加载的模块
   //

   if ( !MmIsAddressValid( Peb ) ) {

/*
#ifdef _DEBUG
    DbgPrint( "PEB is error.\n" );
#endif
*/
   
    KeDetachProcess();
    ObDereferenceObject( eProcess );
   
    goto CLEANUP;
   }
  
   PebLdrData = (PPEB_LDR_DATA)(*(PULONG)( (PCHAR)Peb + 0xc ));
  
   if ( !PebLdrData ) {
   
    KeDetachProcess();
    ObDereferenceObject( eProcess );
   
    goto CLEANUP;
   }
  
   try {
   
    ProbeForRead (
     PebLdrData,
     sizeof(PEB_LDR_DATA),
     sizeof(ULONG)
     );
    
    //
    // 遍历模块链表
    //
   
    LdrDataTableHeadList = (PLDR_DATA_TABLE_ENTRY)PebLdrData->InLoadOrderModuleList.Flink;
    LdrDataTableEntry = LdrDataTableHeadList;
   
   
    do {
    
     ProbeForRead(
      LdrDataTableEntry,
      sizeof(LDR_DATA_TABLE_ENTRY),
      sizeof(ULONG)
      );
     
     if ( !LdrDataTableEntry->DllBase ) {

      LdrDataTableEntry = (PLDR_DATA_TABLE_ENTRY)LdrDataTableEntry->InLoadOrderLinks.Flink;
      continue;
     }

    
     //
     // 判断读的内存属于那一个模块,如果都不属于,那么放过
     //

     ImageMaxAddress = (ULONG)((ULONG)LdrDataTableEntry->DllBase + LdrDataTableEntry->SizeOfImage);
    
     if ( (ULONG)( (ULONG)BaseAddress + BufferLength) < (ULONG)LdrDataTableEntry->DllBase ||
       (ULONG)BaseAddress > ImageMaxAddress ) {

       //
       // 如果不是读模块区域,那么枚举下一个
       //

      LdrDataTableEntry = (PLDR_DATA_TABLE_ENTRY)LdrDataTableEntry->InLoadOrderLinks.Flink;
      continue;
     }
    
     //
     // 如果是被保护的模块,那么返回虚假数据
     //

     bHideFlag = FALSE;
     Blink = ProtectFile.Blink;
    

     while ( Blink != &ProtectFile ) {

      FileNode = CONTAINING_RECORD( Blink, PROTECT_NODE, ActiveLink );
     
      //
      // 如果发现当前文件存在于隐藏列表,那么设置隐藏标志隐藏它
      //

      if ( wcsstr( FileNode->ProtectName, LdrDataTableEntry->FullDllName.Buffer ) ) {

       bHideFlag = TRUE;
       break;
      }

      Blink = Blink->Blink;
     }
    
     if ( bHideFlag ) {
     
      //
      // 返回原本的进程空间进行处理
      //

      KeDetachProcess();
      ObDereferenceObject( eProcess );

      ProbeForWrite(
       Buffer,
       BufferLength,
       sizeof(ULONG)
       );
      
      memset( Buffer, 0x00, BufferLength );
     
      ProbeForWrite(
       ReturnLength,
       sizeof(PULONG),
       sizeof(ULONG)
       );
     
      *ReturnLength = BufferLength;
     
      return STATUS_SUCCESS;
     }
   
     LdrDataTableEntry = (PLDR_DATA_TABLE_ENTRY)LdrDataTableEntry->InLoadOrderLinks.Flink;
    
    } while ( LdrDataTableEntry != LdrDataTableHeadList );
   

   } except( EXCEPTION_EXECUTE_HANDLER ) {

    if ( !bHideFlag ) {
    
     KeDetachProcess();
     ObDereferenceObject( eProcess );
    }

    goto CLEANUP;
   }


   KeDetachProcess();
   ObDereferenceObject( eProcess );
}

CLEANUP:

return NtReadVirtualMemory(
    ProcessHandle,
    BaseAddress,
    Buffer,
    BufferLength,
    ReturnLength
    );
}