获取进程完整路径探索

要想获取进程的完整路径,使用PSAPI提供的函数 GetModuleFileNameEx() 就可以轻松的办到
下面是一个例子:

/*
用户态使用 psapi 函数进程进程查询
*/


#include 
" stdio.h "
#include 
" windows.h "
#include 
" psapi.h "
#pragma  comment(lib,"psapi.lib")

// 需要额外添加  psapi.h 以及 psapi.lib
// 存在一定的问题,system进程不能列出来(当然这个可以根据pid来判别.system的pid是4),
// 卡巴斯基的进程也不行,看来本身还是有缺陷


// 提升进程权限
bool  AdjustPurview()
{
    TOKEN_PRIVILEGES TokenPrivileges;
    BOOL bRet;
    HANDLE hToken;

    LookupPrivilegeValue(NULL, SE_DEBUG_NAME, 
&TokenPrivileges.Privileges[0].Luid);   
    OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, 
&hToken);

    TokenPrivileges.PrivilegeCount 
= 1;   
    TokenPrivileges.Privileges[
0].Attributes = SE_PRIVILEGE_ENABLED;

    bRet 
= AdjustTokenPrivileges(hToken, FALSE, &TokenPrivileges, 0, NULL, NULL);

    CloseHandle(hToken);
    
return bRet == TRUE;
}



void  PrintProcessNameAndID( DWORD processID )
{
    
char szProcessName[MAX_PATH] = "........";

    AdjustPurview();
    
//取得进程的句柄
    HANDLE hProcess = OpenProcess( 
        PROCESS_QUERY_INFORMATION 
|
        PROCESS_VM_READ,
        FALSE, 
        processID );
    
//取得进程名称
    if ( hProcess )
    
{
        
//HMODULE hMod;
        
//DWORD cbNeeded;
        
//if ( EnumProcessModules( hProcess, &hMod, sizeof(hMod), &cbNeeded) )
        {
            GetModuleFileNameEx(hProcess,NULL,szProcessName,MAX_PATH);            
        }

    }


    
//回显进程名称和ID
    printf( " %-20d%-20s", processID , szProcessName);

    CloseHandle( hProcess );
}




void  main( )

{

    DWORD aProcesses[
1024], cbNeeded, cProcesses;

    unsigned 
int i;

    
//枚举系统进程ID列表

    
if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) )
    
{
        
return;
    }


    
//计算进程数量

    cProcesses 
= cbNeeded / sizeof(DWORD);

    
// 输出每个进程的名称和ID

    
for ( i = 0; i < cProcesses; i++ )

        PrintProcessNameAndID( aProcesses[i] );

    
return;

}

 呵呵,方便快捷的实现了进程完整路径的获取,其中比较关键的一句就是 GetModuleFileNameEx(),那么GetModuleFileNameEx()又是如何实现的呢?逆向分析了一下这个函数,发现它就是从进程的PEB中进行检索找出进程完整路径的.
首先来分析一下PEB(进程环境块),其中包含了大量的信息,有多少的信息呢?我们使用内核调试器直接欣赏一下
kd> !peb
PEB at 7ffd9000
InheritedAddressSpace:    No
ReadImageFileExecOptions: No
BeingDebugged:            No
ImageBaseAddress:         01000000
        Ldr                       00181e90
        Ldr.Initialized:          Yes
        Ldr.InInitializationOrderModuleList: 00181f28 . 001824e0
        Ldr.InLoadOrderModuleList:           00181ec0 . 001824d0
        Ldr.InMemoryOrderModuleList:         00181ec8 . 001824d8
        Base TimeStamp                     Module
        1000000 44b01112 Jul 09 04:09:54 2006 D:/Program Files/Debugging Tools
        for Windows/kd.exe
         7c920000 4121457c Aug 17 07:38:36 2004 C:/WINDOWS/system32/ntdll.dll
         7c800000 4121457d Aug 17 07:38:37 2004 C:/WINDOWS/system32/kernel32.dll
         77be0000 412145fe Aug 17 07:40:46 2004 C:/WINDOWS/system32/msvcrt.dll
         2000000 44b011b8 Jul 09 04:12:40 2006 D:/Program Files/Debugging Tools
         for Windows/dbgeng.dll
          3000000 44b01174 Jul 09 04:11:32 2006 D:/Program Files/Debugging Tools
          for Windows/dbghelp.dll
           77da0000 4121454d Aug 17 07:37:49 2004 C:/WINDOWS/system32/ADVAPI32.dll
           77e50000 41214569 Aug 17 07:38:17 2004 C:/WINDOWS/system32/RPCRT4.dll
           77bd0000 41214577 Aug 17 07:38:31 2004 C:/WINDOWS/system32/VERSION.dll
           1d00000 44b011d1 Jul 09 04:13:05 2006 D:/Program Files/Debugging Tools
           for Windows/symsrv.dll
SubSystemData:     00000000
ProcessHeap:       00080000
ProcessParameters: 00020000
WindowTitle:  '"D:/Program Files/Debugging Tools for Windows/livekd.exe"'
ImageFile:    'D:/Program Files/Debugging Tools for Windows/kd.exe'
CommandLine:  'kd.exe      -z C:/WINDOWS/system32/livekd.dmp'
DllPath:      'D:/Program Files/Debugging Tools for Windows;C:/WINDOWS/syste
     m32;C:/WINDOWS/system;C:/WINDOWS;.;d:/perl/bin;C:/WINDOWS/system32;C:/WINDOWS;C:
/WINDOWS/System32/Wbem;D:/Program Files/MySQL/MySQL Server 4.1/bin;C:/Program Fi
les/Microsoft SQL Server/80/Tools/BINN;D:/Program Files/Microsoft Visual Studio/
Common/Tools/WinNT;D:/Program Files/Microsoft Visual Studio/Common/MSDev98/Bin;D
:/Program Files/Microsoft Visual Studio/Common/Tools;D:/Program Files/Microsoft
Visual Studio/VC98/bin'
Environment:  00010000
     =C:=C:/Documents and Settings/galihoo
     ALLUSERSPROFILE=C:/Documents and Settings/All Users
     APPDATA=C:/Documents and Settings/galihoo/Application Data
     CLIENTNAME=Console
     CommonProgramFiles=C:/Program Files/Common Files
     COMPUTERNAME=PERSON-GALIHOO
     ComSpec=C:/WINDOWS/system32/cmd.exe
     DDKROOT=D:/WINDDK/2600
     DRIVERNETWORKS=D:/PROGRA~1/COMPUW~1/SOFTIC~1/DRIVER~2
     DRIVERWORKS=D:/PROGRA~1/COMPUW~1/SOFTIC~1/DRIVER~1
     FP_NO_HOST_CHECK=NO
     HOMEDRIVE=C:
HOMEPATH=/Documents and Settings/galihoo
include=D:/Program Files/Microsoft Visual Studio/VC98/atl/include;D:/Pro
gram Files/Microsoft Visual Studio/VC98/mfc/include;D:/Program Files/Microsoft V
isual Studio/VC98/include
lib=D:/Program Files/Microsoft Visual Studio/VC98/mfc/lib;D:/Program Fil
es/Microsoft Visual Studio/VC98/lib
LOGONSERVER=//PERSON-GALIHOO
MSDevDir=D:/Program Files/Microsoft Visual Studio/Common/MSDev98
NUMBER_OF_PROCESSORS=1
OS=Windows_NT
Path=D:/Program Files/Debugging Tools for Windows/winext/arcade;d:/perl/
bin;C:/WINDOWS/system32;C:/WINDOWS;C:/WINDOWS/System32/Wbem;D:/Program Files/MyS
QL/MySQL Server 4.1/bin;C:/Program Files/Microsoft SQL Server/80/Tools/BINN;D:/P
rogram Files/Microsoft Visual Studio/Common/Tools/WinNT;D:/Program Files/Microso
ft Visual Studio/Common/MSDev98/Bin;D:/Program Files/Microsoft Visual Studio/Com
mon/Tools;D:/Program Files/Microsoft Visual Studio/VC98/bin
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH
perl=D:/perl/bin/
PROCESSOR_ARCHITECTURE=x86
PROCESSOR_IDENTIFIER=x86 Family 6 Model 8 Stepping 1, AuthenticAMD
PROCESSOR_LEVEL=6
PROCESSOR_REVISION=0801
ProgramFiles=C:/Program Files
PROMPT=$P$G
SESSIONNAME=Console
SystemDrive=C:
SystemRoot=C:/WINDOWS
TEMP=C:/DOCUME~1/galihoo/LOCALS~1/Temp
TMP=C:/DOCUME~1/galihoo/LOCALS~1/Temp
USERDOMAIN=PERSON-GALIHOO
USERNAME=galihoo
USERPROFILE=C:/Documents and Settings/galihoo
VS71COMNTOOLS=E:/Program Files/Microsoft Visual Studio 7/Common7/Tools/
VTOOLSD=D:/PROGRA~1/COMPUW~1/SOFTIC~1/VtoolsD
windir=C:/WINDOWS
WORKPATH=D:/WINDDK/MyDrivers
_NT_SYMBOL_PATH=H:/XP_SP2_Symbols

看到了吧,进程映象的基地址,进程中加载的所有的映象,以及各种环境变量都可以从PEB顺藤摸瓜找到

 

PEB的结构
typedef 
struct  _PEB  {

