2013年1月25日星期五

64位驱动的asm与c混合编程


64位汇编的驱动环境的搭建就不说了。

汇编文件如下:

.data

EXTERN OrigKeBugCheckExRestorePointer:PROC
EXTERN KeBugCheckExHookPointer:PROC

.code

;
; Points the stack pointer at the supplied argument and returns to the caller.
;
public AdjustStackCallPointer
AdjustStackCallPointer PROC
    mov rsp, rcx
    xchg r8, rcx
    jmp rdx
AdjustStackCallPointer ENDP

;
; Wraps the overwritten preamble of KeBugCheckEx.
;
public OrigKeBugCheckEx
OrigKeBugCheckEx PROC
    mov [rsp+8h], rcx
    mov [rsp+10h], rdx
    mov [rsp+18h], r8
    lea rax, [OrigKeBugCheckExRestorePointer]
    jmp qword ptr [rax]
OrigKeBugCheckEx ENDP

END

编译命令:
ml64 lib.asm
link /lib lib.obj

上面可能有一些警告(我用ida64打开一看少了一个函数),我忽略了。请高手指点。

c文件如下:

#include <ntddk.h>
#include <ntifs.h>
#include <wdm.h>

DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{

}

// Both of these routines reference the assembly code described above
extern VOID OrigKeBugCheckEx(IN ULONG BugCheckCode, IN ULONG_PTR BugCheckParameter1, IN ULONG_PTR BugCheckParameter2, IN ULONG_PTR BugCheckParameter3, IN ULONG_PTR

BugCheckParameter4);
extern VOID AdjustStackCallPointer(IN ULONG_PTR NewStackPointer, IN PVOID StartAddress, IN PVOID Argument);

// mov eax, ptr
// jmp eax
static CHAR HookStub[] = "\x48\xb8\x41\x41\x41\x41\x41\x41\x41\x41\xff\xe0";

// The offset into the ETHREAD structure that holds the start routine.
static ULONG ThreadStartRoutineOffset = 0;

// The pointer into KeBugCheckEx after what has been overwritten by the hook.
PVOID OrigKeBugCheckExRestorePointer;

VOID KeBugCheckExHook(IN ULONG BugCheckCode, IN ULONG_PTR BugCheckParameter1, IN ULONG_PTR BugCheckParameter2, IN ULONG_PTR BugCheckParameter3, IN ULONG_PTR BugCheckParameter4)
{
    PUCHAR LockedAddress;
    PCHAR  ReturnAddress;
    PMDL   Mdl = NULL;

    // Call the real KeBugCheckEx if this isn't the bug check code we're looking for.
    if (BugCheckCode != 0x109)
    {
        //DebugPrint(("Passing through bug check %.4x to %p.", BugCheckCode, OrigKeBugCheckEx));
        OrigKeBugCheckEx(BugCheckCode, BugCheckParameter1, BugCheckParameter2, BugCheckParameter3, BugCheckParameter4);
    }
    else
    {
        PCHAR CurrentThread = (PCHAR)PsGetCurrentThread();
        PVOID StartRoutine  = *(PVOID **)(CurrentThread + ThreadStartRoutineOffset);
        PVOID StackPointer  = IoGetInitialStack();

        //DebugPrint(("Restarting the current worker thread %p at %p (SP=%p, off=%lu).", PsGetCurrentThread(), StartRoutine, StackPointer, ThreadStartRoutineOffset));
        DbgPrint("拦截了0x109号蓝屏\n");
        DbgPrint("Restarting the current worker thread %p at %p (SP=%p, off=%lu).\n", PsGetCurrentThread(), StartRoutine, StackPointer, ThreadStartRoutineOffset);

        // Shift the stack pointer back to its initial value and call the routine.
        //We subtract eight to ensure that the stack is aligned properly as thread entry point routines would expect.
        AdjustStackCallPointer((ULONG_PTR)StackPointer - 0x8, StartRoutine, NULL);
    }

    // In either case, we should never get here.
    __debugbreak();
}

