PEヘッダを書き換える必要があって、初めてPEを静的に読みました。
LoadLibraryなんかで読み込んだPEヘッダをたぐるのと勝手が全然違ったのでメモメモします。
RVAを作成するときにセクションのVirtualAddressやデータディレクトリのVirtualAddressを足したり引いたりするところは数字が合うようにPEviewを見ながら書いたので何でこうなるのかさっぱり分かりません。どこかに資料が落ちてるといいんですが、ファイルのままのPEを詳しく解説したものは見つかりませんでした・・。
エラー処理は全て省いてあり、コマンドラインに適切なPE形式(PE or PE+)のファイルのフルパスが渡される前提です。エクスポートされている関数の名前を列挙します。
# include <cstdint>
# include <fstream>
# include <iostream>
# include <string>
# include <vector>
# include <Windows.h>
struct module
{
union
{
std::uintptr_t base_addr;
PIMAGE_DOS_HEADER pIDH;
void* pointer;
};
module( std::uintptr_t base_addr ) : base_addr( base_addr ) {}
module( void* pointer ) : pointer( pointer ) {}
template < class Ty > // convert RelativeVirtualAddress to AbsoluteRealAddress
Ty to_ara( DWORD rva ) const { return reinterpret_cast < Ty >( rva + base_addr ); }
};
int main( int argc, char** argv )
{
std::cout << std::hex;
std::ifstream fileDll( argv[1], std::ios::in | std::ios::binary );
std::vector < char > binaryDll;
for( ;;)
{ // load file into buffer
char buffer;
fileDll.read( &buffer, sizeof( buffer ) * 1 );
if( fileDll.eof() ) { break; } // eof
binaryDll.push_back( buffer );
}
module moduleDll( binaryDll.data() );
PIMAGE_NT_HEADERS pINH = moduleDll.to_ara < PIMAGE_NT_HEADERS >( moduleDll.pIDH->e_lfanew );
PIMAGE_OPTIONAL_HEADER pIOH = &pINH->OptionalHeader;
PIMAGE_DATA_DIRECTORY pIDD = &pIOH->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
//
// PIMAGE_EXPORT_DIRECTORY pIED = moduleDll.to_ara < PIMAGE_EXPORT_DIRECTORY >( pIDD->VirtualAddress );
// 通常はこれでエクスポート情報が利用できるが、これは
// LoadLibrary等で読み込み、ローダがごにょごにょしてくれないと使えない
//
// セクションヘッダを列挙し、エクスポート情報(IMAGE_EXPORT_DIRECTORY)を探す
PIMAGE_FILE_HEADER pIFH = &pINH->FileHeader;
// セクションヘッダはNTヘッダのお尻についている
PIMAGE_SECTION_HEADER pISH = reinterpret_cast < PIMAGE_SECTION_HEADER > ( pINH + 1 );
PIMAGE_EXPORT_DIRECTORY pIED = nullptr;
std::uintptr_t rva_to_ied = 0;
// ここからよく分からない
for( int i = 0; i < pIFH->NumberOfSections; ++i )
{
if( pISH[i].VirtualAddress + pISH[i].SizeOfRawData > pIDD->VirtualAddress )
{ // IEDが含まれたセクションを発見
std::cout << "SECTION: " << pISH[i].Name << std::endl;
// IEDへのRVAを作る
rva_to_ied = pIDD->VirtualAddress - pISH[i].VirtualAddress + pISH[i].PointerToRawData;
pIED = moduleDll.to_ara < PIMAGE_EXPORT_DIRECTORY >( rva_to_ied );
break;
}
}
// rva to name pointer table
std::uintptr_t rva_to_npt = rva_to_ied + pIED->AddressOfNames - pIDD->VirtualAddress;
DWORD* table_names = moduleDll.to_ara < DWORD* >( rva_to_npt );
std::cout << std::endl << "** enum export functions **" << std::endl;
for( DWORD i = 0; i < pIED->NumberOfNames; ++i )
{
std::uintptr_t rva_to_name = table_names[i];
char* name = moduleDll.to_ara < char* >( rva_to_name - pIDD->VirtualAddress + rva_to_ied );
std::cout << "NAME: " << name << std::endl;
}
}