免费注册 查看新帖 |

Chinaunix

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

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

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:56:11数据库技术版块每日发帖之星
日期:2016-08-03 06:20:00数据库技术版块每日发帖之星
日期:2016-08-04 06:20:00
发表于 2010-01-29 20:28 |显示全部楼层
原帖由 ytl 于 2010-1-29 16:25 发表


AIX 5.3/GCC, gi没有变,也没segment fault

硬件/编译相关

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
发表于 2010-01-29 21:50 |显示全部楼层

回复 #21 swordfish.cn 的帖子

我猜cjaizss应该是这个意思 :
#include <stdio.h>

int gi = 1212;

void f(void* anchor)
{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void** top = &anchor - 1;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;top[1] = top[0];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;top[0] = (void*)printf;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;top[2] = "mock   p=%p v=%d\n";
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;top[3] = &gi + 1;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;top[4] = (void*)gi;
}

int main(void)
{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void (* volatile disable_inline)(void* ) = f;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("actual p=%p v=%d\n", (void*)&gi, gi);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;disable_inline(0);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;
}


输出:
actual p=00402000 v=1212
mock   p=00402004 v=1212


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

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

悬案……

论坛徽章:
0
发表于 2010-01-30 09:54 |显示全部楼层
本来f返回后应该到main里面。
但那4行程序中的有printf的一行将f自己的返回栈给改动了。这样f返回就直接返回到printf了。
但如果没有其他几行,到printf后,printf取参数时候多数会取无效地址而导致直接CORE,无法打印出错误的信息。
其余几行是给printf一个正确的参数从而让它能打印,给错误信息,就打印出了错误的数值。

程序最后CORE了因为PRINTF的返回,栈错位了,由于以上的参数原因(或其他)而导致CORE掉。
但在某些平台上未必CORE.

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


老大给个标答吧。

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

论坛徽章:
0
发表于 2010-01-30 10:04 |显示全部楼层

  1. #include <stdio.h>

  2. int gi = 1;

  3. f()
  4. {
  5. int i;

  6.   int a[1];
  7.   a[3] = printf;
  8.   a[5] = "addr = %p value = %d\n";
  9.   a[6] = &gi+1;
  10.   a[7] = gi+1;

  11.   for(i = 0; i < 256; i++) {
  12.     printf("addr = %p value = %d\n", &gi, gi);
  13.   }
  14. }

  15. main()
  16. {
  17.   f();
  18. }


复制代码

和cjaizss一个意思的。

论坛徽章:
0
发表于 2010-01-30 10:07 |显示全部楼层
原帖由 swordfish.cn 于 2010-1-30 09:58 发表


老大给个标答吧。

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


cjaizss的就是标准答案。
程序中的局部数组溢出使用,就能改变栈,结果不可预料。打印出荒唐的信息。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
发表于 2010-01-30 15:57 |显示全部楼层

回复 #25 swordfish.cn 的帖子

原帖由 swordfish.cn 于 2010-1-30 09:56 发表
想多了,呵呵,anchor不是必须的,一个top就足够了
了解一下栈的布局,你就清楚cjaizss代码的意义了。cjaizss的代码写得太过紧凑了点,呵呵。


了解一下栈的布局? 我不了解我能写出那些代码吗?
anchor不是必须的?  你看明白它的作用以及为什么需要它么?
就如它的名字一样, 它是用来定位的锚点。

return address        <- &anchor - 1
parameter 0            <- anchor

在i386下, 这样才能更准确定位到return address处。

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

a
i
return address        <- &anchor - 1
parameter 0            <- anchor


还是这么安排的?

a
[pad2]
i
[pad1]
return address        <- &anchor - 1
parameter 0            <- anchor

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


原帖由 swordfish.cn 于 2010-1-30 09:56 发表
另外,就我们目前用的架构来说,printf的实现,再怎么溢出,也是改不了的。


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

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

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
发表于 2010-01-30 17:02 |显示全部楼层
这个符合题意不?没有调用输出,连printf的地址都没引用。

#include <stdio.h>
int gi = 1;

f()
{
int i;

//  /*

}

#define f new_func

#define gi ( *(                                                                     \
i < 10  /* Keep old &gi, gi when i < 10 */                                          \
&nbsp;&nbsp;&nbsp;&nbsp;? &gi                                                                           \
&nbsp;&nbsp;&nbsp;&nbsp;: ( i < 20                                                                      \
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;? ( *(&gi + 1) = 2, &gi + 1 )                                               \
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;: ( *(int *)0 = 0 /* Throw "Segmentation fault" when i == 20" */, &gi + 1 ) \
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)                                                                           \
&nbsp;&nbsp;&nbsp;&nbsp;)                                                                               \
)


f()
{
&nbsp;&nbsp;int i;
&nbsp;&nbsp;
//  */


&nbsp;&nbsp;for(i = 0; i < 256; i++) {
&nbsp;&nbsp;&nbsp;&nbsp;printf("i = %d, addr = %p value = %d\n", i, &gi, gi);
&nbsp;&nbsp;}
}

main()
{
&nbsp;&nbsp;f();
}

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


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

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

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


是的,编译相关。

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

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


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

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

另外,再请教一下,在Linux下面,如何使用mmap来提权?如何map到printf?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP