首页 > 编程语言 >菜鸟笔记之PWN入门(1.1.1)汇编语言基础与堆栈入门

菜鸟笔记之PWN入门(1.1.1)汇编语言基础与堆栈入门

时间:2024-09-18 16:28:08浏览次数:11  
标签:入门 菜鸟 printf C语言 heap memory PWN AX BX

啥是汇编语言?有啥用?

深入了解计算机底层,我们会发现,计算机实际上只能执行一些非常基础的操作,但其速度却非常快。计算机的CPU只能执行机器码,即由一系列0和1组成的指令。不同的0和1组合会触发计算机中的不同电路,从而进行各种操作。由于这些0和1的组合很长,阅读起来不方便,因此通常以16进制形式显示。然而,即便如此,16进制的表示仍然难以理解。为了简化这一过程,汇编语言应运而生,它用更易读的符号来表示这些机器指令,从而使程序员能够更方便地编写和理解代码。

啥是寄存器?

计算机中的所有指令都是由CPU执行的。在计算机结构中,CPU和内存是分开的,而寄存器则位于CPU内部。CPU可以直接访问寄存器中的数据来执行各种指令操作。在程序执行过程中,数据通常从内存 --> 缓存(cache)--> 寄存器,只有到了寄存器中CPU才能对其进行处理。处理完成后,程序决定是否将寄存器中的数据写回内存,以更新内存中的内容。除了存储数据,寄存器还可以用于存储指令、地址、状态信息和其他控制数据。因此,寄存器在计算机中发挥着至关重要的作用,帮助提高处理速度和效率。
下图表介绍一些常用的寄存器

什么是栈?什么是堆?

先贴一张图用来理清楚堆和栈在程序中的位置

栈的简单介绍

在计算机程序运行时,系统会将可执行文件的text段(代码段)和data段(数据段)加载到内存中。在C语言等编程语言中,函数调用过程中需要传递参数创建局部变量。如果这些数据都存储在data段bss段中,会导致内存空间的浪费,并使得管理变得复杂。
为了高效管理函数的参数和局部变量,并在函数调用结束后释放相关资源,我们使用了是一种后进先出(LIFO)的数据结构,它能够在函数调用时创建栈帧来存储函数的局部变量、参数、返回地址等信息。当函数调用结束时,栈帧会被自动销毁,从而释放内存,避免内存浪费。栈不仅节省内存,还确保了函数调用和返回过程的有序进行。

ESP(栈指针)和 EBP(基址指针)之间的空间被称为栈帧栈帧是一个函数调用的栈上空间,主要用于存储函数的局部变量参数返回地址以及保存的寄存器状态等信息。在每次函数调用时,都会为该函数分配一个新的栈帧,并在函数执行完成后释放这个栈帧。栈帧的结构通常如下:

  • 栈顶 (由 ESP 指针指向):函数调用时,栈顶包含函数的局部变量和临时数据。
  • 栈底 (由 EBP 指针指向):栈底用于存储函数调用的参数和返回地址等。

栈帧的设计使得函数调用和返回变得高效,并且支持递归调用等复杂的函数调用模式。

堆的简单介绍

堆是用于存放进程运行中动态分配的内存段,其大小可以在运行时根据需求调整。调用malloccallocrealloc等函数时,会从堆上分配内存。释放内存时使用free函数,以便回收堆内存。堆内存的管理由程序员负责,不会自动释放,需要手动管理内存的分配和释放。

浅浅总结一下:

用于存放各个函数所需要使用的参数,比如:

#include <stdio.h>
int main() {
    char str[30];  // str是一个局部变量,存储在栈上
    scanf("%29s", str);  // 读取字符串到str中
    printf("%s", str);  // 输出str的内容
    return 0;
}

在这个例子中,str是一个局部数组,分配在栈上。

则是用于存放用户的数据,并且由用户决定什么时候释放它。比如:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUFFER_SIZE 100

void create_heap(char **heap_memory) {
    *heap_memory = (char *)malloc(BUFFER_SIZE * sizeof(char));
    if (*heap_memory == NULL) {
        printf("Memory allocation failed\n");
        exit(1);
    }
    printf("Heap memory created.\n");
}

void edit_heap(char *heap_memory) {
    if (heap_memory == NULL) {
        printf("Heap memory not created yet.\n");
        return;
    }
    printf("Enter a string to store in heap memory: ");
    fgets(heap_memory, BUFFER_SIZE, stdin);

    heap_memory[strcspn(heap_memory, "\n")] = '\0';
    printf("Heap memory updated.\n");
}

