PIXNET Logo登入

Rootkit --逆向工程技術--

跳到主文

Rootkit與逆向工程技術研討 歡迎指教:P

部落格全站分類:數位生活

  • 相簿
  • 部落格
  • 留言
  • 名片
  • 5月 05 週六 201214:45
  • 總結一下得到內核模組位址的方法

網上說的比較常見的4種方法:
1、通過DriverEntry傳入的DriverObject參數的DriverSection成員指向LDR_DATA_TABLE_ENTRY結構,通過遍歷這張表得到ntoskrnl的基址和大小
2、ZwQuerySystemInformation大法
3、搜索記憶體 
4、利用KPCR結構
存在的問題:
1、第1種方法和第4種方法得到的結果比ZwQuerySystemInformation少一個
2、第1種方法如果輸出BaseDllName是ntoskrnl.exe,如果輸出FullDllName則是:\WINDOWS\system32\ntkrnlpa.exe,位址都是:804d8000,不明白為何
環境:虛擬機器VMWare:WIN XP SP3  + WDK ---- WINXP Check方式編譯
(繼續閱讀...)
文章標籤

殘月影 發表在 痞客邦 留言(0) 人氣(364)

  • 個人分類:驅動層_Rootkit資安研究
▲top
  • 6月 13 週一 201122:04
  • Rootkit高階技術盛會--HIT2011 台灣駭客嘉年華

官網:台灣駭客年會 HIT2011
一年一度難得的盛會又來囉!!!
台灣Rootkit技術最高的研討會~
(繼續閱讀...)
文章標籤

殘月影 發表在 痞客邦 留言(0) 人氣(304)

  • 個人分類:驅動層_Rootkit資安研究
▲top
  • 6月 07 週二 201123:42
  • [分享]剖析虛擬機的檢測技術

對岸一篇質量非常高的
頗析虛擬機檢測技術,共計6種檢測
用到了IDT等等的內核技術  
我整理成了繁中PDF格式  分享給大家
(繼續閱讀...)
文章標籤

殘月影 發表在 痞客邦 留言(1) 人氣(189)

  • 個人分類:驅動層_Rootkit資安研究
▲top
  • 6月 01 週三 201100:45
  • 隱藏驅動 搜尋方法(可找出某Np開頭的遊戲保護)

Rootkit
下面是關鍵代碼,可以查找斷開 PsLoadedModuleList 鏈的驅動,比如 某Np開頭的遊戲保護

PDIRECTORY_BASIC_INFORMATION    pDriverBuffer = NULL;


pDriverBuffer = (PDIRECTORY_BASIC_INFORMATION)m_cSysInfo.QueryDirectoryObject(L"\\Driver", &uMemSize);


查找驅動物件目錄下的所有物件,查找代碼如下。

PVOID CNativeSysInfo::QueryDirectoryObject(PWSTR pwsDirPath, PULONG puMemSize)
{
    NTSTATUS            ntStatus;
    UNICODE_STRING      usDirPath;
    OBJECT_ATTRIBUTES   oa;
    HANDLE              hDir = NULL;
    PVOID               pBuffer = NULL;
    ULONG               uLength = 0x800;
    ULONG               uContext = 0;
    ULONG               uResult = 0;

    // 判斷函數是否存在
    if(m_lpRtlInitUnicodeString == NULL ||
       m_lpZwOpenDirectoryObject == NULL ||
       m_lpZwQueryDirectoryObject == NULL ||
       m_lpZwClose == NULL)
    {
        return NULL;
    }

    // 打開目錄物件
    m_lpRtlInitUnicodeString(&usDirPath, pwsDirPath);
    InitializeObjectAttributes(&oa, &usDirPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
    ntStatus = m_lpZwOpenDirectoryObject(&hDir, DIRECTORY_QUERY, &oa);
    if(ntStatus != STATUS_SUCCESS)
    {
        TRACE(_T("ZwOpenDirectoryObject failed!"));
        goto _exit;
    }

    // 查詢目錄物件
    do
    {
        if(pBuffer)
            VirtualFree(pBuffer, uLength, MEM_DECOMMIT);

        uLength *= 2;

        pBuffer = VirtualAlloc(NULL, uLength, MEM_COMMIT, PAGE_READWRITE);
        if(pBuffer == NULL)
            goto _exit;

        ntStatus = m_lpZwQueryDirectoryObject(hDir, pBuffer, uLength, FALSE, TRUE, &uContext, &uResult);

    } while(ntStatus == STATUS_MORE_ENTRIES || ntStatus == STATUS_BUFFER_TOO_SMALL);

    // 判斷查詢是否成功完成
    if(ntStatus == STATUS_SUCCESS)
    {
        if(puMemSize)
            *puMemSize = uLength;
    }
    else
    {
        VirtualFree(pBuffer, uLength, MEM_DECOMMIT);
        pBuffer = NULL;
    }

_exit:

    if(hDir)
    {
        m_lpZwClose(hDir);
        hDir = NULL;
    }

    return pBuffer;
}

然後把得到的結果和常規結果比較就可以找到隱藏驅動。隱藏驅動的相關資訊可以通過下面的方式得到。

    PDRIVER_OBJECT          pDrvObject = NULL;

    RtlInitUnicodeString(&usDirPath, (PCWSTR)pvInBuf);
    ntStatus = ObReferenceObjectByName(&usDirPath,
                                       OBJ_CASE_INSENSITIVE,
                                       NULL,
                                       0,
                                       *IoDriverObjectType,
                                       KernelMode,
                                       NULL,
                                       (PVOID*)&pDrvObject);

有了 DRIVER_OBJECT 結構就啥都有了!:)

