他人の空似自作物置場

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);
}