一个有趣的问题

weiym 2008-10-31 05:30:18
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>


void fun1()
{
printf("fun1\n");
}

void fun2()
{
printf("fun2\n");
}

typedef void (*FunProc)();
void SetHook(FunProc pOld, FunProc pNew);

int main(int argc, char* argv[])
{
SetHook(fun1, fun2);

fun1(); //这里实际上调用fun2,输出fun2

getchar();

return 0;
}

//该如何实现
void SetHook(FunProc pOld, FunProc pNew)
{
}



问题: 如何实现SetHook才可以使其在接下来的fun1调用中实际上调用的是fun2(),
使程序输出fun2? 第一个贴出实现的代码的得40分.
...全文
566 30 打赏 收藏 转发到动态 举报
写回复
用AI写文章
30 条回复
切换为时间正序
请发表友善的回复…
发表回复
lufei4205 2009-08-13
  • 打赏
  • 举报
回复
mark
nolatestudy 2008-11-01
  • 打赏
  • 举报
回复
本人对此“十窍通了九窍”。
weiym 2008-11-01
  • 打赏
  • 举报
回复
我发这个帖子的目的是希望大家看到C/C++编译器在背后所作的事情,
同样的函数指针,在Debug和Release版下可能有不同的实现,
知道自己的每行代码在汇编层次是怎么被执行的,这可以说是一个优秀C++程序员的基本功.
weiym 2008-11-01
  • 打赏
  • 举报