    BOOLEAN                 InheritedAddressSpace;
    BOOLEAN                 ReadImageFileExecOptions;
    BOOLEAN                 BeingDebugged;
    BOOLEAN                 Spare;
    HANDLE                  Mutant;
    PVOID                   ImageBaseAddress;
    PPEB_LDR_DATA           LoaderData;
    PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
    PVOID                   SubSystemData;
    PVOID                   ProcessHeap;
    PVOID                   FastPebLock;
    PPEBLOCKROUTINE         FastPebLockRoutine;
    PPEBLOCKROUTINE         FastPebUnlockRoutine;
    ULONG                   EnvironmentUpdateCount;
    PPVOID                  KernelCallbackTable;
    PVOID                   EventLogSection;
    PVOID                   EventLog;
    PPEB_FREE_BLOCK         FreeList;
    ULONG                   TlsExpansionCounter;
    PVOID                   TlsBitmap;
    ULONG                   TlsBitmapBits[
0x2];
    PVOID                   ReadOnlySharedMemoryBase;
    PVOID                   ReadOnlySharedMemoryHeap;
    PPVOID                  ReadOnlyStaticServerData;
    PVOID                   AnsiCodePageData;
    PVOID                   OemCodePageData;
    PVOID                   UnicodeCaseTableData;
    ULONG                   NumberOfProcessors;
    ULONG                   NtGlobalFlag;
    BYTE                    Spare2[
0x4];
    LARGE_INTEGER           CriticalSectionTimeout;
    ULONG                   HeapSegmentReserve;
    ULONG                   HeapSegmentCommit;
    ULONG                   HeapDeCommitTotalFreeThreshold;
    ULONG                   HeapDeCommitFreeBlockThreshold;
    ULONG                   NumberOfHeaps;
    ULONG                   MaximumNumberOfHeaps;
    PPVOID                  
*ProcessHeaps;
    PVOID                   GdiSharedHandleTable;
    PVOID                   ProcessStarterHelper;
    PVOID                   GdiDCAttributeList;
    PVOID                   LoaderLock;
    ULONG                   OSMajorVersion;
    ULONG                   OSMinorVersion;
    ULONG                   OSBuildNumber;
    ULONG                   OSPlatformId;
    ULONG                   ImageSubSystem;
    ULONG                   ImageSubSystemMajorVersion;
    ULONG                   ImageSubSystemMinorVersion;
    ULONG                   GdiHandleBuffer[
0x22];
    ULONG                   PostProcessInitRoutine;
    ULONG                   TlsExpansionBitmap;
    BYTE                    TlsExpansionBitmapBits[
0x80];
    ULONG                   SessionId;

}
 PEB,  * PPEB;


PPEB_LDR_DATA 对我们来说比较重要,看看里面都有什么东西

typedef 
struct  _PEB_LDR_DATA  {
    ULONG                   Length;
    BOOLEAN                 Initialized;
    PVOID                   SsHandle;
    LIST_ENTRY              InLoadOrderModuleList;
    LIST_ENTRY              InMemoryOrderModuleList;
    LIST_ENTRY              InInitializationOrderModuleList;
}
 PEB_LDR_DATA,  * PPEB_LDR_DATA;

后面三个字段都是双向环形链表,链表上的节点由进程中所有的模块的信息组成,遍历这三个链表就可以得到所有的模块,只不过他们在链表中排列的位置不一样, 链表节点指向的实体内容是如下的结构
typedef 
struct  _LDR_MODULE  {
    LIST_ENTRY InLoadOrderModuleList;
    LIST_ENTRY InMemoryOrderModuleList;
    LIST_ENTRY InInitializationOrderModuleList;
    PVOID BaseAddress;
    PVOID EntryPoint;
    ULONG SizeOfImage;
    UNICODE_STRING FullDllName;
    UNICODE_STRING BaseDllName;
    ULONG Flags;
    SHORT LoadCount;
    SHORT TlsIndex;
    LIST_ENTRY HashTableEntry;
    ULONG TimeDateStamp;
}
 LDR_MODULE,  * PLDR_MODULE;

看看 FullDllName ,它就是我们要找得东西
实现的步骤: 
1 . 获得 peb,(可以使用 native api NtQueryInformationProcess 进行获取)
2 . 获得LoaderData (peb + 0xc )
3 . 获得InMemoryOrderModuleList 
(LoaderData 
+   0x14 ,选择第二个链表,不知道为什么,GetModuleFileNameEx就是这么实现的)
4 . 获得FullDllName 
(InMemoryOrderModuleList是双向链表的一个节点,它刚好指向进程的实体映象,因此可以使用 InMemoryOrderModuleList 
+   0x1c  就可以得到FullDllName)
5 . 获得真正的完整路径,
kd
>  dt UNICODE_STRING
+ 0x000  Length           : Uint2B
+ 0x002  MaximumLength    : Uint2B
+ 0x004  Buffer           : Ptr32 Uint2B


