【pwn入门】用gdb调试32位程序

声明

本文是B站你想有多PWN学习的笔记,包含一些视频外的扩展知识。

问题源码

#include 
#include 
#include 
char sh[]="/bin/sh";
int func(char *cmd){
	system(cmd);
	return 0;
}

int main(){
    char a[8] = {};
    char b[8] = {};
	puts("input:");
	gets(a);  // gets函数可以读取超过8个字节的数据,然后写入a,造成越界写b
	printf(a);
	if(b[0]=='a'){ // b数组出现'a',即进入获取shell的分支
		func(sh);
	}
    return 0;
}

编译调试

编译32位的程序

说明:默认64位系统编译64位的程序,如果要编译32位需要添加-m参数,同时需要安装32位的编译支持,参考【pwn入门】基础知识

gcc -m32 question_1.c -o question_1_x86

【pwn入门】用gdb调试32位程序_第1张图片

直接hack

【pwn入门】用gdb调试32位程序_第2张图片

用gdb调试理解这个过程

  1. 反汇编main函数
    disassemble main
    可以看到32位的地址长度只有64位的一半
    【pwn入门】用gdb调试32位程序_第3张图片
    注意这里的0x00001362是反汇编出来的地址偏移,并不是内存中的实际地址。
  2. 获取可以打断点的内存地址
    要获取内存实际的地址,可以用x命令

【pwn入门】用gdb调试32位程序_第4张图片

x/40i $eip

【pwn入门】用gdb调试32位程序_第5张图片

  1. 打断点
b *0x56556379

【pwn入门】用gdb调试32位程序_第6张图片

  1. 输入8个b,一个a

【pwn入门】用gdb调试32位程序_第7张图片
5. 查看内存中的值
在这里插入图片描述
6. eax赋值前查看寄存器的值

没有执行赋值之前,查看eax寄存器的值
【pwn入门】用gdb调试32位程序_第8张图片
7. 查看执行赋值后eax的值
【pwn入门】用gdb调试32位程序_第9张图片
【pwn入门】用gdb调试32位程序_第10张图片
8. 查看程序的执行流程【pwn入门】用gdb调试32位程序_第11张图片9. 验证
多次执行ni命令
【pwn入门】用gdb调试32位程序_第12张图片

32位跟64位的区别

1.地址长度不一样
2.寄存器的名字不一样
32位中以e开头,64位中以r开头。
32位寄存器
eax:通常用来存放函数调用的返回值
esp:栈顶指针,指向栈的顶部
ebp:栈底指针,指向栈的底部,通常用ebp+偏移量的形式来定位函数存放在栈中的局部变量
eip:指针寄存器(instruction pointer) 这个寄存器保持着下一条要执行的指令的地址

64位寄存器
rax:通常用于存储函数调用返回值
rsp:栈顶指针,指向栈的顶部
rbp:存放当前栈帧的栈底地址
rip:指针寄存器(instruction pointer) 这个寄存器保持着下一条要执行的指令的地址
3.同一个源码,编译出的汇编指令不一样。

你可能感兴趣的:(PWN,pwn,网络安全,二进制)