回复
[Quote=引用 24 楼 glacier3d 的回复:]
引用 17 楼 baihacker 的回复:
C/C++ codevoid SetHook(FunProc pOld, FunProc pNew)
{
if (*(unsigned char*)pOld == 0xe9)
{
int data = *(int*)((char*)pNew+1) + (int)pNew - (int)pOld;
DWORD result;
WriteProcessMemory(GetCurrentProcess(), (char*)pOld+1, &data, 4, &result);
}
else if (*(unsigned char*)pOld == 0x55 || *(unsigned char*)pOld ==0x68) …
[/Quote]

恩,如果是inline貌似没有什么好的解决方法,
因为在编译时内联代码已经被拷贝过去,
运行时即使你改变了函数的内容也没什么影响了.
weiym 2008-11-01
  • 打赏
  • 举报
回复
[Quote=引用 25 楼 MilanSpiRiT 的回复:]
实在看不懂,LZ能不能赐教一下,需要哪方面知识才能看懂。

那些if (*(unsigned char*)pOld == 0xe9)
else if (*(unsigned char*)pOld == 0x55 || *(unsigned char*)pOld ==0x68)
都是什么意思啊?
[/Quote]

这些是机器码,和机器相关的,你在调试时把汇编打开就可以看到了,
比如说JMP到一个相对地址,一般机器码是E9XXXXXXXX,表示跳转到相对于当前指令地址XXXXXXXX的地方.
aniuman 2008-11-01
  • 打赏
  • 举报
回复
学习
xxgamexx 2008-11-01
  • 打赏
  • 举报
回复
向baihacker大哥学习!
MilanSpiRiT 2008-11-01
  • 打赏
  • 举报
回复
实在看不懂,LZ能不能赐教一下,需要哪方面知识才能看懂。

那些if (*(unsigned char*)pOld == 0xe9)
else if (*(unsigned char*)pOld == 0x55 || *(unsigned char*)pOld ==0x68)
都是什么意思啊?
glacier3d 2008-11-01
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 baihacker 的回复:]
C/C++ codevoid SetHook(FunProc pOld, FunProc pNew)
{
if (*(unsigned char*)pOld == 0xe9)
{
int data = *(int*)((char*)pNew+1) + (int)pNew - (int)pOld;
DWORD result;
WriteProcessMemory(GetCurrentProcess(), (char*)pOld+1, &data, 4, &result);
}
else if (*(unsigned char*)pOld == 0x55 || *(unsigned char*)pOld ==0x68)
{
int data = (int)pNew -…
[/Quote]

我发现在release模式下,fun1()的调用会被内联,所以在原函数出覆盖了jmp指令后也不起作用,
如下:


SetHook(fun1, fun2);
004010D0 68 10 10 40 00 push offset fun2 (401010h)
004010D5 68 00 10 40 00 push offset fun1 (401000h)
004010DA E8 41 FF FF FF call SetHook (401020h)

fun1(); //这里实际上调用fun2,输出fun2
004010DF 68 FC 70 40 00 push offset string "fun1\n" (4070FCh)
004010E4 E8 29 00 00 00 call printf (401112h)

qkhhxkj102 2008-10-31
  • 打赏
  • 举报
回复
你牛
tangshuiling 2008-10-31
  • 打赏
  • 举报
回复
mark
weiym 2008-10-31
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 baihacker 的回复:]
C/C++ codevoid SetHook(FunProc pOld, FunProc pNew)
{
if (*(unsigned char*)pOld == 0xe9)
{
int data = *(int*)((char*)pNew+1) + (int)pNew - (int)pOld;
DWORD result;
WriteProcessMemory(GetCurrentProcess(), (char*)pOld+1, &data, 4, &result);
}
else if (*(unsigned char*)pOld == 0x55 || *(unsigned char*)pOld ==0x68)
{
int data = (int)pNew -…
[/Quote]

不错,正解

我在Vc6里试了下,
对于Debug版,调用fun1时类似
004010ED E8 13 FF FF FF call @ILT+0(fun1) (00401005)
...
00401005 E9 26 00 00 00 jmp fun1 (00401030)
函数地址实际上是跳转指令的地址
Jmp指令用了相对地址,
所以我们只要直接修改这个相对地址的值就可以了;

但对于Release版,编译时进行了优化
它是总结Call这个函数
00401025 E8 D6 FF FF FF call fun1 (00401000)
这时Call的是真正的函数地址,
所以这里把我们的跳转指令直接写入覆盖,
另外也可以把Fun2的Shellcode直接写入



机智的呆呆 2008-10-31
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 baihacker 的回复:]
C/C++ codevoid SetHook(FunProc pOld, FunProc pNew)
{
if (*(unsigned char*)pOld == 0xe9)
{
int data = *(int*)((char*)pNew+1) + (int)pNew - (int)pOld;
DWORD result;
WriteProcessMemory(GetCurrentProcess(), (char*)pOld+1, &data, 4, &result);
}
else if (*(unsigned char*)pOld == 0x55 || *(unsigned char*)pOld ==0x68)
{
int data = (int)pNew -…
[/Quote]


高手果然是高手~~~~
baihacker 2008-10-31
  • 打赏
  • 举报
回复
void SetHook(FunProc pOld, FunProc pNew)
{
if (*(unsigned char*)pOld == 0xe9)
{
int data = *(int*)((char*)pNew+1) + (int)pNew - (int)pOld;
DWORD result;
WriteProcessMemory(GetCurrentProcess(), (char*)pOld+1, &data, 4, &result);
}
else if (*(unsigned char*)pOld == 0x55 || *(unsigned char*)pOld ==0x68)
{
int data = (int)pNew - (int)pOld - 5;
unsigned char jmp = 0xe9;
DWORD result;
WriteProcessMemory(GetCurrentProcess(), (char*)pOld, &jmp, 1, &result);
WriteProcessMemory(GetCurrentProcess(), (char*)pOld+1, &data, 4, &result);
}
else
{
printf("i can do it\n");
}
}
antss 2008-10-31
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 weiyijiji 的回复:]
引用 13 楼 antss 的回复:
//该如何实现
void SetHook(FunProc pOld, FunProc pNew)
{
pOld=pNew;
}

请多实践
[/Quote]

请把问题再说的明显一些.
weiym 2008-10-31
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 weiyijiji 的回复:]
引用 8 楼 weiym 的回复:
引用 5 楼 hqin6 的回复:
C/C++ code[Quote=引用 2 楼 hqin6 的回复:]
可不可以在SetHook里调用fun2,然后跳过fun1



如果你能实现也可以, 要求Release和Debug版都能正常运行运行.
[/Quote]
那在SetHook里调完fun2 直接EXIT不就好了
[/Quote]

这样意义不大, 违反了题目的本意
weiyijiji 2008-10-31
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 antss 的回复:]
//该如何实现
void SetHook(FunProc pOld, FunProc pNew)
{
pOld=pNew;
}
[/Quote]
请多实践
antss 2008-10-31
  • 打赏
  • 举报
回复
//该如何实现
void SetHook(FunProc pOld, FunProc pNew)
{
pOld=pNew;
}
antss 2008-10-31
  • 打赏
  • 举报
回复
这是个函数指针问题.

仅仅只要将fun1指向fun2

在调用完sethook后,执行了上述的行为

再次调用fun1的时候就输出fun2了.

请指教.
Vegertar 2008-10-31
  • 打赏
  • 举报
回复
菜鸟飘过
加载更多回复(10)

65,210

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