VOID DisablePatchProtectionSystemThreadRoutine(IN PVOID Nothing)
{
    UNICODE_STRING SymbolName;
    NTSTATUS       Status = STATUS_SUCCESS;
    PUCHAR         LockedAddress;
    PUCHAR         CurrentThread = (PUCHAR)PsGetCurrentThread();
    PCHAR          KeBugCheckExSymbol;
    PMDL           Mdl = NULL;

    RtlInitUnicodeString(&SymbolName, L"KeBugCheckEx");

    do
    {
        // Find the thread's start routine offset.
        for (ThreadStartRoutineOffset = 0; ThreadStartRoutineOffset < 0x1000; ThreadStartRoutineOffset += 4)
        {
            if (*(PVOID **)(CurrentThread + ThreadStartRoutineOffset) == (PVOID)DisablePatchProtectionSystemThreadRoutine) //DisablePatchProtection2SystemThreadRoutine
                break;
        }

        //DebugPrint(("Thread start routine offset is 0x%.4x.", ThreadStartRoutineOffset));

        // If we failed to find the start routine offset for some strange reason, then return not supported.
        if (ThreadStartRoutineOffset >= 0x1000)
        {
            Status = STATUS_NOT_SUPPORTED;
            break;
        }

        // Get the address of KeBugCheckEx.
        if (!(KeBugCheckExSymbol = MmGetSystemRoutineAddress(&SymbolName)))
        {
            Status = STATUS_PROCEDURE_NOT_FOUND;
            break;
        }

        // Calculate the restoration pointer.
        OrigKeBugCheckExRestorePointer = (PVOID)(KeBugCheckExSymbol + 0xf);

        // Create an initialize the MDL.
        if (!(Mdl = MmCreateMdl(NULL, (PVOID)KeBugCheckExSymbol, 0xf)))
        {
            Status = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }

        MmBuildMdlForNonPagedPool(Mdl);

        // Probe & Lock.
        if (!(LockedAddress = (PUCHAR)MmMapLockedPages(Mdl, KernelMode)))
        {
            IoFreeMdl(Mdl);
            Status = STATUS_ACCESS_VIOLATION;
            break;
        }

        // Set the aboslute address to our hook.
        *(PULONG64)(HookStub + 0x2) = (ULONG64)KeBugCheckExHook;

        //DebugPrint(("Copying hook stub to %p from %p (Symbol %p).", LockedAddress, HookStub, KeBugCheckExSymbol));

        // Copy the relative jmp into the hook routine.
        RtlCopyMemory(LockedAddress, HookStub, 0xf);

        // Cleanup the MDL.
        MmUnmapLockedPages(LockedAddress, Mdl);

        IoFreeMdl(Mdl);
    } while (0);
   
    KeBugCheckEx(0x109,0,0,0,0);//测试专用。
}

// A pointer to KeBugCheckExHook
PVOID KeBugCheckExHookPointer = KeBugCheckExHook;

NTSTATUS DisablePatchProtection()
{
    OBJECT_ATTRIBUTES Attributes;
    NTSTATUS          Status;
    HANDLE            ThreadHandle = NULL;

    InitializeObjectAttributes(&Attributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);

    // Create the system worker thread so that we can automatically find the offset inside the ETHREAD structure to the thread's start routine.
    Status = PsCreateSystemThread(&ThreadHandle, THREAD_ALL_ACCESS, &Attributes, NULL, NULL, DisablePatchProtectionSystemThreadRoutine, NULL);

    if (ThreadHandle)
        ZwClose(ThreadHandle);

    return Status;
}

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;
   
    DisablePatchProtection();
   
    return 0;
}

关键是在source文件里面加入一行:
TARGETLIBS=lib.lib
那个文件也要复制到相应的位置。与源文件在一个目录里面。

键入bld
enter!
ok!
你看效果吧。

顺便说一下破除PatchGuard的思路:
1.改变或者添加启动模式,如安全,调试,签名等。
2.替换内核文件,那就是吧加载PatchGuard的机制给去掉。
3.从定时器队列中摘除,我没有试验成功,代码没有编译过。
4.就是本文的用到的KeBugCheckEx Hook。
5.异常处理,参考:http://uninformed.org/index.cgi?v=3&a=3&p=16
6.一些hook库。
7.其他,等你告诉我。

注释:隐藏进程的摘链,inline hook都会被PatchGuard发现。
/////////////////////////////////////////////////////////////////////
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
其实还有更简单的:

第一个办法:
在source文件中直接加入:
AMD64_SOURCES = amd64\asm.asm   #这是64位的,32位的可以改为I386_SOURCES
但是SOURCES里面就不要再加入asm.asm了。

