radare2逆向笔记
最近刚开始学习逆向(Reverse Engineering), 发现其学习曲线也是挺陡峭的, 而网上的
许多writeup文章主旨总结就六个字:"你们看我屌吗?" ...几近炫技而对初学者不太友好.
所以我打算以初学者的身份来写写自己从入门到深入的经历.
准备
当前许多逆向的writeup倾向于使用IDA-Pro, 而且似乎都依赖于F5(反编译的快捷键), 直接
从二进制文件转成了可读的C代码. 这对于实际工作来说也许是个捷径, 但对于学习来说却
没什么好处. 所以本文逆向采用了另一个开源的(但也同样强大的)二进制分析工具--Radare2.
如果你是个资深的逆向人员, 那么从本文也可以了解下radare2的一些功能.
知识准备
逆向软件的时候往往面对的是汇编代码, 所以对于指令集要有个大致的认识, 另外对于一些
模式(pattern), 比如函数入口(prologue), 出口(epilogue)和函数调用约定(calling convention)
等也要有所了解. 关于这类知识可以将RE4B(Reverse Engineering for Beginners)
这本书作为参考. 书虽然比较厚, 但比较全面, 包括了X86/ARM/MIPS的内容和许多有趣的历史典故,
一开始可以粗略扫一遍, 遇到问题再回头仔细阅读相关部分即可.
工具准备
当了解了基本汇编知识后(目前x86足矣), 就可以开始准备工具了. 说起工具我想起了一个寓言:
年轻人学有所成, 出山前问师父: "我准备练习武器, 请问哪种武器能让我战无不胜呢?"
师父说: "武器? 如果你的武器比你的头脑更加锋利, 那你将一无是处".
无论何时, 个人的头脑和思维永远是最重要的, 而武器只是工具, 永远不要让工具取代了你的思考.
当然也不是要你肉眼反汇编, 总之...你懂就行了! 我在Linux环境工作, 用到的几个工具如下:
- radare2工具集(用于静态分析)
- gdb(用于调试)
- peda(一个gdb的插件)
目标准备
初步打算是这一系列逆向文章使用IOLI的crackme文件来作为目标, 总共3个平台(Linux/Win32和Arm),
每个平台有10个二进制文件, 都是从同样的源码编译而来的. 可以从radare的git上下载.
crackme0x00
好的, 这是第一个目标, 首先了解你的敌人:
rabin2 -I crackme0x00
rabin2
是radare2
套件中的一个工具, 主要用来提取二进制文件中的信息, 输出如下:
arch x86
binsz 7537
bintype elf
bits 32
canary false
class ELF32
crypto false
endian little
havecode true
intrp /lib/ld-linux.so.2
lang c
linenum true
lsyms true
machine Intel 80386
maxopsz 16
minopsz 1
nx true
os linux
pcalign 0
pic false
relocs true
relro partial
rpath NONE
static false
stripped false
subsys linux
va true
然后查看.rodata
字段里的字符串:
rabin2 -z crackme0x00
输出如下:
000 0x00000568 0x08048568 24 25 (.rodata) ascii IOLI Crackme Level 0x00\n
001 0x00000581 0x08048581 10 11 (.rodata) ascii Password:
002 0x0000058f 0x0804858f 6 7 (.rodata) ascii 250382
003 0x00000596 0x08048596 18 19 (.rodata) ascii Invalid Password!\n
004 0x000005a9 0x080485a9 15 16 (.rodata) ascii Password OK :)\n
运行一下该程序:
$ ./crackme0x00
IOLI Crackme Level 0x00
Password: 123456
Invalid Password!
看样子是要输入密码, 从rabin2的字符串输出里看到250382
也许就是密码, 我们可以输入试试:
$ ./crackme0x00
IOLI Crackme Level 0x00
Password: 250382
Password OK :)
好吧! 看样子确实是. 毕竟是第一关, 有点简单了. 但我还是先假装不知道吧:)
如果目的是进入到Password OK
分支, 那么我们可以有多种解法, 如分析密码的算法,
修改原文件(打patch), 利用漏洞, fuzzy等, 下面挑几个说说.
解法1: 逆向分析
话不多说, 打开radare2:
r2 -A crackme0x00
进入后自动跳转到了函数入口0x08048360, 然后用pdf命令来查看汇编代码:
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze len bytes of instructions for references (aar)
[x] Analyze function calls (aac)
[x] Use -AA or aaaa to perform additional experimental analysis.
[x] Constructing a function name for fcn.* and sym.func.* functions (aan)
-- You can 'copy/paste' bytes using the cursor in visual mode 'c' and using the 'y' and 'Y' keys
[0x08048360]> pdf @ sym.main
pdf表示p(打印)d(反汇编)f(函数), @表示取地址, sym.main为函数符号, 也可以用十六进制整数地址表示.
在r2中查看这些指令的帮助只要在后面输入?
即可, 比如p?
查看打印类的命令,pd?
查看打印反汇编类的命令.
打印反汇编的输出如下:
;-- main:
/ (fcn) main 127
| main ();
| ; var int local_18h @ ebp-0x18
| ; var int local_4h @ esp+0x4
| ; DATA XREF from 0x08048377 (entry0)
| 0x08048414 55 push ebp
| 0x08048415 89e5 mov ebp, esp
| 0x08048417 83ec28 sub esp, 0x28 ; '('
| 0x0804841a 83e4f0 and esp, 0xfffffff0
| 0x0804841d b800000000 mov eax, 0
| 0x08048422 83c00f add eax, 0xf
| 0x08048425 83c00f add eax, 0xf
| 0x08048428 c1e804 shr eax, 4
| 0x0804842b c1e004 shl eax, 4
| 0x0804842e 29c4 sub esp, eax
| 0x08048430 c70424688504. mov dword [esp], str.IOLI_Crackme_Level_0x00 ; [0x8048568:4]=0x494c4f49 ; "IOLI Crackme Level 0x00\n"
| 0x08048437 e804ffffff call sym.imp.printf ; int printf(const char *format)
| 0x0804843c c70424818504. mov dword [esp], str.Password: ; [0x8048581:4]=0x73736150 ; "Password: "
| 0x08048443 e8f8feffff call sym.imp.printf ; int printf(const char *format)
| 0x08048448 8d45e8 lea eax, [local_18h]
| 0x0804844b 89442404 mov dword [local_4h], eax
| 0x0804844f c704248c8504. mov dword [esp], 0x804858c ; [0x804858c:4]=0x32007325
| 0x08048456 e8d5feffff call sym.imp.scanf ; int scanf(const char *format)
| 0x0804845b 8d45e8 lea eax, [local_18h]
| 0x0804845e c74424048f85. mov dword [local_4h], str.250382 ; [0x804858f:4]=0x33303532 ; "250382"
| 0x08048466 890424 mov dword [esp], eax
| 0x08048469 e8e2feffff call sym.imp.strcmp ; int strcmp(const char *s1, const char *s2)
| 0x0804846e 85c0 test eax, eax
| ,=< 0x08048470 740e je 0x8048480
| | 0x08048472 c70424968504. mov dword [esp], str.Invalid_Password ; [0x8048596:4]=0x61766e49 ; "Invalid Password!\n"
| | 0x08048479 e8c2feffff call sym.imp.printf ; int printf(const char *format)
| ,==< 0x0804847e eb0c jmp 0x804848c
| || ; JMP XREF from 0x08048470 (main)
| |`-> 0x08048480 c70424a98504. mov dword [esp], str.Password_OK_: ; [0x80485a9:4]=0x73736150 ; "Password OK :)\n"
| | 0x08048487 e8b4feffff call sym.imp.printf ; int printf(const char *format)
| | ; JMP XREF from 0x0804847e (main)
| `--> 0x0804848c b800000000 mov eax, 0
| 0x08048491 c9 leave
\ 0x08048492 c3 ret
一个典型的32位Linux程序, 这时候要想起函数的调用约定是通过栈来传参, 如果忘了可以再看看RE4B哦.
看到main函数的汇编代码了, 就开始分析了, 我不想像一些文章那样贴个图就说"显而易见, 这里的作用是XXX",
毕竟我也只是个新手, 虽然这只是一个超简单的crackme, 但因为是第一次, 我还是把流程完整地走一遍.
有了汇编接下来就开始分析了, r2和IDA一样可以自己写注释和修改变量名称, 在此之前我们先创建一个工程,
以保存这些修改:
[0x08048360]> Ps ioli0x00
这条指令的意思是保存一个名为ioli0x00
的(新)项目, 通常默认保存在~/.config/radare2/projects
里.
以P开头的命令是项目工程管理相关(Project managment), 还记得之前说的吗,
如果不记得命令, 可以通过P?
来查看帮助.
然后跳转到main并打印本地局部变量:
[0x08048360]> s main
[0x08048414]> afv
var int local_4h @ esp+0x4
var int local_18h @ ebp-0x18
s表示seek, 跳转后发现我们已经到了0x08048414
, afv表示a(分析)f(函数)v(变量), 可以看到有两个局部变量.
(其实只有一个, 因为esp+0x4是传给子函数的参数).
再回到前面的汇编看看, 从0x08048448到0x08048456这几条汇编可以发现local_4h
是local_18h
的地址(指针),
而且local_4h
是scanf的第二个参数, scanf的第一个参数为0x804858c, 这个地址应该是个字符串, 我们打印下看看:
[0x08048414]> ps @ 0x804858c
%s
那么local_18h
应该就是用户输入的字符串了, 我们先给他们改个好听的名字:
afvn local_18h input
afv-local_4h
afv-
表示删除某个名字, 这里删除了local_4h
因为它其实不是本地变量, 这时再次打印汇编就能看到改好的名字了:
0x08048448 8d45e8 lea eax, [input]
0x0804844b 89442404 mov dword [esp+4], eax
0x0804844f c704248c8504. mov dword [esp], 0x804858c ; [0x804858c:4]=0x32007325
0x08048456 e8d5feffff call sym.imp.scanf ; int scanf(const char *format)
0x0804845b 8d45e8 lea eax, [input]
0x0804845e c74424048f85. mov dword [esp+4], str.250382 ; [0x804858f:4]=0x33303532 ; "250382"
0x08048466 890424 mov dword [esp], eax ; 这句和上一句相当于push str.250382; push eax
0x08048469 e8e2feffff call sym.imp.strcmp ; int strcmp(const char *s1, const char *s2)
0x0804846e 85c0 test eax, eax
这下就能比较清楚的看出上述代码的核心目的了, 大约是:
char input[N];
scanf("%s", input)
strcmp(input, "250382")
由前面的sub esp, 0x28
可知, 这里的N应该小于40(没错! 这里有一个栈溢出漏洞!). 不过对于函数
prologue之后的几条汇编我还不是很明白作用是是啥, 希望有大神能告知一下~
至此, crackme0x00的分析基本完成. 虽然有些步骤看起来很繁琐, 但对于分析大型项目还是很有用的.
尤其是给变量/参数命名, 给函数/代码块命名, 这样会使得分析过程步步为营, 柳暗花明.
解法2: 修改程序
当我们能直接接触程序并且有修改权限时, 那么修改该二进制文件也是个快速通关的好办法!
回到刚刚的汇编输出, 我们看到0x08048470
这行有一个跳转分支:
0x0804846e 85c0 test eax, eax
,=< 0x08048470 740e je 0x8048480
| 0x08048472 c70424968504. mov dword [esp], str.Invalid_Password ; [0x8048596:4]=0x61766e49 ; "Invalid Password!\n"
| 0x08048479 e8c2feffff call sym.imp.printf ; int printf(const char *format)
,==< 0x0804847e eb0c jmp 0x804848c
|| ; JMP XREF from 0x08048470 (main)
|`-> 0x08048480 c70424a98504. mov dword [esp], str.Password_OK_: ; [0x80485a9:4]=0x73736150 ; "Password OK :)\n"
| 0x08048487 e8b4feffff call sym.imp.printf ; int printf(const char *format)
| ; JMP XREF from 0x0804847e (main)
`--> 0x0804848c b800000000 mov eax, 0
test a, b
的意思是若a AND b为0, 则设置ZF位(以及SF/PF)
, je表示若ZF位被设置则跳转
,
说人话就是判断前一个函数的返回值是否为0(eax保存strcmp的返回值), 若为0则跳转到0x8048480
(打印"Password OK
radare2逆向笔记的更多相关文章
- 【逆向笔记】OD工具使用-逆向TraceMe.exe
名词注释 System breakpoint:系统断点,OllyDbg用CreateProcessA加载DEBUG_ONLY_THIS_PROCESS参数执行,程序运行之后会触发一个INT13,在系统 ...
- Android逆向笔记之AndroidKiller与Android Studio的使用
https://blog.csdn.net/a_1054280044/article/details/60465267 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog. ...
- 【逆向笔记】2017年全国大学生信息安全竞赛 Reverse 填数游戏
2017年全国大学生信息安全竞赛 Reverse 填数游戏 起因是吾爱破解大手发的解题思路,觉得题挺有意思的,就找来学习学习 这是i春秋的下载链接 http://static2.ichunqiu.co ...
- js逆向笔记
1.nodejs运行js的时候 navigator如果找不到可以可设置为空对象 var navigator={}; 2.使用nodejs如果window对象找不到的时候 可以使用jsdom模块 3.顶 ...
- Box 黑科技 —— 支持手机端反编译 !Box 黑科技 —— 支持手机端反编译 !
项目地址: Box 文末扫码获取最新安装包 . 前言 有将近一个月没有更新文章了,一方面在啃 AOSP ,消化起来确实比较慢.在阅读的过程中,有时候上来就会陷入源码细节,其实这是没有必要的.刚开始更多 ...
- 逆向中静态分析工具——IDA初学者笔记之字符串分析
逆向中静态分析工具——IDA初学者笔记之字符串分析 程序中往往包含很多字符串资源,这些资源存在于PE文件的rdata段,使用IDA反编译后,可以查找到这些字符串, 逆向破解程序通常需要一个突破点,而这 ...
- 逆向中静态分析工具——IDA初学者笔记
逆向中静态分析工具——IDA初学者笔记 //****************************************************************************** ...
- 【Python灰帽子--黑客与逆向工程师的Python编程之道】我的学习笔记,过程.(持续更新HOT)
我的学习笔记---python灰帽子 世界让我遍体鳞伤,但伤口长出的却是翅膀. -------------------------------------------- 前言 本书是由知名安全机构Im ...
- 网络对抗技术 2017-2018-2 20152515 Exp1 PC平台逆向破解 笔记
Exp1 PC平台逆向破解 1.堆栈不可保护: ROP 2.alsr 随机化: 填充NOPS "\90" 3.不加堆栈保护 shellcode: 1.不依赖外部函数 2.不含\00 ...
随机推荐
- 2039: [2009国家集训队]employ人员雇佣
任意门 Description 作为一个富有经营头脑的富翁,小L决定从本国最优秀的经理中雇佣一些来经营自己的公司.这些经理相互之间合作有一个贡献指数,(我们用Ei,j表示i经理对j经理的了解程度),即 ...
- poj_2528Mayor's posters(线段树)
poj_2528Mayor's posters(线段树) 标签: 线段树 题目连接 Mayor's posters Time Limit: 1000MS Memory Limit: 65536K To ...
- ACM_高次同余方程
/*poj 3243 *解决高次同余方程的应用,已知 X^Y = K mod Z, 及X,Z,K的值,求 Y 的值 */ #include<cstdio> #include<cstr ...
- c++(基数排序)
基数排序是另外一种比较有特色的排序方式,它是怎么排序的呢?我们可以按照下面的一组数字做出说明:12. 104. 13. 7. 9 (1)按个位数排序是12.13.104.7.9 (2)再根据十位排序1 ...
- [国嵌笔记][012][GCC程序编译]
GCC特点 GCC(GUN C Compiler)是GUN推出的功能强大.性能优越的多平台编译器.其执行效率与一般编译器相比平均效率要高20%~30%. GCC基本用法 gcc [options] f ...
- 怎么去掉织梦网站首页带的index.html/index.php
方法1. 1)在空间面板里面找到默认首页设置: 我们是需要去掉index.html,这时我们只需要把index.html这个把它移到最顶级去就行,然后点击确定,在打开网站刷新下,就基本可以解决了! 其 ...
- window.top.location.href 和 window.location.href 的区别
window.location.href 是本页面跳转 window.top.location.href是最外层的页面跳转
- (实例篇)LNMP 1.4一键安装包,安装教程
http://mp.weixin.qq.com/s/l6ijKBwD6tt8jkZytWEIsw https://lnmp.org/download.html 2017-09-11 学习与分享 PHP ...
- DedeCMS实现自定义表单提交后发送指定QQ邮箱法
https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&tn=monline_3_dg&wd=dedecms 邮箱&oq=d ...
- PHP 获得当前页面所有变量常量的值
get_defined_vars() - 返回由所有已定义变量所组成的数组,这个函数在二次开发的时候用起来非常给力: get_defined_constants();可以返回当前的所有常量 zend的 ...