void delete_heap(char *heap_memory) {
    if (heap_memory == NULL) {
        printf("Heap memory not created yet.\n");
        return;
    }
    free(heap_memory);
    heap_memory = NULL;
    printf("Heap memory deleted.\n");
}

int main() {
    char *heap_memory = NULL;
    int choice;

    while (1) {
        printf("\nMenu:\n");
        printf("1. Create heap memory\n");
        printf("2. Edit heap memory\n");
        printf("3. Delete heap memory\n");
        printf("4. Exit\n");
        printf("Enter your choice: ");
        scanf("%d", &choice);
        getchar();  

        switch (choice) {
            case 1:
                create_heap(&heap_memory);
                break;
            case 2:
                edit_heap(heap_memory);
                break;
            case 3:
                delete_heap(heap_memory);
                break;
            case 4:
                if (heap_memory != NULL) {
                    free(heap_memory);  
                }
                printf("Exiting program.\n");
                return 0;
            default:
                printf("Invalid choice. Please try again.\n");
                break;
        }
    }
}

(这里例子可能举的有点复杂...但是之后遇到的的题目大多也是类似这样的,所以堆的难度会比大很多,知识量也多很多)
总之上面的代码就是一般堆的用法,不需要理解,只是作为展示,大致内容如下:
输入1,用户可以申请一个堆的空间
输入2,用户可以编辑所申请到的空间
输入3,用户可以删除申请到的空间

常用汇编指令与C语言对比

  1. MOV

    • 功能:将数据从一个位置复制到另一个位置。
    • 汇编MOV AX, 1234h
    • C语言AX = 0x1234;
    • 说明MOV 是把数据从源位置复制到目标位置,类似于C语言中的赋值操作。MOV 不改变源数据,只是复制到目标位置。
  2. ADD / SUB

    • 功能:进行加法和减法运算。
    • 汇编ADD AX, BXAX = AX + BX);SUB CX, 5CX = CX - 5
    • C语言AX += BX;AX = AX + BX);CX -= 5;CX = CX - 5
    • 说明ADD 和 SUB 用于对寄存器或内存中的值进行加减操作,更新结果并设置标志寄存器的状态。
  3. INC / DEC

    • 功能:递增或递减操作数。
    • 汇编INC AXAX = AX + 1);DEC BXBX = BX - 1
    • C语言AX++;AX = AX + 1);BX--;BX = BX - 1
    • 说明INC 和 DEC 只能对寄存器或内存位置操作,不能对立即数操作。
  4. CMP

    • 功能:比较两个值,并设置标志寄存器状态。
    • 汇编CMP AX, BXif (AX == BX)
    • C语言if (AX == BX)AX 和 BX 比较)
    • 说明CMP 实际上是做了 AX - BX 的操作然后判断是否等于0,更新状态标志。
  5. JMP

    • 功能:无条件跳转到指定的地址。
    • 汇编JMP start
    • C语言goto start;
    • 说明JMP 改变程序的执行流,跳转到标记为 start 的位置。
  6. JE / JNE / JZ / JNZ

    • 功能:根据条件跳转到指定地址。
    • 汇编JE equalif (zero flag) goto equal;);JNE not_equalif (not equal) goto not_equal;
    • C语言if (flag == 0) goto equal;JE 跳转条件为零标志);if (flag != 0) goto not_equal;JNE 跳转条件为非零)
    • 说明:这些指令依据先前比较操作的结果决定是否跳转。
  7. CALL / RET

    • 功能:调用和返回函数。
    • 汇编CALL myFunction(调用函数);RET(返回函数)
    • C语言myFunction();(调用函数);return;(从函数返回)
    • 说明CALL 会保存当前的返回地址,并跳转到目标函数;RET 从栈中恢复返回地址并跳转回。
  8. PUSH / POP

    • 功能:压入或弹出栈数据。
    • 汇编PUSH AX(压入栈);POP BX(从栈中弹出)
    • C语言stack.push(AX);(假设有栈操作的C语言函数);BX = stack.pop();(假设有栈操作的C语言函数)
    • 说明PUSH 和 POP 操作栈,PUSH 将数据压入栈顶,POP 从栈顶弹出数据。
  9. NOP

    • 功能:空操作,不产生任何效果。
    • 汇编NOP
    • C语言:没有直接的C语言对应,可以理解为一个空的操作(或者可以理解成C语言的注释符号)。
    • 说明NOP 通常用于占位或调试,不会改变程序状态。
  10. LEA

    • 功能:加载有效地址,将计算得到的地址赋给寄存器。
    • 汇编LEA AX, [BX+SI]
    • C语言AX = &array[BX + SI];(假设 array 是一个数组)
    • 说明LEA 计算一个地址并将其存入寄存器,类似于获取指针地址而不实际访问内存。
  11. AND / OR / XOR / NOT

    • 功能:按位操作。
    • 汇编AND AX, BX(按位与);OR AX, BX(按位或);XOR AX, BX(按位异或);NOT AX(按位取反)
    • C语言AX = AX & BX;(按位与);AX = AX | BX;(按位或);AX = AX ^ BX;(按位异或);AX = ~AX;(按位取反)
    • 说明:这些指令用于位级操作,AND 和 OR 用于逻辑运算,XOR 用于位翻转,NOT 对每一位取反。

