一段linux下分析dll檔案格式的程式

來源:互聯網
上載者:User

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

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.