逆向-Linux的逆向

常用工具和命令

nm 
列出目标文件的所有符号
objdump 
-d参数表示反编译.text段中的程序代码
readelf 
查看ELF文件的各种信息
IDA
gdb
IDA

与PE程序基本类似,将ELF程序拖入IDA也可以快速的反汇编,主要借助hex-ray插件来反编译出可读性较高的伪代码

实验-passwd_generator

trick

patch
dynamic debugging
programming
gdb

gdb是Unix和Unix-like下的一个调试工具 
它没有图形化界面,通过简单明了的命令来调试程序

常用命令: 
- r/run [args] 
加载程序后使用run命令启动程序 
- b/break [address/functions] 
在某个地址(记得在地址前要加*,代表这是一个地址)或符号名 
- c/continue 
继续运行 
- n/ni(next) 
执行一行源代码/汇编代码但不进入函数内部 
建议费事点使用ni,可以避免在有调试信息的时候产生非常神奇的事情(明明只单步了一下汇编却跳了好几行) 
- s/si(step) 
执行一行源代码/汇编代码并进入函数内部 
- x/examine {count} {fmt} {size} {address} 
按照一定格式打印内存地址处的数据 
- cout表示打印的数目,默认为1 
- fmt表示打印格式,如x为16进制,d为10进制,c为字符,s为字符串等,默认为上次使用的fmt 
- size表示打印单位,如b(byte), h(halfword), w(word), g(giant)等,默认为上次使用的size 
- address表示目标地址,也可使用*来取指针值或取寄存器的值−set写内存/寄存器eg:set取寄存器的值−set写内存/寄存器eg:setrsp=0x123456 
set *0x123456=0x654321

有时ELF程序开启了PIE(代码地址随机化),会导致程序每次加载的地址都不同,进而在某些没有符号的函数中难以下断 
此时可以对main/printf/gets/puts等已知符号的函数下断,然后找到主函数调用的偏移,进而根据文件中的偏移来找到加载基址。有了基址以后就好计算其他地址的虚拟地址了

ida的动态调试

远程端的监听程序在ida根目录/dbgsrv/下,linux对应的就是linux_server/linux_server64,由程序版本决定使用哪个。 
将其复制至远端系统后以管理员权限执行即可

ida选择debugger-remote linux debugger后,在Process options中设置hostname(ip),port保持默认的23946即可,password输入该用户的passwd

Start Process(F9)可以直接启动程序,在监听服务器的终端中进行回显和输入 
也可以通过Attach to Process来附加正在运行的程序

综合实验

babyRE

hint:SMC

花指令

由于常见Linux中使用x86指令集,与windows一致,因此花指令的相关内容也基本相同

所谓花指令即是不会执行或是执行了以后没有任何用处的汇编指令

分析识别花指令

当在静态分析时遇到从没见过的汇编指令、程序段中出现了Bad Byte、或是jmp等跳转指令的目标是一个汇编代码的中间时,很有可能这里出现了花指令

当在使用IDA的Hex-rays插件时,如果遇到栈指针错误或是反编译代码明显不对劲等情况时,也有可能是花指令在作祟

最简单的确认花指令与否的手段就是动态调试,看程序是否会执行到该处地方(建议在不可辨识的指令之前下断) 
但是未解密的SMC代码也有可能产生上述现象,因此需要自行甄别,通常情况下大段的代码更可能是未解密代码,而花指令通常仅影响数条汇编指令

去除花指令

需要去除的情况通常有两种: 
1. 大量无用指令造成不便找到关键信息 
2. 不可解析的指令干扰反汇编使得代码难以阅读

花指令一般具备一些格式特征,以便添加和跳过脏字节,例如 
jmp c 
–bad byte– 
c: 
other instruction

当花指令较多时这些特征就能帮助识别

关于去除,通常是将脏字节全部改为NOP,即0x90 
NOP是单字节指令,因此不会影响到其他指令的解析,同时它的作用是什么都不做,因此也不会影响hex-rays的反编译

手动在IDA中去除花指令

实验–easy_junk

编写idc脚本去除花指令

实验–hard_junk

反调试

Linux中由于与Windows系统机制的一些不同,因此反调试也有一些区别

不过由于断点字节同样是0xcc,因此在检测0xcc或者hook0xcc的反调方法中是一样的

PTRACE_TRACEME

大部分调试器、注入的基础技术都使用的是ptrace 
而一个进程只能被一个进程ptrace 
TRACE_ME就是一个对自己调试的参数

如果先执行的TRACE_ME,那么之后的调试器就无法再附加到该进程上 
如果直接由调试器启动,那么TRACE_ME会返回False表示ptrace失败 
从而检测到调试器的存在

反制方法

patch
LD_PRELOAD 
gdb中set environment LD_PRELOAD ./ptrace.so 
直接启动时LD_PRELOAD=./ptrace.so ./traceme 
可防止自校验
调试过程中篡改TRACE_ME的返回值
实验 TraceMe

/proc/self/status

在/proc目录中有每个进程的状态,通过pid可以读到指定进程的状态,包括进程名、State、PPid等等 
其中PPid就是父进程的pid,在没有父进程时该项为0,而被调试器启动时将会显示调试器的pid,因此可以通过PPid来查看调试状态 
另外TracePid会直接显示调试器的Pid,当被附加时PPid将不会是调试器,但TracePid会改变

反制方法

主要是Hook/静态分析open函数,因为status是一个文件描述符,必须通过open来读取 
因此在查看导入符号时如果发现open就要引起注意了,也许是一个反调试机制

ltrace命令可以快速地查看库函数的调用

另外要注意的是,open函数的底层实现是通过Linux的syscall(__NR__open, sys_open)来实现的,有时为了规避导入函数的问题以及避免被轻易发现, 会直接通过syscall来调用

实验 Status

alarm函数

alarm也称为闹钟函数,它可以在进程中设置一个定时器,当定时器指定的时间到时,它向进程发送SIGALRM信号。可以设置忽略或者不捕获此信号,如果采用默认方式其动作是终止调用该alarm函数的进程。

在逆向题目中通常仅仅是一个小花招,如果时间设置的较短可能导致来不及附加,或比较麻烦

反制方法

patch
--------------------- 
作者:奈沙夜影 
来源:CSDN 
原文:https://blog.csdn.net/whklhhhh/article/details/81024134 
版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自blog.csdn.net/hnzwx888/article/details/85261719