关键函数代码如下:

// 通过进程ID,然后读取此进程的PEB,得到进程的模块
int  GetFullPathByID(DWORD dwID)
{
    
// 打开进程    
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,
        FALSE,dwID);
    
if (hProcess == NULL) {
        
int k = GetLastError();
        
return 0;
    }


    PROCESS_BASIC_INFORMATION pi;
    ZeroMemory( 
&pi, sizeof(pi) );

    DWORD LoaderData 
= 0;
    DWORD InMemoryOrderModuleList 
= 0;
    UNICODE_STRING usImagePath;
    WCHAR ImagePath[MAX_PATH] 
= {0};
    usImagePath.MaximumLength 
= MAX_PATH;

    
// 定义函数指针
    LONG (WINAPI *PNtQueryInformationProcess)(HANDLE,PROCESSINFOCLASS,PVOID,ULONG,PULONG);

    
// 获取函数地址
    PNtQueryInformationProcess = (LONG(WINAPI*)(HANDLE,PROCESSINFOCLASS,PVOID,ULONG,PULONG))
        GetProcAddress( GetModuleHandle( 
"ntdll.dll" ),"NtQueryInformationProcess" );

    
// 获取 peb
    if (PNtQueryInformationProcess( hProcess, 
        ProcessBasicInformation, 
        
&pi, 
        
sizeof(pi), 
        NULL) 
== 0 
        )
    
{
        
// 读取 LoaderData
        if (!ReadProcessMemory(hProcess,
            (PVOID 
*)((DWORD)pi.PebBaseAddress+0xc),
            
&LoaderData,
            
sizeof(DWORD),
            NULL)
            )
        
{
            printf(
"LoaderData Failed ");
            
return 0;
        }


        
// 读取 InMemoryOrderModuleList
        if (!ReadProcessMemory(hProcess,
            (PVOID 
*)((DWORD)LoaderData+0x14),
            
&InMemoryOrderModuleList,
            
sizeof(DWORD),
            NULL)
            )
        
{
            printf(
"InMemoryOrderModuleList Failed ");
            
return 0;
        }


        
// 读取 FullDllName
        if (!ReadProcessMemory(hProcess,
            (PVOID 
*)((DWORD)InMemoryOrderModuleList+0x1c),
            
&usImagePath,
            
sizeof(UNICODE_STRING),
            NULL)
            )
        
{
            printf(
"usImagePath Failed ");
            
return 0;
        }


        
// 读取 真正的路径
        if (!ReadProcessMemory(hProcess,
            usImagePath.Buffer,
            
&ImagePath,
            MAX_PATH,
            NULL)
            )
        
{
            printf(
"ImagePath Failed ");
            
return 0;
        }
        

    }


    
char chImagePath[MAX_PATH] = {0};

    
//转换成ANSI
    WideCharToMultiByte(CP_ACP,0,ImagePath,-1,chImagePath,MAX_PATH,NULL,NULL);

    printf(
"%-10d%s ",dwID,chImagePath);

    
return 0;
}


其实另外还可以通过PEB结构中的ProcessParameters来进行路径的获取,其结构定义如下

typedef 
struct  _RTL_USER_PROCESS_PARAMETERS  {
    ULONG MaximumLength;
    ULONG Length;
    ULONG Flags;
    ULONG DebugFlags;
    PVOID ConsoleHandle;
    ULONG ConsoleFlags;
    HANDLE StdInputHandle;
    HANDLE StdOutputHandle;
    HANDLE StdErrorHandle;
    UNICODE_STRING CurrentDirectoryPath;
    HANDLE CurrentDirectoryHandle;
    UNICODE_STRING DllPath;
    UNICODE_STRING ImagePathName;
    UNICODE_STRING CommandLine;
    PVOID Environment;
    ULONG StartingPositionLeft;
    ULONG StartingPositionTop;
    ULONG Width;
    ULONG Height;
    ULONG CharWidth;
    ULONG CharHeight;
    ULONG ConsoleTextAttributes;
    ULONG WindowFlags;
    ULONG ShowWindowFlags;
    UNICODE_STRING WindowTitle;
    UNICODE_STRING DesktopName;
    UNICODE_STRING ShellInfo;
    UNICODE_STRING RuntimeData;
    RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[
0x20];
}
 RTL_USER_PROCESS_PARAMETERS,  * PRTL_USER_PROCESS_PARAMETERS;

ImagePathName 就是完整路径,呵呵,其实这个ImagePathName和上面InMemoryOrderModuleList的FullDllName,他们所指向的缓冲区是一个地方,可以自己玩玩..


ps:这个东西比较老,也没有多大的意义,微软都提供了 GetModuleFileNameEx 这个api,用它就够简单了,呵呵,搞到耍


by:galihoo
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值