这里重点介绍一下PUSH POP 这两个指令
PUSHPOP是对进行操作的指令

我 是 栈 ↓
  ----
 |  5 |  <- 栈底ebp:注意,我是栈底,我在高地址
  ----
 |  4 |
  ----
 |  3 |
  ----
 |  2 |
  ----
 |  1 |  <- 栈顶esp:注意,我是栈顶,我在低地址
  ----
假设这是栈最开始的样子
假设:
  eax = 6
  ebx = 7

我浅浅画了一个非常抽象的,但是这并不影响我们理解它。
当我们执行 POP ebx 这个指令后,那么就会让栈变成这个样子↓

我 是 栈 ↓
  ----
 |  5 |  <- 栈底ebp:我不动,与我无瓜
  ----
 |  4 |
  ----
 |  3 |
  ----
 |  2 |  <- 栈顶esp:执行完POP后,我会向高地址移动,现在我指向2了
  ----
 |  1 |  <-- 1没有消失,只是不在esp和ebp之间的栈帧了,这导致我们无法直接访问
  ----

  eax = 6
  ebx = 1 <-- 注意注意,ebx变成1了

然后来看看PUSH eax

我 是 栈 ↓
  ----
 |  5 |  <- 栈底ebp:我还是不动,依旧与我无瓜
  ----
 |  4 |
  ----
 |  3 |
  ----
 |  2 |  
  ----
 |  6 |  <- 栈顶esp:执行完PUSH后,我会向低地址地址移动,并且将eax的值,也就是6   ----      放入栈当中,替换掉了1
  
  eax = 6
  ebx = 1 

为什么函数调用需要用栈

首先为什么后进先出(LIFO),这样的设计是因为程序的执行符合一种将复杂的大问题拆解成一个个小问题来解决的思想。
大问题的解决需要小问题的答案,而小问题得到答案之后就可以抛弃了。
比如:

#include <stdio.h> // 如果需要使用标准输入输出函数

void func1() {
    printf("hello");
}
void func2() {
    func1();
}
void func3() {
    func2();
}
int main() {
    func3();
    return 0;
}

那么这个程序的执行流程就是 main --> func1 --> func2 --> func3 --> printf
那么栈的空间就是:

  ---------------
 | main 的栈空间  |  <- 栈底 ebp(高地址)
  ---------------
 | func1 的栈空间 |
  ---------------
 | func2 的栈空间 |
  ---------------
 | func3 的栈空间 |
  ---------------
 | printf 的栈空间|  <- 栈顶 esp(低地址)
  ---------------

我们得出规律,大问题函数程序总是最后消失
也就是调用者的生命周期总是长于被调用者
这恰好符合了FILO的特点。所以一定不是被随意设计的,而是一种完美符合计算机程序设计思想的一种数据结构

参考文献:
什么是堆?什么是栈?他们之间有什么区别和联系? - tolin - 博客园 (cnblogs.com)
PWN入门(1-1-2)-bss段、data段、text段、堆(heap)和栈(stack) (yuque.com)
在x86架构中的寄存器 - 知乎 (zhihu.com)
什么是栈,为什么函数式编程语言都离不开栈?_没有栈,都是跟栈有什么关系-CSDN博客
PWN入门(1-1-1)-C函数调用过程原理及函数栈帧分析(Intel) (yuque.com)
linux - C函数调用过程原理及函数栈帧分析 - 编程之道 - SegmentFault 思否

标签:入门,菜鸟,printf,C语言,heap,memory,PWN,AX,BX
From: https://www.cnblogs.com/XiDP0/p/18417560

