2013年2月17日星期日

PsSetLoadImageNotifyRoutine2.c


/*
感谢QQ群:《windbg调试,dump分析》 里面的 虾米在养虾 提供的思路。

虽然有硬编码,但是我觉得通用。

其实我也想过这个办法,觉得麻烦,其实做起来挺简单的。
其实我追求更好,其实只要能完成功能就可以了。

先思路,再手动实现,最后编码实现,计算机的运行速度还是挺快的。

made by correy
QQ:112426112
Email:kouleguan at hotmail dot com
Homepage:http://correy.webs.com
*/

#include <ntddk.h>

#ifdef _X86_
int modify_driver_32(PVOID ImageBase) //她奶奶的,不能用bool和true.
{
    //此时驱动已经加载,但还没有运行。
    //做法是在驱动的入口填写c20800即ret 8。注释不是:retn的机器码c3.
    //不必要再写mov eax,STATUS_UNSUCCESSFUL的机器码了。#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L)
    //wdk编译的驱动入口是添加的,非真正的入口,汇编写的驱动入口才是真正的入口,这里的入口是pe文件的入口和DriverEntry的关系。

    //B8 01 00 00 C0     mov     eax, 0C0000001h
    //c20800             ret 8
    unsigned char opcode[] = {0xB8,0x01,0x00,0x00,0xC0,0xc2,0x08,0x00};

    int pe;//pe的偏移。
    int oep;
    unsigned int x;

    pe = *(unsigned int *)((unsigned int)ImageBase + 0x3c);
    oep = *(unsigned int *)((unsigned int)ImageBase + pe + 4 + 20 + 16);

    x = oep;
    x += (unsigned int)ImageBase;//奶奶的,必须加这两行,直接用好像不行。
    RtlCopyMemory((unsigned int *)x,opcode,8);

    return 1;
}
#endif 

#if defined(_AMD64_) || defined(_IA64_) //defined(_WIN64_) 
int modify_driver_64(PVOID ImageBase) 
{
    //做法是在驱动的入口填写retn的机器码c3.

    //B8 01 00 00 C0     mov     eax, 0C0000001h
    //c3                 retn
    unsigned char opcode[] = {0xB8,0x01,0x00,0x00,0xC0,0xc3};

    int pe;//pe的偏移。
    int oep;
    ULONG64 x;

    pe = *(int *)((ULONG64)ImageBase + 0x3c);
    oep = *(int *)((ULONG64)ImageBase + pe + 4 + 20 + 16);

    //x = (ULONG64 *)ImageBase + oep;//这一行总会把oep*8,所以用下面的两行替换。
    x = oep;
    x += (ULONG64)ImageBase;
    RtlCopyMemory((ULONG64 *)x,opcode,6);//其实直接赋值也可以。

    return 1;//true
}
#endif 

VOID MY_PLOAD_IMAGE_NOTIFY_ROUTINE(__in_opt PUNICODE_STRING  FullImageName, __in HANDLE  ProcessId, __in PIMAGE_INFO  ImageInfo)
{
    NTSTATUS r;
    int n,len;
    wchar_t sysname[] = L"sys.sys";
    UNICODE_STRING u1,u2;
    int b = 0;
    HANDLE hcp;

    hcp = PsGetCurrentProcessId();//如果是驱动模块,ProcessId总为0,这可能是错误的。

    //其实这里也可以把进程给结束了。

    len = wcslen(sysname) * sizeof(wchar_t);
    n = (FullImageName->Length - len)/sizeof(wchar_t); 

    //如果加载的驱动是:sys.sys,就调用ZwUnmapViewOfSection

    RtlInitUnicodeString(&u1,sysname);
    RtlInitUnicodeString(&u2,&FullImageName->Buffer[n]);
    b = RtlEqualUnicodeString(&u1,&u2,1);
    if (b) //判断条件不一定准确。其实也可以写一个函数。
    {

#ifdef _X86_
        modify_driver_32(ImageInfo->ImageBase);
#endif

#if defined(_AMD64_) || defined(_IA64_) //defined(_WIN64_) 
        modify_driver_64(ImageInfo->ImageBase);
#endif 
        
    }
}

DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{
    PsRemoveLoadImageNotifyRoutine(MY_PLOAD_IMAGE_NOTIFY_ROUTINE);
}

DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;

    //KdBreakPoint();//#define KdBreakPoint() DbgBreakPoint() 

    DriverObject->DriverUnload = Unload; 

    status = PsSetLoadImageNotifyRoutine(MY_PLOAD_IMAGE_NOTIFY_ROUTINE);

    return status;
} 
//made 2013.02.17

//一下有改进,但是没有测试。

#include <ntddk.h>

#ifdef _X86_
int modify_driver_32(PVOID ImageBase) //她奶奶的,不能用bool和true.
{
    //此时驱动已经加载,但还没有运行。
    //做法是在驱动的入口填写c20800即ret 8。注释不是:retn的机器码c3.
    //不必要再写mov eax,STATUS_UNSUCCESSFUL的机器码了。#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L)
    //wdk编译的驱动入口是添加的,非真正的入口,汇编写的驱动入口才是真正的入口,这里的入口是pe文件的入口和DriverEntry的关系。

    //B8 01 00 00 C0     mov     eax, 0C0000001h
    //c20800             ret 8
    unsigned char opcode[] = {0xB8,0x01,0x00,0x00,0xC0,0xc2,0x08,0x00};

    int pe;//pe的偏移。
    int oep;
    unsigned int x;

    pe = *(unsigned int *)((unsigned int)ImageBase + 0x3c);
    oep = *(unsigned int *)((unsigned int)ImageBase + pe + 4 + 20 + 16);

    x = oep;
    x += (unsigned int)ImageBase;//奶奶的,必须加这两行,直接用好像不行。
    RtlCopyMemory((unsigned int *)x,opcode,8);

    return 1;
}
#endif 

