我想在C中编写一个小程序来提取COFF可执行文件的PE(入口点)和VA(虚拟地址)。我怎么能这样做?
答案 0 :(得分:5)
/*
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.\
\
\
");
}
请检查以上程序..............
答案 1 :(得分:4)
您想要的两个字段都位于可选标题中(可选,因为它不会显示在目标文件中 - 它是图像中所必需的)。文件中的第一个字节是DOS存根,但在0x3c,您将找到PE签名的偏移量。去那里,你会发现PE签名(PE\0\0
)。紧接着是文件头,长度为0x14字节,之后是可选头。 AddressOfEntryPoint
是可选头中的0x10字节,跨越四个字节,BaseOfCode
紧跟在0x14(也是4个字节)之后。
简而言之:
(PE signature offset)+0x28
开始读取4个字节 - 这是AddressOfEntryPoint
(PE signature offset)+0x2c
开始读取4个字节 - 这是BaseOfCode
请务必在必要时处理字节序