有关thunk的尝试

1 篇文章 0 订阅
1 篇文章 0 订阅

以前听某大牛说过,学习wtl,如果不知道thunk,那么你的wtl就没学好。好吧,下面来看看什么是 传说中的   thunk。


这里只是演示了如何动态生成代码去执行,wtl将hwnd参数改成this指针,是同样的道理。


先贴一段代码:

#pragma pack(push,1)
struct ProgThunk
{
	BYTE m_BJmp;
	int m_reploc;

	void Init(BYTE jmp, DWORD reploc)
	{
		m_BJmp = jmp;
		m_reploc = reploc;
	}
};
#pragma pack(pop)

typedef void (*fun)();

class TestC
{
public:
	static void test()
	{
		cout<<"Hello world"<<endl;
	}
};



int _tmain(int argc, _TCHAR* argv[])
{
	ProgThunk* progthunk;

	if (IsProcessorFeaturePresent(PF_NX_ENABLED)) 
	{
		progthunk = (ProgThunk*)::VirtualAlloc(NULL,sizeof(ProgThunk),MEM_RESERVE | MEM_COMMIT,PAGE_EXECUTE_READWRITE);   
	}
	else 
	{
		progthunk = new ProgThunk;   
	} 

	TestC testa;
	int A = (int)testa.test;
	int B = sizeof(ProgThunk);
	int C = (int)progthunk;
	int reploc = A-B-C;
	progthunk->Init(0xe9, reploc);

	FlushInstructionCache(GetCurrentProcess(), progthunk, sizeof(ProgThunk));

	fun testfun = (fun)(progthunk);
	testfun();

	return 0;
}

看了上面的代码,明白的人自然一看就知道,不明白的人却比较畏惧。我做点简单的解释:

struct ProgThunk  这里定义了一个结构体,也就是一个代码块,里面只有一个字节和一个整形(我知道应该用无符号数,用int可能不能表示4G空间,不过重点不再这里),那个字节后面会初始化成一条jmp指令,也就是0xe9,后面那个int会初始化成一个相对跳转位置,于是,这个代码块就可以跳转到指定的位置去执行代码了。
开始我调试的时候总是报错,访问地址越界,后来突然想到,代码页的读写与可执行的问题,就改成virtualalloc了的方式来分配内存了,果真就OK了。
顺便说一下,FlushInstructionCache不调用也可以执行成功,但是你不能保证所有情况下都成功,万一在某种条件下CPU繁忙,并没有将你的指令回写到内存中,那么,你再调用thunk代码将会造成不可预知的结果



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值