您的位置:首页 > 其它

利用32位PEB结构实现从进程ID中得到进程完整路径

2017-11-20 19:51 441 查看

//PEB.h
#pragma once
#include <windows.h>
#include <iostream>
using namespace std;
//宏,结构体定义,函数声明;
//#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)

//要自己定义PEB结构:

//PEB结构中的查找进程完整路径的结构体
typedef struct _UNICODE_STRING
{
UINT16 Length;//short型
UINT16 MaximumLength;
PWCHAR Buffer;//WCHAR*型(四字节大小的指针)
}UNICODE_STRING,PUNICODE_STRING;
//UNICODE_STRING在Ring3层不公开,(在驱动层才公开)
typedef struct _RTL_USER_PROCESS_PARAMETERS_X86
{
UINT32 MaximumLength;
UINT32 Length;
UINT32 Flags;
UINT32 DebugFlags;
PVOID  ConsoleHandle;
UINT32 ConsoleFlags;//UINT 4B
PVOID  StandardInput;
PVOID  StandardOutput;
PVOID  StandardError;
ULONG32 CurrentDirectory[3];//原来是十二字节的结构体CURDIR
UNICODE_STRING DllPath;
UNICODE_STRING ImagePathName;//完整路径
UNICODE_STRING CommandLine;
} RTL_USER_PROCESS_PARAMETERS_X86, *PRTL_USER_PROCESS_PARAMETERS_X86;
typedef struct _PEB_X86
{
UINT8 InheritedAddressSpace;
UINT8 ReadImageFileExecOptions;
UINT8 BeingDebugged;
UINT8 BitField;//联合体(位域第一位的成员)
PVOID Mutant;//互斥体
PVOID ImageBaseAddress;//模块加载基地址
PVOID Ldr;//结构体(Ldr实际上为结构体类型指针)
PRTL_USER_PROCESS_PARAMETERS_X86 ProcessParameters;
}PEB_X86,*PPEB_X86;

#ifdef _WIN32
#define RTL_USER_PROCESS_PARAMETERS RTL_USER_PROCESS_PARAMETERS_X86
#define PPEB PPEB_X86
#define PEB  PEB_X86
#else
#define PPEB PPEB_X64
#define PEB  PEB_X64
#endif

