实验环境是在64位linux下使用g++编译器
下面是Mark Gordon的答案
 1 The below one works on my system, can't guarantee results though.
 2
 3     #include <iostream>
 4     #include <stdlib.h>
 5     int num;
 6     void(**rptr)();
 7     void foo() {
 8       if(num >= 100) exit(0);
 9       std::cout << ++num << std::endl;
10       *rptr++ = foo;
11     }
12     int main() {
13       rptr = (void(**)())alloca(sizeof(*rptr) * 200) - 1;
14       foo();
15       return 0;
16     }

注意他说在其他人的电脑不一定work,也就是说跟编译器或者机器型号有关

下面是他本人对这个答案的解释

Mark Gordon
16 votes

Show

It's sort of a variation of the return to libc attack.

The alloca call grows the stack downward and gives me a pointer to the top (lowest address) on the stack.  It's right after this where the return address will be pushed on the stack when

I call foo so that's where I initialize rptr.  Then in foo I just write over the return address with foo so when foo returns it jumps back to the beginning.  Each time we return we move down the
stack (higher addresses) so I increment rptr.
大概说的是:这是一种在linux c函数库下 利用return 的一种变种攻击.
默认stack(栈)的生长是向下的(也就是push时RSP地址会减少);alloca 的调用 使得 return 时候使用的返回给RIP的地址 (此时的栈顶地址假设为100减1)赋给 rptr ;当函数进行调用的时候,本来栈顶 放的是call foo这个指令的下一个地址,但是被*rptr ++ = foo();
替换掉了; 返回后将继续执行  foo()的首地址; 每次return 我们将 移出栈,所以我累加 rptr 并赋值;
看到这里,我是很疑惑的,为什么要累加??函数的调用明明有一次push,一次pop(针对RIP指令地址寄存器)
是的,正常情况下,foo(); 汇编会执行call foo  ,但是,我们直接将foo()的入口地址赋值给了栈顶,也就是说,每次return,我们将 直接执行foo(),而没有使用call
这会造成什么样的后果呢?
首先,我们知道call会将下一个指令地址push到栈,然后函数调用结束前ret,将之前push的地址放到RIP,再pop,结束子函数。
现在,RIP放的是foo()入口地址,没有入栈的过程,当第一次foo()调用结束后(正常call),直接执行foo入口指令,此时RSP指向没有调用函数前的位置0x100,没有call使得RSP不能push返回的地址,但是
会执行ret,会出栈,我们都知道在这里默认stack是向下生长,pop会使RSP地址自加,变成0x108(为什么是加8,因为一个指针(64位)8个字节)那么如果我们在ret之前将0x104的内容替换成foo();的进入地址,
不断重复,将会达到不断调用foo()函数的目的;
但是这种方法的结果是:破坏了stack原来保存的信息,我们知道,stack是局部变量和子函数调用时指针地址存放的地方,这样破坏的数据真是太多了。
下面是实验结果:
0x40070d: foo入口地址
 
0x400738:将foo入口地址赋值到rptr指向的栈空间
0x400788:call 指令
下面是gdb单步调试结果
Breakpoint 1, 0x0000000000400745 in main ()
(gdb) si
0x000000000040074a in main ()
(gdb) si
0x000000000040074e in main ()
(gdb) si
0x0000000000400753 in main ()
(gdb) si
0x0000000000400757 in main ()
(gdb) si
0x000000000040075a in main ()
(gdb) si
0x000000000040075f in main ()
(gdb) si
0x0000000000400764 in main ()
(gdb) si
0x0000000000400767 in main ()
(gdb) si
0x000000000040076b in main ()
(gdb) si
0x000000000040076e in main ()
(gdb) si
0x0000000000400771 in main ()
(gdb) si
0x0000000000400775 in main ()
(gdb) si
0x0000000000400779 in main ()
(gdb) info registers rsp
rsp            0x7fffffffd300    0x7fffffffd300
(gdb) si
0x000000000040077d in main ()
(gdb) info registers rsp
rsp            0x7fffffffd300    0x7fffffffd300
(gdb) si
0x0000000000400781 in main ()
(gdb) info registers rsp
rsp            0x7fffffffd300    0x7fffffffd300
(gdb) si
0x0000000000400788 in main ()
(gdb) info registers rsp
rsp            0x7fffffffd300    0x7fffffffd300
(gdb) si
0x000000000040070d in foo() ()
(gdb) info registers rsp
rsp            0x7fffffffd2f8    0x7fffffffd2f8
(gdb) si
0x000000000040070e in foo() ()
(gdb) info registers rsp
rsp            0x7fffffffd2f0    0x7fffffffd2f0
(gdb) si
0x0000000000400711 in foo() ()
(gdb) info registers rsp
rsp            0x7fffffffd2f0    0x7fffffffd2f0
(gdb) si
0x0000000000400717 in foo() ()
(gdb) info registers rsp
rsp            0x7fffffffd2f0    0x7fffffffd2f0
(gdb) si
0x000000000040071a in foo() ()
(gdb) info registers rsp
rsp            0x7fffffffd2f0    0x7fffffffd2f0
(gdb) si
0x0000000000400726 in foo() ()
(gdb) si
0x000000000040072d in foo() ()
(gdb) si
0x0000000000400731 in foo() ()
(gdb) si
0x0000000000400738 in foo() ()
(gdb) si
0x000000000040073f in foo() ()
(gdb) si
0x0000000000400740 in foo() ()
(gdb) si
0x000000000040070d in foo() ()
(gdb) info registers rsp
rsp            0x7fffffffd300    0x7fffffffd300