第二个办法:
工程目录下新建一个名为amd64的文件夹,里面放置汇编文件,
然后再source里面直接添加汇编文件即可。

注意:
如果出现下面的情况:
1>d:\winddk\work\c\amd64\asm.asm(1) : error A2039:line too long
1>d:\winddk\work\c\amd64\asm.asm(1) : error A2088:END directive required at end of file
google一下说是某个版本的ml.exe问题,可能后来改进了。解决办法是:
用系统自带的记事本打开文件,一看源代码只有一行。注释:用别的编辑工具都是好好的。
在记事本里面手工格式化代码就ok!
made by correy
2013.02.18添加。

2013年1月23日星期三

ml64.asm


64位汇编怎能不会。

以前以为64位汇编和32位汇编差不多,学好32位汇编就可以了。

直到用到了,才知道还有点小麻烦。

最主要的是环境的搭建.

支持64位汇编的环境有好几个,这里就不列举了。
因为是Windows上的编程,所以要首选ml64.exe了。

暂时没有发现微软的64位汇编环境,也许孤陋寡闻,也许懒得搜索。
知道masm32的原理,那就自己来吧!

所有的产品来自微软,如:mvs,sdk,wdk,所以需要先安装以上的东西。

收集过程就不说了,假定你已经熟悉mvs和masm32了。
罗嗦一句,那些东西要来自64位的目录。

具体的编写与编译有点小区别,这就令当别论了。

实验一下:

; Sample x64 Assembly Program
; Chris Lomont 2009 www.lomont.org
extrn ExitProcess: PROC   ; external functions in system libraries
extrn MessageBoxA: PROC
.data
caption db '64-bit hello!', 0
message db 'Hello World!', 0
.code
Start PROC
  sub    rsp,28h      ; shadow space, aligns stack
  mov    rcx, 0       ; hWnd = HWND_DESKTOP
  lea    rdx, message ; LPCSTR lpText
  lea    r8,  caption ; LPCSTR lpCaption
  mov    r9d, 0       ; uType = MB_OK
  call   MessageBoxA  ; call MessageBox API function
  mov    ecx, eax     ; uExitCode = MessageBox(...)
  call ExitProcess
Start ENDP
End

编译命令:ml64 hello.asm /link /subsystem:windows /defaultlib:kernel32.lib /defaultlib:user32.lib /entry:Start

从此开始我的64位汇编之旅。

汇编很少用,有时候必须用(或者用变相的方式),因为64位不支持内联汇编。

其实最根本的还是汇编,因为机器运行的是指令,相信汇编,坚信!

2013年1月20日星期日

GetActiveProcessLinksOffset.C


/*
这篇文件本想命名为PsActiveProcessHead.C的,改名为:GetActiveProcessLinksOffset.C吧!

PsActiveProcessHead 内核没有导出这个变量,微软更没有公开,只在一个结构及一些函数中用到了。
定义在:_KDDEBUGGER_DATA64,_KDDEBUGGER_DATA32结构。
#define DEBUG_DATA_PsActiveProcessHeadAddr               80
ULONG64
ExtNtOsInformation::GetKernelProcessListHead(void)
{
return GetNtDebuggerData(DEBUG_DATA_PsActiveProcessHeadAddr,"nt!PsActiveProcessHead",0);
}
以上定义在:engextcpp.cpp,wdbgexts.h,dbgeng.h,WDBGEXTS.H中。

以前觉得能操作内核结构,如:e(k)process,就是牛屄的高手。
慢慢发现这是硬编码,不通用。

后来感觉应该听微软的话,不公开就不用,用操作之的函数,或者别的理论。

但是有时后必须用之,这是下下策。

以前也见过获取eprocees中ActiveProcessLinks成员的偏移量的。
受之启发,几个月后有了自己的思路(方法),有了此文。

此文是获取eprocees中ActiveProcessLinks成员的偏移量的两个办法(函数),力求各个Windows的版本通用,包括32位与64位的。

方法一是:检测ActiveProcessLinks处的有效性,变化之后可得到eprocess,然后检查。
方法二是:通过两个特定进程的关系,如:idle和system,但是idle的eprocess的获取需要汇编,所以放弃。
          system的eprocess的下一个ActiveProcessLinks一般是smss.exe(第一个进程,应该也只用一个)。
          然后比较特定的值,如地址(本办法使用),或者名字等。

本文编译有几个Warnings,正式使用,请去掉。

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

#include <ntddk.h>
#include <ntifs.h>
#include <wdm.h>

extern PEPROCESS PsInitialSystemProcess;

DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{

}

int GetPsActiveProcessHead1()
{
    unsigned int x = 0;
    HANDLE h,h2;
    EPROCESS tem_PEPROCESS;
    NTSTATUS r;
    PEPROCESS CurrentProcess = PsGetCurrentProcess();//用当前的吧!
    int b;
    int n = 0;
    KIRQL  OldIrql;

#ifdef _X86_
    unsigned int y;
#endif

#if defined(_AMD64_) || defined(_IA64_)
    unsigned __int64 y;
#endif

    //代码开始

    KeRaiseIrql(APC_LEVEL, &OldIrql);

    for (x = 8; x<10000; x +=8) //经验所得是8的倍数。eproceess的结构大小不会超过10000。
    {
        if (x == 0x188) //测试专用。
        {
            //KdBreakPoint();
        }

        y =
#ifdef _X86_
            (unsigned int)
#endif
#if defined(_AMD64_) || defined(_IA64_)
        (unsigned __int64)
#endif
        CurrentProcess + x;

        y =
#ifdef _X86_
            *(unsigned int *)
#endif
#if defined(_AMD64_) || defined(_IA64_)
            *(unsigned __int64 *)
#endif          
            y;

        y -= x;

        __try
        {  

//#ifdef _X86_
//            ProbeForRead(y, sizeof (unsigned int), sizeof (unsigned int)); //IRQL  <= APC_LEVEL
//#endif
//#if defined(_AMD64_) || defined(_IA64_)
//            ProbeForRead(y, sizeof (unsigned __int64), sizeof (unsigned __int64));
//#endif

            //必须用MmIsAddressValid,尽管微软已经不建议使用。因为ProbeForRead只检测用户称的。注意IRQL <= APC_LEVEL
            if (!MmIsAddressValid(y))
            {
                continue;
            }

            h = PsGetProcessId(y);//这家伙不检查错误,返回正确不?用异常。
        }
        __except (1)
        {
            continue;
        }

        b = (int)h%4;

        if (8 >= h || h >10000 ||  b != 0)
        {
            continue;
        }

        r = PsLookupProcessByProcessId(h,&tem_PEPROCESS);
        h2 = PsGetProcessId(y);//这个条件还加不加,多余?
        if (r != STATUS_INVALID_PARAMETER && h == h2) // && 不再加附加的验证条件了。
        {
            DbgPrint("0x%x\n", x);

            ObDereferenceObject(tem_PEPROCESS);//必须调用,在某些情况下会死锁,建议使用ObReferenceObjectByHandle

#ifdef _X86_
            KeLowerIrql(OldIrql);
            return x;
#endif

#if defined(_AMD64_) || defined(_IA64_)          

            n++;

            if (n == 2) //第一个是kprocess的ProcessListEntry。
            {
                KeLowerIrql(OldIrql);
                return x;
            }          
#endif

        }
    }

    KeLowerIrql(OldIrql);
    return -1;//失败返回-1.应该不会返回这里。
}

extern UCHAR *PsGetProcessImageFileName(IN PEPROCESS Process); //c++ 才需要"C"

HANDLE GetPidFromProcessName(char * ProcessName)
{
    PEPROCESS Process;
    int h;
    CHAR * pName;
    STRING s1,s2;
    KIRQL  OldIrql;

    KeRaiseIrql(APC_LEVEL, &OldIrql);

    for (h = 0; h < 10000; h += 4) //由于PEPROCESS结构不公开,不采用遍历的办法,反而更通用。
    {
        if (PsLookupProcessByProcessId((HANDLE)h, & Process) != STATUS_INVALID_PARAMETER)
        {
            pName = (CHAR*)PsGetProcessImageFileName(Process);//未公开函数。也有替换的办法。

            //如果pName不可以访问,请退出,不然蓝屏。 解决办法是下面加异常处理

            __try
            {
                if (!MmIsAddressValid(pName))
                {
                    continue;
                }

                RtlInitString(&s1, pName);
                RtlInitString(&s2, ProcessName);
            }
            __except (1)
            {
                continue;
            }

            //ObDereferenceObject(Process);//加这一行蓝屏。

            if (RtlEqualString(&s1, &s2, 1))
            {
                DbgPrint("pid == %08d\n",h);
                KeLowerIrql(OldIrql);
                return (HANDLE)h;
            }
        }
    }

    KeLowerIrql(OldIrql);
    return (HANDLE)-1;
}

int GetPsActiveProcessHead2()
{
    unsigned int x = 0;
    PEPROCESS system_eprocess,smss_eprocess;
    int b;
    int n = 0;
    HANDLE h_system,h_smss;

#ifdef _X86_
    unsigned int y;
#endif

#if defined(_AMD64_) || defined(_IA64_)
    unsigned __int64 y;
#endif

    //代码开始

    h_system = GetPidFromProcessName("system");
    h_smss = GetPidFromProcessName("smss.exe");
    if (h_system == -1 || h_smss == -1)
    {
        return -1;
    }

    if (PsLookupProcessByProcessId(h_system, & system_eprocess) == STATUS_INVALID_PARAMETER ||
        PsLookupProcessByProcessId(h_smss, & smss_eprocess) == STATUS_INVALID_PARAMETER)
    {
        return -1;
    }
   
    for (x = 8; x<10000; x +=8) //经验所得是8的倍数。eproceess的结构大小不会超过10000。
    {

        __try
        {

            y =
#ifdef _X86_
                (unsigned int)
#endif
#if defined(_AMD64_) || defined(_IA64_)
                (unsigned __int64)
#endif
                system_eprocess + x;

            y =
#ifdef _X86_
                *(unsigned int *)
#endif
#if defined(_AMD64_) || defined(_IA64_)
                *(unsigned __int64 *)
#endif          
                y; //主要是看这里的内容可以访问不?其实这里没有问题。

            y -= x;

            if (y == smss_eprocess)
            {
                DbgPrint("0x%x\n", x);

#ifdef _X86_
                return x;
#endif

#if defined(_AMD64_) || defined(_IA64_)          

                n++;

                if (n == 2) //第一个是kprocess的ProcessListEntry。
                {
                    return x;
                }          
#endif
            }
        }
        __except (1)
        {
            continue;
        }
    }

    ObDereferenceObject(system_eprocess);
    ObDereferenceObject(smss_eprocess);

    return -1;//失败返回-1.应该不会返回这里。
}

DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    unsigned __int64 PsActiveProcessHead = 0;
    unsigned __int64 t;
    PEPROCESS Process; //看看和t相等不?
    KSPIN_LOCK  SpinLock;
    KIRQL  OldIrql;

    KdBreakPoint();//#define KdBreakPoint() DbgBreakPoint()
    DriverObject->DriverUnload = Unload;
   
    PsLookupProcessByProcessId(4, & Process);
    t = PsInitialSystemProcess;//断定这个是错误的,和Process不一样,进程的名字为空。
    //DbgPrint("PsInitialSystemProcess == 0x%16x\n", PsInitialSystemProcess);

    //KeInitializeSpinLock(&SpinLock);//里面用KeRaiseIrql,这里就不用了。

    //KeAcquireSpinLock(&SpinLock, &OldIrql);//注意锁的使用。
    PsActiveProcessHead = GetPsActiveProcessHead1();
    //KeReleaseSpinLock(&SpinLock, OldIrql);

    DbgPrint("ActiveProcessLinks 在 eprocess中的偏移是:0x%x\n", PsActiveProcessHead);

    PsActiveProcessHead = GetPsActiveProcessHead2();

    DbgPrint("ActiveProcessLinks 在 eprocess中的偏移是:0x%x\n", PsActiveProcessHead);
   
    return 0;
}

2013年1月18日星期五

PsLookupProcessByProcessId.C

/*
本文就暂时命名为PsLookupProcessByProcessId.C吧!
pid与进程名互换,很简单的问题,不削一顾,可到用的时候才知道重要。
网上很多,那是别人的。
还是自己的感觉好,完全懂,还一个修改。
made by correy
made at 2013.01.18
QQ:112426112
Email:kouleguan at hotmail dot com
Homepage:http://correy.webs.com

If the call to PsLookupProcessByProcessId is successful, PsLookupProcessByProcessID increases the reference count on the object returned in the Process parameter. 
Consequently, when a driver has completed using the Process parameter, the driver must call ObDereferenceObject to dereference the Process parameter received from the PsLookupProcessByProcessID routine. 
*/

