/*
下文的代碼既可在linux亦可在windows下運行。
為什麼要保留這段代碼呢?
1.包含了最近一段時間對pe檔案格式的分析;
以後如果再需要用pe格式只要看看這段代碼就行了,容易上手。
2.pe檔案中rva到檔案位移量的轉換比較頭大;
這段代碼中有較好的函數實現。
此程式的功能是判斷一個檔案是否為.cpl檔案。cpl檔案其實就是dll,但是包含了一個特殊介面。
*/
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <string>
#include <vector>
using namespace std;
//下面的這些結構都是winnt.h中對pe檔案頭的定義
typedef struct _IMAGE_DATA_DIRECTORY {
unsigned long VirtualAddress;
unsigned long Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
typedef struct _IMAGE_FILE_HEADER {
unsigned short Machine;
unsigned short NumberOfSections;
unsigned long TimeDateStamp;
unsigned long PointerToSymbolTable;
unsigned long NumberOfSymbols;
unsigned short SizeOfOptionalHeader;
unsigned short Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
typedef struct _IMAGE_OPTIONAL_HEADER {
//
// Standard fields.
//
unsigned short Magic;
char MajorLinkerVersion;
char MinorLinkerVersion;
unsigned long SizeOfCode;
unsigned long SizeOfInitializedData;
unsigned long SizeOfUninitializedData;
unsigned long AddressOfEntryPoint;
unsigned long BaseOfCode;
unsigned long BaseOfData;
//
// NT additional fields.
//
unsigned long ImageBase;
unsigned long SectionAlignment;
unsigned long FileAlignment;
unsigned short MajorOperatingSystemVersion;
unsigned short MinorOperatingSystemVersion;
unsigned short MajorImageVersion;
unsigned short MinorImageVersion;
unsigned short MajorSubsystemVersion;
unsigned short MinorSubsystemVersion;
unsigned long Win32VersionValue;
unsigned long SizeOfImage;
unsigned long SizeOfHeaders;
unsigned long CheckSum;
unsigned short Subsystem;
unsigned short DllCharacteristics;
unsigned long SizeOfStackReserve;
unsigned long SizeOfStackCommit;
unsigned long SizeOfHeapReserve;
unsigned long SizeOfHeapCommit;
unsigned long LoaderFlags;
unsigned long NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[16];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
typedef struct _IMAGE_NT_HEADERS {
unsigned long Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS;
typedef struct _IMAGE_SECTION_HEADER {
char Name[8];
union {
unsigned long PhysicalAddress;
unsigned long VirtualSize;
} Misc;
unsigned long VirtualAddress;
unsigned long SizeOfRawData;
unsigned long PointerToRawData;
unsigned long PointerToRelocations;
unsigned long PointerToLinenumbers;
unsigned short NumberOfRelocations;
unsigned short NumberOfLinenumbers;
unsigned long Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
typedef IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS;
//這段代碼判斷rva在哪個section中
PIMAGE_SECTION_HEADER imagerva2section(PIMAGE_NT_HEADERS pimage_nt_headers,unsigned long dwRVA)
{
int i;
PIMAGE_SECTION_HEADER pimage_section_header=(PIMAGE_SECTION_HEADER)(((char *)(pimage_nt_headers)) + sizeof(IMAGE_NT_HEADERS));
for(i=0;i<pimage_nt_headers->FileHeader.NumberOfSections;i++) {
//pimage_section_header->VirtualAddress 是section的首地址
//pimage_section_header->SizeOfRawData 是section的長度
if((pimage_section_header->VirtualAddress) && (dwRVA<=(pimage_section_header->VirtualAddress+pimage_section_header->SizeOfRawData)))
return ((PIMAGE_SECTION_HEADER)pimage_section_header);
pimage_section_header++;
}
return(NULL);
}
/*
計算位移量的原理是什麼呢?
先判斷出rva在哪個section中,然後查section表找到與這個section對應的
檔案位移量,再用以下公式計算檔案位移量:
offset=rva-(section虛擬記憶體地址-section檔案位移量)
*/
unsigned long rva2offset(char * praw,unsigned long dwRVA)
{
unsigned long _offset;
PIMAGE_SECTION_HEADER section;
PIMAGE_NT_HEADERS pimage_nt_headers;
pimage_nt_headers = (PIMAGE_NT_HEADERS)(praw);
section=imagerva2section(pimage_nt_headers,dwRVA);
if(section==NULL)
return(-1);
//section->VirtualAddress 就是section的虛記憶體位址
//section->PointerToRawData 就是section的檔案位移量
_offset=dwRVA+section->PointerToRawData-section->VirtualAddress;
return(_offset);
}
// in fact the .cpl file is a .dll file, so we to check if it has "CPlApplet" symbol.
bool _iscpl(FILE * pf)
{
if (NULL==pf)
return false;
char symbolbuff[10];
unsigned long dwOffset = 0;
unsigned short magicnumber = 0;
fseek(pf,0,SEEK_SET);
fread(symbolbuff,1,2,pf);
if (symbolbuff[0]!='M' || symbolbuff[1]!='Z')
return false;
//skip dos stub.
//pe檔案頭是一個dos stub
fseek(pf,60,SEEK_SET);
//read pe offset.
//然後就是一個位移量儲存了真正的pe檔案頭
fread(&dwOffset,1,sizeof(dwOffset),pf);
//read nt header.
//在此讀檔案頭並儲存到一個結構內
fseek(pf,dwOffset,SEEK_SET);
char ntheader[10240];
fread(ntheader,1,sizeof(ntheader),pf);
fseek(pf,dwOffset,SEEK_SET);
//judge pe signature.
//pe檔案頭的首部是一個pe signature.
fread(symbolbuff,1,2,pf);
if (symbolbuff[0]!='P' || symbolbuff[1]!='E')
return false;
//read magic number to determine if the file is pe32 or pe32+.
fseek(pf,22,SEEK_CUR);
fread(&magicnumber,1,sizeof(magicnumber),pf);
//get the offset of optional header data directories
dwOffset = 0;
if (0x10b==magicnumber)
dwOffset = 96-2;
else
dwOffset = 112-2;
fseek(pf,dwOffset,SEEK_CUR);
fread(&dwOffset,1,sizeof(dwOffset),pf);
//seek to Optional Header Data Directories
dwOffset = rva2offset(ntheader,dwOffset);
if(dwOffset==-1)
return false;
fseek(pf,dwOffset,SEEK_SET);
int atenum = 0; //The number of entries in the export address table.
int nnpnum = 0; //The number of entries in the name pointer table. This is also the number of entries in the ordinal table.
fseek(pf,dwOffset+20,SEEK_SET);
fread(&atenum,1,sizeof(atenum),pf);
fseek(pf,dwOffset+24,SEEK_SET);
fread(&nnpnum,1,sizeof(nnpnum),pf);
//skip the export address table.
fseek(pf,dwOffset+40+4*atenum,SEEK_SET);
//now process name table.
vector <int> vecstraddr;
for(int i=0;i<nnpnum;++i){
int nnpaddr = 0;
fread(&nnpaddr,1,sizeof(nnpaddr),pf);
nnpaddr = rva2offset(ntheader,nnpaddr);
if(nnpaddr==-1)
continue;
vecstraddr.push_back(nnpaddr);
}
//compare name string.
for(i=0;i<vecstraddr.size();++i){
char buffstr[128];
int straddr = vecstraddr[i];
fseek(pf,straddr,SEEK_SET);
fread(buffstr,1,sizeof(buffstr),pf);
if(strcmp(buffstr,"CPlApplet")==0)
return true;
}
return false;
}
bool iscpl(const char * inputfile)
{
FILE * pf = fopen(inputfile,"rb");
bool res = _iscpl(pf);
fclose(pf);
return res;
}
int main(int argc, char* argv[])
{
bool res = iscpl("c:\\test.cpl");
return 0;
}
本文轉載自:
http://tassardge.blog.163.com/blog/static/1723017082008102185122256/