注意标注红色的地方RSP的变化

最后一条语句

0x000000000040070d in foo() ()

是直接从ret跳过来的,像上面说的一样,没有使用call,最后会导致rsp不断地址不断增长,并不断进入foo()函数

如果上面有什么说得不对的地方,请多多包涵。

转载于:https://www.cnblogs.com/simonlin/p/5836702.html

利用C++不使用递归,循环和goto,打印1到100 的某一答案分析相关推荐

  1. php暂停循环,在特定数量的递归循环后,PHP停止执行

    我遇到的问题很奇怪. 在执行递归循环时会发生这种情况. 使用for循环或任何其他迭代执行相同任务时,不会发生这种情况. 在?21 000次以下递归调用函数时,一切正常. 超过此数字时会出现问题. 我的 ...

  2. php 递归栏目名叠加,thinkPHP实现递归循环栏目并按照树形结构无限极输出的方法,thinkphp递归...

    thinkPHP实现递归循环栏目并按照树形结构无限极输出的方法,thinkphp递归 本文实例讲述了thinkPHP实现递归循环栏目并按照树形结构无限极输出的方法.分享给大家供大家参考,具体如下: 这 ...

  3. 递归找到节点后跳出递归循环

    递归找到节点后跳出递归循环 在js 的递归循环中,找到了节点想跳出递归循环,如果是单纯的return或者break的时候,并没有阻止递归的循环 // 造一个树数据 const treeList = [ ...

  4. 91.video.ws index php_如何利用videojs实现视频列表循环播放(完整代码)

    本篇文章给大家带来的内容是关于如何利用videojs实现视频列表循环播放(完整代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 庭审直播 .video-js { /* posit ...

  5. java跳出递归_在Java项目中如何跳出递归循环

    在Java项目中如何跳出递归循环 发布时间:2020-11-25 17:16:07 来源:亿速云 阅读:114 作者:Leah 今天就跟大家聊聊有关在Java项目中如何跳出递归循环,可能很多人都不太了 ...

  6. javaScript使用递归循环遍历多层级对象方法(无限不定数层级)

    1.需求 在做一个Echarts关系图项目的时候碰到一个需求,后端传过来的数据格式是这样子的: "data":{name:"小明",relation:nullc ...

  7. python setattr无限递归_如何避免使用setattr和属性setter来避免递归循环?

    在调用setattr时,当试图设置某个带有setter的属性的值时,这将导致无限递归循环:class TypeSystem(object): def __setattr__(self, key, va ...

  8. php打印99乘法表加粗,PHP基础循环语句之打印99乘法表

    PHP基础循环语句之打印99乘法表 指定位置-1两个99乘法表如果font多层php PHP打印数学的99乘法表要用到两个For循环,for循环是php流程控制语句中较常用到的一种,流程控制语句中的结 ...

  9. DL之LSTM之MvP:基于TF利用LSTM基于DIY时间训练csv文件数据预测后100个数据(多值预测)状态

    DL之LSTM之MvP:基于TF利用LSTM基于DIY时间训练csv文件数据预测后100个数据(多值预测)状态 目录 数据集csv文件内容 输出结果 设计思路 训练记录全过程 数据集csv文件内容 输 ...

  10. MAT之PLS:利用PLS(两个主成分的贡献率就可达100%)提高测试集辛烷值含量预测准确度并《测试集辛烷值含量预测结果对比》

    MAT之PLS:利用PLS(两个主成分的贡献率就可达100%)提高测试集辛烷值含量预测准确度并<测试集辛烷值含量预测结果对比> 目录 输出结果 实现代码 输出结果 实现代码 load sp ...

最新文章

  1. Ubuntu14.04上安装TensorRT 2.1操作步骤
  2. C++ string类的方法
  3. Wi-Fi与LTE走向融合,优势互补携手共赢
  4. HH SaaS电商系统的品牌模块设计
  5. 和push的区别_还没有理解let 和 const的用法和区别吗,几百字让你立马搞懂
  6. jquery.cookie中的操作
  7. html编辑器后怎么使用,html在线编辑器怎么用
  8. Elon Musk赞同“火星经济将依靠加密货币运行”言论
  9. JetBrains系列WebStorm等中文输入法无法跟随光标的问题的解决办法
  10. matlab 调用c++编译好的文件出现问题
  11. 2017 4月20日下午
  12. PowerPhotos:Mac照片库管理软件
  13. 02--Activiti初始化表
  14. 困扰我许久的痛楚:闭包
  15. Windows文件夹中文名称英文路径
  16. win10桌面记事本便签有哪款
  17. 如何处理设计的条码与打印出来的不一样的问题
  18. cocos Creator打包
  19. 如何快速的学习ssh框架
  20. ICMP报文格式详解

热门文章

  1. 智能优化算法:足球联赛竞争算法-附代码
  2. Python 编程总结
  3. matlab利用geotiffread读取tif文件报错:‘错误使用 tifflib, 无法打开 TIFF 文件’
  4. 机器学习笔记-回归评价指标scikit-learn
  5. CSS学习总结(2)——选择器
  6. 阅读笔记——《R数据可视化手册》肖楠等;主要ggplot2
  7. oracle中外键的使用方法,Oracle数据库中外键的相关操作整理
  8. 在linux中装多个mysql 服务(亲测有效)
  9. Java 线程池 Executor浅入浅出
  10. 一个例子说明数据库union all的作用