PE 此文章为自查文章,部分内容没有详细解释。具体概念出自李承远《逆向工程核心原理》。
.exe .dll .sys
PE或PE+,注意没有PE64
C:\Windows\system32\notepad.exe //32位
C:\Windows\syswow64\notepad.exe //64位
PE文件的标志
PE格式文件加载到内存中的情形
DOS头 windows.h中有定义 _IMAGE_DOS_HEADE
NULL区域是未使用的区域用0填充的,补齐文件或内存粒度对齐
重点关注0x00 word e_magic=0x5a4d 对应MZ, 和dword(long)0x3c e_ifanew, (PIMAGE_NT_HEADERS)(BYTE )ImageDosHeader+(ImagerDosHeader->e_ifanew)就是NT_Headers的地址 *
64位下的地址为8字节,32位为4字节,如果文件是64位,则4字节定位的地址必为RVA
32、64位的最大区别是NT_HEADERS后面是否跟数字64
NtHeaders除了signature签名还有file optional header两个成员,往下是section header signature里是四个字节的dword或long的PE00,即0x005040
VA是虚拟内存的绝对地址,RVA是相对虚拟地址 RVA+ImageBase = VA
PE头内部信息大多以RVA形式存在,因为PE文件被加载到内存空间的时候,每一次的绝对地址都是不一样的。32位WindowsOS中,各进程分配有4GB内存,即VA的值最多到FFFFFFFF
0-2^32-1 0-0xFFFFFFFF-1
0-2^64-1 0-0xFFFFFFFFFFFFFFFF-1但现在16进制还不使用前四个F。64位下的0是0xFFFF 0000 0000 0000,也就是只用到2^48-1
文件操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 #include <Windows.h> #include <iostream> #include <tchar.h> #include <winnt.h> #include <ImageHlp.h> using namespace std;void _tmain(){ _tsetlocale(LC_ALL, _T("Chinese-simplified" )); char * VirtualAddress = NULL ; DWORD FileSizeLow = 0 ; DWORD FileSizeHigh = 0 ; DWORD NumberOfBytesRead = 0 ; PIMAGE_DOS_HEADER ImageDosHeader = NULL ; PIMAGE_NT_HEADERS ImageNtHeaders = NULL ; PIMAGE_FILE_HEADER ImageFileHeader = NULL ; PIMAGE_OPTIONAL_HEADER32 ImageOptionalHeader32 = NULL ; PIMAGE_OPTIONAL_HEADER64 ImageOptionalHeader64 = NULL ; PIMAGE_DATA_DIRECTORY ImageDataDirectory = NULL ; PIMAGE_SECTION_HEADER ImageSectionHeader = NULL ; WORD Characteristics = 0 ; _tprintf(_T("%p\r\n" ), sizeof (IMAGE_NT_HEADERS)); TCHAR v2[] = _T("CFF Explorer.exe" ); TCHAR v1[] = _T("avfilter-6.dll" ); TCHAR v3[] = _T("hidden.sys" ); TCHAR v4[] = _T("PE文件格式.exe" ); HANDLE FileHandle = CreateFile (v1, GENERIC_READ, FILE_SHARE_READ, NULL , OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (FileHandle == INVALID_HANDLE_VALUE) { goto Exit; } FileSizeLow = GetFileSize (FileHandle, &FileSizeHigh); if (FileSizeLow == 0 ) { goto Exit; } VirtualAddress = new char [FileSizeLow]; if (VirtualAddress == NULL ) { goto Exit; } if (ReadFile (FileHandle, VirtualAddress, FileSizeLow, &NumberOfBytesRead, NULL ) == FALSE) { goto Exit; } ImageDosHeader = (PIMAGE_DOS_HEADER)VirtualAddress; if (ImageDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { goto Exit; } ImageNtHeaders = (PIMAGE_NT_HEADERS)(VirtualAddress + (ImageDosHeader->e_lfanew)); if (ImageNtHeaders->Signature != IMAGE_NT_SIGNATURE) { goto Exit; } ImageFileHeader = &(ImageNtHeaders->FileHeader); if (ImageFileHeader == NULL ) { goto Exit; } switch (ImageFileHeader->Machine) { case IMAGE_FILE_MACHINE_I386: { _tprintf(_T("x86Pe文件\r\n" )); break ; } case IMAGE_FILE_MACHINE_IA64: { _tprintf(_T("Intelx64Pe文件\r\n" )); break ; } case IMAGE_FILE_MACHINE_AMD64: { _tprintf(_T("Amdx64Pe文件\r\n" )); break ; } default : { goto Exit; } } _tprintf(_T("NumberOfSections:%d\r\n" ), ImageFileHeader->NumberOfSections); _tprintf(_T("SizeOfOptionalHeader:%p\r\n" ), ImageFileHeader->SizeOfOptionalHeader); if (ImageFileHeader->Machine == IMAGE_FILE_MACHINE_I386) { if (ImageFileHeader->SizeOfOptionalHeader != sizeof (IMAGE_OPTIONAL_HEADER32)) { goto Exit; } ImageOptionalHeader32 = (PIMAGE_OPTIONAL_HEADER32)&(ImageNtHeaders->OptionalHeader); } else if (ImageFileHeader->Machine == IMAGE_FILE_MACHINE_IA64 || ImageFileHeader->Machine == IMAGE_FILE_MACHINE_AMD64) { if (ImageFileHeader->SizeOfOptionalHeader != sizeof (IMAGE_OPTIONAL_HEADER64)) { goto Exit; } ImageOptionalHeader64 = (PIMAGE_OPTIONAL_HEADER64)&(ImageNtHeaders->OptionalHeader); } else { goto Exit; } if (ImageFileHeader->Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) { _tprintf(_T("ExecutableImage文件\r\n" )); } if (ImageFileHeader->Characteristics & IMAGE_FILE_SYSTEM) { _tprintf(_T("System文件\r\n" )); } if (ImageFileHeader->Characteristics & IMAGE_FILE_DLL) { _tprintf(_T("Dll文件\r\n" )); } if (ImageOptionalHeader32 != NULL ) { if (ImageOptionalHeader32->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) { goto Exit; } _tprintf(_T("程序最先执行的代码起始位置的RVA%p\r\n" ), ImageOptionalHeader32->AddressOfEntryPoint); _tprintf(_T("优先装载地址%p\r\n" ), ImageOptionalHeader32->ImageBase); _tprintf(_T("文件对齐粒度%p\r\n" ), ImageOptionalHeader32->FileAlignment); _tprintf(_T("内存对齐粒度%p\r\n" ), ImageOptionalHeader32->SectionAlignment); _tprintf(_T("镜像大小%p\r\n" ), ImageOptionalHeader32->SizeOfImage); _tprintf(_T("所有头部大小%p\r\n" ), ImageOptionalHeader32->SizeOfHeaders); _tprintf(_T("子系统%p\r\n" ), ImageOptionalHeader32->Subsystem); ImageDataDirectory = &(ImageOptionalHeader32->DataDirectory[0 ]); for (int i = 0 ;i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES;i++) { _tprintf(_T("%d VirtualAddress:%p\r\n" ),i, ImageDataDirectory->VirtualAddress); _tprintf(_T("%d ViewSize:%p\r\n" ), i,ImageDataDirectory->Size); ImageDataDirectory++; } } if (ImageOptionalHeader64 != NULL ) { if (ImageOptionalHeader32->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) { goto Exit; } _tprintf(_T("程序最先执行的代码起始位置的:RVA%p\r\n" ), ImageOptionalHeader32->AddressOfEntryPoint); _tprintf(_T("优先装载地址%p\r\n" ), ImageOptionalHeader32->ImageBase); _tprintf(_T("文件对齐粒度%p\r\n" ), ImageOptionalHeader32->FileAlignment); _tprintf(_T("内存对齐粒度%p\r\n" ), ImageOptionalHeader32->SectionAlignment); _tprintf(_T("镜像大小%p\r\n" ), ImageOptionalHeader32->SizeOfImage); _tprintf(_T("所有头部大小%p\r\n" ), ImageOptionalHeader32->SizeOfHeaders); _tprintf(_T("子系统%p\r\n" ), ImageOptionalHeader32->Subsystem); ImageDataDirectory = &(ImageOptionalHeader32->DataDirectory[0 ]); for (int i = 0 ; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++) { _tprintf(_T("%d VirtualAddress:%p\r\n" ), i, ImageDataDirectory->VirtualAddress); _tprintf(_T("%d ViewSize:%p\r\n" ), i, ImageDataDirectory->Size); ImageDataDirectory++; } } ImageSectionHeader = IMAGE_FIRST_SECTION (ImageNtHeaders); for (int i = 0 ; i < ImageFileHeader->NumberOfSections; i++) { printf ("%s\r\n" , ImageSectionHeader->Name); _tprintf(_T("节区大小(真实大小)%p\r\n" ), ImageSectionHeader->Misc.VirtualSize); _tprintf(_T("节区起始位置(内存粒度RVA)%p\r\n" ), ImageSectionHeader->VirtualAddress); _tprintf(_T("节区大小(文件粒度)%p\r\n" ), ImageSectionHeader->SizeOfRawData); _tprintf(_T("节区起始位置(文件粒度)%p\r\n" ), ImageSectionHeader->PointerToRawData); _tprintf(_T("节区属性%p\r\n" ), ImageSectionHeader->Characteristics); ImageSectionHeader++; } Exit: if (VirtualAddress != NULL ) { delete VirtualAddress; VirtualAddress = NULL ; } if (FileHandle != INVALID_HANDLE_VALUE) { CloseHandle (FileHandle); FileHandle = INVALID_HANDLE_VALUE; } return ; } DWORD rva_to_offset (IMAGE_NT_HEADERS* ImageNtHeaders, DWORD Rva) { DWORD Offset = 0 ; DWORD Limit; IMAGE_SECTION_HEADER* ImageSectionHeader = NULL ; WORD i; ImageSectionHeader = IMAGE_FIRST_SECTION (ImageNtHeaders); if (Rva < ImageSectionHeader->PointerToRawData) return Rva; for (i = 0 ; i < ImageNtHeaders->FileHeader.NumberOfSections; i++) { if (ImageSectionHeader[i].SizeOfRawData) Limit = ImageSectionHeader[i].SizeOfRawData; else Limit = ImageSectionHeader[i].Misc.VirtualSize; if (Rva >= ImageSectionHeader[i].VirtualAddress && Rva < (ImageSectionHeader[i].VirtualAddress + Limit)) { if (ImageSectionHeader[i].PointerToRawData != 0 ) { Offset = Rva - ImageSectionHeader[i].VirtualAddress; Offset += ImageSectionHeader[i].PointerToRawData; } return Offset; } } return 0 ; }
文件头成员
mechine 可以判断位数。IMAGE_FILE_MACHINE_I386, IMAGE_FILE_MACHINE_IA64, IMAGE_FILE_MACHINE_AMD64。
因此32位文件,必须在文件头中的sizeofoptional成员,等于32位的结构体。
可以通过判断characteristics的值,判断该文件的具体属性,0x2(IMAGE_FILE_EXECUTABLE_IMAGE)是exe,0x2000(IMAGE_FILE_DLL)是dll,0x1000(IMAGE_FILE_SYSTEM)是sys。文件可能有多属性,判断时用与运算。这个数字可能有多个属性组成,随便写一个按f12进去看定义可以寻找
32和64位的区别就在于选项头ImageOptionalHeader。
OEP,程序执行的代码起始地址,是一个RVA,加上基地址ImageBase是程序的执行入口
ImageBase是一个绝对地址VA,预设加载值,当PE文件真正开始执行时,就优先放到ImageBase,否则就向下顺延。
读取文件到内存里,节区对齐力度是按百对齐 ImageOptionalHeader->FileAlignment==200,节区在磁盘文件中的最小单位
PE加载器加载、exe加载dll文件等,驱使PE文件变为运行状态,节区对齐粒度是按千对齐,ImageOpetionalHeader->SectionAlignment==1000 节区在内存中的最小单位
所有在PE文件中定义成RVA的成员,都必须以内存力度(按千)对齐结构为基础进行VA值得获取
Subsystem可以判断文件类型。0是unknown gui文件有define为IMAGE_SUBSYSTEM_WINDOWS_GUI,按f12进入看其他的
NumberOfRvaAndSizes一般是16,但也有可能不是
有#define IMAGE_NUMBER_DIRECTOY_NUMS 16
重点:
DataDirectory 设计16成员组成的数组,每个结构体内有两个成员:VirtualAddress(RVA), ViewSize(Size),0-15
在NtHeaders内有一个Signature成员,使用Signature+OptionalHeaders(选项头之前的大小)+SizeOfOptionalHeaders(选项头自身的大小)就可以定位到SectionHeaders(IMAGE_FIRST_SECTION(ImageNtHeaders);)
微软自带的计算偏移的宏FIELD_OFFSET(type, v1);返回值为long型,可以得到v1在type类型中的偏移。
ImageFileHeader中有一个成员是NumberOfSections,代表有多少个节。ImageSectionHeader的Name成员是节的名字,由8个字节构成,如.text
节区头中的重要成员,分别是真实大小(没有填充过的),内存粒度,文件粒度,文件粒度
节头中有个联合体misc,其中virtualSize是真实节大小
VirtualAddress RVA 按千对齐 节的起始位置
SizeOfRawData 节的大小,按200对齐
PointerToRawData 磁盘上节的开始位置,按200对齐
VA绝对地址 RVA相对地址
RVA+ImageBase = VA
内存粒度RVA计算文件粒度公式
如果传入的rva比第一个ImageSectionHeader的pointer to raw data还要小,说明这是一个头部的rva,两边一样,直接返回。否则开始扫描传入的rva属于第几个节。如果size of raw data有值,则把它放进limit变量中(按文件粒度对齐后的节大小),若没有就放入virtual size。如果rva在section header中的virtual address与virtual address+limit之间,则就是在这个区域中。
rva-VirtualAddress+PointToRawData=offset
IAT 导入表
导入函数的汇编,32位下是绝对地址,64位下是相对地址,当前地址加偏移加字节数(6)。所有API的调用均采用这种方式。
动态库的基地址在不同的区域中,不一定在同一个地方
编译生成exe的时候,系统就会生成一个ImageBase,32位下一般是0x400000,dll一般是0x1000000
exe文件有导入表IAT,一般在txt节中。在DataDirectory的16成员中,第二成员指向导入表的位置。即定位到
IMAGE_IMPORT_DESCRIPTOR 导入表描述
结构体中的Name是单字string,存放的是RVA。RVA在32、64下都是四个字节。通过转化为文件粒度,加上VirtualAddress可以定位到导入库的名字。需要强转为char*
OriginalFirstThunk INT库的地址,RVA 每次都要判断所指向的任意内容是否为空,如ul.AddressOfData。转化为offset,加上VirtualAddress,定位到新的结构体,函数名字导入。指向的结构为IMAGE_THUNK_DATA有64位和32位之分,且是一个联合体ul,64位8字节32位4字节。需要强转为DWORD。如果判断为不是名字,则是索引导入。直接用这个值转化为IMAGE_ORDINAL。文件状态下的文件粒度对齐
FirstThunk IAT的地址,RVA 每次都要判断所指向的任意内容是否为空。进入运行状态时其中内容已经更新为地址。运行状态下内存粒度对齐。通过修改FirstThunk中的内容,可以进行IAT注入。
INT与IAT是联合体,32位下是四个字节,64位下是8个字节。
导出表
存在dll中,只有一个
导出表目录 PIMAGE_EXPORT_DIRECTORY 像导入表目录一样定位
有索引、函数名导出两种方式
重定向表 relocation
exe文件加载时,image base默认地址为0x400000,此时代码地址都不需要变化。但如果image base地址不是默认值,就需要重新修复,这就需要把默认情况下地址都存放在重定向表中。
进行修复时,使用真实值-0x400000,加上默认情况下的值
主要针对绝对寻址的,如全局变量、静态变量、自己定义的函数
重定向表不止一张。virtualaddress需要进行rva to offset转换
获取目标进程的dll模块的方法
CreatetoolHelp32Snapshot
GetMoudelHandle、Loadlibary
psapi EnumHandle
PEB NtWow64QueryInformationProcess64获取PROCESS_BASIC_INFORMATION64(32) pbi,NtWow64ReadVirtualMemory64(32位用 ReadProcessMemory)获取(PVOID64)pbi.PebBaseAddress。遍历PEB中的_PEB_LDR_DATA
双向链表,其中_LDR_DATA_TABLE_ENTRY.dllbase
PsGetProcessPeb(EPROCESS)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 #include "stdafx.h" #include <iostream> #include <windows.h> #include <subauth.h> #pragma region 依赖 #define NT_SUCCESS(x) ((x) >= 0) #define ProcessBasicInformation 0 typedef NTSTATUS (WINAPI *pfnNtWow64QueryInformationProcess64) (HANDLE ProcessHandle, UINT32 ProcessInformationClass, PVOID ProcessInformation, UINT32 ProcessInformationLength, UINT32* ReturnLength) ; typedef NTSTATUS (WINAPI *pfnNtWow64ReadVirtualMemory64) (HANDLE ProcessHandle, PVOID64 BaseAddress, PVOID BufferData, UINT64 BufferLength, PUINT64 ReturnLength) ; typedef NTSTATUS (WINAPI *pfnNtQueryInformationProcess) (HANDLE ProcessHandle, ULONG ProcessInformationClass, PVOID ProcessInformation, UINT32 ProcessInformationLength, UINT32* ReturnLength) ; template <typename T>struct _UNICODE_STRING_T { WORD Length; WORD MaximumLength; T Buffer; }; template <typename T>struct _LIST_ENTRY_T { T Flink; T Blink; }; template <typename T, typename NGF, int A>struct _PEB_T { typedef T type; union { struct { BYTE InheritedAddressSpace; BYTE ReadImageFileExecOptions; BYTE BeingDebugged; BYTE BitField; }; T dummy01; }; T Mutant; T ImageBaseAddress; T Ldr; T ProcessParameters; T SubSystemData; T ProcessHeap; T FastPebLock; T AtlThunkSListPtr; T IFEOKey; T CrossProcessFlags; T UserSharedInfoPtr; DWORD SystemReserved; DWORD AtlThunkSListPtr32; T ApiSetMap; T TlsExpansionCounter; T TlsBitmap; DWORD TlsBitmapBits[2 ]; T ReadOnlySharedMemoryBase; T HotpatchInformation; T ReadOnlyStaticServerData; T AnsiCodePageData; T OemCodePageData; T UnicodeCaseTableData; DWORD NumberOfProcessors; union { DWORD NtGlobalFlag; NGF dummy02; }; LARGE_INTEGER CriticalSectionTimeout; T HeapSegmentReserve; T HeapSegmentCommit; T HeapDeCommitTotalFreeThreshold; T HeapDeCommitFreeBlockThreshold; DWORD NumberOfHeaps; DWORD MaximumNumberOfHeaps; T ProcessHeaps; T GdiSharedHandleTable; T ProcessStarterHelper; T GdiDCAttributeList; T LoaderLock; DWORD OSMajorVersion; DWORD OSMinorVersion; WORD OSBuildNumber; WORD OSCSDVersion; DWORD OSPlatformId; DWORD ImageSubsystem; DWORD ImageSubsystemMajorVersion; T ImageSubsystemMinorVersion; T ActiveProcessAffinityMask; T GdiHandleBuffer[A]; T PostProcessInitRoutine; T TlsExpansionBitmap; DWORD TlsExpansionBitmapBits[32 ]; T SessionId; ULARGE_INTEGER AppCompatFlags; ULARGE_INTEGER AppCompatFlagsUser; T pShimData; T AppCompatInfo; _UNICODE_STRING_T<T> CSDVersion; T ActivationContextData; T ProcessAssemblyStorageMap; T SystemDefaultActivationContextData; T SystemAssemblyStorageMap; T MinimumStackCommit; T FlsCallback; _LIST_ENTRY_T<T> FlsListHead; T FlsBitmap; DWORD FlsBitmapBits[4 ]; T FlsHighIndex; T WerRegistrationData; T WerShipAssertPtr; T pContextData; T pImageHeaderHash; T TracingFlags; T CsrServerReadOnlySharedMemoryBase; }; typedef _PEB_T<DWORD, DWORD64, 34 > _PEB32;typedef _PEB_T<DWORD64, DWORD, 30 > _PEB64; typedef struct _STRING_32 { WORD Length; WORD MaximumLength; UINT32 Buffer; } STRING32, *PSTRING32; typedef struct _STRING_64 { WORD Length; WORD MaximumLength; UINT64 Buffer; } STRING64, *PSTRING64; typedef struct _RTL_DRIVE_LETTER_CURDIR_32 { WORD Flags; WORD Length; ULONG TimeStamp; STRING32 DosPath; } RTL_DRIVE_LETTER_CURDIR32, *PRTL_DRIVE_LETTER_CURDIR32; typedef struct _RTL_DRIVE_LETTER_CURDIR_64 { WORD Flags; WORD Length; ULONG TimeStamp; STRING64 DosPath; } RTL_DRIVE_LETTER_CURDIR64, *PRTL_DRIVE_LETTER_CURDIR64; typedef struct _UNICODE_STRING_32 { WORD Length; WORD MaximumLength; UINT32 Buffer; } UNICODE_STRING32, *PUNICODE_STRING32; typedef struct _UNICODE_STRING_64 { WORD Length; WORD MaximumLength; UINT64 Buffer; } UNICODE_STRING64, *PUNICODE_STRING64; typedef struct _CURDIR_32 { UNICODE_STRING32 DosPath; UINT32 Handle; } CURDIR32, *PCURDIR32; typedef struct _RTL_USER_PROCESS_PARAMETERS_32 { ULONG MaximumLength; ULONG Length; ULONG Flags; ULONG DebugFlags; UINT32 ConsoleHandle; ULONG ConsoleFlags; UINT32 StandardInput; UINT32 StandardOutput; UINT32 StandardError; CURDIR32 CurrentDirectory; UNICODE_STRING32 DllPath; UNICODE_STRING32 ImagePathName; UNICODE_STRING32 CommandLine; UINT32 Environment; ULONG StartingX; ULONG StartingY; ULONG CountX; ULONG CountY; ULONG CountCharsX; ULONG CountCharsY; ULONG FillAttribute; ULONG WindowFlags; ULONG ShowWindowFlags; UNICODE_STRING32 WindowTitle; UNICODE_STRING32 DesktopInfo; UNICODE_STRING32 ShellInfo; UNICODE_STRING32 RuntimeData; RTL_DRIVE_LETTER_CURDIR32 CurrentDirectores[32 ]; ULONG EnvironmentSize; } RTL_USER_PROCESS_PARAMETERS32, *PRTL_USER_PROCESS_PARAMETERS32; typedef struct _CURDIR_64 { UNICODE_STRING64 DosPath; UINT64 Handle; } CURDIR64, *PCURDIR64; typedef struct _RTL_USER_PROCESS_PARAMETERS_64 { ULONG MaximumLength; ULONG Length; ULONG Flags; ULONG DebugFlags; UINT64 ConsoleHandle; ULONG ConsoleFlags; UINT64 StandardInput; UINT64 StandardOutput; UINT64 StandardError; CURDIR64 CurrentDirectory; UNICODE_STRING64 DllPath; UNICODE_STRING64 ImagePathName; UNICODE_STRING64 CommandLine; UINT64 Environment; ULONG StartingX; ULONG StartingY; ULONG CountX; ULONG CountY; ULONG CountCharsX; ULONG CountCharsY; ULONG FillAttribute; ULONG WindowFlags; ULONG ShowWindowFlags; UNICODE_STRING64 WindowTitle; UNICODE_STRING64 DesktopInfo; UNICODE_STRING64 ShellInfo; UNICODE_STRING64 RuntimeData; RTL_DRIVE_LETTER_CURDIR64 CurrentDirectores[32 ]; ULONG EnvironmentSize; } RTL_USER_PROCESS_PARAMETERS64, *PRTL_USER_PROCESS_PARAMETERS64; typedef struct _PROCESS_BASIC_INFORMATION64 { NTSTATUS ExitStatus; UINT32 Reserved0; UINT64 PebBaseAddress; UINT64 AffinityMask; UINT32 BasePriority; UINT32 Reserved1; UINT64 UniqueProcessId; UINT64 InheritedFromUniqueProcessId; } PROCESS_BASIC_INFORMATION64; typedef struct _PROCESS_BASIC_INFORMATION32 { NTSTATUS ExitStatus; UINT32 PebBaseAddress; UINT32 AffinityMask; UINT32 BasePriority; UINT32 UniqueProcessId; UINT32 InheritedFromUniqueProcessId; } PROCESS_BASIC_INFORMATION32; #pragma endregion int _tmain(int argc, _TCHAR* argv[]){ HANDLE m_ProcessHandle = OpenProcess ( PROCESS_ALL_ACCESS, FALSE, 8016 ); BOOL bSource = FALSE; BOOL bTarget = FALSE; IsWow64Process ( GetCurrentProcess (), &bSource ); IsWow64Process ( m_ProcessHandle, &bTarget ); if (bTarget == FALSE && bSource == TRUE) { HMODULE NtdllModule = GetModuleHandle ("ntdll.dll" ); pfnNtWow64QueryInformationProcess64 NtWow64QueryInformationProcess64 = (pfnNtWow64QueryInformationProcess64)GetProcAddress (NtdllModule,"NtWow64QueryInformationProcess64" ); pfnNtWow64ReadVirtualMemory64 NtWow64ReadVirtualMemory64 = (pfnNtWow64ReadVirtualMemory64)GetProcAddress (NtdllModule,"NtWow64ReadVirtualMemory64" ); PROCESS_BASIC_INFORMATION64 pbi = {0 }; UINT64 ReturnLength = 0 ; NTSTATUS Status = NtWow64QueryInformationProcess64 (m_ProcessHandle,ProcessBasicInformation,&pbi,(UINT32)sizeof (pbi),(UINT32*)&ReturnLength); if (NT_SUCCESS (Status)){ _PEB64* Peb = (_PEB64*)malloc (sizeof (_PEB64)); RTL_USER_PROCESS_PARAMETERS64* ProcessParameters = (RTL_USER_PROCESS_PARAMETERS64*)malloc (sizeof (RTL_USER_PROCESS_PARAMETERS64)); Status = NtWow64ReadVirtualMemory64 (m_ProcessHandle,(PVOID64)pbi.PebBaseAddress,(_PEB64*)Peb,sizeof (_PEB64),&ReturnLength); std::cout << "PEB地址:" << std::hex << pbi.PebBaseAddress << std::endl; } } else if (bTarget == TRUE && bSource == TRUE) { HMODULE NtdllModule = GetModuleHandle ("ntdll.dll" ); pfnNtQueryInformationProcess NtQueryInformationProcess = (pfnNtQueryInformationProcess)GetProcAddress (NtdllModule,"NtQueryInformationProcess" ); PROCESS_BASIC_INFORMATION32 pbi = {0 }; UINT32 ReturnLength = 0 ; NTSTATUS Status = NtQueryInformationProcess (m_ProcessHandle,ProcessBasicInformation,&pbi,(UINT32)sizeof (pbi),(UINT32*)&ReturnLength); if (NT_SUCCESS (Status)){ _PEB32* Peb = (_PEB32*)malloc (sizeof (_PEB32)); ReadProcessMemory (m_ProcessHandle, (PVOID)pbi.PebBaseAddress,(_PEB32*)Peb,sizeof (_PEB32),NULL ); std::cout << "PEB地址:" << std::hex << pbi.PebBaseAddress << std::endl; } } getchar (); return 0 ; }