首页
社区
课程
招聘
[原创]新手对07年某强删工具sys的逆向学习
发表于: 2013-3-20 18:12 10210

[原创]新手对07年某强删工具sys的逆向学习

2013-3-20 18:12
10210

新手对07年某强删工具sys的逆向学习

[前置说明] 纯新手的动手过程,事无巨细,大牛飘过
[使用工具] IDA,WinDbg,wsyscheck
[系统环境] windows xp sp3

打开该程序后,用wsyscheck观察驱动模块,发现它平时并不加载驱动。于是自己写一个hook_NtLoadDriver的sys,发

现只有点击程序界面的“删除文件”后,才会加载驱动,并且删除完成后会删掉该驱动。于是在hook_NtLoadDriver里

加入copyfile,顺利复制到该驱动。附件中包含hook_NtLoadDriver,早期代码,没有考虑hook时多核安全性。

将该sys拖入IDA,到入口点,

观察到以下字样,

INIT:0001268A                 mov     eax, dword_12604
INIT:0001268F                 test    eax, eax
INIT:00012691                 mov     ecx, 0BB40h
......
INIT:0001269C                 mov     edx, ds:KeTickCount
INIT:000126A2                 mov     eax, offset dword_12604

此段可google "/gs Cookie" 得到一些解释,推荐阅读:
794K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3q4V1N6X3c8T1k6#2)9J5k6h3!0J5k6#2)9J5c8X3u0D9L8$3N6K6i4K6u0r3j5h3c8$3k6r3u0Y4i4K6g2X3M7%4W2K6N6r3g2E0i4K6u0r3j5i4u0@1K9h3y4D9k6i4y4Q4x3V1j5@1x3K6u0Q4x3X3g2S2M7%4m8^5

该驱动主要功能如下:首先是对FSD的hook的处理,

一、RemoveAttachedDevice:
void __stdcall RemoveAttachedDevice(PCWSTR pwStr)    // L"\\FileSystem\\Ntfs" & L"\\FileSystem\\Fastfat"
{
    UNICODE_STRING DestinationString;
    PDRIVER_OBJECT pDrvObj;

    RtlInitUnicodeString(&DestinationString, pwStr);

    if (ObReferenceObjectByName(&DestinationString,
        OBJ_CASE_INSENSITIVE,
        0,
        0,
        *IoDriverObjectType,
        KernelMode,
        0,
        &pDrvObj))
    {
        return;
    }

    if (pDrvObj)
    {
        PDEVICE_OBJECT pDevObj = NULL;
        KIRQL Irql;
        Irql = KfAcquireSpinLock(&SpinLock);
        __asm
        {
            mov eax, cr0
                and eax, not 10000h
                mov cr0, eax
                cli
        }
        for ( pDevObj = pDrvObj->DeviceObject; pDevObj; pDevObj = pDevObj->NextDevice )
            pDevObj->AttachedDevice = NULL;

        ObfDereferenceObject(pDrvObj);
        __asm
        {
            sti
                mov eax, cr0
                or eax, 10000h
                mov cr0, eax
        }
        KfReleaseSpinLock(&SpinLock, Irql);
    }
}

注意IDA5.5附带的Hex-Rays Decompiler plugin,貌似是1.1版,会忽略cli与sti指令。

二、RestoreFSDDispatchRoutine
分别获取当前内存中FSD的DispatchRoutine地址,和根据实际文件中(Fastfat.sys & Ntfs.sys)计算得到的DispatchRoutine,比较之,不同则恢复。
其中,从文件中获取DispatchRoutine的方法是,先根据PE结构查到进入点,然后匹配opcode来查找DispatchRoutine地址,就是所谓的硬编码。
PE结构参考“新手入门文章 by 野男孩.CHM”,还有从网上找的一张PE图,附件提供该图。

弄清PE相关偏移时有用的windbg命令:
1. dt STRUCT (显示某结构)
   dt STRUCT -r
   dt STRUCT -r1(或-r2 -r3。。。)

2. ??sizeof(STRUCT) (计算某结构大小)

opcode参考“6eeK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3I4#2L8$3y4G2L8X3N6Q4x3X3g2U0L8$3#2Q4x3V1k6D9k6h3q4J5L8X3W2F1k6$3!0H3j5$3!0V1k6g2)9J5c8X3W2F1k6r3g2^5i4K6u0W2K9s2c8E0i4@1f1J5i4K6R3H3i4K6W2p5i4@1g2r3i4@1u0o6i4K6S2o6
比如:        if ( *((UCHAR *)pBuf + x) == 0xC7    // opcode C7 mov
            &&  *((UCHAR *)pBuf + x + 2) == v36 
            &&  *((UCHAR *)pBuf + x + 7) == 0xC7
            && (*((UCHAR *)pBuf + x + 1) == 0x46 || *((UCHAR *)pBuf + x + 1) == 0x43)
            )

