目录
1:纪念一下第一个自己独立做出来re题(虽然很简单):
2:攻防世界新手区no-strings-attached复现:
3:攻防世界simple-check-100复现:
1:纪念一下第一个自己独立做出来re题(虽然很简单):
open-source复现:
给出一段c源码:
#include <stdio.h>#include <string.h>int main(int argc, char *argv[]) {if (argc != 4) {printf("what?\n");exit(1);}unsigned int first = atoi(argv[1]);if (first != 0xcafe) {printf("you are wrong, sorry.\n");exit(2);}unsigned int second = atoi(argv[2]);if (second % 5 == 3 || second % 17 != 8) {printf("ha, you won't get it!\n");exit(3);}if (strcmp("h4cky0u", argv[3])) {printf("so close, dude!\n");exit(4);}printf("Brr wrrr grr\n");unsigned int hash = first * 31337 + (second % 17) * 11 + strlen(argv[3]) - 1615810207;printf("Get your key: ");printf("%x\n", hash);return 0;}
分析:方法1:
C 库函数 int atoi(const char *str) 把参数 str 所指向的字符串转换为一个整数(类型为 int 型)。
First=0xcafe=51966D
Second%17=8
argv[3]= "h4cky0u"
方法2,发现有些人是把c++源码编译成exe文件直接运行生成flag的,学习了如何生成exe文件的方法:
但会发现,把这个exe文件放在别的电脑上不一定能执行,因为缺少运行环境,以vc++2010所需要的运行时环境为例,发现生成的exe文件闪退的话,开头加上#include <stdlib.h>;在main函数的末尾加上 system("pause"); 如果有 return ;,那么加在 return ; 的前面。
总结:
1:学习了怎么通过c++生成exe文件
2:学习了生成的exe文件闪退的解决方法
3:关于c++的一些基础语法可以了解一下
学习了ida的断点调试、idapy脚本、Linux下gdb动态调试的使用:
2:攻防世界新手区no-strings-attached复现:
方法1:脚本求解:
查壳,发现是Linux elf 格式的可执行文件,于是去虚拟机运行,并没有发现什么有价值的东西,并且出错了
Main函数,逐一分析main函数里的函数,发现authenticate()函数中有字符串比较:
跟进authenticate()函数:
意思是&s, &dword_8048A90中的值解密赋给s2,键盘输入赋给ws,s2和ws进行比较是否相等,可得s2就是要找的flag,其中有一些看不懂的函数:
- fgetws/fgets(ws,n,stdin) 函数中的 stdin 表示标准输入,如键盘输入。函数作用是判断ws输入值是否为空
- wcslen()函数:返回字符串的长度,\0之前的字符长度
跟进decrypt函数,s2是怎么加密的:
malloc()函数向系统申请分配size字节的内存空间。
dest存储了s的值,用s的每一个字符和a2相减得到新值,注意这里有两个循环,a2的字符数比s少,所以a2可以多次循环直到s的字符串减完。
找到&s, &dword_8048A90中的值,这里可以用idapy脚本分别提取ascii码值(File->script command),发现并没有什么用,于是shift+e导出10进制值:
导出10进制:
两个参数的类型都是 wchar_t 类型(长度 16 位或 32 位,即2字节或4 字节),显然这里是32位即4字节的变量,4字节为一个整体,所以删除后面 4 个字节的 0,也可以不删。
写脚本:
方法2:ida下断点动调:
准备工作,因为是Linux下的elf文件,所以ida动调要连接远程Linux虚拟机:
提取s2的值:
F9运行,出现提示框:
点ok后进入ida动态调试:
双击eax:
Idapython运行一下,提取字符(File->script command):
方法3:Gdb动调(gdb是基于Linux下的,因为本题的文件是Linux的elf文件):
找到该函数下的汇编语句(text view跳转),发现decrypt函数返回的值存在0x8048725地址处的eax处:
用gdb动态调试:
gdb 123 -q——启动gdb并导入文件:
在decrypt函数处下断点:
r运行至decrypt断点处,此处的地址是0x804865c:
n单步步过,执行0x804865c处decrypt函数的命令:
i r查看此时寄存器值
x/6sw $eax,显示eax寄存器中前6行数据
6:显示6行数据
s:字符串形式
w:word(4字节)形式
发现不能用OD动调,因为OD只能调试32位的pe文件,而该文件是elf文件,现在发现除了OD,可以进行动调的还有Linux下的gdb、ida
进阶:
3:攻防世界simple-check-100复现:
解压出来3个文件:
main函数:
这道题有些意思,发现check_key函数里输入的值v39只和if条件为真有关,和interesting_function函数最后输出的flag值无关,所以想直接interesting_function函数写脚本求解,但是发现a1是一个十进制数,v6=a1,也就是v3值是a1各内存单元里的值,但是不知道怎么提取,所以就不知道静态怎么做,试试动态调试。
动态调试的话,可以用ida调试exe文件,修改eax值,使check函数为真
Ida调试exe文件
准备:
Ida准备:
Hostname选择127.0.0.1,最后点F9运行进入调试界面
在004015A4、004015B3处下断点,命令行key:输入任意值,回车运行至第一个断点处,修改eax返回值,使if条件为真,F9运行至第二个断点处。同时输出flag
F9继续运行
发现是乱码,不是正确的flag,于是使用压缩包里的elf文件。
除更改eax返回值外,还可以阻止jz跳转(把jz改成nop或其他无关指令,下断点运行)
将004015A6处的指令修改为任意指令,F9
修改汇编指令:
方法一:
方法二:
F2保存
也可以用OD调试exe文件。
ctrl+g跳转至004015A4处,下断点F9,je跳转命令用nop填充,F8单步步过至调用完interesting_function函数(call 00401432),输出flag,当然也通过可以更改eax返回值为1的发生输出flag
发现给的压缩包里除了exe还有elf文件,也试试Linux下的gdb动态调试。
介绍gdb:gdb(GNU Debugger),可用于在开发程序时检查正在运行的进程并解决问题。设置断点是学习使用 GNU 调试器的第一步。程序在达到断点时停止,可以运行 gdb 的命令对其进行检查或更改变量,然后再允许该程序继续运行。
简而言之,gdb是Linux下的调试器,可以调试elf文件,类似于windows下的OD。
思路:改变check_key函数的返回值(set $eax=1),使函数条件为真,c继续运行输出flag
gdb
File XXX 是导入XXX文件的意思——相当于gdb XXX -q
gdb 111 -q 启动gdb并导入文件111
b main 在main函数处下断点,也可以直接b *0x4008dd
r 运行
现在运行至0x4007c0地址处 |
n 单步运行直到运行至0x4008E2处,此时已调用了check_key函数,产生 eax返回值,为使if条件为真,把eax返回值修改为1
set $eax=1
(i r eax 查看eax的值)
c 继续运行,输出flag
总结:
1:ida中text view汇编语句的理解,注意和伪代码对应
2:eax里保存函数返回值
3:gdb调试器的命令使用
4:test命令:
含义:test AX,BX 与add AX,BX命令有相同效果,只是test指令不改变AX和BX的内容,而add指令会把结果保存到AX中。
用法:用来测试一方寄存器是否为空,如果eax相加的临时值为零,设置ZF零标志为1,jz跳转至else,所以该题要不使 jz执行,就要让eax不为0,可以设置为1,这是把eax返回值修改为1的汇编层面解释。
Ps:jnz跳转的条件和jz相反,jnz是text相加的临时值为1, ZF=0
Ps:peda一款实用的GDB插件增强gdb的显示:在调试过程中着色并显示反汇编代码,寄存器和内存信息。可以学习怎么安装peda。
Ps:elf文件和pe文件:
PE是windows引入的一种可执行文件格式,该格式和Linux系统的ELF文件格式同源,都是由COFF格式发展而来。