#include <ntddk.h>
#include <ntifs.h> 

extern UCHAR *PsGetProcessImageFileName(IN PEPROCESS Process); //c++ 才需要"C"

DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{

}

HANDLE GetPidFromProcessName(char * ProcessName)
{
    PEPROCESS Process;
    int h;
    CHAR * pName;
    STRING s1,s2;
    for (h = 0; h < 10000; h += 4) //由于PEPROCESS结构不公开,不采用遍历的办法,反而更通用。
    {
        if (PsLookupProcessByProcessId((HANDLE)h, & Process) != STATUS_INVALID_PARAMETER)
        {
            pName = (CHAR*)PsGetProcessImageFileName(Process);//未公开函数。也有替换的办法。
            RtlInitString(&s1, pName);
            RtlInitString(&s2, ProcessName);
            if (RtlEqualString(&s1, &s2, 1))
            {
                DbgPrint("pid == %08d\n",h);
                return (HANDLE)h;
            }
        }
    }
    return (HANDLE)-1;
}

char * GetProcessNameFromPid(HANDLE pid)
{
    PEPROCESS Process;
    if (PsLookupProcessByProcessId(pid, & Process) == STATUS_INVALID_PARAMETER)
    {
        return "pid不存在";
    }
    DbgPrint("ProcessName is %s\n",PsGetProcessImageFileName(Process));
    return (CHAR*)PsGetProcessImageFileName(Process);//未公开函数。也有替换的办法。
}

DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    HANDLE h;
    char * ProcessName;
    //KdBreakPoint();//#define KdBreakPoint() DbgBreakPoint()
    DriverObject->DriverUnload = Unload;
   
    h = GetPidFromProcessName("explorer.exe");
    ProcessName = GetProcessNameFromPid(h);
    return 0;
}

//////////////////////////////////////////////////////////////////////////////
//改进版,排除了死进程。有一些垃圾的东西。
/*
本文就暂时命名为PsLookupProcessByProcessId.C吧!
pid与进程名互换,很简单的问题,不削一顾,可到用的时候才知道重要。
网上很多,那是别人的。
还是自己的感觉好,完全懂,还可以修改。
made by correy
made at 2013.01.24
QQ:112426112
Email:kouleguan at hotmail dot com
Homepage:http://correy.webs.com
*/

#include <ntddk.h>
#include <ntifs.h>  

typedef struct _SYSTEM_THREAD_INFORMATION {
    LARGE_INTEGER KernelTime;
    LARGE_INTEGER UserTime;
    LARGE_INTEGER CreateTime;
    ULONG WaitTime;
    PVOID StartAddress;
    CLIENT_ID ClientId;
    KPRIORITY Priority;
    KPRIORITY BasePriority;
    ULONG ContextSwitchCount;
    LONG State;
    LONG WaitReason;
} SYSTEM_THREAD_INFORMATION, * PSYSTEM_THREAD_INFORMATION;

typedef struct _SYSTEM_PROCESS_INFORMATION {
    ULONG NextEntryDelta;
    ULONG ThreadCount;
    ULONG Reserved1[6];
    LARGE_INTEGER CreateTime;
    LARGE_INTEGER UserTime;
    LARGE_INTEGER KernelTime;
    UNICODE_STRING ProcessName;
    KPRIORITY BasePriority;
    ULONG ProcessId;
    ULONG InheritedFromProcessId;
    ULONG HandleCount;
    ULONG Reserved2[2];
    VM_COUNTERS VmCounters;
    IO_COUNTERS IoCounters;
    SYSTEM_THREAD_INFORMATION Threads[1];
} SYSTEM_PROCESS_INFORMATION, * PSYSTEM_PROCESS_INFORMATION;

extern UCHAR *PsGetProcessImageFileName(IN PEPROCESS Process); //c++ 才需要"C"
extern int PsGetProcessExitStatus(PEPROCESS Process);

extern NTSTATUS ZwQuerySystemInformation( int SystemInformationClass,
                          PVOID SystemInformation,
                          ULONG SystemInformationLength,
                          PULONG ReturnLength OPTIONAL);

DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{

}