上面参考资料的教程不全,看完后仍然没有解释C7是什么,那这里自己来找。其实在IDA里面双击这个驱动的DriverEntry,切到IDA View窗口,点击设置分发函数的那些mov,然后切到Hex View窗口,可见有的mov是B8,有的mov是89,有的mov是C7,肉眼观测C7的mov指令长度为7字节,后4字节是一个32位地址,也就是说C7是把一个32位立即数弄到XXX里去的mov指令,那个上面的代码里pBuf + x + 7就是下一条指令了,它也是个mov。

HANDLE __stdcall ItsOpenFile(PCWSTR SourceString, ACCESS_MASK DesiredAccess, ULONG ShareAccess)    // done!
{
    NTSTATUS status;
    //
    UNICODE_STRING    DestinationString;
    OBJECT_ATTRIBUTES ObjectAttributes;
    HANDLE            FileHandle;
    IO_STATUS_BLOCK   IoStatusBlock;

    if ( KeGetCurrentIrql() )
        return 0;

    RtlInitUnicodeString(&DestinationString, SourceString);

    ObjectAttributes.RootDirectory = 0;
    ObjectAttributes.SecurityDescriptor = 0;
    ObjectAttributes.SecurityQualityOfService = 0;
    ObjectAttributes.Length = 24;
    ObjectAttributes.Attributes = 576;
    ObjectAttributes.ObjectName = &DestinationString;

    status = IoCreateFile(
        &FileHandle,
        DesiredAccess,
        &ObjectAttributes,
        &IoStatusBlock,
        0,
        0x80u,
        ShareAccess,
        1u,
        0,
        0,
        0,
        0,
        0,
        0x100u);

    if ( status )
    {
        return 0;
    }

    return FileHandle;
}

PULONG __stdcall SetFileAttributeNormal(HANDLE handle)      // done!
{
    NTSTATUS status;
    //
    PFILE_OBJECT    pFileObject;
    PDEVICE_OBJECT  pDevObj;
    IO_STATUS_BLOCK IoStatusBlock = {0};
    FILE_BASIC_INFORMATION  FileInformation = {0};
    KEVENT Event;
    PIRP   pIrp;
    PIO_STACK_LOCATION pIrpSp;

    status = ObReferenceObjectByHandle(
        handle,
        DELETE,
        *IoFileObjectType,
        0,
        (PVOID*)&pFileObject,
        0);
    if ( status )
    {
        return 0;
    }

    pDevObj = IoGetRelatedDeviceObject(pFileObject);
    pIrp = IoAllocateIrp(pDevObj->StackSize, TRUE);
    if ( pIrp )
    {
        KeInitializeEvent(&Event, SynchronizationEvent, 0);

        pIrp->AssociatedIrp.SystemBuffer = &FileInformation;
        pIrp->UserEvent = &Event;
        pIrp->UserIosb  = &IoStatusBlock;
        pIrp->Tail.Overlay.OriginalFileObject = pFileObject;
        pIrp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
        pIrp->RequestorMode = 0;

        FileInformation.FileAttributes = FILE_ATTRIBUTE_NORMAL;

        pIrpSp = ((char *)pIrp->Tail.Overlay.CurrentStackLocation - 36);
        pIrpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
        pIrpSp->DeviceObject = pDevObj;
        pIrpSp->FileObject = pFileObject;
        pIrpSp->Parameters.SetFile.Length = sizeof(FILE_BASIC_INFORMATION);
        pIrpSp->Parameters.SetFile.FileInformationClass = FileBasicInformation;
        pIrpSp->Parameters.SetFile.FileObject = pFileObject;

        pIrpSp->CompletionRoutine = SetFileAttributeCompletion;
        pIrpSp->Context = 0;
        pIrpSp->Control = 0xE0;
        IofCallDriver(pDevObj, pIrp);
        KeWaitForSingleObject(&Event, 0, 0, 1u, 0);
    }

    ObfDereferenceObject(pFileObject);
    return IoStatusBlock.Status;
}

PULONG __stdcall SetFileAttributeDelete(HANDLE handle)      // done!
{
    PFILE_OBJECT    pFileObject;
    PDEVICE_OBJECT  pDevObj;
    IO_STATUS_BLOCK IoStatusBlock = {0};
    FILE_DISPOSITION_INFORMATION FileInformation;
    PIRP   pIrp;
    KEVENT Event;
    PIO_STACK_LOCATION pIrpSp;

    if ( ObReferenceObjectByHandle(
        handle,
        DELETE,
        *IoFileObjectType,
        0,
        (PVOID*)&pFileObject,
        0) )
    {
        return 0;
    }

    pDevObj = IoGetRelatedDeviceObject(pFileObject);
    pIrp = IoAllocateIrp(pDevObj->StackSize, TRUE);
    if ( pIrp )
    {
        KeInitializeEvent(&Event, SynchronizationEvent, 0);

        pIrp->AssociatedIrp.SystemBuffer = &FileInformation;
        pIrp->UserEvent = &Event;
        pIrp->UserIosb  = &IoStatusBlock;
        pIrp->Tail.Overlay.OriginalFileObject = pFileObject;
        pIrp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
        pIrp->RequestorMode = 0;

        FileInformation.DeleteFile = TRUE;

        pIrpSp = ((char *)pIrp->Tail.Overlay.CurrentStackLocation - 36);
        pIrpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
        pIrpSp->DeviceObject = pDevObj;
        pIrpSp->FileObject = pFileObject;
        pIrpSp->Parameters.SetFile.Length = sizeof(FILE_DISPOSITION_INFORMATION);
        pIrpSp->Parameters.SetFile.FileInformationClass = FileDispositionInformation;
        pIrpSp->Parameters.SetFile.FileObject = pFileObject;

        pIrpSp->CompletionRoutine = SetFileAttributeCompletion;
        pIrpSp->Context = 0;
        pIrpSp->Control = 0xE0;
        IofCallDriver(pDevObj, pIrp);
        KeWaitForSingleObject(&Event, 0, 0, 1u, 0);
    }

    ObfDereferenceObject(pFileObject);
    return IoStatusBlock.Status;
}


