Skip to content

Instantly share code, notes, and snippets.

@kohnakagawa
Created May 30, 2020 09:36
Show Gist options
  • Save kohnakagawa/dbbf720dbddcd73d7497b56e7d4f9912 to your computer and use it in GitHub Desktop.
Save kohnakagawa/dbbf720dbddcd73d7497b56e7d4f9912 to your computer and use it in GitHub Desktop.
Loader によって IAT エントリーが上書きされる前の値を取得するためのサンプルコード
#include <Windows.h>
#include <DbgHelp.h>
#include <iostream>
#include <fstream>
#include <filesystem>
#include <vector>
#pragma comment(lib, "Dbghelp.lib")
namespace fs = std::filesystem;
// NOTE: https://tech.blog.aerie.jp/entry/2016/01/12/130001
LPVOID RvaToVa(LPVOID pvBase, uint64_t dwRva)
{
return static_cast<LPBYTE>(pvBase) + dwRva;
}
LPVOID RvaToVa(LPVOID pvBase, uint64_t dwRva, BOOL bLoaded, IMAGE_SECTION_HEADER ** ppSectionHeader = nullptr)
{
auto va = static_cast<LPBYTE>(RvaToVa(pvBase, dwRva));
if (!bLoaded)
{
auto pNtHeaders = ImageNtHeader(pvBase);
auto pSectionHeader = IMAGE_FIRST_SECTION(pNtHeaders);
for (int i = 0; i < pNtHeaders->FileHeader.NumberOfSections; ++i, ++pSectionHeader)
{
auto pSection = static_cast<LPBYTE>(RvaToVa(pvBase, pSectionHeader->VirtualAddress));
if (pSection <= va && va < (pSection + pSectionHeader->SizeOfRawData))
{
auto diff = pSectionHeader->VirtualAddress - pSectionHeader->PointerToRawData;
va -= diff;
if (ppSectionHeader != nullptr)
{
*ppSectionHeader = pSectionHeader;
}
break;
}
}
}
return va;
}
int main(int argc, char* argv[]) {
if (argc != 2) {
std::cout << "Usage: ";
std::cout << argv[0] << " PE_file" << std::endl;
return EXIT_FAILURE;
}
std::ifstream fin(argv[1], std::ios::binary);
if (!fin) {
std::cout << "Cannot find file " << argv[1];
return EXIT_FAILURE;
}
fs::path p = argv[1];
const auto fsize = fs::file_size(p);
std::vector<BYTE> buffer(fsize);
fin.read((char*)buffer.data(), fsize);
// https://tech.blog.aerie.jp/entry/2016/01/13/013206
ULONG uSize = 0;
auto pImport = static_cast<IMAGE_IMPORT_DESCRIPTOR *>(
ImageDirectoryEntryToData(buffer.data(), FALSE, IMAGE_DIRECTORY_ENTRY_IMPORT, &uSize));
char* pvBase = (char*)buffer.data();
while (pImport->Characteristics != 0) {
auto pName = static_cast<LPCSTR>(RvaToVa(pvBase, pImport->Name, false));
printf_s("%s\n", pName);
auto pINT = static_cast<IMAGE_THUNK_DATA *>(RvaToVa(pvBase, pImport->OriginalFirstThunk, false));
auto pIAT = static_cast<IMAGE_THUNK_DATA *>(RvaToVa(pvBase, pImport->FirstThunk, false));
while (pINT->u1.AddressOfData != 0 && pIAT->u1.Function != 0)
{
// INT
if (IMAGE_SNAP_BY_ORDINAL(pINT->u1.Ordinal))
{
int ordinal = IMAGE_ORDINAL(pINT->u1.Ordinal);
printf_s("\t @%u\n", ordinal);
}
else
{
auto pFuncName = static_cast<IMAGE_IMPORT_BY_NAME *>(RvaToVa(pvBase, pINT->u1.AddressOfData, false));
printf_s("\t%4u %s %p\n", pFuncName->Hint, pFuncName->Name, pFuncName->Name);
}
// IAT
auto pFunction = reinterpret_cast<FARPROC>(pIAT->u1.Function);
// NOTE: 基本的にバインドされる前はINTのNameと同じアドレスをIATは指している (もしくは序数)
printf_s("\t %p\n", RvaToVa(pvBase, (uint64_t)pFunction, false));
++pINT;
++pIAT;
}
++pImport;
}
return EXIT_SUCCESS;
}
@kohnakagawa
Copy link
Author

基本的に IAT エントリーが上書きされる前は

  • 序数
  • INTのさす name が保持されている領域へのRVA
    のどちらかが格納されており、ローダーが上記二つの値を実行時に実際のAPIのアドレスで上書きする。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment