一段linux下分析dll文件格式的程序

/*
下文的代码既可在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/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值