テストケースを作っていて、他オブジェクトの関数の返り値を変えたかったけれど、ソースをいじりたくなかったのでチャレンジ。
class Debug_HookFunction{ private: void *m_base_fp; unsigned long m_base_instruction; public: Debug_HookFunction(){ ASSERT(0); }; // base_p = 上書きされるAPI // new_p = 上書きするAPI。base_pと返り値/引数の型、数が一致していること Debug_HookFunction(void *base_p,void *new_p); ~Debug_HookFunction(); // 復元する void restore(); };
#include "Debug_HookFunction.h" // base_p = 上書きされるAPI // new_p = 上書きするAPI。base_pと返り値/引数の型、数が一致していること Debug_HookFunction::Debug_HookFunction(void *base_p,void *new_p){ m_base_fp = base_p; m_base_instruction = (*(unsigned long*)(base_p)); // 最初の命令を new_pへのjump 命令に書き換える(計算式の詳細はARM本のP103を参照してね) unsigned long rewrite_instruction = 0xea000000 + (((((unsigned long)new_p - (unsigned long)base_p -8)>>2)&0xffffff)); memcpy((void*)base_p,&rewrite_instruction,sizeof(rewrite_instruction)); } Debug_HookFunction::~Debug_HookFunction(){ this->restore(); } // 復元する void Debug_HookFunction::restore(){ memcpy((void*)m_base_fp,&m_base_instruction,sizeof(m_base_instruction)); }
使い方
void function_base(){ printf("base.\r\n"); } void function_hook(){ printf("hook.\r\n"); } void main(){ Debug_HookFunction hook((void*)function_base,(void*)function_hook); function_base(); hook.restore(); function_base(); }
結果
hook. base.
CODEエリアにキャッシュが効いてると、せっかく上書きしたのをシカトされちゃうので、
キャッシュの効いていないメモリエリアで行うか、
キャッシュクリアしてから使うべし。