下面是一個隱藏驅動的例子,用上面的辦法可以發現。

void _EraseDrvFromModList(PDRIVER_OBJECT pDrvObject)
{
    PLDR_DATA_TABLE_ENTRY   pOwen;
    PLDR_DATA_TABLE_ENTRY   pPrev;
    PLDR_DATA_TABLE_ENTRY   pNext;

    pOwen = (PLDR_DATA_TABLE_ENTRY)pDrvObject->DriverSection;
    pPrev = (PLDR_DATA_TABLE_ENTRY)pOwen->InLoadOrderModuleList.Blink;
    pNext = (PLDR_DATA_TABLE_ENTRY)pOwen->InLoadOrderModuleList.Flink;
    pPrev->InLoadOrderModuleList.Flink = (PLIST_ENTRY)pNext;
    pNext->InLoadOrderModuleList.Blink = (PLIST_ENTRY)pPrev;

    pOwen->InLoadOrderModuleList.Flink = (PLIST_ENTRY)pOwen;
    pOwen->InLoadOrderModuleList.Blink = (PLIST_ENTRY)pOwen;
}
(繼續閱讀...)
文章標籤

殘月影 發表在 痞客邦 留言(0) 人氣(343)

  • 個人分類:驅動層_Rootkit資安研究
▲top
  • 5月 31 週二 201123:55
  • 隱藏自身驅動 輕鬆繞過XueTr 0.39檢測

當系統載入一個驅動時,會為這個驅動建立一個_KLDR_DATA_TABLE_ENTRY結構體,DRIVER_OBJECT結構體的DriverSection成員指向這個結構體。以下是WRK中_KLDR_DATA_TABLE_ENTRY結構體的定義:
typedef struct _KLDR_DATA_TABLE_ENTRY {
    LIST_ENTRY InLoadOrderLinks;
    PVOID ExceptionTable;
    ULONG ExceptionTableSize;
    // ULONG padding on IA64
    PVOID GpValue;
    PNON_PAGED_DEBUG_INFO NonPagedDebugInfo;
    PVOID DllBase;
    PVOID EntryPoint;
    ULONG SizeOfImage;
    UNICODE_STRING FullDllName;
    UNICODE_STRING BaseDllName;
    ULONG Flags;
    USHORT LoadCount;
    USHORT __Unused5;
    PVOID SectionPointer;
    ULONG CheckSum;
    // ULONG padding on IA64
    PVOID LoadedImports;
    PVOID PatchInformation;
} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;
其中 PVOID DllBase; 成員指明了驅動的載入基址;
UNICODE_STRING FullDllName;指明了驅動.sys檔的全路徑;
所有驅動的結構體通過InLoadOrderLinks成員連結起來,鏈表頭部為PsLoadedModuleList,因此可以通過遍歷PsLoadedModuleList來得到所有載入的驅動。
在測試中發現,如果將某一驅動的DllBase或FullDllName.buffer填為0,那麼XueTr就不會顯示這個驅動,以下是將DllBase填0時的驗證代碼:
(繼續閱讀...)
文章標籤

