class CFI
{
public:
int FI(char *strFileName, char *strInfo);
public:
CFI();
~CFI();
private:
BYTE Buff_H[0x400]; // 头缓冲
BYTE Buff_E[0x400]; // 入口缓冲
FILE *fp;
int File_Length; // 文件长度
int File_Type; // 文件类型 1-com 2-exe 8-pe
DWORD EP; // 入口
private:
int GetFileSize(FILE *pFile);
int SRead(int FilePos, PBYTE pPage, int nReadLen);
int SWrite(int FilePos, PBYTE pPage, int nReadLen);
DWORD Rva2Phys(IMAGE_NT_HEADERS *pPE_Header, DWORD dwAddr);
int InitBuff();
bool HexstrToHex(char *str, BYTE &Val);
int LoadLib_GT();
int LoadLib_PE();
int LoadLib();
FILETYPEDATA_GT *FI_GT();
FILETYPEDATA_PE *FI_PE();
char *FIRec(char *str);
cli_file_t cli_filetype(const char *buf, size_t buflen, char *strInfo);
};
CFI::CFI()
{
fp = NULL;
File_Type = -1;
File_Length = 0;
EP = 0;
}
CFI::~CFI()
{
}
//------------------------------------------------------------------------------- 公用函数
// 函数功能:获取文件的大小
int CFI::GetFileSize(FILE *pFile)
{
int Pos = ftell(pFile);
fseek(pFile, 0, SEEK_END);
int FileSize = ftell(pFile);
fseek(pFile, Pos, SEEK_SET);
return FileSize;
}
// 函数功能:读文件到制定缓冲区
int CFI::SRead(int FilePos, PBYTE pPage, int nReadLen)
{
if (FilePos < 0 || pPage == NULL || nReadLen <= 0)
return 0;
fseek(fp, FilePos, SEEK_SET);
return fread(pPage, 1, nReadLen, fp);
}
// ------------------------------------------------------------------------------- 功能函数
// 函数功能:将PE文件的Image中的线性地址转换成实际偏移
DWORD CFI::Rva2Phys(IMAGE_NT_HEADERS *pPE_Header, DWORD dwAddr)
{
int i;
DWORD dwSectionOffset; // 节表偏移
IMAGE_SECTION_HEADER *pSection_Header;
if (pPE_Header == NULL)
return dwAddr;
// 范围判断
if (dwAddr < pPE_Header->OptionalHeader.SizeOfHeaders && (int)dwAddr < File_Length)
return dwAddr;
// 遍历节表
dwSectionOffset = pPE_Header->FileHeader.SizeOfOptionalHeader + 0x18;
for (i = 0; i < pPE_Header->FileHeader.NumberOfSections; i ++, dwSectionOffset += 0x28)
{
pSection_Header = (IMAGE_SECTION_HEADER*)((BYTE*)pPE_Header + dwSectionOffset);
if ((dwAddr >= pSection_Header->VirtualAddress) && (dwAddr < pSection_Header->VirtualAddress+pSection_Header->Misc.VirtualSize))
return pSection_Header->PointerToRawData + dwAddr - pSection_Header->VirtualAddress ;
}
return dwAddr;
}
// 函数功能:初始化缓冲区
// 函数返回:0-失败;1-成功
int CFI::InitBuff()
{
int nPeOff;
IMAGE_DOS_HEADER *pDos_Head;
IMAGE_NT_HEADERS *pPE_Header;
if (File_Type == -1)
{
memset(Buff_H, 0, sizeof(Buff_H)); // 头缓冲
memset(Buff_E, 0, sizeof(Buff_E)); // 入口缓冲
}
File_Type = 1;
EP = 0;
SRead(0, Buff_H, 0x400); // 读头
// 判断类型
switch(*(WORD*)Buff_H)
{
case 'MZ':
case 'ZM':
File_Type = 2;
break;
default:
break;
}
// 继续判断
switch(File_Type)
{
case 1:
{
// 做为COM文件处理
EP = 0;
SRead(EP, Buff_E, 0x400);
}
break;
case 2:
{
pDos_Head = (IMAGE_DOS_HEADER*)Buff_H;
EP = (pDos_Head->e_cs + pDos_Head->e_cparhdr * 0x10 + pDos_Head->e_ip) & 0xfffff;
SRead(EP, Buff_E, 0x400);
// 是否存在PE
nPeOff = *(DWORD*)(Buff_H+0x3c);
if (nPeOff != 0 && File_Length > nPeOff)
{
SRead(nPeOff, Buff_E, 8);
if (*(WORD*)Buff_E == 'EP')
{
SRead(nPeOff, Buff_H, 0x400);
File_Type = 8;
// 读PE入口代码到Buff_E
pPE_Header = (IMAGE_NT_HEADERS*)Buff_H;
EP = Rva2Phys(pPE_Header, pPE_Header->OptionalHeader.AddressOfEntryPoint);
SRead(EP, Buff_E, 0x400);
}
}
}
break;
default:
SRead(0, Buff_E, 0x400);
break;
}
return 1;
}
// 函数功能:16进制字符串转化为数字
// 函数返回:0不是16进制数,1是十六进制数
bool CFI::HexstrToHex(char *str, BYTE &Val)
{
int nLen;
int i;
int pow;
BYTE s;
char ch;
char *p;
nLen = 2;
p = str + nLen;
s = 0;
pow = 1;
for(i = nLen; i > 0; i --)
{
ch = *(--p);
if ((ch >= 'a') && (ch <= 'f'))
ch = ch - 'a' + 10;
else if ((ch >= 'A') && (ch <= 'F'))
ch = ch - 'A' + 10;
else if ((ch >= '0') && (ch <= '9'))
ch = ch - '0';
else
return false;
s += ch * pow;
pow *= 16;
}
Val = s;
return 1;
}
// 函数功能:加载文件类型数据
// 函数返回:0-失败;1-成功
int CFI::LoadLib_GT()
{
int i, j;
int nRecCount;
int nStrLen;
char *p;
FILETYPEDATA_GT *pRecGT;
// 加载GT库
pRecGT = FileTypeRec_GT;
nRecCount = sizeof(FileTypeRec_GT)/sizeof(FILETYPEDATA_GT);
for (i = 0; i < nRecCount; i ++, pRecGT ++)
{
memset(pRecGT->RecData, 0, sizeof(pRecGT->RecData));
nStrLen = strlen(pRecGT->strData);
pRecGT->nRecLen = nStrLen/2;
p = pRecGT->strData;
for (j = 0; j < pRecGT->nRecLen; j ++)
{
if (!HexstrToHex(p, pRecGT->RecData[j]))
break;
p += 2;
}
}
return 1;
}
// 函数功能:加载文件类型数据
// 函数返回:0-失败;1-成功
int CFI::LoadLib_PE()
{
int i, j;
int nRecCount;
int nStrLen;
char *p;
FILETYPEDATA_PE *pRecPE;
// 加载PE库
pRecPE = FileTypeRec_PE;
nRecCount = sizeof(FileTypeRec_PE)/sizeof(FILETYPEDATA_PE);
for (i = 0; i < nRecCount; i ++, pRecPE ++)
{
// Pos
memset(pRecPE->PosData, 0, sizeof(pRecPE->PosData));
nStrLen = strlen(pRecPE->Pos);
pRecPE->nPosLen = nStrLen/2;
p = pRecPE->Pos;
for (j = 0; j < pRecPE->nPosLen; j ++)
{
if (!HexstrToHex(p, pRecPE->PosData[j]))
break;
p += 2;
}
// Fea
memset(pRecPE->FeaData, 0, sizeof(pRecPE->FeaData));
nStrLen = strlen(pRecPE->Fea);
pRecPE->nFeaLen = nStrLen/2;
p = pRecPE->Fea;
for (j = 0; j < pRecPE->nFeaLen; j ++)
{
if (!HexstrToHex(p, pRecPE->FeaData[j]))
break;
p += 2;
}
}
return 1;
}
// 函数功能:加载文件类型数据
// 函数返回:0-失败;1-成功
int CFI::LoadLib()
{
LoadLib_GT();
LoadLib_PE();
return 1;
}
// 分析文件类型GT
FILETYPEDATA_GT *CFI::FI_GT()
{
int i, j, s;
int nRecCount;
BYTE *p;
FILETYPEDATA_GT *pRecGT;
// GT库
pRecGT = FileTypeRec_GT;
nRecCount = sizeof(FileTypeRec_GT)/sizeof(FILETYPEDATA_GT);
for (i = 0; i < nRecCount; i ++, pRecGT ++)
{
s = 0;
p = pRecGT->RecData;
for (j = 0; j < pRecGT->nRecLen; j ++, p ++)
{
if (*p == 0)
continue;
s = s + (*p ^ Buff_E[j]);
if (s != 0)
break;
}
if (s == 0)
return pRecGT;
}
return NULL;
}
// 分析文件类型PE
FILETYPEDATA_PE *CFI::FI_PE()
{
int i, j;
int nRecCount;
BYTE *p;
FILETYPEDATA_PE *pRecPE;
// PE库
pRecPE = FileTypeRec_PE;
nRecCount = sizeof(FileTypeRec_PE)/sizeof(FILETYPEDATA_PE);
for (i = 0; i < nRecCount; i ++, pRecPE ++)
{
p = pRecPE->FeaData;
if (pRecPE->IsOrdered)
{
for (j = 0; j < pRecPE->nFeaLen; j ++, p ++)
{
if (*p != Buff_E[j])
break;
}
if (j == pRecPE->nFeaLen)
return pRecPE;
}
else
{
for (j = 0; j < pRecPE->nFeaLen; j ++, p ++)
{
if (*p != Buff_E[pRecPE->PosData[j]-1])
break;
}
if (j == pRecPE->nFeaLen)
return pRecPE;
}
}
return NULL;
}
// 分析文件类型
char *CFI::FIRec(char *str)
{
FILETYPEDATA_GT *pRecGT;
FILETYPEDATA_PE *pRecPE;
// PE
if ((pRecPE=FI_PE()) != NULL)
{
strcpy(str, pRecPE->Info);
return str;
}
// GT
if ((pRecGT=FI_GT()) != NULL)
{
strcpy(str, pRecGT->strName);
strcat(str, " ");
strcat(str, pRecGT->strType);
return str;
}
return NULL;
}
// 函数功能:分析文件类型
cli_file_t CFI::cli_filetype(const char *buf, size_t buflen, char *strInfo)
{
int i, ascii = 1, len;
for(i = 0; cli_magic[i].magic; i++)
{
if(buflen >= cli_magic[i].offset+cli_magic[i].length)
{
if(memcmp(buf+cli_magic[i].offset, cli_magic[i].magic, cli_magic[i].length) == 0)
{
strcpy(strInfo, cli_magic[i].descr);
return cli_magic[i].type;
}
}
}
buflen < 25 ? (len = buflen) : (len = 25);
for(i = 0; i < len; i++)
{
if(!internat[buf[i] & 0xff])
{
ascii = 0;
break;
}
}
if (ascii)
strcpy(strInfo, "Text file.");
else
strcpy(strInfo, "COM file or Others.");
return ascii ? CL_TYPE_UNKNOWN_TEXT : CL_TYPE_UNKNOWN_DATA;
}
// 分析文件加壳等类型
int CFI::FI(char *strFileName, char *strInfo)
{
// 打开文件
if ((fp = fopen(strFileName, "rb")) == NULL)
{
strcpy(strInfo, "Open file failed.");
return false;
}
// 读文件大小
if ((File_Length = GetFileSize(fp)) == 0)
{
strcpy(strInfo, "Size of file is 0.\n");
return false;
}
// 初始化缓冲区
if (!InitBuff())
{
strcpy(strInfo, "Isn't exe file.\n");
return false;
}
// 加载类型库
if (!LoadLib())
{
strcpy(strInfo, "Load filetype lib failed.\n");
return false;
}
// 判断类型
if (!FIRec(strInfo))
{
if (File_Type == 2)
strcpy(strInfo, "DOS execute file!\n");
else if (File_Type == 8)
strcpy(strInfo, "PE file!\n");
else
{
SRead(0, Buff_H, sizeof(Buff_H));
cli_filetype((char*)Buff_H, sizeof(Buff_H), strInfo);
}
}
return true;
}
void main(int avgc, char **argv)
{
char strFileInfo[0x200];
CFI aFi;
// 初始化
printf("FileInfo v1.0 (c) 2006.10.23 by wangwei.\n");
printf("My bolg: http://hi.baidu.com/avengine\n\n");
memset(strFileInfo, 0, sizeof(strFileInfo));
if (avgc != 2)
{
printf("Fi [FILE]\n");
return;
}
// 判断类型
aFi.FI(argv[1], strFileInfo);
printf("%s\n", strFileInfo);
}