#if defined(_AMD64_) || defined(_IA64_) //defined(_WIN64_) 
int modify_driver_64(PVOID ImageBase) 
{
    //做法是在驱动的入口填写retn的机器码c3.

    //B8 01 00 00 C0     mov     eax, 0C0000001h
    //c3                 retn
    unsigned char opcode[] = {0xB8,0x01,0x00,0x00,0xC0,0xc3};

    int pe;//pe的偏移。
    int oep;
    ULONG64 x;

    pe = *(int *)((ULONG64)ImageBase + 0x3c);
    oep = *(int *)((ULONG64)ImageBase + pe + 4 + 20 + 16);

    //x = (ULONG64 *)ImageBase + oep;//这一行总会把oep*8,所以用下面的两行替换。
    x = oep;
    x += (ULONG64)ImageBase;
    RtlCopyMemory((ULONG64 *)x,opcode,6);//其实直接赋值也可以。

    return 1;//true
}
#endif 

int IsMyfilter(__in_opt PUNICODE_STRING  FullImageName)
{
    NTSTATUS r;
    int n,len;
    wchar_t sysname[] = L"sys.sys";
    UNICODE_STRING u1,u2;
    int b = 0;
    HANDLE hcp;

    hcp = PsGetCurrentProcessId();//如果是驱动模块,这个值大多为system的pid.

    len = wcslen(sysname) * sizeof(wchar_t);
    n = (FullImageName->Length - len)/sizeof(wchar_t); 

    RtlInitUnicodeString(&u1,sysname);
    RtlInitUnicodeString(&u2,&FullImageName->Buffer[n]);
    return RtlEqualUnicodeString(&u1,&u2,1);
}

VOID MY_PLOAD_IMAGE_NOTIFY_ROUTINE(__in_opt PUNICODE_STRING  FullImageName, __in HANDLE  ProcessId, __in PIMAGE_INFO  ImageInfo)
{
    int b = 0;

    if (ProcessId == 0) //如果监控的是驱动,加上这一句,计算机会运行快一些,因为自己发现:如果是驱动模块,ProcessId总为0
    {
        b = IsMyfilter(FullImageName);
        if (b) //判断条件不一定准确。其实也可以写一个函数。
        {

#ifdef _X86_
            modify_driver_32(ImageInfo->ImageBase);
#endif

#if defined(_AMD64_) || defined(_IA64_) //defined(_WIN64_) 
            modify_driver_64(ImageInfo->ImageBase);
#endif 

        }
    }
}

DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{
    PsRemoveLoadImageNotifyRoutine(MY_PLOAD_IMAGE_NOTIFY_ROUTINE);
}

DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;

    //KdBreakPoint();//#define KdBreakPoint() DbgBreakPoint() 

    DriverObject->DriverUnload = Unload; 

    status = PsSetLoadImageNotifyRoutine(MY_PLOAD_IMAGE_NOTIFY_ROUTINE);

    return status;
} 

2013年2月7日星期四

PsSetLoadImageNotifyRoutine.C


#include <ntddk.h>

VOID MY_PLOAD_IMAGE_NOTIFY_ROUTINE(__in_opt PUNICODE_STRING  FullImageName, __in HANDLE  ProcessId, __in PIMAGE_INFO  ImageInfo)
{
    NTSTATUS r;
    int n,len;
    wchar_t sysname[] = L"sys.sys";
    UNICODE_STRING u1,u2;
    int b = 0;
    HANDLE hcp;

    hcp = PsGetCurrentProcessId();//如果是驱动模块,ProcessId总为0,这可能是错误的。

    //其实这里也可以把进程给结束了。

    len = wcslen(sysname) * sizeof(wchar_t);
    n = (FullImageName->Length - len)/sizeof(wchar_t);

    //如果加载的驱动是:sys.sys,就调用ZwUnmapViewOfSection

    RtlInitUnicodeString(&u1,sysname);
    RtlInitUnicodeString(&u2,&FullImageName->Buffer[n]);
    b = RtlEqualUnicodeString(&u1,&u2,1);
    if (b)
    {
        //Note  If the call to this function occurs in user mode, you should use the name "NtUnmapViewOfSection" instead of "ZwUnmapViewOfSection".
        r = ZwUnmapViewOfSection(ProcessId,ImageInfo->ImageBase); //得到的结论是不能卸载驱动,断言只能卸载dll.
        if (r == STATUS_ACCESS_DENIED )
        {
            DbgPrint("The caller does not have access rights to the process object or to the base virtual address of the view.");
        }

        //RtlZeroMemory(ImageInfo->ImageBase,ImageInfo->ImageSize);//这个蓝屏,难道要锁定内存。

        //更深入的函数有:IopDeleteDriver等。
    }

    //如果阻止驱动加载呢?难道必须用hook?
}

DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{
    PsRemoveLoadImageNotifyRoutine(MY_PLOAD_IMAGE_NOTIFY_ROUTINE);
}

DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;

    KdBreakPoint();//#define KdBreakPoint() DbgBreakPoint()

    DriverObject->DriverUnload = Unload;

    status = PsSetLoadImageNotifyRoutine(MY_PLOAD_IMAGE_NOTIFY_ROUTINE);

    return status;
}
//made 2013.02.07