相关文章

  • 菜鸟笔记之PWN入门(1.1.3)Linux基础操作和ELF文件保护
    这里不讨论Linux的历史及其与Windows的比较。直接介绍一些简单基础的操作。首先我们需要安装一个Linux操作系统(首先推荐Ubuntu),我们需要安装一个VM虚拟机,然后在里面搭建一个Ubuntu的虚拟机可以直接百度搜索,这里推荐一个文章安装虚拟机(VMware)保姆级教程(附安装包)_vmware虚拟机-......
  • 菜鸟笔记之PWN入门(1.1.2)C程序调用过程与函数栈变化(32位 vs 64位)(Intel)
    本文使用Intel的32位为例子进行举例。64位本质上和32位类似,主要区别在于函数参数的调用方式,文章结尾会简要提及。重新回顾一下栈pop和push指令//将0x50的压入栈push0x50//将esp指向的数据放入指定的寄存器中pop寄存器名字比如:popeax执行之后eax的值就变成了0x50......
  • 菜鸟笔记之PWN入门(1.1.0)ELF 文件格式和程序段解析(简版)
    ELF(ExecutableandLinkableFormat):是一种用于可执行文件、目标文件和库的文件格式,类似于Windows下的PE文件格式。ELF主要包括三种类型的文件:可重定位文件(relocatable):编译器和汇编器产生的 .o 文件,由 Linker 处理。可执行文件(executable): Linker ......
  • Transformer从入门到精通的实战指南看这本书就够了—《Transformers in Action》(附PDF
    前言TransformersinAction将革命性的Transformers架构添加到您的AI工具包中。您将深入了解模型架构的基本细节,通过易于理解的示例和巧妙的类比解释所有复杂的概念-从袜子分类到滑雪!即使是复杂的基础概念也从实际应用开始,因此您永远不必为抽象理论而苦恼。这本书包括一个广......
  • 教育培训小程序开发,简单实用的入门指南
    教育培训小程序可以帮助教育机构和个人老师提供更灵活的在线教学服务,满足学生的学习需求。对于初学者来说,开发一个功能齐全的教育培训小程序并不复杂,只需掌握一些基础的开发知识和工具即可。本文将带你了解如何使用微信小程序开发工具,创建一个简单实用的教育培训小程序,并展示一些关......
  • ESP32使用microPython编程入门
    网络ESP32教程地址:https://www.itprojects.cn/coursecenter-hardware.html 一、Python+ESP32快速上手1.整体流程说明(EPS32-S3类似)2.下载&安装Thonny(EPS32-S3类似)3.下载MicroPython (EPS32-S3类似)不一样的地方有:3.1下载EPS32-S3的MicroPython固件,此处下载地址不一......
  • 图形学系列教程,带你从零开始入门图形学(包含配套代码)—— 透明度和深度
    图形学系列专栏序章初探图形编程第1章你的第一个三角形第2章变换顶点变换视图矩阵&帧速率第3章纹理映射第4章透明度和深度第5章裁剪区域和模板缓冲区第6章场景图第7章场景管理第8章索引缓冲区第9章骨骼动画第10章后处理第11章实时光照(一)第12章实时光照(二)......
  • 【2024年最新】AI教程-AI大模型知识,零基础入门到精通
    1、什么是AIAI(ArtificialIntelligence)是人工智能的缩写,通俗地讲,AI就是让机器或计算机系统能够模仿、延伸和扩展人类的智能,执行一些通常需要人类智能才能完成的任务。AI的目标是让机器能够胜任一些通常需要人类智能才能完成的复杂工作。AI可以让机器......
  • 20个Python入门基础语法要点
    今天,我们将聚焦于Python的20个基础语法要点,让你的编程之旅更加顺畅。第一部分:环境搭建与基本概念1.Hello,World!你的第一行代码:这是编程旅程的传统起点。这行代码告诉Python显示文本,print是关键函数,用于输出信息。2.变量与赋值存储信息的盒子:变量就像容器,用来......
  • 从小白到入门,写给程序员的LLM学习指南
    年初的时候,我第一次接触了ChatGPT,在被深深震撼之后,我意识到一个新的时代正在来临,作为程序员的我有了从未有过的危机感,经过过去几个月的学习,我逐渐度过了不知所措的阶段,慢慢地对以ChatGPT为代表的LLM有了一些感觉,这篇文章就把过去这段时间的学习整理成一个学习路线图,希望能对......