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

GDB动态调试攻防世界SimpleCheck100

文章目录题目IDA静态分析gdb动态调试gdb基本使用gdbpeda插件函数校验绕过总结题目攻防世界Reverse高手区题目链接simple-check-100,如

文章目录

  • 题目
  • IDA静态分析
  • gdb动态调试
    • gdb 基本使用
    • gdb peda插件
    • 函数校验绕过
  • 总结


题目

攻防世界 Reverse 高手区题目链接 simple-check-100,如下:
在这里插入图片描述解压缩得到三个文件:
在这里插入图片描述三个文件依次是一个 32 位 elf,一个 64 位 elf 和一个 32 位 exe。

ELF 文件 (Executable Linkable Format) 是一种用于二进制文件、可执行文件、目标代码、共享库和核心转储格式文件。Linux 下的目标文件和可执行文件都按照该格式进行存储,它是 Linux 的主要可执行文件格式。


IDA静态分析

1、查壳发现未加壳:
在这里插入图片描述
2、这 3 个文件拖进 IDA 后的反汇编结果是大体一致的,以 64 位 elf 文件为例进行分析,定位到 main 函数:
在这里插入图片描述3、按 F5 查看反汇编结果的的 C 语言伪代码:
在这里插入图片描述完整代码如下:

int __cdecl main(int argc, const char **argv, const char **envp)
{void *v3; // rspconst char **v5; // [rsp+0h] [rbp-60h] BYREFint v6; // [rsp+Ch] [rbp-54h]char v7[28]; // [rsp+1Ch] [rbp-44h] BYREF__int64 v8; // [rsp+38h] [rbp-28h]const char ***v9; // [rsp+40h] [rbp-20h]unsigned __int64 v10; // [rsp+48h] [rbp-18h]v6 = argc;v5 = argv;v10 = __readfsqword(0x28u);v7[0] = 84;v7[1] = -56;v7[2] = 126;v7[3] = -29;v7[4] = 100;v7[5] = -57;v7[6] = 22;v7[7] = -102;v7[8] = -51;v7[9] = 17;v7[10] = 101;v7[11] = 50;v7[12] = 45;v7[13] = -29;v7[14] = -45;v7[15] = 67;v7[16] = -110;v7[17] = -87;v7[18] = -99;v7[19] = -46;v7[20] = -26;v7[21] = 109;v7[22] = 44;v7[23] = -45;v7[24] = -74;v7[25] = -67;v7[26] = -2;v7[27] = 106;v8 = 19LL;v3 = alloca(32LL);v9 = &v5;printf("Key: ");__isoc99_scanf("%s", v9);if ( (unsigned int)check_key(v9) )interesting_function(v7);elseputs("Wrong");return 0;
}

可以看到,程序的核心是让输入一个字符串,然后使用 check_key 函数进行判断,如果返回非 0(为真),则执行 interesting_fuction 函数。

4、双击跟进查看 interesting_fuction 函数伪代码:
在这里插入图片描述该函数对输入的 v7(未知)进行加密处理,最后 putchar 输出。

5、check_key 函数是一个计算校验和与正确的校验和对比的一个函数:
在这里插入图片描述
解题思路

只要让程序绕过 check_key 函数的检查,强行执行 interesting_function 函数,就能获得目标 Flag。故可以对程序进行动态调试,将 check_key 的返回结果改为 1,就能调用 interesting_function 函数并得到正确的 key。

gdb动态调试

GDB (GNU Debugger)是一个由 GNU 开源组织发布的、UNIX/LINUX 操作系统下的、基于命令行的、功能强大的程序调试工具。像所有的调试器一样,GDB 可以让你调试一个程序,包括让程序在你希望的地方停下,此时你可以查看变量、寄存器、内存及堆栈,更进一步你可以修改变量及内存值。对于一名 Linux 下工作的 C/C++ 程序员或逆向工作者,gdb 是必不可少的工具。

基础使用教程:linux下gdb调试方法与技巧整理、CTF 竞赛入门指南(CTF All In One)。


gdb 基本使用

gdb 的常用命令如下:
在这里插入图片描述
本人在自己的 VPS 服务器(Centos8)上安装 gdb,步骤如下:

#安装C++编译器
yum install gcc gcc-c++
#下载源码包
wget http://ftp.gnu.org/gnu/gdb/gdb-10.2.tar.gz
#编译安装
tar -zxvf gdb-10.2.tar.gz
cd gdb-10.2
./configure --with-python=/usr/bin/python --enable-targets=all
make
sudo make install
#查看是否安装成功
gdb -v

注意防坑】编译 gdb 时必须加上--with-python参数指定本地的 Python 路径,否则后续使用 gdb 插件时将各种报错(为此我浪费了整整一天……最终参照 博文 找到了该解决的办法)。

如下已成功安装 gdb 工具:
在这里插入图片描述
GDB基础用法演示

下面给出一个具有 test.c 的程序:

#include
int getSum(int n) {int sum&#61;0,i;for (i&#61;1;i<&#61;n;i&#43;&#43;)sum&#43;&#61;i;return sum;
}
int main(){int res&#61;getSum(100);printf("1&#43;2&#43;...&#43;100&#61;%d\n",res);
}

1、使用 gcc 编译 C 语言程序&#xff1a;
在这里插入图片描述
【注意】如果要调试程序&#xff0c;则在进行 gcc 编译的时候要加上 -g 参数&#xff08;表示 debug 模式&#xff09;&#xff0c;即gcc -g test.c -o test (如果是 C&#43;&#43; 程序的话则是g&#43;&#43; -g test.cpp -o test&#xff09;。如果没有 -g 参数&#xff0c;你将看不见程序的函数名、变量名&#xff0c;所代替的全是运行时的内存地址。

2、执行命令 gdb test&#xff0c;开始使用 GDB 对生成的 test 可执行程序进行调试&#xff08;GDB 会显示自己的提示符 gbd&#xff0c;提示并等待你输入调试命令&#xff09;&#xff1a;
在这里插入图片描述3、输入l命令&#xff08;相当于 list&#xff09;&#xff0c;gdb 将从第一行开始列出源码&#xff08;默认前 10 行&#xff09;&#xff1a;
在这里插入图片描述
直接回车表示&#xff0c;重复上一次命令&#xff08;继续输出第 10-20 行的源码&#xff09;&#xff1a;
在这里插入图片描述
4、执行命令break 9break getSum&#xff0c;表示在第 9 行处、getSum 函数处设置断点&#xff0c;同时执行命令info break可查看设置的断点信息&#xff1a;
在这里插入图片描述
5、执行命令run(简写 r) &#xff0c;开始从头运行程序&#xff0c;直到程序结束或者遇到断点并等待下一个命令&#xff1a;
在这里插入图片描述
6、执行命令 continue&#xff08;简写 c&#xff09;&#xff0c;表示从暂停处继续运行程序&#xff1a;
在这里插入图片描述
7、执行 step 命令&#xff0c;表示向前执行一步&#xff08;可进入被调用函数中&#xff09;&#xff0c;进一步可利用 print i&#xff08;变量名&#xff09;来查看变量的值&#xff1a;
在这里插入图片描述
8、执行命令 backtrace&#xff08;简写 bt&#xff09;&#xff0c;可查询当前函数调用栈&#xff0c;执行命令 finish&#xff0c;可退出当前函数并返回到上层函数中&#xff08;本例为 main 主函数&#xff09;&#xff1a;
在这里插入图片描述
9、执行命令set res &#61; 6666&#xff0c;可改变程序中指定变量的值&#xff1a;
在这里插入图片描述
10、info reg 命令可查看寄存器使用情况&#xff0c;info stack命令可查看堆栈使用情况&#xff1a;
在这里插入图片描述
最后执行命令 quit&#xff08;简写 q&#xff09;&#xff0c;即可退出 gdb&#xff1a;
在这里插入图片描述
而未被篡改变量值的程序正常的运行输出应当如下&#xff1a;
在这里插入图片描述

gdb peda插件

从上面的演示实例中也可以看出&#xff0c;gdb 非常强大&#xff0c;但是在调试过程中对于需要查看的辅助信息&#xff08;如寄存器信息&#xff09;都要手动输入命令&#xff0c;未免有点麻烦&#xff0c;所以就出现了插件&#xff0c;把某一些经常要查看的信息每一步都自动帮你显示出来&#xff0c;方便调试。一般来说有常用的 3 个 GDB 插件&#xff1a;peda、gef、gdbinit。
&#xff0c;完整介绍可参见&#xff1a;GDB的三个插件&#xff08;gef gdbinit peda&#xff09;。Github 上已经有人把这 3 个插件的项目合成了一个&#xff0c;使得插件的安装使用很方便&#xff1a;

# 从 Github 将汇聚了 gdb 的 3 个插件的项目拷贝到本地
git clone https://github.com/gatieme/GdbPlugins.git ~/GdbPlugin
# GdbPlugins 文件夹包含的 3 个插件对应启动命令&#xff1a;
echo "source ~/GdbPlugins/peda/peda.py" > ~/.gdbinit
echo "source ~/GdbPlugins/gef/gef.py" > ~/.gdbinit
echo "source ~/GdbPlugins/gdbinit/gdbinit" > ~/.gdbinit

成功克隆到本地后可以看到包含 3 个插件的文件夹&#xff1a;
在这里插入图片描述
下文将介绍其中的 peda 插件——peda 是 gdb 调试工具的插件&#xff0c;用于增强 gdb 的调试能力&#xff0c;同时增强 gdb 的显示&#xff1a;在调试过程中着色并显示反汇编代码&#xff0c;寄存器和内存信息&#xff08;单纯的 gdb 在内存信息、汇编信息的显示和查看上的不方便&#xff09;。

