print_dll_info.zip/print_dll_info/main.cpp
#include <iostream>
#include <Windows.h>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/format.hpp>
#include <boost/range/irange.hpp>
const IMAGE_DOS_HEADER *getMz(const unsigned char * const data) {
return reinterpret_cast<const IMAGE_DOS_HEADER *>(data);
}
const IMAGE_NT_HEADERS32 *getPe(const unsigned char * const data, const IMAGE_DOS_HEADER &mz) {
return reinterpret_cast<const IMAGE_NT_HEADERS32 *>(data + mz.e_lfanew);
}
const IMAGE_SECTION_HEADER *getSectionHeader(const unsigned char * const data, const IMAGE_DOS_HEADER &mz, const IMAGE_NT_HEADERS32 &pe) {
return reinterpret_cast<const IMAGE_SECTION_HEADER *>(
data
+ mz.e_lfanew
+ sizeof(IMAGE_NT_HEADERS32) - sizeof(IMAGE_OPTIONAL_HEADER32)
+ pe.FileHeader.SizeOfOptionalHeader);
}
bool LoadImage(const boost::filesystem::path &path, std::vector<unsigned char> &out) {
if (!boost::filesystem::exists(path)) {
return false;
}
boost::filesystem::ifstream ifs(path, std::ios::binary);
if (!ifs.is_open()) {
return false;
}
// MZヘッダーの読み込み
out.resize(sizeof(IMAGE_DOS_HEADER));
ifs.read(reinterpret_cast<char*>(&out.front()), out.size());
const IMAGE_DOS_HEADER *mz = getMz(&out.front());
if (!ifs.good() || mz->e_magic != 0x5A4D) {
return false;
}
// PEヘッダーの読み込み
out.resize(mz->e_lfanew + sizeof(IMAGE_NT_HEADERS32) - sizeof(IMAGE_OPTIONAL_HEADER32));
mz = getMz(&out.front());
ifs.seekg(0, std::ios::beg);
ifs.read(reinterpret_cast<char*>(&out.front()), out.size());
const IMAGE_NT_HEADERS32 *pe = getPe(&out.front(), *mz);
if (!ifs.good() || pe->Signature != 0x00004550) {
return false;
}
// PEオプショナルヘッダーからセクションリストまでの読み込み
out.resize(
mz->e_lfanew
+ sizeof(IMAGE_NT_HEADERS32) - sizeof(IMAGE_OPTIONAL_HEADER32)
+ pe->FileHeader.SizeOfOptionalHeader
+ sizeof(IMAGE_SECTION_HEADER) * pe->FileHeader.NumberOfSections);
mz = getMz(&out.front());
pe = getPe(&out.front(), *mz);
ifs.seekg(0, std::ios::beg);
ifs.read(reinterpret_cast<char*>(&out.front()), out.size());
if (!ifs.good()) {
return false;
}
// セクションの読み込み
const IMAGE_SECTION_HEADER *sectionList = getSectionHeader(&out.front(), *mz, *pe);
for (unsigned int i = 0; i < pe->FileHeader.NumberOfSections; i++) {
if (sectionList[i].Misc.VirtualSize == 0) {
continue;
}
if (out.size() < sectionList[i].VirtualAddress + sectionList[i].Misc.VirtualSize) {
out.resize(sectionList[i].VirtualAddress + sectionList[i].Misc.VirtualSize);
mz = getMz(&out.front());
pe = getPe(&out.front(), *mz);
sectionList = getSectionHeader(&out.front(), *mz, *pe);
}
ifs.seekg(sectionList[i].PointerToRawData, std::ios::beg);
ifs.read(reinterpret_cast<char*>(&out[sectionList[i].VirtualAddress]), (std::min)(sectionList[i].Misc.VirtualSize, sectionList[i].SizeOfRawData));
if (!ifs.good()) {
return false;
}
}
return true;
}
std::wstring getDataDirectoryName(const unsigned int index) {
switch (index) {
#define MACRO(NAME) case NAME: return L#NAME
MACRO(IMAGE_DIRECTORY_ENTRY_EXPORT);
MACRO(IMAGE_DIRECTORY_ENTRY_IMPORT);
MACRO(IMAGE_DIRECTORY_ENTRY_RESOURCE);
MACRO(IMAGE_DIRECTORY_ENTRY_EXCEPTION);
MACRO(IMAGE_DIRECTORY_ENTRY_SECURITY);
MACRO(IMAGE_DIRECTORY_ENTRY_BASERELOC);
MACRO(IMAGE_DIRECTORY_ENTRY_DEBUG);
MACRO(IMAGE_DIRECTORY_ENTRY_ARCHITECTURE);
MACRO(IMAGE_DIRECTORY_ENTRY_GLOBALPTR);
MACRO(IMAGE_DIRECTORY_ENTRY_TLS);
MACRO(IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG);
MACRO(IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT);
MACRO(IMAGE_DIRECTORY_ENTRY_IAT);
MACRO(IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT);
MACRO(IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR);
#undef MACRO
default:
return (boost::wformat(L"UNKNOWN_%d") % index).str();
}
}
bool ExeParse(const boost::filesystem::path &path) {
if (!boost::filesystem::exists(path)) {
std::cout << "ファイルが見つかりませんでした\n";
return false;
}
std::vector<unsigned char> image;
if (!LoadImage(path, image)) {
std::cout << "ファイルを開けないか、実行可能形式ファイルではありません\n";
return false;
}
const unsigned char * const baseAddr = &image.front();
const IMAGE_DOS_HEADER &mz = *getMz(baseAddr);
const IMAGE_NT_HEADERS32 &pe = *getPe(baseAddr, mz);
std::wcout << boost::wformat(L"ImageBase: %08x\n") % pe.OptionalHeader.ImageBase;
const unsigned int dataDirectoriesCount =
(
pe.FileHeader.SizeOfOptionalHeader
- (sizeof(IMAGE_OPTIONAL_HEADER32) - sizeof(IMAGE_DATA_DIRECTORY) * _countof(IMAGE_OPTIONAL_HEADER32::DataDirectory))
) / sizeof(IMAGE_DATA_DIRECTORY);
std::wcout << boost::wformat(L"data directories count: %d\n") % dataDirectoriesCount;
for (const unsigned int i : boost::irange(0U, dataDirectoriesCount)) {
const IMAGE_DATA_DIRECTORY &dir = pe.OptionalHeader.DataDirectory[i];
std::wcout << boost::wformat(L"%2$08x %3$08x %1$s\n") % getDataDirectoryName(i) % dir.VirtualAddress % dir.Size;
}
const unsigned int sectionCount = static_cast<unsigned int>(pe.FileHeader.NumberOfSections);
std::wcout << boost::wformat(L"section count: %d\n") % sectionCount;
const IMAGE_SECTION_HEADER * const sectionList = getSectionHeader(baseAddr, mz, pe);
for (const unsigned int i : boost::irange(0U, sectionCount)) {
const IMAGE_SECTION_HEADER §ion = sectionList[i];
std::cout << boost::format("%2$08x %3$08x %1$s\n")
% std::string(§ion.Name[0], §ion.Name[_countof(section.Name)])
% section.VirtualAddress
% section.SizeOfRawData;
}
if (pe.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size != 0) {
const IMAGE_DATA_DIRECTORY &loadConfigDir = pe.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG];
const IMAGE_LOAD_CONFIG_DIRECTORY32 &loadConfig = *reinterpret_cast<const IMAGE_LOAD_CONFIG_DIRECTORY32 *>(baseAddr + loadConfigDir.VirtualAddress);
std::wcout << boost::wformat(L"load config size: %d\n") % loadConfig.Size;
if (loadConfig.Size >= 0x5C) {
std::wcout << boost::wformat(L" ptr: %08x\n") % loadConfig.GuardCFCheckFunctionPointer;
std::wcout << boost::wformat(L" table: %08x\n") % loadConfig.GuardCFFunctionTable;
std::wcout << boost::wformat(L" count: %08x\n") % loadConfig.GuardCFFunctionCount;
std::wcout << boost::wformat(L" flag: %08x\n") % loadConfig.GuardFlags;
if ((loadConfig.GuardFlags & IMAGE_GUARD_CF_FUNCTION_TABLE_PRESENT) != 0) {
std::wcout << boost::wformat(L" dump table:\n");
const unsigned int * const funcPtr = reinterpret_cast<const unsigned int *>(baseAddr + loadConfig.GuardCFFunctionTable - pe.OptionalHeader.ImageBase);
for (const unsigned int i : boost::irange(0U, static_cast<unsigned int>(loadConfig.GuardCFFunctionCount))) {
std::wcout << boost::wformat(L"%08x ") % funcPtr[i];
}
}
}
}
return true;
}
int main(const unsigned int argc, const char * const * argv) {
if (argc != 2) {
std::wcout << boost::wformat(L"usage: %s path") % boost::filesystem::path(argv[0]).filename().wstring();
return 1;
}
return ExeParse(argv[1]) ? 0 : 1;
}