首页
社区
课程
招聘
[原创]解析静态库(Lib)文件,提取出所有函数信息,组织成自定义格式文件
发表于: 2010-6-28 18:04 30004

[原创]解析静态库(Lib)文件,提取出所有函数信息,组织成自定义格式文件

2010-6-28 18:04
30004

附件:我现在是临时用户,附件限制太小了。要代码的,我直接mail吧

目的:确定函数SIZE的方案还不够严谨,望牛人指教

标准:《Microsoft可移植可执行文件和通用目标文件格式文件规范》,简称《PE COFF文件规范》

注意:这里的LIB指的是静态库,要和编写DLL所生成的lib区别开来
《PE COFF文件规范》 中称静态库格式为:
档案(库)文件格式,在WinNT.h中称Archive format.
《PE COFF文件规范》 中称另一种Lib为:
导入库格式-是描述由一个映像导出供其它映像使用的符号的库

具体思路:
1.解析静态库(Lib)文件,提取出其中的所有目标文件成员(obj)
2.解析各个目标文件成员(obj),提取出其中的函数信息(函数名,函数数据,函数数据大小)
3.把提取出的函数信息,组织成自定义文件格式(flb)
函数库(.flb)文件格式: 签名-函数头表-函数名称段-函数数据段

一.解析静态库(Lib)文件,提取出其中的所有目标文件成员(obj)

1.静态库(Lib)文件结构
档案(库)文件(.lib)结构非常简单,就是签名+很多个成员,详细参见《PE COFF文件规范》第7节,或者看这里:http://dev.csdn.net/htmls/21/21543.html
签名,WinNT.h是这么定义的:

#define IMAGE_ARCHIVE_START_SIZE             8
#define IMAGE_ARCHIVE_START                  "!<arch>\n"
typedef struct _IMAGE_ARCHIVE_MEMBER_HEADER {
        BYTE     Name[16];         // File member name - `/' terminated.
        BYTE     Date[12];         // File member date - decimal.
        BYTE     UserID[6];        // File member user id - decimal.
        BYTE     GroupID[6];       // File member group id - decimal.
        BYTE     Mode[8];          // File member mode - octal.
        BYTE     Size[10];         // File member size – 头部大小不计算在内.
        BYTE     EndHeader[2];     // String to end header.
} IMAGE_ARCHIVE_MEMBER_HEADER, *PIMAGE_ARCHIVE_MEMBER_HEADER;
#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR      60
 #define IMAGE_ARCHIVE_LINKER_MEMBER          "/               "
#define IMAGE_ARCHIVE_LONGNAMES_MEMBER       "//              "
PBYTE CLibParser::GetFirstObjSection()
{
  int iCtrl=0;
  //第一个链接器成员
  PBYTE pSect = m_pLibImage+IMAGE_ARCHIVE_START_SIZE;
  if(!pSect)return NULL;
  while(pSect)
  {
    //第二个链接器成员
    if(memcmp(((PIMAGE_ARCHIVE_MEMBER_HEADER)pSect)->Name,IMAGE_ARCHIVE_LINKER_MEMBER,16)==0)
    {
      //Nothing
    }
    //第三个长名称成员
    else if(memcmp(((PIMAGE_ARCHIVE_MEMBER_HEADER)pSect)->Name,IMAGE_ARCHIVE_LONGNAMES_MEMBER,16)==0)//LONG Name
    {
      //Nothing
      //尽管长名称成员的头部必须存在,但它本身却可以为空。
    }  
    else //第一个目标文件成员
    {
      return pSect;
    }
    //注意BYTE Size[10];要用atol((LPSTR)..)这种方法才能得到正确size
    PIMAGE_ARCHIVE_MEMBER_HEADER pAME=(PIMAGE_ARCHIVE_MEMBER_HEADER)pSect;
    pSect += atol((LPSTR)pAME->Size) + sizeof(IMAGE_ARCHIVE_MEMBER_HEADER);
    //两个成员之间有可能是由\n隔开
    if(*pSect=='\n') pSect++;

    iCtrl++;//防止遇到错误的Lib文件,而死在这里面
    if (iCtrl>3)
    {
      break;
    }
  }
  return NULL;
}
BOOL CLibParser::ParseObjs(PBYTE pObjSect)
{
  do 
  {
    PIMAGE_ARCHIVE_MEMBER_HEADER pAME=(PIMAGE_ARCHIVE_MEMBER_HEADER)pObjSect;
    pObjSect+=sizeof(IMAGE_ARCHIVE_MEMBER_HEADER);//去掉头部,剩下的就是Obj(COFF格式)

    //判断是否是导入库格式,以防止错误的把导入库lib当做静态库lib,而程序直接挂掉
    if(bImportlibraryFormat(pObjSect))
    {
      MessageBox(NULL,"This is not a Archive Format File,it's a Import Format File!",
        "WARNING",MB_ICONWARNING);
      return FALSE;
    }

    //解析目标成员(OBJ)
    CObjParser objParser;
    objParser.Parse(pObjSect,m_pNameFile,m_pDataFile,&m_FuncTable);

    //注意:BYTE Size[10];要用atol((LPSTR)..)这种方法才能得到正确size
    pObjSect += atol((LPSTR)pAME->Size) ;

    //注意:两个成员之间有可能是由\n隔开,《PE COFF 文件格式》中并没有提到
    if(*pObjSect=='\n') 
      pObjSect++;

  } while (pObjSect<m_pLibImage+m_fsize);

  return TRUE;
}
typedef struct _IMAGE_FILE_HEADER {
    WORD    Machine;
    WORD    NumberOfSections;
    DWORD   TimeDateStamp;
    DWORD   PointerToSymbolTable;//指向符号表
    DWORD   NumberOfSymbols;//符号表的大小
    WORD    SizeOfOptionalHeader;
    WORD    Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
typedef struct _IMAGE_SECTION_HEADER {
    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];
    union {
            DWORD   PhysicalAddress;
            DWORD   VirtualSize;
    } Misc;
    DWORD   VirtualAddress;
    DWORD   SizeOfRawData;//指定节大小
    DWORD   PointerToRawData;//指向节数据
    DWORD   PointerToRelocations;//指向此节重定位信息表
    DWORD   PointerToLinenumbers;
    WORD    NumberOfRelocations;//此节重定位信息表的大小
    WORD    NumberOfLinenumbers;
    DWORD   Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 7
支持
分享
最新回复 (55)
雪    币: 97
活跃值: (28)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
一.解析.flb文件
1.加载.flb文件
//加载flb文件
	FILE* pFile;
	fopen_s(&pFile,szLib,"rb");
	if (!pFile)
	{
		CHAR ErrorStr[MAX_PATH];
		sprintf_s(ErrorStr,MAX_PATH,"Can't Open %s",szLib);
		MessageBox(NULL,ErrorStr,"Error",MB_ICONWARNING);
		return FALSE;
	}
	int len=_filelength(_fileno(pFile));
	m_pImage=(PBYTE)malloc(len);
	fread_s(m_pImage,len,len,1,pFile);
	fclose(pFile);

2.检测签名
//检测签名
	if (memcmp(m_pImage,IMAGE_FLB_START,IMAGE_FLB_START_SIZE)!=0)
	{
		return FALSE;
	}

3.定位函数头表
//定位函数头表
	m_pFuncHeader=(PFuncHeader)(m_pImage+IMAGE_FLB_START_SIZE);

4.检测函数,只要遍历函数头表就可以了
//遍历函数库
	do 
	{
		if(CheckFunc(pFuncHeader,pFuncDat))
		{	
			pNam=(PCSTR)(m_pImage+pFuncHeader->NameOff);
			return pNam;
		}
		pFuncHeader++;
	} while (pFuncHeader->DataSize);//函数头表以一个完全为空的函数头成员结尾

BOOL CLibScanner::CheckFunc(PFuncHeader pFuncHeader,PCBYTE pFuncDat)
{
	PBYTE pImpFuncDat=m_pImage+pFuncHeader->DataOff;
	//进行逐字节比对
	for (DWORD i=0;i<pFuncHeader->DataSize;i++)
	{
		//跳过重定位信息
		//只要是连续四个字节为,就当作重定位信息处理
		//注意while:有可能两个重定位信息相邻,比如两个操作数的情况
		while(*(PDWORD)(pImpFuncDat+i)==0)
		{	
			i+=4;
		}
		if (pImpFuncDat[i]!=pFuncDat[i])
		{
			return FALSE;
		}
	}
	return TRUE;
}

这样就可以使用flb文件了

二.拿到函数数据
要想测试flb文件,你还得拿到函数数据,我使用的是PVDasm,下面说一下我的方法:
1.        解析PE文件,获得代码段
2.        使用反汇编引擎,PVDasm,监控Call指令(只做0xe8),获得函数数据
3.        加载相应的flb文件,检测每个获得函数数据,是否属于此flb文件中的函数

我已经把各个版本的C语言静态库都搞成相应的flb文件了,我写了几个test,(附件里都有)并和ida做过比较,占时还没发现问题,但那个函数数据size的问题,就像锅里的一坨S,请大家帮帮忙!

最后再提一下我的问题,希望有前辈指点一下!
函数数据的size确定问题,我现在的方法是:直接断定一个节中只有一个函数数据!
《PE COFF文件规范》里提到一种:
“5.5.1 辅助符号表记录格式之一:函数定义”;里面可以拿到size;
但悲剧的是每个函数符号后面一张辅助符号表都没有,所以这种方法流产了
我到现在也找不到好方法,望有牛人提点!
2010-6-28 18:26
0
雪    币: 95
活跃值: (15)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
谢lz,学习。。。。
2010-6-29 09:05
0
雪    币: 97
活跃值: (28)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
坐等大牛现身!
2010-6-29 17:14
0
雪    币: 60
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
学习了
2010-7-6 14:37
0
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
膜拜, 帮顶
2010-7-6 23:33
0
雪    币: 40
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
顶,学习了。。
2010-7-7 10:09
0
雪    币: 11
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
pes
8
对lib了解不多,受教
2010-7-7 10:48
0
雪    币: 80
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
牛人啊,顶一下,顺便看转正还要多久
2010-7-7 10:58
0
雪    币: 26
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
学习!
2010-7-7 11:04
0
雪    币: 284
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
球代码
email: jerrynpc#gmail.com
2010-7-7 12:30
0
雪    币: 160
活跃值: (29)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
12
解析lib文件,在很多场景中都需要,好棒!
2010-7-7 14:42
0
雪    币: 97
活跃值: (28)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
13
代码已发!

注意,我的测试非常有限,而且还有一个size的问题有待解决
2010-7-7 19:36
0
雪    币: 1708
活跃值: (586)
能力值: ( LV15,RANK:670 )
在线值:
发帖
回帖
粉丝
14
代码是否可以上传论坛?
2010-7-7 19:38
0
雪    币: 97
活跃值: (28)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
15
传不上去啊,RAR:1,000,0kb  后面那个逗号太邪恶了
2010-7-7 19:51
0
雪    币: 61
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
2010-7-8 10:58
0
雪    币: 1708
活跃值: (586)
能力值: ( LV15,RANK:670 )
在线值:
发帖
回帖
粉丝
17
那找个网盘共享吧
2010-7-8 11:18
0
雪    币: 370
活跃值: (15)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
18
太邪恶了,请顺便就用途做个教程
2010-7-8 17:00
0
雪    币: 45
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
太邪恶了,新手那看的懂啊,我们要的是教程,不是代码.
2010-7-8 19:30
0
雪    币: 2477
活跃值: (20)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
每一个原创帖子都要顶一下
2010-7-23 14:49
0
雪    币: 517
活跃值: (64)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
21
找了一晚上,终于找到了。

不容易啊
2011-6-8 23:18
0
雪    币: 1149
活跃值: (888)
能力值: ( LV13,RANK:260 )
在线值:
发帖
回帖
粉丝
22
mark then check it ...
2011-6-9 00:02
0
雪    币: 23
活跃值: (31)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
23
同上,mark then check it ...
2011-6-9 00:53
0
雪    币: 345
活跃值: (20)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
学习下。。。
2011-6-9 11:43
0
雪    币: 27
活跃值: (77)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
感谢 分享
2011-6-10 08:56
0
游客
登录 | 注册 方可回帖
返回
//