殘月影 發表在 痞客邦 留言(0) 人氣(634)

  • 個人分類:驅動層_Rootkit資安研究
▲top
  • 5月 30 週一 201112:15
  • 檔案過濾驅動學習筆記(還原軟體的基礎)

最近幾天學習了下檔案過濾驅動, 這方面的資料確實很少
這篇文章是我這幾天學習的總結, 特此貼出來供大家一起學習,
畢竟是初學檔案過濾驅動, 錯誤之處難免, 還請多多見諒.
下面進入正題
1.DriverEntry常式
(1)創建過濾驅動的控制設備, 以後我們的IO控制碼就是發到這個設備上面
//這裡的設備名與普通設備有所不同.
//當然, 最簡單的可以直接寫成 L"\\Device\\Filemontor";(FileMon中是這麼寫的, 調試過可行)
RtlInitUnicodeString( &nameString, L"\\FileSystem\\Filters\\FileMonitor" );
status = IoCreateDevice( DriverObject,
             0,                     //has no device extension  
                        //這是與其他Attach到別的設備上的設備的不同之處 
             &nameString,
             FILE_DEVICE_DISK_FILE_SYSTEM,
             FILE_DEVICE_SECURE_OPEN,
             FALSE,
             &gSFilterControlDeviceObject );
