常用工具和命令
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
版权声明:本文为博主原创文章,转载请附上博文链接!