2014年5月17日星期六

以另一个用户启动一个进程

#include "stdafx.h"

/*
runas是一个常用的命令,你会用吗?
我不会,但我要探究它的进一步的原理。
其实很简单,参见:http://msdn.microsoft.com/en-us/library/windows/desktop/ms682431(v=vs.85).aspx
注意事项:见注释。

不过要在不同的会话中运行,那就麻烦了。
普通的程序需要提权。
而进程的权限是继承自用户的,所以还要给用户分派权限。
具体的设置可以参考本地安全策略:http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/08bc7712-548c-4308-a49c-d551a4b5e245.mspx?mfr=true。
注意:这些设置还要重启后生效。
所以常用的办法是用服务,服务默认是具有这些权限的。再次郑重说明:不用服务也是可以的。
正好这有解决了服务在Vista及以后系统的编程交互(如:弹出对话框)的问题。

提示:命令行输入空的参数,可以使用双引号,也就是这两个引号之间没有内容,包括空格。

made by correy
made at 2014.05.17
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com
*/

#include <windows.h>
#include <stdio.h>
#include <userenv.h>

#pragma comment(lib, "userenv.lib")

void DisplayError(LPWSTR pszAPI)
{
    LPVOID lpvMessageBuffer;

    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpvMessageBuffer, 0, NULL);

    //... now display this string
    wprintf(L"ERROR: API        = %s.\n", pszAPI);
    wprintf(L"       error code = %d.\n", GetLastError());
    wprintf(L"       message    = %s.\n", (LPWSTR)lpvMessageBuffer);
        
    LocalFree(lpvMessageBuffer);// Free the buffer allocated by the system
    ExitProcess(GetLastError());
}

void wmain(int argc, WCHAR *argv[])
{    
    if (argc != 4)
    {
        wprintf(L"Usage: %s [user@domain] [password] [cmd]", argv[0]);
        wprintf(L"\n\n");
        return;
    }

    // TO DO: change NULL to '.' to use local account database
    HANDLE    hToken;
    if (!LogonUser(argv[1], NULL, argv[2], LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &hToken)) { //必须有密码,不然失败。
        DisplayError(L"LogonUser");
    }

    //得到的内容其实就是:The environment block is an array of null-terminated Unicode strings. The list ends with two nulls (\0\0).
    LPVOID    lpvEnv;
    if (!CreateEnvironmentBlock(&lpvEnv, hToken, TRUE)) {
        DisplayError(L"CreateEnvironmentBlock");
    }

    //获取用户的文件夹。
    WCHAR               szUserProfile[256] = L""; 
    DWORD dwSize = sizeof(szUserProfile)/sizeof(WCHAR);
    if (!GetUserProfileDirectory(hToken, szUserProfile, &dwSize)) {//用户必须登录运行过一次,不必此时这个用户运行着。
        DisplayError(L"GetUserProfileDirectory");
    }

    // TO DO: change NULL to '.' to use local account database
    STARTUPINFO         si = {0};
    si.cb = sizeof(STARTUPINFO);
    PROCESS_INFORMATION pi = {0};
    if (!CreateProcessWithLogonW(argv[1], NULL, argv[2], LOGON_WITH_PROFILE, NULL, argv[3], CREATE_UNICODE_ENVIRONMENT, lpvEnv, szUserProfile, &si, &pi)) {
        DisplayError(L"CreateProcessWithLogonW");
    }

    if (!DestroyEnvironmentBlock(lpvEnv)) {
        DisplayError(L"DestroyEnvironmentBlock");
    }

    CloseHandle(hToken);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
}

2014年5月10日星期六

驱动中枚举进程/线程的方法

#include <ntifs.h>

/*
本文的目的是在驱动中列举一个进程的所有的线程。
以系统进程为例子演示。

办法想采用通用稳定的,所以选择了NtQuerySystemInformation的SystemProcessInformation。
尽管http://msdn.microsoft.com/en-us/library/windows/desktop/ms724509(v=vs.85).aspx上如是说:
[NtQuerySystemInformation may be altered or unavailable in future versions of Windows. Applications should use the alternate functions listed in this topic.]
可是他也没有说这个功能的替换办法(尽管有几个能获取这个结构中的某几个值)。

其实这个功能是枚举进程的,不是枚举线程的。
有的地方用#define SystemProcessAndThreadInformation 5.

made by correy
made at 2014.05.10
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com
*/

/*
一下定义摘自:
C:\Program Files (x86)\Windows Kits\8.0\Include\um\winternl.h或者
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include\winternl.h
更多的信息,可看:
http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/System%20Information/SYSTEM_INFORMATION_CLASS.html#SystemProcessInformation
http://doxygen.reactos.org/d2/d5c/ntddk__ex_8h_source.html
*/
typedef enum _SYSTEM_INFORMATION_CLASS {
    SystemBasicInformation = 0,
    SystemPerformanceInformation = 2,
    SystemTimeOfDayInformation = 3,
    SystemProcessInformation = 5,
    SystemProcessorPerformanceInformation = 8,
    SystemInterruptInformation = 23,
    SystemExceptionInformation = 33,
    SystemRegistryQuotaInformation = 37,
    SystemLookasideInformation = 45
} SYSTEM_INFORMATION_CLASS;

//摘自:c:\Program Files (x86)\Windows Kits\8.0\Include\shared\minwindef.h
typedef unsigned char       BYTE;

/*
一下定义摘自:
C:\Program Files (x86)\Windows Kits\8.0\Include\um\winternl.h或者
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include\winternl.h 或者
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724509(v=vs.85).aspx
注意这个是NtQuerySystemInformation用的。
*/
//typedef struct _SYSTEM_PROCESS_INFORMATION {
//    ULONG NextEntryOffset;
//    BYTE Reserved1[52];
//    PVOID Reserved2[3];
//    HANDLE UniqueProcessId;
//    PVOID Reserved3;
//    ULONG HandleCount;
//    BYTE Reserved4[4];
//    PVOID Reserved5[11];
//    SIZE_T PeakPagefileUsage;
//    SIZE_T PrivatePageCount;
//    LARGE_INTEGER Reserved6[6];
//} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;

/*
这个是ZwQuerySystemInformation用的结构。
http://msdn.microsoft.com/en-us/library/windows/desktop/ms725506(v=vs.85).aspx
*/
typedef struct _SYSTEM_PROCESS_INFORMATION {
    ULONG NextEntryOffset;
    ULONG NumberOfThreads;
    BYTE Reserved1[48];
    PVOID Reserved2[3];
    HANDLE UniqueProcessId;
    PVOID Reserved3;
    ULONG HandleCount;
    BYTE Reserved4[4];
    PVOID Reserved5[11];
    SIZE_T PeakPagefileUsage;
    SIZE_T PrivatePageCount;
    LARGE_INTEGER Reserved6[6];
} SYSTEM_PROCESS_INFORMATION;

/*
摘自:http://msdn.microsoft.com/en-us/library/windows/desktop/ms724509(v=vs.85).aspx。
有修改。
*/
NTSTATUS /* WINAPI NtQuerySystemInformation */ ZwQuerySystemInformation(
  _In_       SYSTEM_INFORMATION_CLASS SystemInformationClass,
  _Inout_    PVOID SystemInformation,
  _In_       ULONG SystemInformationLength,
  _Out_opt_  PULONG ReturnLength
);


#define tag 'tset' //test


DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{

}


DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL; 
    SYSTEM_PROCESS_INFORMATION * pspi = 0;
    SYSTEM_PROCESS_INFORMATION * pspi_temp = 0;
    ULONG SystemInformationLength = 0;
    ULONG ReturnLength = 0;
    
    KdBreakPoint();

    DriverObject->DriverUnload = Unload;    

     //获取需要的内存。
    status = ZwQuerySystemInformation(SystemProcessInformation, pspi, SystemInformationLength, &ReturnLength);
    if( !NT_SUCCESS( status ) && status != STATUS_INFO_LENGTH_MISMATCH)
    { 
        KdPrint(("ZwQuerySystemInformation fail with 0x%x in line %d\n",status, __LINE__));
        return status;
    }
    ReturnLength *= 2;//第一次需求0x9700,第二次需求0x9750,所以乘以2.
    SystemInformationLength = ReturnLength;
    pspi = ExAllocatePoolWithTag( NonPagedPool, ReturnLength, tag);
    if (pspi == NULL) {
        KdPrint(("ExAllocatePoolWithTag fail with 0x%x\n",status));
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    RtlZeroMemory(pspi, ReturnLength);    

    status = ZwQuerySystemInformation(SystemProcessInformation, pspi, SystemInformationLength, &ReturnLength);
    if( !NT_SUCCESS( status ) )
    {
        KdPrint(("ZwQuerySystemInformation fail with 0x%x in line %d\n",status, __LINE__));
        ExFreePoolWithTag( pspi, tag );
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    for (pspi_temp = pspi ; /* pspi_temp->NextEntryOffset != 0 */; /*pspi_temp++*/) //注释的都是有问题的,如少显示一个等。
    {
        KdPrint(("PID:%d\tNumberOfThreads:%d\tHandleCount:%d\n",pspi_temp->UniqueProcessId, pspi_temp->NumberOfThreads, pspi_temp->HandleCount));

        /*
        The start of the next item in the array is the address of the previous item plus the value in the NextEntryOffset member. 
        For the last item in the array, NextEntryOffset is 0.
        摘自:http://msdn.microsoft.com/en-us/library/windows/desktop/ms724509(v=vs.85).aspx。
        说明:NextEntryOffset的值是不固定的,更不是SYSTEM_PROCESS_INFORMATION结构的大小。所以不能加一个结构的大小来遍历。
        */

        if (pspi_temp->NextEntryOffset == 0)
        {
            break;
        }

        pspi_temp = (SYSTEM_PROCESS_INFORMATION *)((char *)pspi_temp + pspi_temp->NextEntryOffset);
    }

    ExFreePoolWithTag( pspi, tag );

    return status;//STATUS_SUCCESS
} 

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

#include <ntifs.h>
#include <windef.h>

/*
本文的目的是在驱动中列举一个进程的所有的线程。
以系统进程为例子演示。

办法想采用通用稳定的,所以选择了NtQuerySystemInformation的SystemProcessInformation。
尽管http://msdn.microsoft.com/en-us/library/windows/desktop/ms724509(v=vs.85).aspx上如是说:
[NtQuerySystemInformation may be altered or unavailable in future versions of Windows. Applications should use the alternate functions listed in this topic.]
可是他也没有说这个功能的替换办法(尽管有几个能获取这个结构中的某几个值)。

其实这个功能是枚举进程的,不是枚举线程的。
有的地方用#define SystemProcessAndThreadInformation 5.

其实也是可以枚举线程的,只不过有的结构还没有公开而已,或者我没有在官方的资料/WRK/wdk/msdn中找到。

made by correy
made at 2014.05.13
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com
不当之处,请指正。
*/

/*
一下定义摘自:
C:\Program Files (x86)\Windows Kits\8.0\Include\um\winternl.h或者
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include\winternl.h
更多的信息,可看:
http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/System%20Information/SYSTEM_INFORMATION_CLASS.html#SystemProcessInformation
http://doxygen.reactos.org/d2/d5c/ntddk__ex_8h_source.html
*/
typedef enum _SYSTEM_INFORMATION_CLASS {
    SystemBasicInformation = 0,
    SystemPerformanceInformation = 2,
    SystemTimeOfDayInformation = 3,
    SystemProcessInformation = 5,
    SystemProcessorPerformanceInformation = 8,
    SystemInterruptInformation = 23,
    SystemExceptionInformation = 33,
    SystemRegistryQuotaInformation = 37,
    SystemLookasideInformation = 45
} SYSTEM_INFORMATION_CLASS;

//摘自:c:\Program Files (x86)\Windows Kits\8.0\Include\shared\minwindef.h
//typedef unsigned char       BYTE;

/*
一下定义摘自:
C:\Program Files (x86)\Windows Kits\8.0\Include\um\winternl.h或者
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include\winternl.h 或者
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724509(v=vs.85).aspx
注意这个是NtQuerySystemInformation用的。
*/
//typedef struct _SYSTEM_PROCESS_INFORMATION {
//    ULONG NextEntryOffset;
//    BYTE Reserved1[52];
//    PVOID Reserved2[3];
//    HANDLE UniqueProcessId;
//    PVOID Reserved3;
//    ULONG HandleCount;
//    BYTE Reserved4[4];
//    PVOID Reserved5[11];
//    SIZE_T PeakPagefileUsage;
//    SIZE_T PrivatePageCount;
//    LARGE_INTEGER Reserved6[6];
//} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;

/*
这个是ZwQuerySystemInformation用的结构。
http://msdn.microsoft.com/en-us/library/windows/desktop/ms725506(v=vs.85).aspx
*/
//typedef struct _SYSTEM_PROCESS_INFORMATION {
//    ULONG NextEntryOffset;
//    ULONG NumberOfThreads;
//    BYTE Reserved1[48];
//    PVOID Reserved2[3];
//    HANDLE UniqueProcessId;
//    PVOID Reserved3;
//    ULONG HandleCount;
//    BYTE Reserved4[4];
//    PVOID Reserved5[11];
//    SIZE_T PeakPagefileUsage;
//    SIZE_T PrivatePageCount;
//    LARGE_INTEGER Reserved6[6];
//} SYSTEM_PROCESS_INFORMATION;

//http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/System%20Information/Structures/SYSTEM_PROCESS_INFORMATION.html
//typedef struct _SYSTEM_PROCESS_INFORMATION {
//  ULONG                   NextEntryOffset;
//  ULONG                   NumberOfThreads;
//  LARGE_INTEGER           Reserved[3];
//  LARGE_INTEGER           CreateTime;
//  LARGE_INTEGER           UserTime;
//  LARGE_INTEGER           KernelTime;
//  UNICODE_STRING          ImageName;
//  KPRIORITY               BasePriority;
//  HANDLE                  ProcessId;
//  HANDLE                  InheritedFromProcessId;
//  ULONG                   HandleCount;
//  ULONG                   Reserved2[2];
//  ULONG                   PrivatePageCount;
//  VM_COUNTERS             VirtualMemoryCounters;
//  IO_COUNTERS             IoCounters;
//  SYSTEM_THREAD           Threads[0];
//} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;


//摘自:http://msdn.microsoft.com/en-us/library/gg750724.aspx 这个WRK也有的。
typedef struct {
  LARGE_INTEGER KernelTime;
  LARGE_INTEGER UserTime;
  LARGE_INTEGER CreateTime;
  ULONG WaitTime;
  PVOID StartAddress;
  CLIENT_ID ClientId;
  LONG Priority;
  LONG BasePriority;
  ULONG ContextSwitches;
  ULONG ThreadState;
  ULONG WaitReason;
} SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION;


//摘自:http://doxygen.reactos.org/de/d22/ndk_2extypes_8h_source.html,有修改。
typedef struct _SYSTEM_PROCESS_INFORMATION
{
     ULONG NextEntryOffset;
     ULONG NumberOfThreads;
     LARGE_INTEGER WorkingSetPrivateSize; //VISTA
     ULONG HardFaultCount; //WIN7
     ULONG NumberOfThreadsHighWatermark; //WIN7
     ULONGLONG CycleTime; //WIN7
     LARGE_INTEGER CreateTime;
     LARGE_INTEGER UserTime;
     LARGE_INTEGER KernelTime;
     UNICODE_STRING ImageName;//这个名字好像不超过15-16个字符。
     KPRIORITY BasePriority;
     HANDLE UniqueProcessId;
     HANDLE InheritedFromUniqueProcessId;
     ULONG HandleCount;
     ULONG SessionId;
     ULONG_PTR PageDirectoryBase;
 
     //
     // This part corresponds to VM_COUNTERS_EX.
     // NOTE: *NOT* THE SAME AS VM_COUNTERS!
     //
     SIZE_T PeakVirtualSize;
     SIZE_T VirtualSize;
     ULONG PageFaultCount;
     SIZE_T PeakWorkingSetSize;
     SIZE_T WorkingSetSize;
     SIZE_T QuotaPeakPagedPoolUsage;
     SIZE_T QuotaPagedPoolUsage;
     SIZE_T QuotaPeakNonPagedPoolUsage;
     SIZE_T QuotaNonPagedPoolUsage;
     SIZE_T PagefileUsage;
     SIZE_T PeakPagefileUsage;
     SIZE_T PrivatePageCount;
 
     //
     // This part corresponds to IO_COUNTERS
     //
     LARGE_INTEGER ReadOperationCount;
     LARGE_INTEGER WriteOperationCount;
     LARGE_INTEGER OtherOperationCount;
     LARGE_INTEGER ReadTransferCount;
     LARGE_INTEGER WriteTransferCount;
     LARGE_INTEGER OtherTransferCount;
     SYSTEM_THREAD_INFORMATION TH[1];//这个本来是注释掉的。
} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;


//摘自:WRK。可见里面没有SYSTEM_THREAD_INFORMATION。
//typedef struct _SYSTEM_PROCESS_INFORMATION {
//    ULONG NextEntryOffset;
//    ULONG NumberOfThreads;
//    LARGE_INTEGER SpareLi1;
//    LARGE_INTEGER SpareLi2;
//    LARGE_INTEGER SpareLi3;
//    LARGE_INTEGER CreateTime;
//    LARGE_INTEGER UserTime;
//    LARGE_INTEGER KernelTime;
//    UNICODE_STRING ImageName;
//    KPRIORITY BasePriority;
//    HANDLE UniqueProcessId;
//    HANDLE InheritedFromUniqueProcessId;
//    ULONG HandleCount;
//    ULONG SessionId;
//    ULONG_PTR PageDirectoryBase;
//    SIZE_T PeakVirtualSize;
//    SIZE_T VirtualSize;
//    ULONG PageFaultCount;
//    SIZE_T PeakWorkingSetSize;
//    SIZE_T WorkingSetSize;
//    SIZE_T QuotaPeakPagedPoolUsage;
//    SIZE_T QuotaPagedPoolUsage;
//    SIZE_T QuotaPeakNonPagedPoolUsage;
//    SIZE_T QuotaNonPagedPoolUsage;
//    SIZE_T PagefileUsage;
//    SIZE_T PeakPagefileUsage;
//    SIZE_T PrivatePageCount;
//    LARGE_INTEGER ReadOperationCount;
//    LARGE_INTEGER WriteOperationCount;
//    LARGE_INTEGER OtherOperationCount;
//    LARGE_INTEGER ReadTransferCount;
//    LARGE_INTEGER WriteTransferCount;
//    LARGE_INTEGER OtherTransferCount;
//} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;


//http://msdn.microsoft.com/en-us/library/cc248685.aspx
typedef struct _NT6_TS_UNICODE_STRING {
  USHORT Length;
  USHORT MaximumLength;
  //[size_is(MaximumLength/2), length_is(Length/2)] 
  PWSTR Buffer;
} NT6_TS_UNICODE_STRING;


/*
http://msdn.microsoft.com/en-us/library/cc248684.aspx
http://msdn.microsoft.com/en-us/library/cc248873.aspx 这是allproc.h,但是WDK和WRK里面都没有,注释wdk8.1我没有安装。
*/
typedef struct _TS_SYS_PROCESS_INFORMATION_NT6 {
  ULONG NextEntryOffset;
  ULONG NumberOfThreads;
  LARGE_INTEGER SpareLi1;
  LARGE_INTEGER SpareLi2;
  LARGE_INTEGER SpareLi3;
  LARGE_INTEGER CreateTime;
  LARGE_INTEGER UserTime;
  LARGE_INTEGER KernelTime;
  NT6_TS_UNICODE_STRING ImageName;
  LONG BasePriority;
  DWORD UniqueProcessId;
  DWORD InheritedFromUniqueProcessId;
  ULONG HandleCount;
  ULONG SessionId;
  ULONG SpareUl3;
  SIZE_T PeakVirtualSize;
  SIZE_T VirtualSize;
  ULONG PageFaultCount;
  ULONG PeakWorkingSetSize;
  ULONG WorkingSetSize;
  SIZE_T QuotaPeakPagedPoolUsage;
  SIZE_T QuotaPagedPoolUsage;
  SIZE_T QuotaPeakNonPagedPoolUsage;
  SIZE_T QuotaNonPagedPoolUsage;
  SIZE_T PagefileUsage;
  SIZE_T PeakPagefileUsage;
  SIZE_T PrivatePageCount;

  //这个结构和SYSTEM_PROCESS_INFORMATION差不多,不过后面少了些。
} TS_SYS_PROCESS_INFORMATION_NT6, *PTS_SYS_PROCESS_INFORMATION_NT6;


/*
摘自:http://msdn.microsoft.com/en-us/library/windows/desktop/ms724509(v=vs.85).aspx。
有修改。
*/
NTSTATUS /* WINAPI NtQuerySystemInformation */ ZwQuerySystemInformation(
  _In_       SYSTEM_INFORMATION_CLASS SystemInformationClass,
  _Inout_    PVOID SystemInformation,
  _In_       ULONG SystemInformationLength,
  _Out_opt_  PULONG ReturnLength
);


#define tag 'tset' //test


DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{

}


DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL; 
    SYSTEM_PROCESS_INFORMATION * pspi = 0;
    SYSTEM_PROCESS_INFORMATION * pspi_temp = 0;
    ULONG SystemInformationLength = 0;
    ULONG ReturnLength = 0;
    ULONG i = 0;
    PSYSTEM_THREAD_INFORMATION psti = 0;
    
    KdBreakPoint();

    DriverObject->DriverUnload = Unload;    

     //获取需要的内存。
    status = ZwQuerySystemInformation(SystemProcessInformation, pspi, SystemInformationLength, &ReturnLength);
    if( !NT_SUCCESS( status ) && status != STATUS_INFO_LENGTH_MISMATCH)
    { 
        KdPrint(("ZwQuerySystemInformation fail with 0x%x in line %d\n",status, __LINE__));
        return status;
    }
    ReturnLength *= 2;//第一次需求0x9700,第二次需求0x9750,所以乘以2.
    SystemInformationLength = ReturnLength;
    pspi = ExAllocatePoolWithTag( NonPagedPool, ReturnLength, tag);
    if (pspi == NULL) {
        KdPrint(("ExAllocatePoolWithTag fail with 0x%x\n",status));
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    RtlZeroMemory(pspi, ReturnLength);    

    status = ZwQuerySystemInformation(SystemProcessInformation, pspi, SystemInformationLength, &ReturnLength);
    if( !NT_SUCCESS( status ) )
    {
        KdPrint(("ZwQuerySystemInformation fail with 0x%x in line %d\n",status, __LINE__));
        ExFreePoolWithTag( pspi, tag );
        return status;
    }

    //枚举进程信息。
    //判定系统进程的好的办法是和PEPROCESS PsInitialSystemProcess比较。
    for (pspi_temp = pspi ; /* pspi_temp->NextEntryOffset != 0 */; /*pspi_temp++*/) //注释的都是有问题的,如少显示一个等,可以改为while。
    {
        KdPrint(("PID:%d\tNumberOfThreads:%d\tHandleCount:%d\n",pspi_temp->UniqueProcessId, pspi_temp->NumberOfThreads, pspi_temp->HandleCount));

        //枚举线程信息。
        for (i = 0, psti = pspi_temp->TH; i < pspi_temp->NumberOfThreads; i++)
        {
            /*
            注意:
            1.有同一个地址跑多个线程的情况。特别是在系统进程。
            2.X64系统上有的线程地址为0等.感觉这个不重要,重要的是获取了TID。
            */            
            KdPrint(("    TID:%d属于PID:%d,StartAddress:%p\n", psti->ClientId.UniqueThread, psti->ClientId.UniqueProcess, psti->StartAddress));

            /*
            并且断言:psti <= ((char *)pspi_temp + pspi_temp->NextEntryOffset)
            */
            psti = (PSYSTEM_THREAD_INFORMATION)((char *)psti + sizeof(SYSTEM_THREAD_INFORMATION));
        }

        /*
        The start of the next item in the array is the address of the previous item plus the value in the NextEntryOffset member. 
        For the last item in the array, NextEntryOffset is 0.
        摘自:http://msdn.microsoft.com/en-us/library/windows/desktop/ms724509(v=vs.85).aspx。
        说明:NextEntryOffset的值是不固定的,更不是SYSTEM_PROCESS_INFORMATION结构的大小。所以不能加一个结构的大小来遍历。
        */

        if (pspi_temp->NextEntryOffset == 0)
        {
            break;
        }

        pspi_temp = (SYSTEM_PROCESS_INFORMATION *)((char *)pspi_temp + pspi_temp->NextEntryOffset);
    }

    ExFreePoolWithTag( pspi, tag );

    return status;//STATUS_SUCCESS
} 

2014年5月7日星期三

在驱动中获取进程的全路径

#include <ntifs.h>

/*
功能:获取进程的全路径。
优点:进程的名字没有15-16个字符的限制。

此办法早就知道,一直没有实验成功。
今天用DBGVIEW.EXE观察成功,但是没有用WINDBG.EXE调试。

尽管MSDN上这样说:
ZwQueryInformationProcess may be altered or unavailable in future versions of Windows. 
Applications should use the alternate functions listed in this topic.
可是ProcessImageFileName的功能也没有说没有替代的函数。

made by correy
made at 2014.05.06
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com
*/

#define tag  'tset' //test

//2008版本的MSDN,非WDK。
//http://msdn.microsoft.com/en-us/library/windows/desktop/ms687420(v=vs.85).aspx
//上面的一些标注在低版本上的WDK出错。
NTSTATUS /* WINAPI */ ZwQueryInformationProcess(
  __in          HANDLE ProcessHandle,
  __in          PROCESSINFOCLASS ProcessInformationClass,
  __out         PVOID ProcessInformation,
  __in          ULONG ProcessInformationLength,
  __out_opt     PULONG ReturnLength
);

void print_ProcessImageFileName(IN HANDLE PId)
{
    NTSTATUS status = 0;
    PVOID us_ProcessImageFileName = 0;//UNICODE_STRING
    ULONG ProcessInformationLength = 0;
    ULONG ReturnLength = 0;
    PEPROCESS  EProcess = 0;
    HANDLE  Handle = 0;

    /*
    必须转换一下,不然是无效的句柄。
    大概是句柄的类型转换为内核的。
    */
    status = PsLookupProcessByProcessId(PId, &EProcess);
    if (!NT_SUCCESS( status )) 
    {
        KdPrint(("PsLookupProcessByProcessId fail with 0x%x in line %d\n",status, __LINE__));
        return;        
    }
    ObDereferenceObject(EProcess); //微软建议加上。
    status = ObOpenObjectByPointer(EProcess, OBJ_KERNEL_HANDLE, NULL, GENERIC_READ, *PsProcessType, KernelMode, &Handle);//注意要关闭句柄。  
    if (!NT_SUCCESS( status )) 
    {
        KdPrint(("ObOpenObjectByPointer fail with 0x%x in line %d\n",status, __LINE__));
        return;        
    }

    //获取需要的内存。
    status = ZwQueryInformationProcess(Handle, ProcessImageFileName,us_ProcessImageFileName, ProcessInformationLength, &ReturnLength);
    if( !NT_SUCCESS( status ) && status != STATUS_INFO_LENGTH_MISMATCH)
    { 
        KdPrint(("ZwQueryInformationProcess fail with 0x%x in line %d\n",status, __LINE__));
        ZwClose(Handle);
        return;
    }
    ProcessInformationLength = ReturnLength;
    us_ProcessImageFileName = ExAllocatePoolWithTag( NonPagedPool, ReturnLength, tag);
    if (us_ProcessImageFileName == NULL) {
        KdPrint(("ExAllocatePoolWithTag fail with 0x%x\n",status));
        status = STATUS_INSUFFICIENT_RESOURCES;
        ZwClose(Handle);
        return;
    }
    RtlZeroMemory(us_ProcessImageFileName, ReturnLength);

    status = ZwQueryInformationProcess(Handle, ProcessImageFileName,us_ProcessImageFileName, ProcessInformationLength, &ReturnLength);
    if( !NT_SUCCESS( status ) )
    {
        KdPrint(("ZwQueryInformationProcess fail with 0x%x in line %d\n",status, __LINE__));
        ExFreePoolWithTag( us_ProcessImageFileName, tag );
        ZwClose(Handle);
        return;
    }

    KdPrint(("ProcessImageFileName:%wZ\n",us_ProcessImageFileName));//注意:中间有汉字是不会显示的。
    //形如:ProcessImageFileName:\Device\HarddiskVolume1\aa\Dbgvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvview.exe

    ExFreePoolWithTag( us_ProcessImageFileName, tag );
    ZwClose(Handle);
}

VOID ProcessCreateMon ( IN HANDLE hParentId, IN HANDLE PId,IN BOOLEAN bCreate )
{
    if ( bCreate )
    {
        print_ProcessImageFileName(PId);
    }
    else
    {
        DbgPrint( "TERMINATED == PROCESS ID: %d\n", PId);
    }
}

DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;

    status = PsSetCreateProcessNotifyRoutine(ProcessCreateMon, TRUE);
    if (!NT_SUCCESS( status )) 
    {
        DbgPrint( "PsSetCreateProcessNotifyRoutine fail %d\n", status);
        return;
    }
}

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

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

    DriverObject->DriverUnload = Unload;     

    status = PsSetCreateProcessNotifyRoutine(ProcessCreateMon, FALSE);    
    if (!NT_SUCCESS( status )) 
    {
        DbgPrint( "PsSetCreateProcessNotifyRoutine fail %d\n", status);
        return status;
    }

    return 0;//STATUS_SUCCESS
} 

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include <ntifs.h>
#include <windef.h>

