热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

逆向工程栈

为什么栈会逆增长多数的栈是逆增长的,它会从高地址向低地址增长。历史原因。当计算机尚未小型化的时候,它还有数个房间那么大。在那个时候,内

为什么栈会逆增长

多数的栈是逆增长的,它会从高地址向低地址增长。

历史原因。当计算机尚未小型化的时候,它还有数个房间那么大。在那个时候,内存就分为两个部分,即"堆/heap"和栈/stack。当然,在程序执行过程中,堆和栈到底会增长到什么地址并不好说,所以人们干脆把它们分开:

 

栈的用途

1)保存函数结束时的返回地址

x86

当程序使用call指令调用其他函数时,call指令结束后的返回地址将被保存在栈里;在call所调用的函数结束之后,程序将执行无条件跳转指令,跳转到这个返回地址。

CALL指令等价于PUSH返回地址和JMP函数地址的指令对。

被调用函数里的RET指令,会从栈中读取返回地址,然后跳转到这个地址,就相当于POP返回地址+JMP返回地址指令。

栈是有隐姓埋名的,溢出它很容易。直接使用无限递归,栈就会满

ARM

如果一个函数不调用其他函数,它就像树上的枝杈末端的叶子那样。这种函数就叫作叶函数leaf function。

叶函数的特点是,它不必保存LR寄存器的值。如果叶函数的代码短到用不了几个寄存器,那么它也可能根本不会使用数据栈。所以,调用叶函数的时候确实可能不会涉及栈操作。

 

2)参数传递

在x86平台的程序中,最常用的参数传递约定是cdecl。

push arg3

push arg2

push arg1

call f

add esp,12

被调用方法函数通过栈指针获取其所需的参数。

ESP

返回地址

ESP+4

arg1,它在IDA里记为arg_0

ESP+8

 

arg2,它在IDA里记为arg_4

ESP+0xC

arg3,它在IDA里记为arg_8

 

3)存储局部变量

通过向栈底调整栈指针的方法,函数即可在数据栈里分配也一片可用于存储局部变量的内存空间。可见,无论函数声明了多少个局部变量,都不影响它分配栈空间的速度。

4)SEH结构化异常处理

5)缓冲区溢出保护

6)alloca()函数

直接使用栈来分配内存,除些之外,它与malloc()比偶没有显著的区别。

函数尾声的代码会还原ESP的值,把数据还原为函数启动之前的状态,直接抛弃由alloca()函数分配的内存。所以程序不需要特地使用free()函数来释放由这个函数申请的内存。

 

栈的噪音

#includevoid f1(){int a=1,b=2,c=3;};void f2(){int a,b,c;printf("%d, %d, %d\n",a,b,c);}int main(){f1();f2();}MSVC$SG2752 '%d, %d, %d',0aH,00H_c$=-12 ;size=4_b$=-8 ;size=4_a$=-4 ;size=4_f1 PROCpush ebpmov ebp,espsub esp,12mov DWORD PTR _a$[ebp],1mov DWORD PTR _b$[ebp],2mov DWORD PTR _c$[ebp],3mov esp,ebppop ebpret 0_f1 ENDP_c$=-12 ;size=4_b$=-8 ;size=4_a$=-4 ;size=4_f2 PROCpush ebpmov mov ebp,espsub esp,12mov eax, DWORD PTR _c$[ebp]push eaxmov ecx, DWORD PTR _b$[ebp]push ecxmov edx, DWORD PTR _a$[ebp]push edxpush OFFSET $SG2752; ‘%d, %d, %d'call DWORD PTR __imp_printfadd esp,16mov esp,ebppop ebpret 0_f2 ENDPmain PROCpush ebpmov ebp,espcall _f1call _f2xor eax,eaxpop ebpret 0_main ENDP

在运行第二个函数时,栈中的所有值(即内存中的单元)受前一个函数的影响,而获得了前一个函数的变量的值。来格地说,这些地址的值不是随机值,而是可预测的伪随机值。


推荐阅读
  • 本文概述了JNI的原理以及常用方法。JNI提供了一种Java字节码调用C/C++的解决方案,但引用类型不能直接在Native层使用,需要进行类型转化。多维数组(包括二维数组)都是引用类型,需要使用jobjectArray类型来存取其值。此外,由于Java支持函数重载,根据函数名无法找到对应的JNI函数,因此介绍了JNI函数签名信息的解决方案。 ... [详细]
  • x86 linux的进程调度,x86体系结构下Linux2.6.26的进程调度和切换
    进程调度相关数据结构task_structtask_struct是进程在内核中对应的数据结构,它标识了进程的状态等各项信息。其中有一项thread_struct结构的 ... [详细]
  • 本文介绍了[从头学数学]中第101节关于比例的相关问题的研究和修炼过程。主要内容包括[机器小伟]和[工程师阿伟]一起研究比例的相关问题,并给出了一个求比例的函数scale的实现。 ... [详细]
  • CentOS 7部署KVM虚拟化环境之一架构介绍
    本文介绍了CentOS 7部署KVM虚拟化环境的架构,详细解释了虚拟化技术的概念和原理,包括全虚拟化和半虚拟化。同时介绍了虚拟机的概念和虚拟化软件的作用。 ... [详细]
  • 本文讨论了在iOS平台中的Metal框架中,对于if语句中的判断条件的限制和处理方式。作者提到了在Metal shader中,判断条件不能写得太长太复杂,否则可能导致程序停留或没有响应。作者还分享了自己的经验,建议在CPU端进行处理,以避免出现问题。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • 嵌入式处理器的架构与内核发展历程
    本文主要介绍了嵌入式处理器的架构与内核发展历程,包括不同架构的指令集的变化,以及内核的流水线和结构。通过对ARM架构的分析,可以更好地理解嵌入式处理器的架构与内核的关系。 ... [详细]
  • Mono为何能跨平台
    概念JIT编译(JITcompilation),运行时需要代码时,将Microsoft中间语言(MSIL)转换为机器码的编译。CLR(CommonLa ... [详细]
  • 原文地址http://balau82.wordpress.com/2010/02/28/hello-world-for-bare-metal-arm-using-qemu/最开始时 ... [详细]
  • C++ STL复习(13)容器适配器
    STL提供了3种容器适配器,分别为stack栈适配器、queue队列适配器以及priority_queue优先权队列适配器。不同场景下,由于不同的序列式 ... [详细]
  • vue使用
    关键词: ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • Ihaveaworkfolderdirectory.我有一个工作文件夹目录。holderDir.glob(*)>holder[ProjectOne, ... [详细]
  • python中安装并使用redis相关的知识
    本文介绍了在python中安装并使用redis的相关知识,包括redis的数据缓存系统和支持的数据类型,以及在pycharm中安装redis模块和常用的字符串操作。 ... [详细]
author-avatar
乐果Meng_501
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有