Skip to content

Instantly share code, notes, and snippets.

@kobake
Last active December 18, 2015 11:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kobake/5774678 to your computer and use it in GitHub Desktop.
Save kobake/5774678 to your computer and use it in GitHub Desktop.
APIフック (Cライブラリ関数やWindowsAPIの書き換え) と、その応用例 ref: http://qiita.com/items/8d3d3637c7af0b270098
Module:KERNEL32.dll Hint:234, Name:EncodePointer
Module:KERNEL32.dll Hint:532, Name:GetModuleFileNameW
Module:USER32.dll Hint:526, Name:MessageBoxA
Module:imagehlp.dll Hint:18, Name:ImageDirectoryEntryToData
Module:MSVCR100D.dll Hint:289, Name:_CRT_RTC_INITW
Module:MSVCR100D.dll Hint:1289, Name:_wassert
Module:MSVCR100D.dll Hint:1499, Name:getchar ← 今回はこれを書き替えてみます
Module:MSVCR100D.dll Hint:1474, Name:fopen
Module:MSVCR100D.dll Hint:1560, Name:printf
#include <stdio.h>
#include <windows.h>
#include <imagehlp.h>
#pragma comment(lib,"imagehlp.lib")
void* RewriteFunctionImp(const char* szRewriteModuleName, const char* szRewriteFunctionName, void* pRewriteFunctionPointer)
{
for(int i = 0; i < 2; i++){
// ベースアドレス
DWORD dwBase = 0;
if(i == 0){
if(szRewriteModuleName){
dwBase = (DWORD)(intptr_t)::GetModuleHandleA(szRewriteModuleName);
}
}
else if(i == 1){
dwBase = (DWORD)(intptr_t)GetModuleHandle(NULL);
}
if(!dwBase)continue;
// イメージ列挙
ULONG ulSize;
PIMAGE_IMPORT_DESCRIPTOR pImgDesc = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData((HMODULE)(intptr_t)dwBase, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize);
for(; pImgDesc->Name; pImgDesc++){
const char* szModuleName = (char*)(intptr_t)(dwBase+pImgDesc->Name);
// THUNK情報
PIMAGE_THUNK_DATA pFirstThunk = (PIMAGE_THUNK_DATA)(intptr_t)(dwBase+pImgDesc->FirstThunk);
PIMAGE_THUNK_DATA pOrgFirstThunk = (PIMAGE_THUNK_DATA)(intptr_t)(dwBase+pImgDesc->OriginalFirstThunk);
// 関数列挙
for(;pFirstThunk->u1.Function; pFirstThunk++, pOrgFirstThunk++){
if(IMAGE_SNAP_BY_ORDINAL(pOrgFirstThunk->u1.Ordinal))continue;
PIMAGE_IMPORT_BY_NAME pImportName = (PIMAGE_IMPORT_BY_NAME)(intptr_t)(dwBase+(DWORD)pOrgFirstThunk->u1.AddressOfData);
if(!szRewriteFunctionName){
// 表示のみ
printf("Module:%s Hint:%d, Name:%s\n", szModuleName, pImportName->Hint, pImportName->Name);
}
else{
// 書き換え判定
if(stricmp((const char*)pImportName->Name, szRewriteFunctionName) != 0)continue;
// 保護状態変更
DWORD dwOldProtect;
if( !VirtualProtect(&pFirstThunk->u1.Function, sizeof(pFirstThunk->u1.Function), PAGE_READWRITE, &dwOldProtect) )
return NULL; // エラー
// 書き換え
void* pOrgFunc = (void*)(intptr_t)pFirstThunk->u1.Function; // 元のアドレスを保存しておく
WriteProcessMemory(GetCurrentProcess(), &pFirstThunk->u1.Function, &pRewriteFunctionPointer, sizeof(pFirstThunk->u1.Function), NULL);
pFirstThunk->u1.Function = (DWORD)(intptr_t)pRewriteFunctionPointer;
// 保護状態戻し
VirtualProtect(&pFirstThunk->u1.Function, sizeof(pFirstThunk->u1.Function), dwOldProtect, &dwOldProtect);
return pOrgFunc; // 元のアドレスを返す
}
}
}
}
return NULL;
}
void* RewriteFunction(const char* szRewriteModuleName, const char* szRewriteFunctionName, void* pRewriteFunctionPointer)
{
return RewriteFunctionImp(szRewriteModuleName, szRewriteFunctionName, pRewriteFunctionPointer);
}
void PrintFunctions()
{
printf("----\n");
RewriteFunctionImp(NULL, NULL, NULL);
printf("----\n");
}
/*! 関数コール書き換え。
@param [in] szRewriteModuleName 書き替えたいモジュール名
@param [in] szRewriteFunctionName 書き替えたい関数名
@param [in] pRewriteFunctionAddress 書き替え後の関数アドレス
@return 元の関数アドレス
*/
void* RewriteFunction(
const char* szRewriteModuleName,
const char* szRewriteFunctionName,
void* pRewriteFunctionAddress
);
void PrintFunctions();
#include <assert.h>
#include <stdio.h>
#include "rewrite.h"
void __cdecl _wassert2(const wchar_t* expr, const wchar_t* filename, unsigned lineno)
{
// ※ここで filename や lineno で条件チェックを行うほうがより丁寧ですが
//  とりあえず今回は全スキップしてみました
}
int main()
{
void* p = RewriteFunction("MSVCR100D.dll", "_wassert", _wassert2);
printf("start\n");
assert(0); // このassertはスルーされる
printf("end\n");
RewriteFunction("MSVCR100D.dll", "_wassert", p); // 戻す
return 0;
}
#include <stdio.h>
#include <Windows.h>
#include "rewrite.h"
typedef HANDLE (WINAPI *CreateFileTypeW)(
LPCWSTR name, DWORD dw1, DWORD dw2, LPSECURITY_ATTRIBUTES lps,
DWORD dw3, DWORD dw4, HANDLE h);
CreateFileTypeW org;
HANDLE WINAPI MyCreateFileW(
LPCWSTR name, DWORD dw1, DWORD dw2, LPSECURITY_ATTRIBUTES lps,
DWORD dw3, DWORD dw4, HANDLE h)
{
printf("CreateFileW: %ls\n", name);
return org(name, dw1, dw2, lps, dw3, dw4, h);
}
int main()
{
org = (CreateFileTypeW)RewriteFunction("KERNEL32.dll", "CreateFileW", MyCreateFileW);
fopen("app.fopen", "rb");
CreateFileW(L"app.createfileW", GENERIC_READ, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
CreateFileA("app.createfileA", GENERIC_READ, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
RewriteFunction("KERNEL32.dll", "CreateFileW", org); // 戻す
return 0;
}
#include <stdio.h>
#include <time.h>
#include "rewrite.h"
typedef __time64_t (__cdecl *time64type)(__time64_t* t);
time64type orgtime;
__time64_t __cdecl mytime64(__time64_t* t)
{
__time64_t value = orgtime(t);
value += 60 * 60 * 24; // 1日進める
if(t)*t = value;
return value;
}
int main()
{
printf("time: %d\n", time(NULL));
orgtime = (time64type)RewriteFunction("MSVCR100D.dll", "_time64", mytime64);
printf("time: %d\n", time(NULL));
RewriteFunction("MSVCR100D.dll", "_time64", orgtime); // 戻す
return 0;
}
#include <stdio.h>
#include "rewrite.h"
int main()
{
PrintFunctions();
if(0){
// ※実際にプログラム内で使われている関数が表示されるので
//  書き替えたい関数が決まっていればダミーでも良いので
//  どこかで呼んでおく。
getchar();
}
return 0;
}
#include <stdio.h>
#include "rewrite.h"
int __cdecl mygetchar(void)
{
return 'A';
}
int main()
{
void* p = RewriteFunction("MSVCR100D.dll", "getchar", mygetchar);
printf("%c\n", getchar());
RewriteFunction("MSVCR100D.dll", "getchar", p); // 戻す
return 0;
}
_Check_return_ _CRTIMP int __cdecl getchar(void);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment