此程序用来仿真
PE
加载器,可以直接运行内存中的程序。
bool PELoader ( char * lpStaticPEBuff , long lStaticPELen )
{
long lPESignOffset = *( long *)( lpStaticPEBuff + 0x3c );
IMAGE_NT_HEADERS * pINH = ( IMAGE_NT_HEADERS *)( lpStaticPEBuff + lPESignOffset );
//取加载到内存中大小
long lImageSize = pINH - >OptionalHeader . SizeOfImage ;
char * lpDynPEBuff = new char [ lImageSize ];
if ( lpDynPEBuff == NULL )
{
return false ;
}
memset ( lpDynPEBuff , 0 , lImageSize );
//取PE文件的节数量
long lSectionNum = pINH - >FileHeader . NumberOfSections ;
//计算PE头信息及节表信息占用内存大小
long lPEHeadSize = lPESignOffset + sizeof ( IMAGE_NT_HEADERS ) + lSectionNum * sizeof ( IMAGE_SECTION_HEADER );
//加载PE头部信息及其各个节表
memcpy ( lpDynPEBuff , lpStaticPEBuff , lPEHeadSize );
//加载各个节
long lFileAlignMask = pINH - >OptionalHeader . FileAlignment - 1 ; //各节在磁盘中的对齐掩码
long lSectionAlignMask = pINH - >OptionalHeader . SectionAlignment - 1 ; //各节在load后内存中的对齐掩码
IMAGE_SECTION_HEADER * pISH = ( IMAGE_SECTION_HEADER *)(( char *) pINH + sizeof ( IMAGE_NT_HEADERS ));
for ( int nIndex = 0 ; nIndex < lSectionNum ; nIndex ++, pISH ++)
{
//判定各节的对齐属性,合法不
if (( pISH - >VirtualAddress & lSectionAlignMask ) || ( pISH - >SizeOfRawData & lFileAlignMask ))
{
//出现非法节
delete lpDynPEBuff ;
return false ;
}
//加载改节
memcpy ( lpDynPEBuff + pISH - >VirtualAddress , lpStaticPEBuff + pISH - >PointerToRawData , pISH - >SizeOfRawData );
}
//修改导入表,导入程序执行过程中要用到的API函数地址
if ( pINH - >OptionalHeader . DataDirectory [ IMAGE_DIRECTORY_ENTRY_IMPORT ]. Size > 0 ) //大于0说明有导入表
{
IMAGE_IMPORT_DESCRIPTOR * pIID = ( IMAGE_IMPORT_DESCRIPTOR *)( lpDynPEBuff + /
pINH - >OptionalHeader . DataDirectory [ IMAGE_DIRECTORY_ENTRY_IMPORT ]. VirtualAddress );
//循环扫描每个将有函数导入的dll
for (; pIID - >Name != NULL ; pIID ++)
{
/*曾看过OllyDump源代码,那里在重建导入表的时候,并没有初始化OriginalFirstThunk这个字段,
所以这里也不对OriginalFirstThunk这个字段进行处理了*/
IMAGE_THUNK_DATA * pITD = ( IMAGE_THUNK_DATA *)( lpDynPEBuff + pIID - >FirstThunk );
HINSTANCE hInstance = LoadLibrary ( lpDynPEBuff + pIID - >Name );
if ( hInstance == NULL )
{
//导入这个dll失败
delete lpDynPEBuff ;
return false ;
}
//循环扫描dll内每个被导入函数
for (; pITD - >u1 . Ordinal != 0 ; pITD ++)
{
FARPROC fpFun ;
if ( pITD - >u1 . Ordinal & IMAGE_ORDINAL_FLAG32 )
{
//函数是以序号的方式导入的
fpFun = GetProcAddress ( hInstance , ( LPCSTR )( pITD - >u1 . Ordinal & 0x0000ffff ));
}
else
{
//函数是以名称方式导入的
IMAGE_IMPORT_BY_NAME * pIIBN = ( IMAGE_IMPORT_BY_NAME *)( lpDynPEBuff + pITD - >u1 . Ordinal );
fpFun = GetProcAddress ( hInstance , ( LPCSTR ) pIIBN - >Name );
}
if ( fpFun == NULL )
{
//导出这个函数失败
delete lpDynPEBuff ;
return false ;
}
pITD - >u1 . Ordinal = ( long ) fpFun ;
}
FreeLibrary ( hInstance );
}
}
//重定位处理
if ( pINH - >OptionalHeader . DataDirectory [ IMAGE_DIRECTORY_ENTRY_BASERELOC ]. Size > 0 )
{
//取第一个重定位块
IMAGE_BASE_RELOCATION * pIBR = ( IMAGE_BASE_RELOCATION *)( lpDynPEBuff + /
pINH - >OptionalHeader . DataDirectory [ IMAGE_DIRECTORY_ENTRY_BASERELOC ]. VirtualAddress );
long lDifference = ( long ) lpDynPEBuff - pINH - >OptionalHeader . ImageBase ;
//循环每个重定位块
for (; pIBR - >VirtualAddress != 0 ; )
{
char * lpMemPage = lpDynPEBuff + pIBR - >VirtualAddress ;
long lCount = ( pIBR - >SizeOfBlock - sizeof ( IMAGE_BASE_RELOCATION )) >> 1 ;
//对这个页面中的每个需重定位的项进行处理
short int * pRelocationItem = ( short int *)(( char *) pIBR + sizeof ( IMAGE_BASE_RELOCATION ));
for ( int nIndex = 0 ; nIndex < lCount ; nIndex ++)
{
int nOffset = pRelocationItem [ nIndex ] &0x0fff ;
int nType = pRelocationItem [ nIndex ] >> 12 ;
//虽然windows定义了很多重定位类型,但是在PE文件中只能见到0和3两种
if ( nType == 3 )
{
*( long *)( lpDynPEBuff + nOffset ) += lDifference ;
}
else if ( nType == 0 )
{
//什么也不做
}
}
//pIBR指向下一个重定位块
pIBR = ( IMAGE_BASE_RELOCATION *)( pRelocationItem + lCount );
}
}
delete lpDynPEBuff ;
return true ;
}
bool PELoader ( char * lpStaticPEBuff , long lStaticPELen )
{
long lPESignOffset = *( long *)( lpStaticPEBuff + 0x3c );
IMAGE_NT_HEADERS * pINH = ( IMAGE_NT_HEADERS *)( lpStaticPEBuff + lPESignOffset );
//取加载到内存中大小
long lImageSize = pINH - >OptionalHeader . SizeOfImage ;
char * lpDynPEBuff = new char [ lImageSize ];
if ( lpDynPEBuff == NULL )
{
return false ;
}
memset ( lpDynPEBuff , 0 , lImageSize );
//取PE文件的节数量
long lSectionNum = pINH - >FileHeader . NumberOfSections ;
//计算PE头信息及节表信息占用内存大小
long lPEHeadSize = lPESignOffset + sizeof ( IMAGE_NT_HEADERS ) + lSectionNum * sizeof ( IMAGE_SECTION_HEADER );
//加载PE头部信息及其各个节表
memcpy ( lpDynPEBuff , lpStaticPEBuff , lPEHeadSize );
//加载各个节
long lFileAlignMask = pINH - >OptionalHeader . FileAlignment - 1 ; //各节在磁盘中的对齐掩码
long lSectionAlignMask = pINH - >OptionalHeader . SectionAlignment - 1 ; //各节在load后内存中的对齐掩码
IMAGE_SECTION_HEADER * pISH = ( IMAGE_SECTION_HEADER *)(( char *) pINH + sizeof ( IMAGE_NT_HEADERS ));
for ( int nIndex = 0 ; nIndex < lSectionNum ; nIndex ++, pISH ++)
{
//判定各节的对齐属性,合法不
if (( pISH - >VirtualAddress & lSectionAlignMask ) || ( pISH - >SizeOfRawData & lFileAlignMask ))
{
//出现非法节
delete lpDynPEBuff ;
return false ;
}
//加载改节
memcpy ( lpDynPEBuff + pISH - >VirtualAddress , lpStaticPEBuff + pISH - >PointerToRawData , pISH - >SizeOfRawData );
}
//修改导入表,导入程序执行过程中要用到的API函数地址
if ( pINH - >OptionalHeader . DataDirectory [ IMAGE_DIRECTORY_ENTRY_IMPORT ]. Size > 0 ) //大于0说明有导入表
{
IMAGE_IMPORT_DESCRIPTOR * pIID = ( IMAGE_IMPORT_DESCRIPTOR *)( lpDynPEBuff + /
pINH - >OptionalHeader . DataDirectory [ IMAGE_DIRECTORY_ENTRY_IMPORT ]. VirtualAddress );
//循环扫描每个将有函数导入的dll
for (; pIID - >Name != NULL ; pIID ++)
{
/*曾看过OllyDump源代码,那里在重建导入表的时候,并没有初始化OriginalFirstThunk这个字段,
所以这里也不对OriginalFirstThunk这个字段进行处理了*/
IMAGE_THUNK_DATA * pITD = ( IMAGE_THUNK_DATA *)( lpDynPEBuff + pIID - >FirstThunk );
HINSTANCE hInstance = LoadLibrary ( lpDynPEBuff + pIID - >Name );
if ( hInstance == NULL )
{
//导入这个dll失败
delete lpDynPEBuff ;
return false ;
}
//循环扫描dll内每个被导入函数
for (; pITD - >u1 . Ordinal != 0 ; pITD ++)
{
FARPROC fpFun ;
if ( pITD - >u1 . Ordinal & IMAGE_ORDINAL_FLAG32 )
{
//函数是以序号的方式导入的
fpFun = GetProcAddress ( hInstance , ( LPCSTR )( pITD - >u1 . Ordinal & 0x0000ffff ));
}
else
{
//函数是以名称方式导入的
IMAGE_IMPORT_BY_NAME * pIIBN = ( IMAGE_IMPORT_BY_NAME *)( lpDynPEBuff + pITD - >u1 . Ordinal );
fpFun = GetProcAddress ( hInstance , ( LPCSTR ) pIIBN - >Name );
}
if ( fpFun == NULL )
{
//导出这个函数失败
delete lpDynPEBuff ;
return false ;
}
pITD - >u1 . Ordinal = ( long ) fpFun ;
}
FreeLibrary ( hInstance );
}
}
//重定位处理
if ( pINH - >OptionalHeader . DataDirectory [ IMAGE_DIRECTORY_ENTRY_BASERELOC ]. Size > 0 )
{
//取第一个重定位块
IMAGE_BASE_RELOCATION * pIBR = ( IMAGE_BASE_RELOCATION *)( lpDynPEBuff + /
pINH - >OptionalHeader . DataDirectory [ IMAGE_DIRECTORY_ENTRY_BASERELOC ]. VirtualAddress );
long lDifference = ( long ) lpDynPEBuff - pINH - >OptionalHeader . ImageBase ;
//循环每个重定位块
for (; pIBR - >VirtualAddress != 0 ; )
{
char * lpMemPage = lpDynPEBuff + pIBR - >VirtualAddress ;
long lCount = ( pIBR - >SizeOfBlock - sizeof ( IMAGE_BASE_RELOCATION )) >> 1 ;
//对这个页面中的每个需重定位的项进行处理
short int * pRelocationItem = ( short int *)(( char *) pIBR + sizeof ( IMAGE_BASE_RELOCATION ));
for ( int nIndex = 0 ; nIndex < lCount ; nIndex ++)
{
int nOffset = pRelocationItem [ nIndex ] &0x0fff ;
int nType = pRelocationItem [ nIndex ] >> 12 ;
//虽然windows定义了很多重定位类型,但是在PE文件中只能见到0和3两种
if ( nType == 3 )
{
*( long *)( lpDynPEBuff + nOffset ) += lDifference ;
}
else if ( nType == 0 )
{
//什么也不做
}
}
//pIBR指向下一个重定位块
pIBR = ( IMAGE_BASE_RELOCATION *)( pRelocationItem + lCount );
}
}
delete lpDynPEBuff ;
return true ;
}