/*
写作目的:
工作中的一次试验:拦截test.exe的某个操作。可死活拦截不了,郁闷了几天,在同事的探讨中发现了这个问题。
1.eprocees 中:ImageFileName    : [15]  ""
2.运行PsGetProcessImageFileName后,发现:
kd> db rax
fffffa80`1aed78b0  74 65 73 74 2e 65 78 65-70 70 6c 69 63 61 00 02  test.exepplica..
3.其实还有个限制就是不能超过15-16个字符。

这些问题百年不遇,以前用的好好的,今天突然出现这些问题,而且概率性还挺高的。
所以选用别的办法,放弃此函数。
以此纪念。

made by correy
made at 2014.06.17
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com
*/

#define tag  'tset' //test

//2008版本的MSDN,非WDK。
//http://msdn.microsoft.com/en-us/library/windows/desktop/ms687420(v=vs.85).aspx
//上面的一些标注在低版本上的WDK出错。
NTSTATUS /* WINAPI */ ZwQueryInformationProcess(
  __in          HANDLE ProcessHandle,
  __in          PROCESSINFOCLASS ProcessInformationClass,
  __out         PVOID ProcessInformation,
  __in          ULONG ProcessInformationLength,
  __out_opt     PULONG ReturnLength
);


BOOL GetProcessImageFileName(IN HANDLE PId, OUT UNICODE_STRING * file_name )
{
    NTSTATUS status = 0;
    PVOID us_ProcessImageFileName = 0;//UNICODE_STRING
    ULONG ProcessInformationLength = 0;
    ULONG ReturnLength = 0;
    PEPROCESS  EProcess = 0;
    HANDLE  Handle = 0;
    UNICODE_STRING * p = {0};
    UNICODE_STRING temp = {0};
    USHORT i = 0;

    /*
    必须转换一下,不然是无效的句柄。
    大概是句柄的类型转换为内核的。
    */
    status = PsLookupProcessByProcessId(PId, &EProcess);
    if (!NT_SUCCESS( status )) 
    {
        KdPrint(("PsLookupProcessByProcessId fail with 0x%x in line %d\n",status, __LINE__));
        return FALSE ;        
    }
    ObDereferenceObject(EProcess); //微软建议加上。
    status = ObOpenObjectByPointer(EProcess, OBJ_KERNEL_HANDLE, NULL, GENERIC_READ, *PsProcessType, KernelMode, &Handle);//注意要关闭句柄。  
    if (!NT_SUCCESS( status )) 
    {
        KdPrint(("ObOpenObjectByPointer fail with 0x%x in line %d\n",status, __LINE__));
        return FALSE;        
    }

    //获取需要的内存。
    status = ZwQueryInformationProcess(Handle, ProcessImageFileName,us_ProcessImageFileName, ProcessInformationLength, &ReturnLength);
    if( !NT_SUCCESS( status ) && status != STATUS_INFO_LENGTH_MISMATCH)
    { 
        KdPrint(("ZwQueryInformationProcess fail with 0x%x in line %d\n",status, __LINE__));
        ZwClose(Handle);
        return FALSE ;
    }
    ProcessInformationLength = ReturnLength;
    us_ProcessImageFileName = ExAllocatePoolWithTag( NonPagedPool, ReturnLength, tag);
    if (us_ProcessImageFileName == NULL) {
        KdPrint(("ExAllocatePoolWithTag fail with 0x%x\n",status));
        status = STATUS_INSUFFICIENT_RESOURCES;
        ZwClose(Handle);
        return FALSE ;
    }
    RtlZeroMemory(us_ProcessImageFileName, ReturnLength);

    status = ZwQueryInformationProcess(Handle, ProcessImageFileName,us_ProcessImageFileName, ProcessInformationLength, &ReturnLength);
    if( !NT_SUCCESS( status ) )
    {
        KdPrint(("ZwQueryInformationProcess fail with 0x%x in line %d\n",status, __LINE__));
        ExFreePoolWithTag( us_ProcessImageFileName, tag );
        ZwClose(Handle);
        return FALSE ;
    }

    //KdPrint(("ProcessImageFileName:%wZ\n",us_ProcessImageFileName));//注意:中间有汉字是不会显示的。
    //形如:ProcessImageFileName:\Device\HarddiskVolume1\aa\Dbgvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvview.exe
    p = (UNICODE_STRING *)us_ProcessImageFileName;

    //从末尾开始搜索斜杠。
    for (i = p->Length/2 - 1 ; ;i-- )
    {
        if (p->Buffer[i] == L'\\')
        {
            break;
        }
    }

    i++;//跳过斜杠。

    //构造文件名结构,复制用的。
    temp.Length = p->Length - i * 2;
    temp.MaximumLength = p->MaximumLength - i * 2;
    temp.Buffer = &p->Buffer[i];

    //这个内存由调用者释放。
    file_name->Buffer = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH, tag);
    if (file_name->Buffer == NULL) { 
        DbgPrint("发生错误的文件为:%s, 代码行为:%d\n", __FILE__, __LINE__);
        ExFreePoolWithTag( us_ProcessImageFileName, tag );
        ZwClose(Handle);
        return FALSE ;
    }
    RtlZeroMemory(file_name->Buffer, MAX_PATH);
    RtlInitEmptyUnicodeString(file_name, file_name->Buffer,MAX_PATH);

    RtlCopyUnicodeString(file_name, &temp);
    KdPrint(("ProcessImageFileName:%wZ\n",file_name));

    ExFreePoolWithTag( us_ProcessImageFileName, tag );
    ZwClose(Handle);
    return TRUE ;
}


VOID ProcessCreateMon ( IN HANDLE hParentId, IN HANDLE PId,IN BOOLEAN bCreate )
{
    UNICODE_STRING file_name;
    BOOL B = FALSE ;

    if ( bCreate )
    {
        B = GetProcessImageFileName(PId,  &file_name );
        if (!B)
        {
            DbgPrint( "GetProcessImageFileName fail!\n");
        }
        RtlFreeUnicodeString(&file_name);
    }
    else
    {
        DbgPrint( "TERMINATED == PROCESS ID: %d\n", PId);
    }
}


DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;

    status = PsSetCreateProcessNotifyRoutine(ProcessCreateMon, TRUE);
    if (!NT_SUCCESS( status )) 
    {
        DbgPrint( "PsSetCreateProcessNotifyRoutine fail %d\n", status);
        return;
    }
}


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

    KdBreakPoint();

    DriverObject->DriverUnload = Unload;     

    status = PsSetCreateProcessNotifyRoutine(ProcessCreateMon, FALSE);    
    if (!NT_SUCCESS( status )) 
    {
        DbgPrint( "PsSetCreateProcessNotifyRoutine fail %d\n", status);
        return status;
    }

    return 0;//STATUS_SUCCESS
}