ARMにて関数を動的に書き換えてみた

テストケースを作っていて、他オブジェクトの関数の返り値を変えたかったけれど、ソースをいじりたくなかったのでチャレンジ。

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エリアにキャッシュが効いてると、せっかく上書きしたのをシカトされちゃうので、
キャッシュの効いていないメモリエリアで行うか、
キャッシュクリアしてから使うべし。