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;
}

没有评论:

发表评论