Driver를 숨기는 부분은 DRIVER_OBJECT의 DriverSection을 통해 PsLoadedModuleList에 접근하여

LIST_ENTRY를 끊어 줌으로써 가능하다.

이렇게 숨겨진 드라이버를 찾는 방법역시 rootkit.com에서 조안나의 modGREPER처럼 찾는 방법이 있는가 하면

이 역시도 방법이 많은것으로 알고 있다. 그 방법중에서 DevObj처럼 \\Driver 라는 NameSpace에 있는 리스트를 얻어와,

PsLoadedModuleList에 있는 리스트를 비교 후 \\Driver에만 있는 드라이버를 숨겨져 있는
 
드라이버라고 간주 하는 방법이다.

드라이버도 오브젝트로 관리가 되고 오브젝트 메니져는 오브젝트를 관리함에 있어서 오브젝트에 따라

NameSpace라는 공간으로 나눠서 각각을 관리하고 있다. 그 NameSpace중 하나가 \\Driver라는 NameSpace이다.

이 것은 중국인 블로그에서 소스코드를 참조 하여 작성한 것이다.

#include <ntddk.h>
#include <NtStrsafe.h>
#include "ntifs.h"
#define BYTE unsigned char
#define WORD unsigned short
#define DWORD unsigned long
#define PDWORD unsigned long*
#define MODULE_ENTRY_OFFSET 0x14
#define EXCEPTION_ACCESS_VIOLATION 0xC0000005
#define __MAX_SIZE__ 190
//////////////////////////////////////////////////////
//모듈엔트리의 일부분
//////////////////////////////////////////////////////
typedef struct _MODULE_ENTRY
{
 //모듈을 연결하는 리스트
 LIST_ENTRY module_list_entry;
 DWORD unknown1[4];
 DWORD base;  
 DWORD driver_start;
 DWORD unknown2; 
 UNICODE_STRING driver_path;
 UNICODE_STRING driver_name;
}MODULE_ENTRY, *PMODULE_ENTRY;
//////////////////////////////////////////////////////
//Object의 Name과 Type
//////////////////////////////////////////////////////
typedef struct _OBJECT_DIRECTORY_INFORMATION
{
 UNICODE_STRING Name;
 UNICODE_STRING TypeName;
}OBJECT_DIRECTORY_INFORMATION, *POBJECT_DIRECTORY_INFORMATION;

typedef struct _MATCH
{
 BYTE flag;
 UNICODE_STRING uniStr_Driver_Name;
 UNICODE_STRING uniStr_Name_Space;
}MATCH;
//MATCH gDriver_Module[__MAX_SIZE__];
PLIST_ENTRY pRestore_List[50];
int gnloop;
NTSTATUS
ObOpenObjectByName(POBJECT_ATTRIBUTES ObjectAttributes,
       POBJECT_TYPE ObjectType,
       PVOID ParseContext,
       KPROCESSOR_MODE AccessMode,
       ACCESS_MASK DesiredAccess,
       PACCESS_STATE PassedAccessState,
       PHANDLE Handle);
