1 |
|
生成固定长度攻击字串及计算偏移
使用pwntools里面的cyclic工具(仅限32bit)
1 |
|
使用pattern.py(32bit/64bit通用)
1 |
|
打开系统coredump
1 |
|
关闭ASLR
1 |
|
readelf
1 |
|
objdump
1 |
|
ROPgadget
1 |
|
IDA
byte ptr [eax] #1byte
word ptr [eax] #2byte
dword ptr [eax] #4byte
反调试
常用反调试函数MD5值:
库 | 偏移 | 函数名 | MD5值 |
---|---|---|---|
ntdll.dll | 771fe56e | ZwQuerySystemInformation | a7d7bcc95a86a6df3b0a1ccb3c69d440 |
ntdll.dll | 771feb5b | ZwSetInformationThread | 8eb35a28209979fe6a9983cff0d23c5a |
kernel32.dll | CheckRemoteDebuggerPresent | 05577e1568efa10b8166728bfb414c59 |
运行时调整/打印数据
设置断点->Debugger->Breakpoints->Breakpoint,选中其中一个断点,
右键->Edit->Condition处输入IDC脚本:Message(“ECX: %x\n, ECX);
如果仅仅需要输出,不需要拦截,Actions处把Break前的勾去掉
修改binary
选中需要修改的字节,Edit->Patch program->Change byte(或者右键直接Fill with NOPs),然后Edit->Patch program->Apply patches to input file。
反汇编界面
按D可以定义数据,按P可以变成函数,按U可以转成未定义,按C可以变成代码,按A变成字符串。
call analysic failed
无法识别调用参数,按y设置参数类型和个数int sub_401390(int, int)
。
sp-analysis failed,调用栈不平衡
Option->General->Disassembly, 将选项Stack pointer打勾 观察每条call sub_xxxxxx前后的堆栈指针是否平衡
.text:0000000000000F5A 020 xor eax, eax
.text:0000000000000F5C 020 jz short loc_F62
.text:0000000000000F5E 020 add rsp, 4
.text:0000000000000F62
.text:0000000000000F62 loc_F62:
.text:0000000000000F62 01C pop rax
由于xor eax,eax一定会引起跳转,因此F5E处的add rsp,4可认为是花指令,选中F5E 的add rsp, 4,右键
-
Fill with NOPs(推荐)
-
change stack pointer(alt+K),将0x4修改为0x0
按D再按C键刷一下函数定义
花指令
- jz/jnz
.text:0025157C 74 03 jz short near ptr loc_251580+1
.text:0025157C 75 01 jnz short near ptr loc_251580+1
.text:00251580 loc_251580:
.text:00251580 E3 E8 #jz和jnz都跳转251580+1,因此251580字节为花指令,Fill with NOPs
- call $+5 pop rax/rbx(sample:flodbg-dfjkctf-2019)
.text:4009A9 E8 00 00 00 00 call $+5 #call偏移量为0(即下一条指令),并将其作为返回地址压栈
.text:4009AE 58 pop rax #出栈
.text:4009AF 48 83 C0 0A add rax, 0Ah #加0x0A
.text:4009B3 FF E0 jmp rax #跳到0x4009AE+0x0A=4009B8处
.text:4009B5 EB EB EB db 3 dup(0EBh) #可以为任意值
.text:4009B8
;类似,可以借助rbx等其他寄存器
.text:4009B8 E8 00 00 00 00 call $+5
.text:4009BD 5B pop rbx
.text:4009BE 48 83 C3 0A add rbx, 0Ah
.text:4009C2 FF E3 jmp rbx #跳到0x4009BD+0x0A=0x4009C7处
.text:4009C4 EB EB EB
- EB FF/05(sample:flodbg-dfjkctf-2019)
.text:4009E0 EB FF jmp loc_4009E0+1 #jmp 0x4009E2+0xFF=0x4009E1
.text:4009E2 C0 db 0C0h
.text:4009E3 FF C8 dec eax
;patch 0x4009E0为90,得到0x4009E1
.text:4009E1 FF C0 inc eax
.text:4009E3 FF C8 dec eax
.text:4009E5 66 B8 EB 05 mov ax, 5EBh
.text:4009E9 31 C0 xor eax, eax
.text:4009EB 74 FA jz loc_4009E5+2 #必然跳转4009E5+2=4009E7
.text:4009ED EB 90 jmp short loc_40097F
;patch 0x4009E5为90,得到0x4009E7
.text:4009E7 EB 05 jmp loc_4009ED+1 #跳转到4009E9+5=4009EE
.text:4009E9 31 C0 xor eax, eax
.text:4009EB 74 FA jz short loc_4009E7
.text:4009ED EB 90 jmp short loc_40097F
- jmp rax
1 |
|
查找系统调用
(G->输入GetWindowTextA)/(Ctrl+L,找到GetWindowTextA) -> X(Jump to cross ref)
Alt+T->输入GetWindowTextA,Find all occurences
查找数据
Jump->Jump to segment(Ctrl+S),找.rdata(readONLY)和.data(writable)
View->Open subviews->String(Shift+F12)
查找函数调用关系
View -> Open subview -> Function calls 上半部分列出所有调用当前函数的位置,下半部分列出当前函数调用的别的函数
提取数据
- View->Open Subviews->Strings,选中某个字符串
- 右键->Array,填数组长度,转换为Array
Shift+E提取数据
反汇编界面显示字节码
Options->General->Number of opcode bytes (non-graph) : 8
运行脚本
File->Script Command
1 |
|
1 |
|
The function has undefined instruction/data at the specified address.
在下方Output Windows找到对应位置,将指令更改为nop。(sample:find_key-安恒周周练-2018-03)
please position the cursor within a function:
右键 creat func
ida动态调试
-
dbgsrv目录下的
linux_server
或者linux_serverx64
放到Linux虚拟机中,运行,会监听端口,默认23946,IDA Debugger选Remote Linux debugger,设置:Application=Inputfile=/mnt/shared/path/crackme
Directory=/mnt/shared/path
Hostname填Linux的IP
-
Windows类似,运行
win32_remote
或win64_remote64
,选Remote Windows debugger
,HostName填:127.0.0.1
IDA下断点,然后start process(注意attach process会报无权限)
too big function
修改cfg\hexrays.cfg
,MAX_FUNCSIZE=1024
。
恢复符号表
rizzo插件,打开可能对应的库文件如:libc.so.6,File->Produce file->Rizzo signature file,然后打开去除了符号表的文件,File->Load file->Rizzo signature file。
Windbg
bu fathom!SetFile #设断点 (view->Disassembly->输入GWoC+0x134c,按F9加断点)
bl #列断点
p/t #步过、步进
db/dd/dQ ebp-30 #1/2/4字节
OllyDbg
F2 下断点,Backspace 删除分析,Shift+F9 忽略异常运行
ESP定律脱壳
OEP(Original Entry Point):程序的入口点 。当PE文件运行开始的时候,也就是进入壳的第一行代码的时候 ,寄存器的值和即将执行OEP的时候完全相同(除了EIP)。
根据经验,多数壳运行到OEP的时候,ESP=0012FFC4,而到达OEP之后,绝大多数的程序第一句都是压栈,因此对0012FFC0下硬件断点(右键->Breakpoint/Hardware,on execution,或者命令行键入:HW 12FFC0),即可以停在OEP的第二句,右击程序当前位置第一行代码,选择OllyDump脱壳调试进程。
内存断点不修改原代码,遇到代码校验(会导致INT3断点失败),硬件断点失灵的情况下,可以用内存断点代替:
- 内存断点等效与命令bpm,他的中断要用到DR0-DR7的调试寄存器,也就是说OD通过这些DR0-DR7的调试寄存器来判断是否断下
- 普通断点(F2下断)等效于bpx,他是在所执行的的代码的当前地址的一个字节修改为CC(INT3)。当程序运行到INT3的时候就会产生一个异常,而这个异常将交给OD处理,把这个异常的regEIP-1以后就正好停在了需要的中断的地方(这个根据系统不同会不一样),同时OD在把上面的int3修改回原来的代码。
两次内存断点法,前提:壳的解码按code段,data段,rsrc段的顺序,因此假如data段或者rsrc段内存断点被触发,意味code段解码完成:
- 对data段下内存访问(写入)断点 ,断在壳对data段的解压写入数据
- 对code段下内存访问(执行)断点,断在执行OEP处
无法使用内存断点法的情况:
- 像UPX和ASPACK这样当一个壳如果在JMP到OEP前的一行代码仍在对code段解压,就没必要使用内存断点
- 在OEP处有stolen code的代码
ctrl+A 分析代码
右键反汇编窗口任意位置→复制到可执行文件→所有修改→全部复制
gdb
finish
执行到当前函数返回
重定向输入
1 |
|
断点
1 |
|
跟踪访问
1 |
|
修改内存/寄存器
1 |
|
查看内存
x/<n/f/u> <addr>
Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal),t(binary), f(float), a(address), i(instruction), c(char) and s(string).
Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).
1 |
|
pwndbg
参考调教gdb
1 |
|
- 使得heap命令打印chunk的时候prevsize和size显示为16进制,将def malloc_chunk(addr):倒数第二行print(header, chunk[“value”])修改为:
1
2
3
4
5
6
7## edit start chunk_str='{\n' for key in chunk["value"].type.keys(): chunk_str+=' %s = %s,\n'%(str(key),hex(int(chunk["value"][key]))) chunk_str+='}' print(header, chunk_str) ## edit end
- 加入fake_fastbin_all函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31@pwndbg.commands.ParsedCommand @pwndbg.commands.OnlyWhenRunning def fake_fastbin_all(addr): """ Finds candidate fake fast chunks that will overlap with the specified address. Used for fastbin dups and house of spirit """ main_heap = pwndbg.heap.current max_fast = main_heap.global_max_fast max_idx = main_heap.fastbin_index(max_fast) start = int(addr) - int(max_fast) mem = pwndbg.memory.read(start, max_fast, partial=True) fmt = { 'little': '<', 'big': '>' }[pwndbg.arch.endian] + { 4: 'I', 8: 'Q' }[pwndbg.arch.ptrsize] print(C.banner("FAKE CHUNKS")) for idx in range(max_idx +1): if pwndbg.arch.ptrsize == 8: print(message.hint(hex((idx+2)<<4))+": ") else: print(message.hint(hex((idx+2)<<3))+": ") for offset in range(max_fast - pwndbg.arch.ptrsize): candidate = mem[offset:offset + pwndbg.arch.ptrsize] if len(candidate) == pwndbg.arch.ptrsize: value = struct.unpack(fmt, candidate)[0] if main_heap.fastbin_index(value&0xffffffff) == idx: print('[+]',hex(start+offset-pwndbg.arch.ptrsize),', padding len:',hex(int(addr)-start-offset-pwndbg.arch.ptrsize))
查找fast chunk
1 |
|
找rop,一般由ROPgadget代替
1 |
|
查找数值或字符串
1 |
|
直接计算数值
1 |
|
查看各段地址和权限
1 |
|
查看栈
1 |
|
查看格式化字符串参数偏移
1 |
|
DOSBox
1 |
|
qemu调试arm和mips
环境搭建
1 |
|
You can override the default sysroot by setting the QEMU_LD_PREFIX
environment variable. This affects where qemu
will look for files when open()
is called, e.g. when the linker is attempting to resolve libc.so
调试
1 |
|
反编译mips代码
retdec和retdec-idaplugin
- 安装配置python3到PATH
- 下载Windows版本retdec
- 下载最新版本retdec-idaplugin,解压retdec.dll到ida的plugins目录
- 打开ida->Options,配置retdec-decompiler.py脚本的路径
- 选中代码,Ctrl+D即可反编译