//HANDLE GetPidFromProcessName(char * ProcessName)
//int IsActiveProcess(int h)
//{//枚举进程
//    NTSTATUS ntStatus;
//    ULONG cbBuffer = 0x8000;
//    PVOID pBuffer = NULL;
//    PSYSTEM_PROCESS_INFORMATION pInfo;
//    UNICODE_STRING us1,us2;
//
//    do {
//        pBuffer = ExAllocatePoolWithTag(NonPagedPool, cbBuffer,'tag');  
//        if (pBuffer == NULL)  {
//            return 0;
//        }
//
//        ntStatus = ZwQuerySystemInformation(5, pBuffer, cbBuffer, NULL);
//        if (ntStatus == STATUS_INFO_LENGTH_MISMATCH)  {
//            ExFreePoolWithTag(pBuffer,'tag');
//            cbBuffer *= 2;
//        } else if (!NT_SUCCESS(ntStatus)) {
//            ExFreePoolWithTag(pBuffer,'tag');
//            return 0;
//        }
//    } while(ntStatus == STATUS_INFO_LENGTH_MISMATCH);
//
//    pInfo = (PSYSTEM_PROCESS_INFORMATION)pBuffer;
//    while(TRUE)
//    {
//        /*LPWSTR pszProcessName = pInfo->ProcessName.Buffer;
//        if (pszProcessName == NULL) {
//            pszProcessName = L"NULL";
//        }*/
//
//        DbgPrint("pid == %08d;pname:%wZ\n", pInfo->ProcessId,pInfo->ProcessName.Buffer);
//
//        RtlInitUnicodeString(&us1, pInfo->ProcessName.Buffer);
//        RtlInitUnicodeString(&us2, L"explorer.exe"); ///wgclient.exe
//
//        if (RtlEqualUnicodeString(&us1, &us2, 1))   {
//            ExFreePoolWithTag(pBuffer,'tag');
//            return h;
//        }
//
//        /*if (pInfo->ProcessId == h)   {
//            ExFreePoolWithTag(pBuffer,'tag');
//            return h;
//        }*/
//
//        if (pInfo->NextEntryDelta == 0) {
//            break;
//        }
//        pInfo = (PSYSTEM_PROCESS_INFORMATION)(((PUCHAR)pInfo)+pInfo->NextEntryDelta);   
//    }
//
//    ExFreePoolWithTag(pBuffer,'tag');
//}

//用ZwQueryInformationProcess ProcessBasicInformation->ExitStatus的办法没有能实现,
//不用eprocess的exittime和判断ObjectTable是否为0 ,
//更不用ZwQuerySystemInformation的5号功能枚举。
//也没有使用peb的办法。
int IsActiveProcess(int h)
{
    PEPROCESS Process;
    int ExitCode;

    if (PsLookupProcessByProcessId((HANDLE)h, & Process) != STATUS_INVALID_PARAMETER)
    {
        __try
        {
            ExitCode = PsGetProcessExitStatus(Process);
            if (ExitCode == 259) //这个观察所得。
            {
                return 1;
            }
            else //等于1就是退出了。
            {
                return 0;
            }
        }
        __except (1)
        {
            //这时候大多是Process是错误的。
        }
    }

    return 0;
}

HANDLE GetPidFromProcessName(char * ProcessName)
{
    PEPROCESS Process;
    int h;
    CHAR * pName;
    STRING s1,s2;
    KIRQL  OldIrql;

    KeRaiseIrql(APC_LEVEL, &OldIrql);

    for (h = 0; h < 10000; h += 4) //由于PEPROCESS结构不公开,不采用遍历的办法,反而更通用。
    {
        if (PsLookupProcessByProcessId((HANDLE)h, & Process) != STATUS_INVALID_PARAMETER)
        {
            pName = (CHAR*)PsGetProcessImageFileName(Process);//未公开函数。也有替换的办法。

            //如果pName不可以访问,请退出,不然蓝屏。 解决办法是下面加异常处理

            //KeRaiseIrql(APC_LEVEL, &OldIrql);

            __try
            {
                if (!MmIsAddressValid(pName))
                {
                    continue;
                }

                RtlInitString(&s1, pName);
                RtlInitString(&s2, ProcessName);
            }
            __except (1)
            {
                //KeLowerIrql(OldIrql);
                continue;
            }

            //KeLowerIrql(OldIrql);

            //ObDereferenceObject(Process);//加这一行蓝屏。

            if (RtlEqualString(&s1, &s2, 1))
            {
                DbgPrint("pid == %08d\n",h);
                //KeLowerIrql(OldIrql);

                //放置在这里会运行的快一点。放到上一个if语句,运行的很慢。
                //排除已经退出的进程。
                if (IsActiveProcess(h)) 
                {
                    KeLowerIrql(OldIrql);
                    return (HANDLE)h;
                }
            }

            s1.MaximumLength = 0;//释放,避免以后还运行。
            s2.MaximumLength = 0;
        }
    }

    KeLowerIrql(OldIrql);
    return (HANDLE)-1;
}

char * GetProcessNameFromPid1(HANDLE pid)
{
    PEPROCESS Process;

    if (PsLookupProcessByProcessId(pid, & Process) == STATUS_INVALID_PARAMETER)
    {
        return "pid不存在";
    }

    DbgPrint("ProcessName is %s\n",PsGetProcessImageFileName(Process));

    return (CHAR*)PsGetProcessImageFileName(Process);//未公开函数。也有替换的办法。
}

DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    HANDLE h;
    char * ProcessName;
    int b = 0;
    LARGE_INTEGER   interval;

    KdBreakPoint();//#define KdBreakPoint() DbgBreakPoint() 
    DriverObject->DriverUnload = Unload; 

    for (;;)  //主要是测试用的。
    {
        if (b)
        {
            break;
        }

        h = GetPidFromProcessName("explorer.exe");
        ProcessName = GetProcessNameFromPid1(h);
        
        interval.QuadPart = (1 * (((-10) * 1000) * 1000)); //暂停5秒钟。
        KeDelayExecutionThread(KernelMode, FALSE, &interval);//这3行是新添加的.
    }

    return 0;
} 
还有一个种微软公开,但过时的办法:ZwQuerySystemInformation和ZwQueryInformationProcess

2013年1月6日星期日

QueryPerformanceCounter.Cpp


/*

QueryPerformanceCounter.Cpp

本文开启我的算法之旅.
c的c++(stl)的.

排序(升降)
查找(最大,最小,特定)

还有树,图等.

不停的更新改进中.
没有考虑效率,也不是最优秀的算法,关键是能实现.
*/

#include <windows.h>

//也可以考虑用链表.
int x[100] = {};//100个元素,最后一个的索引是99.

void init ()
{
    LARGE_INTEGER counter;

    for (int i = 0;i<100;i++)
    {
        //Sleep(0);//不加这个会重复,加这个相差为1.
        Sleep(i);//这个效果比较好.

        QueryPerformanceCounter(&counter);//失败的可能性很小,不考虑了.
        x[i] = counter.QuadPart % 1000;//这个没有重复的,在双核的cpu上.

        //x[i] = GetTickCount() % 1000;//这个有一些是重复的.

        //x[i] = GetTickCount64() % 1000;//这个有一些是重复的.
    }
}

void ergodic()
{
    for (int i = 0;i<100;i++)
    {
        printf("%4d\n", x[i]);
    }
}

int find_max()
{
    int m = 0;

    for (int i = 0;i<100;i++)
    {
        if (m <= x[i])
        {
            m = x[i];
        }
    }

    return m;
}

int find_min()
{
    int m = x[0];

    for (int i = 0;i<100;i++)
    {
        if (m >= x[i])
        {
            m = x[i];
        }
    }

    return m;
}

int find(int n)
{
    //返回索引,如果找不到返回-1.

    unsigned int m = -1;

    for (int i = 0;i<100;i++)
    {
        if (n == x[i])
        {
            return i;
        }
    }

    return m;
}

void sort_up()
{
    for (int j = 0;j<100;j++)
    {
        for (int i = 0;i<100-1;i++)
        {
            if (x[i] > x[i+1])
            {
                int t = x[i];
                x[i] = x[i+1];
                x[i+1] = t;              
            }
        }
    }
}

void sort_down()
{
    for (int j = 0;j<100;j++)
    {
        for (int i = 0;i<100;i++)
        {
            if (x[i] < x[i+1])
            {
                int t = x[i];
                x[i] = x[i+1];
                x[i+1] = t;              
            }
        }
    }
}

int main()
{
    int r = 0;

    init();

    ergodic();

    r = find_max();//返回最大的.
    printf("最大是:%4d\n", r);
    r = find_min();//返回最小的.
    printf("最小是:%4d\n", r);

    int n = x[99];
    r = find(n);//查询索引.

    sort_up();//升序,从小到大
    sort_down();  //降序,从大到小
}