//有关查找PEB地址的属于进程内存的结构体
typedef struct _PROCESS_BASIC_INFORMATION
{
NTSTATUS ExitStatus;
PPEB     PebBaseAddress;   //地址
ULONG    AffinityMask;
LONG     BasePriority;
ULONG    UniqueProcessId;
ULONG    InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION;
typedef PROCESS_BASIC_INFORMATION *PPROCESS_BASIC_INFORMATION;

//函数指针原型定义:
typedef enum _PROCESSINFOCLASS {
ProcessBasicInformation,
ProcessQuotaLimits,
ProcessIoCounters,
ProcessVmCounters,
ProcessTimes,
ProcessBasePriority,
ProcessRaisePriority,
ProcessDebugPort,
ProcessExceptionPort,
ProcessAccessToken,
ProcessLdtInformation,
ProcessLdtSize,
ProcessDefaultHardErrorMode,
ProcessIoPortHandlers,          // Note: this is kernel mode only
ProcessPooledUsageAndLimits,
ProcessWorkingSetWatch,
ProcessUserModeIOPL,
ProcessEnableAlignmentFaultFixup,
ProcessPriorityClass,
ProcessWx86Information,
ProcessHandleCount,
ProcessAffinityMask,
ProcessPriorityBoost,
ProcessDeviceMap,
ProcessSessionInformation,
ProcessForegroundInformation,
ProcessWow64Information,
ProcessImageFileName,
ProcessLUIDDeviceMapsEnabled,
ProcessBreakOnTermination,
ProcessDebugObjectHandle,
ProcessDebugFlags,
ProcessHandleTracing,
ProcessIoPriority,
ProcessExecuteFlags,
ProcessResourceManagement,
ProcessCookie,
ProcessImageInformation,
MaxProcessInfoClass
} PROCESSINFOCLASS;

typedef
NTSTATUS(NTAPI *pfnNtQueryInformationProcess)(
IN HANDLE ProcessHandle,//,进程句柄,查谁
IN PROCESSINFOCLASS ProcessInformationClass,//枚举类型结构体,查什么信息
OUT PVOID ProcessInformation,//结构体首地址,查出来的东西放在哪里
IN UINT32 ProcessInformationLength,//结构体大小
OUT PUINT32 ReturnLength);//校验值
//#define NTAPI __stdcall,指调用约定
//定义函数指针
//
BOOL GetProcessFullPathByProcessID(ULONG32 ProcessID, WCHAR* BufferData, ULONG BufferLegnth);


// PEB.cpp : 定义控制台应用程序的入口点。
//

#include "PEB.h"

#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
int main()
{
BOOL bOk = FALSE;
ULONG32 ProcessID = 0;
WCHAR   BufferData[MAX_PATH] = { 0 };
//定义完整路径数组,
//windows规定存放完整路径的数组最大为260个字节;
printf("Input Process ID\r\n");
scanf_s("%d", &ProcessID);
bOk = GetProcessFullPathByProcessID(ProcessID,BufferData, MAX_PATH);
//用自定义函数实现从进程ID得到进程完整路径的过程(进程ID,完整路径(存放的数组名),数组长度)

cout << bOk << endl;
if (bOk==TRUE)
{
printf("%S\r\n", BufferData);
//BufferData双字,故用大S输出字符串;
}
return 0;
}

BOOL GetProcessFullPathByProcessID(ULONG32 ProcessID,WCHAR* BufferData,ULONG BufferLegnth)
//先找到peb结构在进程中的地址,再从peb结构中找到完整路径所在的地址;
//GetPebByProcessID,GetProcessFullPathByPeb,
{
BOOL						bOk = FALSE;
NTSTATUS					Status = 0;
//一种int型返回值
PEB	                        Peb = { 0 };
//PEB结构体初始化
HANDLE						ProcessHandle = NULL;

//*打开目标进程空间
ProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION| PROCESS_VM_READ, FALSE, ProcessID);
//ProcessHandle值是目标进程的进程句柄,是一个正数(-1是GetCurrentProcess函数,代表自己进程的伪句柄);
//OpenProcess为Windows库函数,“打开(对方)进程空间”(想要行使的权限(查询|读),BOOL型,目标进程ID)

if (ProcessHandle == NULL)
{
return FALSE;
}
pfnNtQueryInformationProcess	NtQueryInformationProcess =
(pfnNtQueryInformationProcess)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtQueryInformationProcess");
//GetModuleHandle为Windows库函数(GetModuleHandleW),“返回加载模块的基地址”(所以模块名字传为双字!)
//GetProcAddress为Windows库函数,“从当前进程的导出表中获得目标函数地址”(实际上就是遍历导出表来搜索这个函数)
//								本语句意思是从ntdll.dll的导出表中搜索NtQueryInformationProcess函数!
//此时函数地址得到的是自己的,(1自己的基地址,2自己的函数)//没有用目标函数进程
//
//GetProcAddress从当前函数的导出表搜索函数	//从当前进程空间的ntdll模块的导出表中获得一个函数NtQueryInformationProcess的地址
//而不从导入表中获得(直接调用)原因是:
//有可能就没有导入!(涉及到VS编译未公开函数等原因)GetProcAddress返回的是一个泛型,

//得到函数地址以后,发生强制类型转换,
if (NtQueryInformationProcess == NULL)
{
CloseHandle(ProcessHandle);
ProcessHandle = NULL;
return FALSE;
}

//**通过 NtQueryInformationProcess 获得 ProcessBasicInformation
PROCESS_BASIC_INFORMATION	pbi = { 0 };
ULONG32						ReturnLength = 0;
//开始查进程的ProcessBasicInformation
Status = NtQueryInformationProcess(ProcessHandle,
ProcessBasicInformation, &pbi, sizeof(PROCESS_BASIC_INFORMATION),
(PUINT32)&ReturnLength);
//参数:查谁,查什么,

//Status=0
//NT_SUCCESS(Status)=1
if (!NT_SUCCESS(Status))
{
CloseHandle(ProcessHandle);
ProcessHandle = NULL;
return FALSE;
}

//***通过ReadProcessMemory 从进程里面 PebBaseAddress 内存数据读取出来
bOk = ReadProcessMemory(ProcessHandle, pbi.PebBaseAddress, &Peb, sizeof(PEB), (SIZE_T*)&ReturnLength);
//ReadProcessMemory是Windows库函数,“读进程空间的内存”,
//(目标进程句柄,目标地址,读到peb这个结构体指针里,结构体大小,校验值)
//SIZE_T相当于ULONG_PTR;
if (bOk == FALSE)
{
CloseHandle(ProcessHandle);
ProcessHandle = NULL;
return FALSE;
}

RTL_USER_PROCESS_PARAMETERS RtlUserProcessParameters = { 0 };
bOk = ReadProcessMemory(ProcessHandle, Peb.ProcessParameters, &RtlUserProcessParameters,
sizeof(RTL_USER_PROCESS_PARAMETERS), (SIZE_T*)&ReturnLength);

if (RtlUserProcessParameters.ImagePathName.Buffer!=NULL)
{
ULONG v1 = 0;
if (RtlUserProcessParameters.ImagePathName.Length<BufferLegnth)
{
v1 = RtlUserProcessParameters.ImagePathName.Length;
}
else
{
v1 = BufferLegnth-10;
}
bOk = ReadProcessMemory(ProcessHandle, RtlUserProcessParameters.ImagePathName.Buffer,
Bu
4000
fferData,v1,(SIZE_T*)&ReturnLength);
if (bOk == FALSE)
{
CloseHandle(ProcessHandle);
ProcessHandle = NULL;
return FALSE;
}
}
CloseHandle(ProcessHandle);
return TRUE;
}


本程序只使用于32位!
即只能寻找32位进程的完整路径!

使用PEB结构以得到进程的完整路径(包括从进程ID得到进程PEB地址和从PEB结构得到进程完整路径)

GetProcessFullPathByProcessID相当于两个函数GetPebByProcessID,GetProcessFullPathByPeb的合并。

从PEB结构中得到进程的完整路径:

通过PEB结构中的RTL_USER_PROCESS_PARAMETERS类型的ProcessParameters成员,ProcessParameters成员中有ImagePathName成员。

从进程ID中得到进程PEB结构地址:
使用微软未公开的函数NtQueryInformationProcess,其中用到枚举类型结构体PROCESSINFOCLASS,该结构体的成员PROCESS_BASIC_INFORMATION,从其中再找到PPEB类型的PebBaseAddress成员,该结构体的地址即为peb的地址。找到了peb的地址相当于已经可以开始读取PEB的结构了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