[培训]科锐逆向工程师培训第53期2025年7月8日开班!

上传的附件:
收藏
免费 6
支持
分享
最新回复 (17)
雪    币: 278
活跃值: (709)
能力值: ( LV15,RANK:520 )
在线值:
发帖
回帖
粉丝
2
hook过来,hook过去有意思么?
2013-3-20 18:25
0
雪    币: 278
活跃值: (709)
能力值: ( LV15,RANK:520 )
在线值:
发帖
回帖
粉丝
3
抱歉,楼主,我没其他意思,互相学习,致敬!
2013-3-20 18:26
0
雪    币: 284
活跃值: (3824)
能力值: ( LV5,RANK:75 )
在线值:
发帖
回帖
粉丝
4
在说“hook过来,hook过去有意思么?”之前,请指教在这个用途里比hook更simple的方式?
2013-3-20 18:33
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
5
HIPS拦截驱动加载,然后在它加载之前把驱动拷出来就行了,不用写代码~
2013-3-20 21:54
0
雪    币: 284
活跃值: (3824)
能力值: ( LV5,RANK:75 )
在线值:
发帖
回帖
粉丝
6
这个我知道,懒得装HIPS,嘿嘿
2013-3-20 22:47
0
雪    币: 284
活跃值: (3824)
能力值: ( LV5,RANK:75 )
在线值:
发帖
回帖
粉丝
7
手边有hook的代码,随便改改bld一下就能用么,
2013-3-20 22:50
0
雪    币: 862
活跃值: (329)
能力值: ( LV9,RANK:165 )
在线值:
发帖
回帖
粉丝
8
个人感觉hook  loaddriver 比装hips更麻烦~
2013-3-20 23:20
0
雪    币: 284
活跃值: (3824)
能力值: ( LV5,RANK:75 )
在线值:
发帖
回帖
粉丝
9
当时去MSDN查了下ntloaddriver原型,再用wsyscheck查了下它的编号,也挺快的。目的是学习
2013-3-21 00:16
0
雪    币: 55
活跃值: (531)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
10
thanks
2013-3-23 08:48
0
雪    币: 14
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
11
HOOK真心没有意思, 但在这个全民HOOK的年代,不把HOOK给玩出点花样来,还真心连面试都难过! 悲剧
2013-3-23 09:26
0
雪    币: 496
活跃值: (311)
能力值: ( LV13,RANK:400 )
在线值:
发帖
回帖
粉丝
12
真心不用Hook,下个断点就能办到的事。
2013-3-23 09:49
0
雪    币: 284
活跃值: (3824)
能力值: ( LV5,RANK:75 )
在线值:
发帖
回帖
粉丝
13
虚拟机里断还是实机?这个是实机。
2013-3-23 14:46
0
雪    币: 496
活跃值: (311)
能力值: ( LV13,RANK:400 )
在线值:
发帖
回帖
粉丝
14
想拿他的驱动方法太多了。。
1.查看资源文件法,如果他的驱动程序被当作资源文件释放并且没有加密,那就直接提取资源文件。
2.调试跟踪,找到应用层程序加载驱动的地方,下个断点,然后程序运行到断点的时候看一下驱动加载的路劲,直接去把路径文件拷贝出来一份。
3.内存拷贝模块,程序加载驱动之后,直接用工具把驱动模块从内存中拷贝一份出来。

完全不需要写代码的。
2013-3-23 15:29
0
雪    币: 278
活跃值: (709)
能力值: ( LV15,RANK:520 )
在线值:
发帖
回帖
粉丝
15
LZ,向你说声对不起,完全是我的错.
2013-3-23 15:31
0
雪    币: 284
活跃值: (3824)
能力值: ( LV5,RANK:75 )
在线值:
发帖
回帖
粉丝
16
你没错,就是给我把楼歪了~
2013-3-23 16:14
0
雪    币: 284
活跃值: (3824)
能力值: ( LV5,RANK:75 )
在线值:
发帖
回帖
粉丝
17
这个程序是易语言写的,不知道提取资源容易不。断服务相关函数是可以,当时没想到。这个程序在点“删除文件”时加载驱动,功能完成后立即就把驱动删了貌似。总之写那点代码几分钟的事情,没想那么多,方法确实很多的。
2013-3-23 16:25
0
雪    币: 298
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
all roads lead to Rome
2013-4-12 12:41
0
游客
登录 | 注册 方可回帖
返回