//////////////////////////////////////////////////////
//Driver Module을 얻는다.
//
//////////////////////////////////////////////////////
LONG Get_Driver_Module(IN PDRIVER_OBJECT pDriverObject)
{
 //////////////////////////////////////////////////////
 //현재 PsLoadedModuleList 의 정보를 저장할 변수
 //////////////////////////////////////////////////////
 PMODULE_ENTRY pFirst_Module_Entry, pModule_Entry;
 PLIST_ENTRY pFirst_Module_List, pModule_List;
 //////////////////////////////////////////////////////
 //////////////////////////////////////////////////////
 //Object의 정보를 저장할 변수
 //////////////////////////////////////////////////////
 PMODULE_ENTRY pObject_Module_Entry;
 PLIST_ENTRY pObject_List;
 HANDLE DirectroyHandle, ObjectHandle; //Directory를 가리키는 헨들
 UNICODE_STRING uniDirPath; //Driver의 path저장
 OBJECT_ATTRIBUTES ObjectAttributes, BodyAttributes;
 POBJECT_DIRECTORY_INFORMATION DirEntry, pBuffer = NULL;
 
 DWORD Context, ReturnLength;
 DWORD dwLength = 0x800;
 PVOID pObjectBody; //Namespace로 부터 객체를 얻어올때 이용
 NTSTATUS ntStatus;
 int nloop, nexist = 0;
 //////////////////////////////////////////////////////

 //////////////////////////////////////////////////////
 //Object의 정보를 저장할 변수
 //////////////////////////////////////////////////////
 WCHAR TEMP[30];
 WCHAR TEMP1[30];  //글자를 바꾸기위한 버퍼
 MATCH Driver_Module[__MAX_SIZE__];
 //////////////////////////////////////////////////////
 
 RtlInitUnicodeString(&uniDirPath, L"\\Driver"); 
 
 //Driver에 대한 오브젝트 속성을 채움
 InitializeObjectAttributes(&ObjectAttributes, &uniDirPath, OBJ_CASE_INSENSITIVE, NULL, NULL);  
 //Query access to the directory object ObjectAttributes가 속한 디렉토리 핸들을 얻음
 ZwOpenDirectoryObject(&DirectroyHandle, DIRECTORY_QUERY, &ObjectAttributes);  
 //////////////////////////////////////////////////////
 //모듈을 저장할 버퍼의 크기를 구함
 //////////////////////////////////////////////////////
 do
 {
  if (pBuffer)
  {
   ExFreePool(pBuffer);
  }
  dwLength *= 2;
  pBuffer = (POBJECT_DIRECTORY_INFORMATION)ExAllocatePool(NonPagedPool, dwLength);
  if (!pBuffer)
  {
    DbgPrint("ExAllocatePool failed! \n");
    break;
  }
  //Driver디렉토리에 있는 정보를 pBuffer에 저장
  ntStatus = ZwQueryDirectoryObject(DirectroyHandle, pBuffer, dwLength, FALSE, TRUE, &Context, &ReturnLength);
  
  DbgPrint("ReturnLength : %d\n ", ReturnLength);
 } while (ntStatus == STATUS_MORE_ENTRIES || ntStatus == STATUS_BUFFER_TOO_SMALL);
 //////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////
 //DriverObject에서 ModuleEntry를 구함
 //////////////////////////////////////////////////////
 pFirst_Module_Entry = *((PMODULE_ENTRY*)((DWORD)pDriverObject + MODULE_ENTRY_OFFSET));
 //////////////////////////////////////////////////////
 //ModuleEntry에서 링크를 구함
 //////////////////////////////////////////////////////
 pFirst_Module_List = &(pFirst_Module_Entry->module_list_entry);
 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 //ObjectManager의 Namespace와 PsLoadedModuleList와 비교후 숨겨진 드라이버 모듈을 찾아냄
 //
 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 for(DirEntry = pBuffer, nloop = 0; DirEntry->Name.Length != 0 && DirEntry->TypeName.Length != 0; DirEntry++, nloop++)
 {
  //Namespace의 이름을 저장
  RtlInitUnicodeString(&Driver_Module[nloop].uniStr_Name_Space, DirEntry->Name.Buffer);

  //////////////////////////////////////////////////////
  //PsLoadedModuleList와 비교하기위하여 Namespace의 이름뒤에 .sys를 붙임
  RtlStringCchCopyW(TEMP, 30, DirEntry->Name.Buffer);
  RtlStringCchCatW(TEMP, 30, L".sys");
  RtlInitUnicodeString(&DirEntry->Name, TEMP);
  //////////////////////////////////////////////////////
  for(pModule_List = pFirst_Module_List; pModule_List->Flink != pFirst_Module_List; pModule_List = pModule_List->Flink)
  {
   pModule_Entry = (PMODULE_ENTRY)pModule_List;
   
   //이름 비교 후 다르다면 flag를 0으로
   if(RtlCompareUnicodeString(&(DirEntry->Name), &(pModule_Entry->driver_name), TRUE) != 0)
   {
    RtlInitUnicodeString(&(Driver_Module[nloop].uniStr_Driver_Name), DirEntry->Name.Buffer);
    Driver_Module[nloop].flag = 0;
   }
   //이름 비교 후 같다면 flag를 1로
   //결국 Namespace에 있는 모듈이름만 flag가 0으로 됨
   else
   {
    Driver_Module[nloop].flag = 1;
    break;
   }
  }
  if(Driver_Module[nloop].flag == 0)
  {
   //Namespace에 있는 모듈의 이름으로 Object에 접근하기위하여 경로 설정
   RtlStringCchCopyW(TEMP1, 30, uniDirPath.Buffer);
   RtlStringCchCatW(TEMP1, 30, L"\\");
   RtlStringCchCatW(TEMP1, 30, Driver_Module[nloop].uniStr_Name_Space.Buffer);
   RtlInitUnicodeString(&(Driver_Module[nloop].uniStr_Name_Space), TEMP1);
   DbgPrint("uniDirPath.Buffer : %S\n", Driver_Module[nloop].uniStr_Name_Space);
   //Namespace에 있는 모듈의 ObjectAttributes를 초기화함
   InitializeObjectAttributes(&BodyAttributes, &(Driver_Module[nloop].uniStr_Name_Space), OBJ_CASE_INSENSITIVE, NULL, NULL);  
   //ObjectAttributes로 부터 객체의 핸들을 얻음
   ntStatus = ObOpenObjectByName(&BodyAttributes, 0L, 0L, 0L, 0L, 0L, &ObjectHandle);

   if(ntStatus != STATUS_SUCCESS)
   {
    DbgPrint("ObOpenObjectByName failed\n");
    return 0;
   }
   //오브젝트 핸들로 부터 오브젝트 바디를 얻음
   ntStatus = ObReferenceObjectByHandle(ObjectHandle, 0x80000000, NULL, 0, &pObjectBody, NULL);
   if(ntStatus != STATUS_SUCCESS)
   {
    DbgPrint("ObReferenceObjectByHandle failed\n");
    ZwClose(ObjectHandle);
    return 0;
   }
   //driver_object로 부터 driver_section멤버로 접근하여 리스트를 얻음
   pObject_Module_Entry = *((PMODULE_ENTRY*)((DWORD)pObjectBody + MODULE_ENTRY_OFFSET));
   pObject_List = &(pObject_Module_Entry->module_list_entry);
   __try
   {
    //DbgPrint("Driver_Module[%d].uniStr_Driver_Name : %S\n", nloop, Driver_Module[nloop].uniStr_Driver_Name.Buffer);
    if(pObject_List->Flink->Blink != pObject_List->Blink->Flink || pObject_List->Flink == pObject_List->Blink)
    {
     DbgPrint("Hidden DriverName : %S\n", ((PMODULE_ENTRY)pObject_List)->driver_name.Buffer);
     DbgPrint("Hidden DriverPath : %S\n", ((PMODULE_ENTRY)pObject_List)->driver_path.Buffer);
     pRestore_List[nexist] = pObject_List;
     nexist++;
    }
   }
   __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
   {
    pObject_List = NULL;
    //DbgPrint("break\n");
    //break;
   }
   //오브젝트에 대해 접근이 끝나면 핸들을 닫고 객체 참조를 줄여줘야함
   //중요!!! 객체참조수가 있으면 오브젝트에 대해 접근이 끝나도 오브젝트가 사라지지 않음
   ZwClose(ObjectHandle);
   ObDereferenceObject(pObjectBody);
   //DbgPrint("=========Find=========\n ");
   //
   //DbgPrint("Driver_Module[%d].uniStr_Name_Space : %S\n", nloop, Driver_Module[nloop].uniStr_Name_Space.Buffer);
   //DbgPrint("======================\n");
  }
 }
 gnloop = nexist;
 if(nexist == 0)
 {
  DbgPrint("There are not exist hidden driver!!\n");
  ExFreePool(pBuffer);
  return 0;
 }
 else
 {
  ExFreePool(pBuffer);
  return 1;
 }
}
VOID RestoreDeviceDriver(IN PDRIVER_OBJECT pDriverObject)
{
 int nloop;
 PLIST_ENTRY pDriverList;
 PMODULE_ENTRY pDriver_Module;

 pDriver_Module = *((PMODULE_ENTRY*)((DWORD)pDriverObject + MODULE_ENTRY_OFFSET));
 pDriverList = &(pDriver_Module->module_list_entry);
 for(nloop = 0; nloop < gnloop; nloop++)
 {
  pRestore_List[nloop]->Flink = pDriverList->Flink;
  pRestore_List[nloop]->Blink = pDriverList->Flink->Blink;
  pDriverList->Flink->Blink = pRestore_List[nloop];
  pDriverList->Flink = pRestore_List[nloop];
 }
 DbgPrint("Restore Success!!!\n");
 
}
VOID Unload(IN PDRIVER_OBJECT pDriverObject)
{
 DbgPrint("Unload Sucess~!!\n");
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegPath)
{
 int nexist = 0;
 pDriverObject->DriverUnload = Unload;
 nexist = Get_Driver_Module(pDriverObject);
 if(nexist > 0)
 {
  RestoreDeviceDriver(pDriverObject);
 }

 return STATUS_SUCCESS;
}

이 역시 코드가 걸레스럽다. ㅡ.ㅡ;;
신고
Posted by kyh1026