check_guard_cf.zip/check_guard_cf/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>
#include <boost/optional.hpp>
#include <boost/program_options.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;
}
boost::optional<bool> checkGuardCF(const boost::filesystem::path &path, const bool isSilent) {
if (!boost::filesystem::exists(path)) {
if (!isSilent) {
std::wcout << L"ファイルが見つかりませんでした\n";
}
return{};
}
std::vector<unsigned char> image;
if (!LoadImage(path, image)) {
if (!isSilent) {
std::wcout << L"ファイルを開けないか、実行可能形式ファイルではありません\n";
}
return{};
}
const unsigned char * const baseAddr = &image.front();
const IMAGE_DOS_HEADER &mz = *getMz(baseAddr);
const IMAGE_NT_HEADERS32 &pe = *getPe(baseAddr, mz);
const unsigned int dataDirectoriesCount =
(
pe.FileHeader.SizeOfOptionalHeader
- (sizeof(IMAGE_OPTIONAL_HEADER32) - sizeof(IMAGE_DATA_DIRECTORY) * _countof(IMAGE_OPTIONAL_HEADER32::DataDirectory))
) / sizeof(IMAGE_DATA_DIRECTORY);
if (dataDirectoriesCount <= IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG) {
return false;
}
if (pe.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size == 0) {
return false;
}
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);
if (loadConfig.Size < 0x5C) {
return false;
}
if ((loadConfig.GuardFlags & IMAGE_GUARD_CF_FUNCTION_TABLE_PRESENT) == 0) {
return false;
}
return true;
}
int main(const unsigned int argc, const char * const * argv) {
std::locale loc = std::locale("japanese").combine<std::numpunct<char> >(std::locale::classic()).combine<std::numpunct<wchar_t> >(std::locale::classic());
std::locale::global(loc);
std::wcout.imbue(loc);
std::cout.imbue(loc);
boost::program_options::variables_map opt_list;
try {
using boost::program_options::value;
boost::program_options::options_description opt("オプション");
opt.add_options()
("help,h", "ヘルプを表示")
("silent,s", "標準出力に出さない")
("target,t", value<std::string>(), "対象の.exe/.dll");
boost::program_options::positional_options_description pos;
pos.add("target", 1);
boost::program_options::store(boost::program_options::command_line_parser(argc, argv).options(opt).positional(pos).run(), opt_list);
boost::program_options::notify(opt_list);
if (opt_list.count("help") != 0 || opt_list.count("target") == 0) {
std::wcout << boost::wformat(L"usage: %s [OPTION] [--target] path\n") % boost::filesystem::path(argv[0]).filename().wstring();
std::cout << opt << std::endl;
return 1;
}
} catch (std::exception& ex) {
std::cout << "コマンドライン引数の指定に誤りがあります: " << ex.what() << std::endl;
return 1;
}
const bool isSilent = (opt_list.count("silent") != 0);
const boost::optional<bool> result = checkGuardCF(opt_list["target"].as<std::string>(), isSilent);
if (!isSilent) {
if (!result) {
std::wcout << L"エラーが発生しました\n";
} else {
if (*result) {
std::wcout << L"GuardCFが有効です\n";
} else {
std::wcout << L"GuardCFが無効です\n";
}
}
}
return (!result || !*result ? 1 : 0);
}