ReadApiSetSchema.zip/main.cpp
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <filesystem>
#include <fstream>
#include <optional>
#include <Windows.h>
#include <boost/spirit/home/support/detail/endian.hpp>
#include <boost/utility.hpp>
namespace endian = boost::spirit::endian;
class MzHeader : boost::noncopyable {
public:
char signature[2];
endian::ulittle8_t unknown[58];
endian::ulittle32_t peHeaderAddress;
bool IsValid() const {
return std::equal(signature, &signature[_countof(signature)], "MZ");
}
};
class PeHeader : boost::noncopyable {
public:
char signature[4];
endian::ulittle8_t unknown1[2];
endian::ulittle16_t sectionCount;
endian::ulittle8_t unknown2[4];
endian::ulittle32_t symbolTableAddress;
endian::ulittle32_t symbolTableCount;
endian::ulittle16_t optionalHeaderSize;
endian::ulittle16_t attributes;
bool IsValid() const {
if (!std::equal(signature, &signature[_countof(signature)], "PE\0\0")) {
return false;
}
return true;
}
};
class SectionHeader : boost::noncopyable {
public:
char name[8];
endian::ulittle32_t virtualSize;
endian::ulittle32_t virtualAddress;
endian::ulittle32_t size;
endian::ulittle32_t address;
endian::ulittle32_t relocateAddress;
endian::ulittle8_t unknown[8];
endian::ulittle32_t flags;
enum FLAGS {
FLAGS_WRITE = 0x80000000, FLAGS_READ = 0x40000000, FLAGS_EXECUTE = 0x20000000
};
};
bool TryExistsSystemDir(const std::filesystem::path &fileName, std::filesystem::path &result) {
wchar_t dirPath[MAX_PATH];
if (::GetSystemDirectoryW(dirPath, _countof(dirPath)) == 0) {
return false;
}
result = dirPath;
return std::filesystem::exists(result / fileName);
}
bool TryExistsSysnativeDir(const std::filesystem::path &fileName, std::filesystem::path &result) {
wchar_t dirPath[MAX_PATH];
if (::GetWindowsDirectoryW(dirPath, _countof(dirPath)) == 0) {
return false;
}
result = std::filesystem::path(dirPath) / L"Sysnative";
return std::filesystem::exists(result / fileName);
}
const SectionHeader *GetSectionHeader(const std::vector<unsigned char> &data, const std::string &name) {
const unsigned char * const baseAddr = &data.front();
const MzHeader &mz = *reinterpret_cast<const MzHeader *>(baseAddr);
const PeHeader &pe = *reinterpret_cast<const PeHeader *>(baseAddr + mz.peHeaderAddress);
const SectionHeader *sectionList = reinterpret_cast<const SectionHeader *>(baseAddr + mz.peHeaderAddress + sizeof(PeHeader) + pe.optionalHeaderSize);
for (unsigned int i = 0; i < pe.sectionCount; i++) {
if (std::equal(name.begin(), name.end(), sectionList[i].name)) {
return §ionList[i];
}
}
return NULL;
}
class ApiSetSchemaBase : boost::noncopyable {
public:
virtual std::optional<std::map<std::wstring, std::wstring> > main(const SectionHeader * const sectionHeader, const unsigned char * const baseAddr) = 0;
std::optional<std::map<std::wstring, std::wstring> > Read(const std::filesystem::path &path) {
std::ifstream ifs(path, std::ios::binary);
if (!ifs.is_open()) {
return {};
}
const unsigned int size = static_cast<unsigned int>(std::filesystem::file_size(path));
if (size == 0) {
return {};
}
std::vector<unsigned char> data(size);
ifs.read(reinterpret_cast<char *>(&data.front()), data.size());
if (!ifs.good()) {
return {};
}
ifs.close();
const SectionHeader * const sectionHeader = GetSectionHeader(data, ".apiset");
if (sectionHeader == NULL || sectionHeader->address > data.size() ||sectionHeader->size > data.size() - sectionHeader->address) {
return {};
}
const unsigned char * const baseAddr = &data.front() + sectionHeader->address;
return main(sectionHeader, baseAddr);
}
static std::optional<std::map<std::wstring, std::wstring> > ReadAll(const std::filesystem::path &path);
};
class ApiSetSchema7 : public ApiSetSchemaBase {
private:
class Header : boost::noncopyable {
public:
endian::ulittle32_t schemaVersion;
endian::ulittle32_t count;
};
class ForwardHeader : boost::noncopyable {
public:
endian::ulittle32_t dllNameOffset;
endian::ulittle32_t dllNameLength;
endian::ulittle32_t forwardInfoOffset;
};
class ForwardInfo : boost::noncopyable {
public:
endian::ulittle32_t type;
endian::ulittle32_t destDllNameOffset2;
endian::ulittle32_t unknown;
endian::ulittle32_t destDllNameOffset;
endian::ulittle32_t destDllNameLength;
};
protected:
virtual std::optional<std::map<std::wstring, std::wstring> > main(const SectionHeader * const sectionHeader, const unsigned char * const baseAddr) {
if (sectionHeader->size < sizeof(Header)) {
return {};
}
const Header &header = *reinterpret_cast<const Header *>(baseAddr);
if (header.schemaVersion != 2 || header.count * sizeof(ForwardHeader) > sectionHeader->size) {
return {};
}
const ForwardHeader * const forwordheaderList = reinterpret_cast<const ForwardHeader *>(baseAddr + sizeof(header));
std::map<unsigned int, std::wstring> nameList;
std::list<std::pair<std::wstring, unsigned int> > dest2List;
std::map<std::wstring, std::wstring> result;
for (unsigned int i = 0; i < header.count; i++) {
const ForwardHeader &forward = forwordheaderList[i];
if (forward.dllNameOffset > sectionHeader->size || forward.dllNameLength > sectionHeader->size - forward.dllNameOffset ||
forward.forwardInfoOffset > sectionHeader->size || sizeof(ForwardInfo) > sectionHeader->size - forward.forwardInfoOffset)
{
return {};
}
const std::wstring dllName = L"Api-" + std::wstring(reinterpret_cast<const wchar_t *>(baseAddr + forward.dllNameOffset), forward.dllNameLength / sizeof(wchar_t));
const ForwardInfo &info = *reinterpret_cast<const ForwardInfo *>(baseAddr + forward.forwardInfoOffset);
if (info.destDllNameOffset > sectionHeader->size || info.destDllNameLength > sectionHeader->size - info.destDllNameOffset) {
return {};
}
nameList.insert(std::make_pair(forward.dllNameOffset, dllName));
if (info.type == 1) {
const std::wstring destDllName(reinterpret_cast<const wchar_t *>(baseAddr + info.destDllNameOffset), info.destDllNameLength / sizeof(wchar_t));
result.insert(std::make_pair(dllName, destDllName));
} else if (info.type == 2) {
dest2List.push_back(std::make_pair(dllName, info.destDllNameOffset2));
} else {
return {};
}
}
while (!dest2List.empty()) {
std::pair<std::wstring, unsigned int> dest2 = dest2List.front();
dest2List.pop_front();
const std::map<unsigned int, std::wstring>::const_iterator it = nameList.find(dest2.second);
if (it == nameList.end()) {
return {};
}
const std::map<std::wstring, std::wstring>::const_iterator dest = result.find(it->second);
if (dest == result.end()) {
dest2List.push_back(dest2);
continue;
}
result.insert(std::make_pair(dest2.first, dest->second));
}
return result;
}
};
class ApiSetSchema81 : public ApiSetSchemaBase {
private:
class Header : boost::noncopyable {
public:
endian::ulittle32_t schemaVersion;
endian::ulittle64_t size;
endian::ulittle32_t count;
};
class ForwardHeader : boost::noncopyable {
public:
endian::ulittle32_t type; // 3:ext- 1:api-
endian::ulittle32_t dllNameOffset1;
endian::ulittle32_t dllNameLength;
endian::ulittle32_t dllNameOffset2;
endian::ulittle32_t unknown; // 必ずdllNameLength-8の値
endian::ulittle32_t forwardInfoOffset;
};
class ForwardInfo : boost::noncopyable {
public:
endian::ulittle32_t unknown1; // 常に0
endian::ulittle32_t type; // 大体1、たまに2
endian::ulittle32_t unknown2; // 常に0
endian::ulittle32_t unknown3; // 常に0
endian::ulittle32_t unknown4; // 常に0
endian::ulittle32_t destDllNameOffset;
endian::ulittle32_t destDllNameLength;
};
protected:
virtual std::optional<std::map<std::wstring, std::wstring> > main(const SectionHeader * const sectionHeader, const unsigned char * const baseAddr) {
if (sectionHeader->size < sizeof(Header)) {
return {};
}
const Header &header = *reinterpret_cast<const Header *>(baseAddr);
if (header.schemaVersion != 4 || header.count * sizeof(ForwardHeader) > sectionHeader->size || header.size != sectionHeader->virtualSize) {
return {};
}
const ForwardHeader * const forwordheaderList = reinterpret_cast<const ForwardHeader *>(baseAddr + sizeof(header));
std::map<unsigned int, std::wstring> nameList;
std::list<std::pair<std::wstring, unsigned int> > dest2List;
std::map<std::wstring, std::wstring> result;
for (unsigned int i = 0; i < header.count; i++) {
const ForwardHeader &forward = forwordheaderList[i];
if (forward.dllNameOffset1 > sectionHeader->size || forward.dllNameOffset2 > sectionHeader->size ||
forward.dllNameLength > sectionHeader->size - forward.dllNameOffset1 || forward.dllNameLength > sectionHeader->size - forward.dllNameOffset2 ||
forward.forwardInfoOffset > sectionHeader->size || sizeof(ForwardInfo) > sectionHeader->size - forward.forwardInfoOffset)
{
return {};
}
const std::wstring dllNameRaw(reinterpret_cast<const wchar_t *>(baseAddr + forward.dllNameOffset1), forward.dllNameLength / sizeof(wchar_t));
const std::wstring dllName = (forward.type == 1 ? L"api-" : L"ext-") + dllNameRaw + L".dll";
const ForwardInfo &info = *reinterpret_cast<const ForwardInfo *>(baseAddr + forward.forwardInfoOffset);
if (info.destDllNameOffset > sectionHeader->size || info.destDllNameLength > sectionHeader->size - info.destDllNameOffset) {
return {};
}
const std::wstring destDllName = (info.destDllNameOffset == 0) ?
L"Null(Definition only" :
std::wstring(reinterpret_cast<const wchar_t *>(baseAddr + info.destDllNameOffset), info.destDllNameLength / sizeof(wchar_t));
result.insert(std::make_pair(dllName, destDllName));
}
return result;
}
};
class ApiSetSchema10 : public ApiSetSchema81 {
private:
class Header : boost::noncopyable {
public:
endian::ulittle32_t schemaVersion;
endian::ulittle64_t size;
endian::ulittle32_t count;
endian::ulittle32_t unknown1;
endian::ulittle32_t unknownOffset;
endian::ulittle32_t unknown2;
};
class ForwardHeader : boost::noncopyable {
public:
endian::ulittle32_t type; // 大体1、たまに0
endian::ulittle32_t dllNameOffset;
endian::ulittle32_t dllNameLength;
endian::ulittle32_t unknown1; // 必ずdllNameLength-4の値
endian::ulittle32_t forwardInfoOffset;
endian::ulittle32_t unknown2; // 大体1、たまに2
};
class ForwardInfo : boost::noncopyable {
public:
endian::ulittle32_t unknown1; // ほぼ0、たまに何か入ってる
endian::ulittle32_t unknown2; // 常に0
endian::ulittle32_t unknown3; // 常に0
endian::ulittle32_t destDllNameOffset;
endian::ulittle32_t destDllNameLength;
};
protected:
virtual std::optional<std::map<std::wstring, std::wstring> > main(const SectionHeader * const sectionHeader, const unsigned char * const baseAddr) {
if (sectionHeader->size < sizeof(Header)) {
return {};
}
const Header &header = *reinterpret_cast<const Header *>(baseAddr);
if (header.schemaVersion != 6 || header.count * sizeof(ForwardHeader) > sectionHeader->size || header.size != sectionHeader->virtualSize) {
return {};
}
const ForwardHeader * const forwordheaderList = reinterpret_cast<const ForwardHeader *>(baseAddr + sizeof(header));
std::map<unsigned int, std::wstring> nameList;
std::list<std::pair<std::wstring, unsigned int> > dest2List;
std::map<std::wstring, std::wstring> result;
for (unsigned int i = 0; i < header.count; i++) {
const ForwardHeader &forward = forwordheaderList[i];
if (forward.dllNameOffset > sectionHeader->size || forward.dllNameLength > sectionHeader->size - forward.dllNameOffset ||
forward.forwardInfoOffset > sectionHeader->size || sizeof(ForwardInfo) > sectionHeader->size - forward.forwardInfoOffset)
{
return {};
}
const std::wstring dllNameRaw(reinterpret_cast<const wchar_t *>(baseAddr + forward.dllNameOffset), forward.dllNameLength / sizeof(wchar_t));
const std::wstring dllName = dllNameRaw + L".dll";
const ForwardInfo &info = *reinterpret_cast<const ForwardInfo *>(baseAddr + forward.forwardInfoOffset);
if (info.destDllNameOffset > sectionHeader->size || info.destDllNameLength > sectionHeader->size - info.destDllNameOffset) {
return {};
}
const std::wstring destDllName = (info.destDllNameOffset == 0) ?
L"Null(Definition only" :
std::wstring(reinterpret_cast<const wchar_t *>(baseAddr + info.destDllNameOffset), info.destDllNameLength / sizeof(wchar_t));
result.insert(std::make_pair(dllName, destDllName));
}
return result;
}
};
std::optional<std::map<std::wstring, std::wstring> > ApiSetSchemaBase::ReadAll(const std::filesystem::path &path) {
auto result = ApiSetSchema7().Read(path);
if (result) {
return result;
}
result = ApiSetSchema81().Read(path);
if (result) {
return result;
}
result = ApiSetSchema10().Read(path);
if (result) {
return result;
}
return {};
}
std::filesystem::path getApiSetSchemaPath() {
const std::filesystem::path fileName = L"apisetschema.dll";
std::filesystem::path dir;
if (!TryExistsSystemDir(fileName, dir)) {
if (!TryExistsSysnativeDir(fileName, dir)) {
return {};
}
}
return dir / fileName;
}
bool run(const std::filesystem::path &path = getApiSetSchemaPath()) {
const std::optional<std::map<std::wstring, std::wstring> > list = ApiSetSchemaBase::ReadAll(path);
if (!list) {
return false;
}
for (const auto &pair : *list) {
std::wcout << pair.first << " => " << pair.second << std::endl;
}
return true;
}
int main(const unsigned int argc, const char * const * argv) {
const bool result = (argc == 2) ? run(argv[1]) : run();
std::cin.get();
return result ? 0 : 1;
}