if (status == STATUS_OBJECT_PATH_NOT_FOUND) {
  RtlInitUnicodeString( &nameString, L"\\FileSystem\\FileMonitor" );
  status = IoCreateDevice( DriverObject,
               0,                      
               &nameString,
               FILE_DEVICE_DISK_FILE_SYSTEM,
               FILE_DEVICE_SECURE_OPEN,
               FALSE,
               &gSFilterControlDeviceObject );
} 
//創建符號連結
RtlInitUnicodeString(&syblnkString, L"\\DosDevices\\FileMonitor");
status = IoCreateSymbolicLink( &syblnkString, &nameString );
if (!NT_SUCCESS(status)) {
  IoDeleteSymbolicLink( &syblnkString );
  status = IoCreateSymbolicLink( &syblnkString, &nameString );
  
  if (!NT_SUCCESS(status)) {
    KdPrint(("創建符號連結失敗~\n"));
    IoDeleteDevice(gSFilterControlDeviceObject);
    return status;
  }
}
(2)設置常式
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
  DriverObject->MajorFunction[i] = SfDispatch;
}
DriverObject->MajorFunction[IRP_MJ_CREATE] = SfCreate;
DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = SfFsControl;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = SfCleanupClose;
(3)調用IoRegisterFsRegistrationChange函數來通知我們檔案系統的載入和卷的mount.
2.SfCreate 常式
(1)sfilter的原版中是這麼寫的
if (IS_MY_CONTROL_DEVICE_OBJECT(DeviceObject)) {
  Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  Irp->IoStatus.Information = 0;
  IoCompleteRequest( Irp, IO_NO_INCREMENT );
  return STATUS_INVALID_DEVICE_REQUEST;
}
這樣寫的後果是我們用CreateFile函數在R3下打開此控制設備符號連結的時候失敗
我剛開始學習檔過濾驅動的時候對此不是很瞭解, CreateFile老是失敗, 
起初還以為是符號連結名寫錯了, 後來參看了FileMon的代碼才反應過來
於是修改如下:
if (IS_MY_CONTROL_DEVICE_OBJECT(DeviceObject)) {
    
  Irp->IoStatus.Status = STATUS_SUCCESS;
  Irp->IoStatus.Information = FILE_OPENED;
  IoCompleteRequest( Irp, IO_NO_INCREMENT );
  return STATUS_SUCCESS;
}
(2)根據不同軟體的需要, 編寫此函數的接下來部分
[1]比如我們要阻止病毒在Windows目錄下創建檔, 那麼我們就要在此檔還沒創建的時候得到此檔的全路徑.
要在這個時候得到檔的路徑, 楚狂人也說了有點麻煩. 下面提供一個函數給大家, 用於在檔創建前得到路徑.
BOOLEAN MzfGetFileFullPathPreCreate(PFILE_OBJECT pFile, PUNICODE_STRING path )
{
   NTSTATUS status;
   POBJECT_NAME_INFORMATION pObjName = NULL;
   WCHAR buf[256] = {0};
   void *obj_ptr = NULL;
   ULONG ulRet = 0;
   BOOLEAN bSplit = FALSE;
   if (pFile == NULL) return FALSE;
   if (pFile->FileName.Buffer == NULL) return FALSE;
   pObjName = (POBJECT_NAME_INFORMATION)buf;
   if (pFile->RelatedFileObject != NULL)
      obj_ptr = (void *)pFile->RelatedFileObject;
   else
      obj_ptr = (void *)pFile->DeviceObject;
   status = ObQueryNameString(obj_ptr, pObjName, 256*sizeof(WCHAR), &ulRet);
   if (status == STATUS_INFO_LENGTH_MISMATCH)
   {
      pObjName = (POBJECT_NAME_INFORMATION)ExAllocatePool(NonPagedPool, ulRet);
      if (pObjName == NULL)  return FALSE;
      RtlZeroMemory(pObjName, ulRet);
      status = ObQueryNameString(obj_ptr, pObjName, ulRet, &ulRet);
      if (!NT_SUCCESS(status)) return FALSE;
   }
 //拼接的時候, 判斷是否需要加 '\\'
 if (pFile->FileName.Length > 2 && 
  pFile->FileName.Buffer[0] != L'\\' &&
  pObjName->Name.Buffer[pObjName->Name.Length/sizeof(WCHAR) -1] != L'\\')
    bSplit = TRUE;
 
 ulRet = pObjName->Name.Length + pFile->FileName.Length;
 if (path->MaximumLength < ulRet)  return FALSE;
 RtlCopyUnicodeString(path, &pObjName->Name);
 if (bSplit)
   RtlAppendUnicodeToString(path, L"\\");
 RtlAppendUnicodeStringToString(path, &pFile->FileName);
 if ((void*)pObjName != (void*)buf)
    ExFreePool(pObjName);
 return TRUE;
}
至此, 得到了檔的路徑以後, 我們就可以做出判斷了, 如果要阻止檔創建, 
那麼直接用IoCompleteRequest函數結束此IRP即可, 否則下發
IoSkipCurrentIrpStackLocation( Irp );
return IoCallDriver( ((PSFILTER_DEVICE_EXTENSION) DeviceObject->DeviceExtension)->AttachedToDeviceObject, Irp );
[2]要是像FileMon那樣只是記錄系統中創建了哪些檔的話, 我們可以設置此函數的完成常式.
然後等檔創建完成了之後, 只要調用 IoQueryFileDosDeviceName 函數即可知道檔的全路徑了.
設置完成常式如下:
{
  KEVENT waitEvent;
  KeInitializeEvent( &waitEvent, NotificationEvent, FALSE );
  IoCopyCurrentIrpStackLocationToNext( Irp );
  IoSetCompletionRoutine(Irp, SfCreateCompletion, &waitEvent, TRUE, TRUE, TRUE );
  status = IoCallDriver( ((PSFILTER_DEVICE_EXTENSION) DeviceObject->DeviceExtension)->AttachedToDeviceObject, Irp );
  if (STATUS_PENDING == status) {
    NTSTATUS localStatus = KeWaitForSingleObject(&waitEvent, Executive, KernelMode, FALSE, NULL);
    ASSERT(STATUS_SUCCESS == localStatus);
  }
  //此處檔已經創建完成了, 我們可以調用IoQueryFileDosDeviceName函數得到檔的全路徑
  //最後結束此IRP
  status = Irp->IoStatus.Status;
  IoCompleteRequest( Irp, IO_NO_INCREMENT );
  return status;
}
3.SfDispatch常式
在此常式中要判斷是不是我們的控制設備, 如果使我們的控制設備, 則要處理相應的IO控制碼.
否則, 下發此IRP
NTSTATUS SfDispatch ( IN PDEVICE_OBJECT DeviceObject,  IN PIRP Irp )
{
  NTSTATUS status = STATUS_SUCCESS;
    PIO_STACK_LOCATION irpStack;
    
    if (IS_MY_CONTROL_DEVICE_OBJECT(DeviceObject)) {
        Irp->IoStatus.Information = 0;
        irpStack = IoGetCurrentIrpStackLocation( Irp );
    
        switch (irpStack->MajorFunction) {
      
    case IRP_MJ_DEVICE_CONTROL:
      // 此函數用來執行相應的控制碼
      status = SpyCommonDeviceIoControl( Irp->AssociatedIrp.SystemBuffer,
                                                   irpStack->Parameters.DeviceIoControl.InputBufferLength,
                                                   Irp->AssociatedIrp.SystemBuffer,
                                                   irpStack->Parameters.DeviceIoControl.OutputBufferLength,
                                                   irpStack->Parameters.DeviceIoControl.IoControlCode,
                                                   &Irp->IoStatus );
      break;
      
    case IRP_MJ_CLEANUP
      status = STATUS_SUCCESS;
      break;
      
    default:
      status = STATUS_INVALID_DEVICE_REQUEST;
        }
    
        Irp->IoStatus.Status = status;
        IoCompleteRequest( Irp, IO_NO_INCREMENT );
        return status;
    }
  
  //不是我們的控制設備則下發此IRP
    return SfPassThrough( DeviceObject, Irp );
}
IO控制碼也可以在FASTIO常式的SfFastIoDeviceControl函數中處理,如下:
當然, 最簡單的還是在FASTIO常式中返回FALSE. 這樣, 系統便會調用我們上面的SfDispatch函數.
if (IS_MY_CONTROL_DEVICE_OBJECT(DeviceObject)) {
    
        SpyCommonDeviceIoControl( InputBuffer,
      InputBufferLength,
      OutputBuffer,
      OutputBufferLength,
      IoControlCode,
      IoStatus );
    
        return TRUE;
(繼續閱讀...)
文章標籤

殘月影 發表在 痞客邦 留言(0) 人氣(428)

  • 個人分類:驅動層_Rootkit資安研究
▲top
  • 5月 29 週日 201121:01
  • 實現用IDA調試內核驅動


以前總想知道 IDA 是否能夠實現內核調試,後來找了一段時間沒什麼結果就暫時放棄了。 今天在國外的一個博客上偶然看到了用 IDA 實現內核調試的方法,其實現在國內也有很多文 章介紹了 IDA 通過串口進行調試的文章,如果大家想看的話可以搜索下。
這裡只是參考原文把實現的方法大體的用中文表述了一下。在調試之前需要安裝如下的 軟體:
1. IDA PRO 這個我想大家都應該有了;
2. Windbg 如果調試過驅動或者系統內核的話這個東西也應該有了;
3. VirtualKd 這個東西我想大家如果沒有做過使用 IDA 調試內核的話這個東西應該是 還沒有。
(繼續閱讀...)
文章標籤

殘月影 發表在 痞客邦 留言(0) 人氣(198)

  • 個人分類:驅動層_Rootkit資安研究
▲top
  • 5月 29 週日 201120:13
  • 超強驅動防行程終止

Rootkit
2011.5.29測試有效
【提示】能加驅動進內核,就沒必要弄EXE了,所以我個人覺得沒啥實際用途,僅供觀看
Windows會給每一個進程建立一個EPROCESS結構,給每一個執行緒建立ETHREAD結構,EPROCESS結構第一個成員是KPROCESS結構,ETHREAD結構第一個成員是KTHREAD結構。每個進程的執行緒的ETHREAD結構都會按下圖所示連結起來: 
(繼續閱讀...)
文章標籤

殘月影 發表在 痞客邦 留言(0) 人氣(305)

  • 個人分類:驅動層_Rootkit資安研究
▲top
  • 5月 19 週四 201120:46
  • Hook Shadow SSDT

網上很多文章都有關於SSDT的完整的實現,但是沒有關於Shadow SSDT的完整實現,目前最好的文章是《shadow ssdt學習筆記 by zhuwg》,我這裡的程式也很多參考了他的文章,在這裡謝謝了。我這裡給出一個hook shadow ssdt的完整實現的驅動和3層的代碼。

這裡主要是hook 了NtUserFindWindowEx,NtUserBuildHwndList,NtUserQueryWindow,NtUserGetForegroundWindow,NtUserWindowFromPoint來防止其他應用程式通過FindWindow,EnumWindow,WindowFromPoint,GetForegroundWindow這些函數來枚舉我們的視窗,不過這個程式對於GetWindowText這個東西無法防護,如果有朋友在驅動層實現了對該函數的保護,是否能一起交流呢。

關於hook的流程,看了上面zhuwg的文章,大家應該很好的瞭解了。下面的代碼也很簡單。大家隨便看看吧,通信方面,隨便使用了METHOD_NEITHER方法,這個方法不好,有問題,不過懶得改了,懂驅動的應該很容易改為BUFFERED模式吧。

在這裡謝謝給了很多幫助的各位牛人,特別是NetRoc,很細心的幫我測試。。
(繼續閱讀...)
文章標籤

殘月影 發表在 痞客邦 留言(0) 人氣(409)

  • 個人分類:驅動層_Rootkit資安研究
▲top
  • 5月 14 週六 201123:28
  • objectHook簡單介紹

3.jpg
其實這東西很多大牛多玩膩了的東西,看下論壇上比較少這類的,就來獻獻醜,科普一下 大牛們直接
可以飄過,這東西主要是自我複習一下OBJECT的一些知識,技術這東西久了不弄容易忘記,所以
拿出來跟和我一樣菜的菜鳥們分享一下。如果有不對的地方歡迎大家指正,這樣對於自己也進步得
快點,多多交流,互相學習,水準才能提高得快。
   
第一我們先看下OBJECT的組成 主要是3部分 如下圖
              
         |---------| 
             | 
附加資訊| --->  主要的幾個結構是 OBJECT_HEADER_CREATOR_INFO 創建資訊 
                              OBJECT_HEADER_NAME_INFO 
這裡面有物件名等主要資訊 
                              OBJECT_HEADER_HANDLE_INFO 
一些控制碼資訊          
         |_________|                 
             |                   | 
             | 
物件頭      |---->     一個重要的結構   OBJECT_HEADER              
             |_________|  
             |                  | 
             | OBJECT      | --->       
對象                
         |_________|  
   
我們主要看下OBJECT_HEADER這個資料結構幾個重要我成員我注釋出來

typedef struct _OBJECT_HEADER { 
  LONG PointerCount; 
  union { 
    LONG HandleCount; 
    PSINGLE_LIST_ENTRY SEntry; 
  }; 
  POBJECT_TYPE Type; //
這個很重要HOOK就靠它,物件類型結構也是一個物件,TYPE它是系統第一個創建出來的物件類型 
  UCHAR NameInfoOffset; //OBJECT_HEADER_NAME_INFO 
偏移
  UCHAR HandleInfoOffset; //OBJECT_HEADER_HANDLE_INFO 
偏移
  UCHAR QuotaInfoOffset; 
  UCHAR Flags; 
  union 
  { 
    POBJECT_CREATE_INFORMATION ObjectCreateInfo; 
    PVOID QuotaBlockCharged; 
  };
  
  PSECURITY_DESCRIPTOR SecurityDescriptor; 
  QUAD Body;//
物件本身 
} OBJECT_HEADER, *POBJECT_HEADER; 
物件類型結構
typedef struct _OBJECT_TYPE { 
  ERESOURCE Mutex; 
  LIST_ENTRY TypeList; //
佇列
  UNICODE_STRING Name; 
  PVOID DefaultObject; 
  ULONG Index; 
  ULONG TotalNumberOfObjects; 
  ULONG TotalNumberOfHandles; 
  ULONG HighWaterNumberOfObjects; 
  ULONG HighWaterNumberOfHandles; 
  OBJECT_TYPE_INITIALIZER TypeInfo; //
這個很重要,下面講這個結構
#ifdef POOL_TAGGING 
  ULONG Key; 
#endif 
} OBJECT_TYPE, *POBJECT_TYPE;
物件類型結構主要是創建物件類型比如*IoFileObjectType,*PsProcessType,*PsThreadType這些類型
系統初始化的時候第一個創建的物件類型結構就是TYPE類型結構生成物件目錄\ObjectTypes 其它後面的
比如檔物件類型就掛在\ObjectTypes\File 再比如\ObjectTypes\Device
說白點就是你要生成物件就會創建(指定)相對應的物件類型結構
 
最重要的一個資料結構
typedef struct _OBJECT_TYPE_INITIALIZER {
  USHORT Length;
  BOOLEAN UseDefaultObject;
  BOOLEAN CaseInsensitive;
  ULONG InvalidAttributes;
  GENERIC_MAPPING GenericMapping;
  ULONG ValidAccessMask;
  BOOLEAN SecurityRequired;
  BOOLEAN MaintainHandleCount;
  BOOLEAN MaintainTypeList;
  POOL_TYPE PoolType;
  ULONG DefaultPagedPoolCharge;
  ULONG DefaultNonPagedPoolCharge;
  PVOID DumpProcedure;/*
  PVOID OpenProcedure;        
這幾個函數指標就是我們最需要的
  PVOID CloseProcedure;       
這些函數都是決定你的物件的的一些
  PVOID DeleteProcedure;      
操作或者叫方法,比如打開 創建 刪除
  PVOID ParseProcedure;       
不同的物件類型(OBJECT_TYPE)操作也不同
  PVOID SecurityProcedure;    
所以要清楚的知道(OBJECT_TYPE)物件是什麼類型
  PVOID QueryNameProcedure;   
如果沒有配置系統調用的物件類型 都是用NtOpenFile
  PVOID OkayToCloseProcedure;*/
} OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;


這些方法何時被調用呢,我舉個例子
當你調用NtCreateFile->IoCreateFile->ObOpenObjectByName->ObpLookupObjectName->IopParseFile->IopParseDevice
IopParseFile
最終也會調用IopParseDevice
ObjectHook
其實就是比如你要HOOK 創建打開就是OBJECT_TYPE_INITIALIZER->ParseProcedure
說了一大堆廢話 上段代碼。
#include <ntddk.h>

#define OBJECT_TO_OBJECT_HEADER(o)\
      CONTAINING_RECORD((o),OBJECT_HEADER,Body)
#define CONTAINING_RECORD(address,type,field)\
      ((type*)(((ULONG_PTR)address)-(ULONG_PTR)(&(((type*)0)->field))))


typedef struct _OBJECT_TYPE_INITIALIZER {
  USHORT Length;
  BOOLEAN UseDefaultObject;
  BOOLEAN CaseInsensitive;
  ULONG InvalidAttributes;
  GENERIC_MAPPING GenericMapping;
  ULONG ValidAccessMask;
  BOOLEAN SecurityRequired;
  BOOLEAN MaintainHandleCount;
  BOOLEAN MaintainTypeList;
  POOL_TYPE PoolType;
  ULONG DefaultPagedPoolCharge;
  ULONG DefaultNonPagedPoolCharge;
  PVOID DumpProcedure;
  PVOID OpenProcedure;
  PVOID CloseProcedure;
  PVOID DeleteProcedure;
  PVOID ParseProcedure;
  PVOID SecurityProcedure;
  PVOID QueryNameProcedure;
  PVOID OkayToCloseProcedure;
} OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;


typedef struct _OBJECT_TYPE { 
  ERESOURCE Mutex; 
  LIST_ENTRY TypeList; 
  UNICODE_STRING Name; 
  PVOID DefaultObject; 
  ULONG Index; 
  ULONG TotalNumberOfObjects; 
  ULONG TotalNumberOfHandles; 
  ULONG HighWaterNumberOfObjects; 
  ULONG HighWaterNumberOfHandles; 
  OBJECT_TYPE_INITIALIZER TypeInfo; 
#ifdef POOL_TAGGING 
  ULONG Key; 
#endif 
} OBJECT_TYPE, *POBJECT_TYPE;

typedef struct _OBJECT_CREATE_INFORMATION { 
  ULONG Attributes; 
  HANDLE RootDirectory; 
  PVOID ParseContext; 
  KPROCESSOR_MODE ProbeMode; 
  ULONG PagedPoolCharge; 
  ULONG NonPagedPoolCharge; 
  ULONG SecurityDescriptorCharge; 
  PSECURITY_DESCRIPTOR SecurityDescriptor; 
  PSECURITY_QUALITY_OF_SERVICE SecurityQos; 
  SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService; 
} OBJECT_CREATE_INFORMATION, *POBJECT_CREATE_INFORMATION;



typedef struct _OBJECT_HEADER { 
  LONG PointerCount; 
  union { 
    LONG HandleCount; 
    PSINGLE_LIST_ENTRY SEntry; 
  }; 
  POBJECT_TYPE Type; 
  UCHAR NameInfoOffset; 
  UCHAR HandleInfoOffset; 
  UCHAR QuotaInfoOffset; 
  UCHAR Flags; 
  union 
  { 
    POBJECT_CREATE_INFORMATION ObjectCreateInfo; 
    PVOID QuotaBlockCharged; 
  };
  
  PSECURITY_DESCRIPTOR SecurityDescriptor; 
  QUAD Body; 
} OBJECT_HEADER, *POBJECT_HEADER;
POBJECT_TYPE pType= NULL;
POBJECT_HEADER addrs=NULL;
PVOID OldParseProcedure = NULL;


NTSTATUS NewParseProcedure(IN PVOID ParseObject,
             IN PVOID ObjectType,
             IN OUT PACCESS_STATE AccessState,
             IN KPROCESSOR_MODE AccessMode,
             IN ULONG Attributes,
             IN OUT PUNICODE_STRING CompleteName,
             IN OUT PUNICODE_STRING RemainingName,
             IN OUT PVOID Context OPTIONAL,
             IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
             OUT PVOID *Object) 
{
     NTSTATUS Status;
     KdPrint(("object is hook\n"));
 
  __asm
  {
      push eax
      push Object
      push SecurityQos
      push Context
      push RemainingName
      push CompleteName
      push Attributes
      movzx eax, AccessMode
      push eax
      push AccessState
      push ObjectType
      push ParseObject
      call OldParseProcedure
      mov Status, eax
      pop eax

      
  } 
  return Status;

}
NTSTATUS Hook()
{
  NTSTATUS  Status;
  HANDLE hFile;
  UNICODE_STRING Name;
  OBJECT_ATTRIBUTES Attr;
  IO_STATUS_BLOCK ioStaBlock;
  PVOID pObject = NULL;
  
  
  RtlInitUnicodeString(&Name,L"\\Device\\HarddiskVolume1\\1.txt");
  InitializeObjectAttributes(&Attr,&Name,OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE ,\
    0,NULL);
  Status = ZwOpenFile(&hFile,GENERIC_ALL,&Attr,&ioStaBlock,\
    0,FILE_NON_DIRECTORY_FILE);
  if (!NT_SUCCESS(Status))
  {
    KdPrint(("File is Null\n"));
    return Status;
  }
 
  Status = ObReferenceObjectByHandle(hFile,GENERIC_ALL,NULL,KernelMode,&pObject,NULL);
  if (!NT_SUCCESS(Status))
  {
    KdPrint(("Object is Null\n"));
    return Status;
  }
 
 KdPrint(("pobject is %08X\n",pObject));

 addrs=OBJECT_TO_OBJECT_HEADER(pObject);//
獲取對象頭


pType=addrs->Type;//
獲取物件類型結構 object-10h

KdPrint(("pType is %08X\n",pType));
OldParseProcedure = pType->TypeInfo.ParseProcedure;//
獲取服務函數原始位址OBJECT_TYPE+9C位置為打開
KdPrint(("OldParseProcedure addrs is %08X\n",OldParseProcedure));
KdPrint(("addrs is %08X\n",addrs));
//
這裡最好檢查一下OldParseProcedure ,我真的是太懶了。
__asm
  {
    cli;
    mov eax, cr0;
    and eax, not 10000h;
    mov cr0, eax;
  }
pType->TypeInfo.ParseProcedure = NewParseProcedure;//hook
  __asm
  {
    mov eax, cr0;
    or eax, 10000h;
    mov cr0, eax;
    sti;
  }
 Status = ZwClose(hFile);
  return Status;
}

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath)
{
  NTSTATUS Status = STATUS_SUCCESS;
  Status=Hook();
  return Status;
}
(繼續閱讀...)
文章標籤

殘月影 發表在 痞客邦 留言(0) 人氣(178)

  • 個人分類:驅動層_Rootkit資安研究
▲top
123»