免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: 思一克
打印 上一主题 下一主题

一个所谓的全局变量地址改变的例子 [复制链接]

论坛徽章:
0
1 [报告]
发表于 2010-01-29 18:00 |显示全部楼层
原帖由 cjaizss 于 2010-1-29 12:21 发表
*(&i+4) = (int)("addr = %p value = %d\n");
*(&i+5) = (int)(&gi+1);
*(&i+6) = gi+1;
*(&i+2) = (int)((int*)printf);


直接把栈给改写了,呵呵。

论坛徽章:
0
2 [报告]
发表于 2010-01-29 19:17 |显示全部楼层
cjaizss的代码改了一下,我直接放main里面不成,呵呵。


  1. #include <stdio.h>

  2. int gi = 1;

  3. void f()
  4. {
  5.   int i;
  6.   *(&i+4) = (int)("addr = %p value = %d\n");
  7.   *(&i+5) = (int)(&gi+1);
  8.   *(&i+6) = gi+1;
  9.   *(&i+2) = (int)((int*)printf);
  10.   printf("addr = %p value = %d\n", &gi, gi);
  11. }

  12. int main()
  13. {
  14.   f();
  15.   return 0;
  16. }

复制代码

论坛徽章:
0
3 [报告]
发表于 2010-01-30 09:56 |显示全部楼层
原帖由 OwnWaterloo 于 2010-1-29 21:50 发表
我猜cjaizss应该是这个意思 :
输出:
actual p=00402000 v=1212
mock   p=00402004 v=1212


但是, 这已经不是直接调用printf了。
&gi是一个符号的地址。 再怎么溢出, 也只是修改符号的内容, 不可能修改符号的地址。 除非链接出了问题。
当链接完成后, &gi 就是不变的了。

printf("%p\n", (void*)&gi); 可以输出不同的地址 ……
要不就是不小心溢出, 把printf的实现代码给改掉了……

悬案……


想多了,呵呵,anchor不是必须的,一个top就足够了,另外,我觉得也没必要用这么多gcc自带的extension,这段代码,从原理上来说,已经可以达到目的了。至于实际用起来行与不行,那就是硬件、编译相关的了。我的实验情况是,放在main里面,即使用-fno-stack-protector,效果也出不来,所以直接放一个小函数里面好了。

了解一下栈的布局,你就清楚cjaizss代码的意义了。cjaizss的代码写得太过紧凑了点,呵呵。

他的代码并没有修改符号的地址。只是取用gi的地址作了计算。

另外,就我们目前用的架构来说,printf的实现,再怎么溢出,也是改不了的。

论坛徽章:
0
4 [报告]
发表于 2010-01-30 09:58 |显示全部楼层
原帖由 思一克 于 2010-1-30 09:54 发表
本来f返回后应该到main里面。
但那4行程序中的有printf的一行将f自己的返回栈给改动了。这样f返回就直接返回到printf了。
但如果没有其他几行,到printf后,printf取参数时候多数会取无效地址而导致直接CORE, ...


老大给个标答吧。

那个for就不要了吧,障眼法。

论坛徽章:
0
5 [报告]
发表于 2010-01-30 17:06 |显示全部楼层
了解一下栈的布局? 我不了解我能写出那些代码吗?
anchor不是必须的?  你看明白它的作用以及为什么需要它么?
就如它的名字一样, 它是用来定位的锚点。


下面你不是已经定义了一个变量top了吗?再用一个anchor是不是有点多余呢?

而函数内的局部变量, 你无法得知它们到return address之间有多少padding。
是这么安排的

不同的编译器以及编译选项, 就会产生不同的结果。


是的,编译相关。

有什么改不了的?
memcpy( (void*)&printf, src, size );

如果有写保护, VirtualProtect 或者mmap提升就完了。


请问这是由于“溢出”而导致的改写吗?另外,我的那句话还有另外一层意思,那就是.text一般是不能写的,写会引发segfault。

总的来说,我比较在意代码的紧凑,而您更注重清晰,我没有什么其他的意思,哈哈。

另外,再请教一下,在Linux下面,如何使用mmap来提权?如何map到printf?

论坛徽章:
0
6 [报告]
发表于 2010-01-30 17:29 |显示全部楼层
翻译的结果是否高效与正确, 同源代码是否紧凑没有必然联系。
编译器不是傻瓜。

同时, 我觉得即使是C语言, 代码的首要功能也是给人读。


那就怪我原来没有说明白吧,我的意思是想在写尽量少的代码的时候,实现功能。原来的代码,可能有需要加上stack相关的编译参数才可以实现。

很明显,这是一个编译相关的问题。我想搞清楚这一点,请问你的写法,是否能保证在stack相关选项变化的时候,得到一样的效果?

论坛徽章:
0
7 [报告]
发表于 2010-01-30 17:42 |显示全部楼层
原帖由 OwnWaterloo 于 2010-1-30 17:33 发表


当然是不能保证的。 C标准里几乎没怎么提stack-frame, 好像只有一个function image还是什么的。
也没说参数一定是由栈传入。


如果将讨论限制到i386下的cdecl调用约定, 你觉得呢? 返回地址和第0个参 ...


是我的话,我就直接加编译参数了。所以这个offset是可计算的。所以,回到我的出发点,我就觉得anchor有点多余了。

发现整天对着计算机,要和人解释清楚自己的想法还真不是一般的难啊。

另,我在Linux试了一下,即使是mprotect改了权限,也不能把printf改写,怎么办?


  1. unsigned long page = ((unsigned long)printf >> 12) << 12;
  2. unsigned long offset = ((unsigned long)printf) % 4096;

  3. mprotect(page, 4096, PROT_WRITE|PROT_READ);

  4. memcpy((void*)printf, "12345", 5);
复制代码


会segfault的。

论坛徽章:
0
8 [报告]
发表于 2010-01-30 18:37 |显示全部楼层
难道你觉得让代码的行为依赖于编译参数是很好的做法? 你依然觉得anchor多余?


“让代码的行为依赖于编译参数”不是好办法。但是在这个例子的情况下,我认为是最好的选择。既然anchor也无法完全确保程序的行为,我也就不再需要它了。当然,这是个别情况。


mprotect首个参数的类型是long???

你可以先检查一下mprotect的返回值。  看是否执行成功。
而且, 你将printf的执行权限给取消了。


实际调用的时候做了转换,而且执行也成功了(返回0)。现在尚未到执行一步,直接在memcpy就segfault了。

Windows的代码就没办法测试了,没有环境。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP