如何使用 C++ 获取有关 Windows 可执行文件 (.exe) 的信息
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2789017/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to get information about a Windows executable (.exe) using C++
提问by ereOn
I have to create a software that will scan several directories and extracts information about the executables found.
我必须创建一个软件来扫描多个目录并提取有关找到的可执行文件的信息。
I need to do two things:
我需要做两件事:
- Determine if a given file is an executable (
.exe
,.dll
, and so on) - Checking the extension is probably not good enough. - Get the information about this executable (the company name, the product name, and so on).
- 确定给定文件是否是可执行文件(
.exe
、.dll
等) - 检查扩展名可能不够好。 - 获取有关此可执行文件的信息(公司名称、产品名称等)。
I never did this before and thus am not aware if there is a Windows API (or lightweight C/C++ library) to do that or if it is even possible. I guess it is, because explorer.exe
does it.
我以前从未这样做过,因此不知道是否有 Windows API(或轻量级 C/C++ 库)可以做到这一点,或者是否有可能。我想是的,因为explorer.exe
确实如此。
Do you guys know anything that could point me in the right direction ?
你们知道什么可以指出我正确的方向吗?
Thank you very much for your help.
非常感谢您的帮助。
回答by Jerry Coffin
You can verify as much of the PE File Formatas you want. If you want to, you can also check for a PE file signature. You can then use the File Version APIto retrieve the company name, product name, version numbers, etc.
您可以根据需要验证尽可能多的PE 文件格式。如果需要,您还可以检查PE 文件签名。然后,您可以使用文件版本 API来检索公司名称、产品名称、版本号等。
回答by Vineel Kumar Reddy
Check this code and modify according to ur needs....
检查此代码并根据您的需要进行修改....
/*
Program to dump the PE,DOS headers and Hex Dump of particular section
Sat 03/24/2007
by
K.Vineel Kumar Reddy
In VC++ 6.0
ref : http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
tools used : Hiew
BRIEF VIEW OF PE FILE
.----------------------.
| |
| Other stuff not |
| touched in this |
| program |
| |
|----------------------|
| |
| Various Section like |
| ..... |
| ..... |
.------>| .reloc |
| .---->| .idata |
| | .-->| .data |
| | | .>| .text |
| | | | |----------------------|
'-|-|-|-| | <--- Each entry in section table have pointer
'-|-|-| Section | offsets to actual sections
'-|-| Header or Table |
'-| | ---.----------------.
|----------------------|-----/ | PE Optional | 1) ImageBase
| | | Header |
| | | |
| NT Headers | |----------------|
| | | COFF/PE | 1) NumberOfSections
| | | Header Info | 2) SizeOfOptionalHeader
|----------------------|----- |----------------|
| UNUSED | \ | PE Signature |
|----------------------| ---'----------------'
| MS-DOS stub |
|----------------------|
| UNUSED |
|----------------------|
| MS-DOS Header | <-- Here at 0x3c location we have the offset of NT Header
'----------------------'
Structres related to these exe headers
--------------------------------------
1) MS-DOS Header ---> IMAGE_DOS_HEADER
2) NT Header ---> IMAGE_NT_HEADERS --->contain
--->IMAGE_FILE_HEADER dealing with COFF/PE Header
--->IMAGE_OPTIONAL_HEADER dealing with Optional PE Header
3) Section Table ---> IMAGE_SECTION_HEADER
Key Points
----------
dosHeader = Memory mapped base address
ntHeader = (IMAGE_NT_HEADER)((DWORD)dosHeader + dosHeader->e_lfanew)
sectionHeader = (IMAGE_SECTION_HEADER)((DWORD)ntHeader + OFFSET(OptionalHeader) + sizeof(OptionalHeader))
each section = (char *)((DWORD)dosHeader + sectionHeader.PointerToRawData)
ASCII ART by
Vineel :)
*/
#include<stdio.h>
#include<windows.h>
#include<time.h>
#include<tchar.h>
void Help()
{
printf("\nUsage \ntest <path to exe file> [ -h <section> ]\n");
}
void HexDump(char * p ,int size,int secAddress)
{
int i=1,temp=0;
wchar_t buf[18]; //Buffer to store the character dump displayed at the right side
printf("\n\n%x: |",secAddress);
buf[temp] = ' ' ; //initial space
buf[temp+16] = ' ' ; //final space
buf[temp+17] = 0 ; //End of buf
temp++; //temp = 1;
for( ; i <= size ; i++, p++,temp++)
{
buf[temp] = !iswcntrl((*p)&0xff)? (*p)&0xff :'.';
printf("%-3.2x",(*p)&0xff );
if(i%16 == 0){ //print the chracter dump to the right
_putws(buf);
if(i+1<=size)printf("%x: ",secAddress+=16);
temp=0;
}
if(i%4==0)printf("|");
}
if(i%16!=0){
buf[temp]=0;
for(;i%16!=0;i++)
printf("%-3.2c",' ');
_putws(buf);
}
}
main(int argc , char ** argv){
int i=0;
HANDLE hMapObject,hFile; //File Mapping Object
LPVOID lpBase; //Pointer to the base memory of mapped file
PIMAGE_DOS_HEADER dosHeader; //Pointer to DOS Header
PIMAGE_NT_HEADERS ntHeader; //Pointer to NT Header
IMAGE_FILE_HEADER header; //Pointer to image file header of NT Header
IMAGE_OPTIONAL_HEADER opHeader; //Optional Header of PE files present in NT Header structure
PIMAGE_SECTION_HEADER pSecHeader; //Section Header or Section Table Header
if(argc>1){
//Open the Exe File
hFile = CreateFile(argv[1],GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile == INVALID_HANDLE_VALUE){printf("\nERROR : Could not open the file specified\n"); goto info;};
//Mapping Given EXE file to Memory
hMapObject = CreateFileMapping(hFile,NULL,PAGE_READONLY,0,0,NULL);
lpBase = MapViewOfFile(hMapObject,FILE_MAP_READ,0,0,0);
//Get the DOS Header Base
dosHeader = (PIMAGE_DOS_HEADER)lpBase;// 0x04000000
//Check for Valid DOS file
if(dosHeader->e_magic == IMAGE_DOS_SIGNATURE){
//Dump the Dos Header info
printf("\nValid Dos Exe File\n------------------\n");
printf("\nDumping DOS Header Info....\n---------------------------");
printf("\n%-36s%s ","Magic number : ",dosHeader->e_magic==0x5a4d?"MZ(Mark Zbikowski)":"-");
printf("\n%-36s%#x","Bytes on last page of file :",dosHeader->e_cblp);
printf("\n%-36s%#x","Pages in file : ",dosHeader->e_cp);
printf("\n%-36s%#x","Relocation : ",dosHeader->e_crlc);
printf("\n%-36s%#x","Size of header in paragraphs : ",dosHeader->e_cparhdr);
printf("\n%-36s%#x","Minimum extra paragraphs needed : ",dosHeader->e_minalloc);
printf("\n%-36s%#x","Maximum extra paragraphs needed : ",dosHeader->e_maxalloc);
printf("\n%-36s%#x","Initial (relative) SS value : ",dosHeader->e_ss);
printf("\n%-36s%#x","Initial SP value : ",dosHeader->e_sp);
printf("\n%-36s%#x","Checksum : ",dosHeader->e_csum);
printf("\n%-36s%#x","Initial IP value : ",dosHeader->e_ip);
printf("\n%-36s%#x","Initial (relative) CS value : ",dosHeader->e_cs);
printf("\n%-36s%#x","File address of relocation table : ",dosHeader->e_lfarlc);
printf("\n%-36s%#x","Overlay number : ",dosHeader->e_ovno);
printf("\n%-36s%#x","OEM identifier : ",dosHeader->e_oemid);
printf("\n%-36s%#x","OEM information(e_oemid specific) :",dosHeader->e_oeminfo);
printf("\n%-36s%#x","RVA address of PE header : ",dosHeader->e_lfanew);
printf("\n===============================================================================\n");
}
else {
printf("\nGiven File is not a valid DOS file\n");
goto end;
}
//Offset of NT Header is found at 0x3c location in DOS header specified by e_lfanew
//Get the Base of NT Header(PE Header) = dosHeader + RVA address of PE header
ntHeader = (PIMAGE_NT_HEADERS)((DWORD)(dosHeader) + (dosHeader->e_lfanew));
//Identify for valid PE file
if(ntHeader->Signature == IMAGE_NT_SIGNATURE){
printf("\nValid PE file \n-------------\n");
//Dump NT Header Info....
printf("\nDumping COFF/PE Header Info....\n--------------------------------");
printf("\n%-36s%s","Signature :","PE");
//Get the IMAGE FILE HEADER Structure
header = ntHeader->FileHeader;
//Determine Machine Architechture
printf("\n%-36s","Machine Architechture :");
switch(header.Machine){ //Only few are determined (for remaining refer to the above specification)
case 0x0: printf("All "); break;
case 0x14d: printf("Intel i860"); break;
case 0x14c: printf("Intel i386,i486,i586"); break;
case 0x200: printf("Intel Itanium processor"); break;
case 0x8664: printf("AMD x64"); break;
case 0x162: printf("MIPS R3000"); break;
case 0x166: printf("MIPS R4000"); break;
case 0x183: printf("DEC Alpha AXP"); break;
default: printf("Not Found"); break;
}
//Determine the characteristics of the given file
printf("\n%-36s","Characteristics : ");
if((header.Characteristics&0x0002) == 0x0002) printf("Executable Image ,");
if((header.Characteristics&0x0020) == 0x0020) printf("Application can address > 2GB ,");
if((header.Characteristics&0x1000) == 0x1000) printf("System file (Kernel Mode Driver(I think)) ,");
if((header.Characteristics&0x2000) == 0x2000) printf("Dll file ,");
if((header.Characteristics&0x4000) == 0x4000) printf("Application runs only in Uniprocessor ,");
printf("\n%-36s%s","Time Stamp :",ctime(&(header.TimeDateStamp))); //Determine Time Stamp
printf("%-36s%d","No.sections(size) :",header.NumberOfSections); //Determine number of sections
printf("\n%-36s%d","No.entries in symbol table :",header.NumberOfSymbols);
printf("\n%-36s%d","Size of optional header :",header.SizeOfOptionalHeader);
printf("\n\nDumping PE Optional Header Info....\n-----------------------------------");
//Info about Optional Header
opHeader = ntHeader->OptionalHeader;
//printf("\n\nInfo of optional Header\n-----------------------");
printf("\n%-36s%#x","Address of Entry Point : ",opHeader.AddressOfEntryPoint);
printf("\n%-36s%#x","Base Address of the Image : ",opHeader.ImageBase);
printf("\n%-36s%s","SubSystem type : ",
opHeader.Subsystem==1?"Device Driver(Native windows Process)":
opHeader.Subsystem==2?"Windows GUI":
opHeader.Subsystem==3?"Windows CLI":
opHeader.Subsystem==9?"Windows CE GUI":
"Unknown"
);
printf("\n%-36s%s","Given file is a : ",opHeader.Magic==0x20b?"PE32+(64)":"PE32");
printf("\n%-36s%d","Size of code segment(.text) : ",opHeader.SizeOfCode);
printf("\n%-36s%#x","Base address of code segment(RVA) :",opHeader.BaseOfCode);
printf("\n%-36s%d","Size of Initialized data : ",opHeader.SizeOfInitializedData);
printf("\n%-36s%#x","Base address of data segment(RVA) :",opHeader.BaseOfData);
printf("\n%-36s%#x","Section Alignment :",opHeader.SectionAlignment);
printf("\n%-36s%d","Major Linker Version : ",opHeader.MajorLinkerVersion);
printf("\n%-36s%d","Minor Linker Version : ",opHeader.MinorLinkerVersion);
printf("\n\nDumping Sections Header Info....\n--------------------------------");
//Retrive a pointer to First Section Header(or Section Table Entry)
for(pSecHeader = IMAGE_FIRST_SECTION(ntHeader),i=0;i<ntHeader->FileHeader.NumberOfSections;i++,pSecHeader++){
printf("\n\nSection Info (%d of %d)",i+1,ntHeader->FileHeader.NumberOfSections);
printf("\n---------------------");
printf("\n%-36s%s","Section Header name : ", pSecHeader->Name);
printf("\n%-36s%#x","ActualSize of code or data : ", pSecHeader->Misc.VirtualSize);
printf("\n%-36s%#x","Virtual Address(RVA) :", pSecHeader->VirtualAddress);
printf("\n%-36s%#x","Size of raw data (rounded to FA) : ", pSecHeader->SizeOfRawData);
printf("\n%-36s%#x","Pointer to Raw Data : ", pSecHeader->PointerToRawData);
printf("\n%-36s%#x","Pointer to Relocations : ", pSecHeader->PointerToRelocations);
printf("\n%-36s%#x","Pointer to Line numbers : ", pSecHeader->PointerToLinenumbers);
printf("\n%-36s%#x","Number of relocations : ", pSecHeader->NumberOfRelocations);
printf("\n%-36s%#x","Number of line numbers : ", pSecHeader->NumberOfLinenumbers);
printf("\n%-36s%s","Characteristics : ","Contains ");
if((pSecHeader->Characteristics&0x20)==0x20)printf("executable code, ");
if((pSecHeader->Characteristics&0x40)==0x40)printf("initialized data, ");
if((pSecHeader->Characteristics&0x80)==0x80)printf("uninitialized data, ");
if((pSecHeader->Characteristics&0x80)==0x80)printf("uninitialized data, ");
if((pSecHeader->Characteristics&0x200)==0x200)printf("comments and linker commands, ");
if((pSecHeader->Characteristics&0x10000000)==0x10000000)printf("shareable data(via DLLs), ");
if((pSecHeader->Characteristics&0x40000000)==0x40000000)printf("Readable, ");
if((pSecHeader->Characteristics&0x80000000)==0x80000000)printf("Writable, ");
// If -h or /h option is given then provide HexDump
if(argc==4&& (!strcmpi(argv[2],"-h")||!strcmpi(argv[2],"/h"))){
if(!strcmpi(argv[3],pSecHeader->Name))
if(pSecHeader->SizeOfRawData!=0)
HexDump((char *)((DWORD)dosHeader + pSecHeader->PointerToRawData) , pSecHeader->SizeOfRawData , opHeader.ImageBase + pSecHeader->VirtualAddress);
}
}
printf("\n===============================================================================\n");
}
else goto end;
end:
//UnMaping
UnmapViewOfFile(lpBase);
CloseHandle(hMapObject);
}
else Help();
info:
printf("\
\
\
This Program is written by\
K.Vineel Kumar Reddy.\
III/IV IT\
Gayathri Vidya Parishad college of Eng.\
\
\
");
}
回答by Nick Meyer
You may find this CodeProject article which wraps the file version APIto be helpful for the second task. To check that a file is executable, you probably want to parse the PE headers.
您可能会发现这篇 CodeProject 文章包装了文件版本 API,这对第二个任务很有帮助。要检查文件是否可执行,您可能需要解析PE 标头。
回答by ChrisW
Not all executables are PE files: for example batch/command files are (in a sense) executable, as are DOS-format executables.
并非所有的可执行文件都是 PE 文件:例如批处理/命令文件(在某种意义上)是可执行的,DOS 格式的可执行文件也是如此。