1、设置 gdb 以 peda 插件的执行形式启动&#xff0c;并调试上面编译好的 test 程序&#xff1a;
在这里插入图片描述
2、输入 start 命令开始调试程序&#xff0c;从下图中可以看到寄存器 (registers)&#xff0c;汇编代码 (code)&#xff0c;栈空间数据 (stack) 等信息&#xff1a;
在这里插入图片描述

在前面的文章 浅析缓冲区溢出漏洞的利用与Shellcode编写 中曾经介绍了函数调用过程中的内存堆栈变化&#xff0c;建议读者同步阅读博文 基于GDB-peda汇编调试理解函数调用栈 &#xff0c;作者利用 peda 插件来汇编调试一段程序&#xff0c;帮助深入理解函数调用栈。

函数校验绕过

返回到 CTF 题目中&#xff0c;在 Linux 中正常运行程序如下&#xff1a;
在这里插入图片描述
下面开始借助 gdb 对程序进行动态调试&#xff0c;将 check_key 函数的返回结果改为真即可正确的 key。

1、启动 gdb 调试程序&#xff0c;执行命令 break main 在 main 函数设置断点&#xff08;Breakpoint 1 at 0x4007c0&#xff09;&#xff0c;然后执行命令 run 开始运行程序&#xff1a;
在这里插入图片描述程序暂停在断点处&#xff1a;
在这里插入图片描述

2、上述程序暂停在 main 函数断点处&#xff0c;执行命令 next 开始一步步单步执行程序&#xff08;一直按回车键重复执行 next 命令即可&#xff09;&#xff0c;直到运行至 check_key 函数所在位置&#xff0c;随意输入 key 之后会有判断函数&#xff0c;所以注意看 check_key 所在位置&#xff1a;
在这里插入图片描述3、当判断函数执行完之后&#xff0c;再次跳到test eax, eax时候&#xff0c;可以用printi $eax查看寄存器的值&#xff0c;发现是 0&#xff1a;
在这里插入图片描述4、这样的话不会跳转藏有 flag 函数的位置&#xff0c;所以执行命令 set $eax&#61;1&#xff0c;手动篡改寄存器 eax 的值&#xff0c;最后执行命令 continue&#xff0c;运行程序直至程序终止&#xff0c;可获得 flag 值如下&#xff1a;
在这里插入图片描述提交 flag&#xff0c;over&#xff01;
在这里插入图片描述

总结

本文通过一道 CTF 题目&#xff0c;学习记录了 GDB 调试工具及其 peda 插件的使用&#xff0c;实现了对二进制程序的内存数值进行篡改并成功绕过程序的逻辑校验的目的&#xff0c;这有点类似于 Android 中使用 Frida 对 APP 的函数返回值进行 hook 拦截和篡改。


推荐阅读
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 本文介绍了PHP常量的定义和使用方法,包括常量的命名规则、大小写敏感性、全局范围和标量数据的限制。同时还提到了应尽量避免定义resource常量,并给出了使用define()函数定义常量的示例。 ... [详细]
  • 本文详细介绍了GetModuleFileName函数的用法,该函数可以用于获取当前模块所在的路径,方便进行文件操作和读取配置信息。文章通过示例代码和详细的解释,帮助读者理解和使用该函数。同时,还提供了相关的API函数声明和说明。 ... [详细]
  • 电话号码的字母组合解题思路和代码示例
    本文介绍了力扣题目《电话号码的字母组合》的解题思路和代码示例。通过使用哈希表和递归求解的方法,可以将给定的电话号码转换为对应的字母组合。详细的解题思路和代码示例可以帮助读者更好地理解和实现该题目。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • WhenIusepythontoapplythepymysqlmoduletoaddafieldtoatableinthemysqldatabase,itdo ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • Python爬虫中使用正则表达式的方法和注意事项
    本文介绍了在Python爬虫中使用正则表达式的方法和注意事项。首先解释了爬虫的四个主要步骤,并强调了正则表达式在数据处理中的重要性。然后详细介绍了正则表达式的概念和用法,包括检索、替换和过滤文本的功能。同时提到了re模块是Python内置的用于处理正则表达式的模块,并给出了使用正则表达式时需要注意的特殊字符转义和原始字符串的用法。通过本文的学习,读者可以掌握在Python爬虫中使用正则表达式的技巧和方法。 ... [详细]
  • 本文讨论了编写可保护的代码的重要性,包括提高代码的可读性、可调试性和直观性。同时介绍了优化代码的方法,如代码格式化、解释函数和提炼函数等。还提到了一些常见的坏代码味道,如不规范的命名、重复代码、过长的函数和参数列表等。最后,介绍了如何处理数据泥团和进行函数重构,以提高代码质量和可维护性。 ... [详细]
author-avatar
陈怡伶翰纬
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有