wywwzjj's Blog

二进制学习

字数统计: 10.6k阅读时长: 44 min
2020/10/07 Share

每天学点新东西

exeinfo 可以看到壳信息
upx -d upx脱壳

编译x86程序依赖
sudo apt-get install -y build-essential module-assistant gcc-multilib g++-multilib

搜索shellcode
gdb-peda$ shellcode search sh
Connecting to shell-storm.org...
Found 289 shellcodes
ScId Title
[132] Aix - execve /bin/sh - 88 bytes
[134] Alpha - /bin/sh - 80 bytes
[107] BSD/ppc - execve(/bin/sh) - 128 bytes
[814] BSD/x86 - setreuid(geteuid(), geteuid()) and execve(/bin/sh, /bin/sh, 0)
[92] BSD/x86 - execve(/bin/sh) & setuid(0) - 29 bytes
[601] BSD/x86 - bindshell on port 2525 - 167 bytes
[362] BSD/x86 - execve /bin/sh Crypt /bin/sh - 49 bytes
[93] BSD/x86 - execve(/bin/sh) - 27 bytes
[144] Cisco IOS - Connectback shellcode v1.0
[142] Cisco IOS - Tiny shellcode v1.0
[143] Cisco IOS - Bind shellcode v1.0
[131] Sco/x86 - execve(/bin/sh, ..., NULL) - 43 bytes
[106] FreeBSD/x86-64 - exec(/bin/sh) Shellcode - 31 bytes

查看 shellcode
gdb-peda$ shellcode display 98
Connecting to shell-storm.org...

; sm4x - 2008
; reverse portbind /bin/sh
; NULL free if address is.
; setuid(0); socket(); connect(); exit();
; 89 bytes
; FreeBSD 7.0-RELEASE

global _start
_start:

xor eax, eax

; --- setuid(0)
push eax
push eax
mov al, 0x17
push eax
int 0x80



socat tcp-l:4000,fork exec:./pwn
nc 127.0.0.1 4000

libc查询 http://libcdb.com/

查找到gadget

objdump -d babypwn4 | egrep "ret|pop"

linux下shellcode的编写

  • 在 shellcode 中不能出现 /x00也就是NULL字符,当出现NULL字符的时候将会导致shellcode被截断,从而无法完成其应有的功能
  • 有一个int $0x80来执行系统调用

windows shellcode

# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include <windows.h>

int main(void) {
char *shellcode =
"\x33\xc9\x64\x8b\x49\x30\x8b\x49\x0c\x8b"
"\x49\x1c\x8b\x59\x08\x8b\x41\x20\x8b\x09"
"\x80\x78\x0c\x33\x75\xf2\x8b\xeb\x03\x6d"
"\x3c\x8b\x6d\x78\x03\xeb\x8b\x45\x20\x03"
"\xc3\x33\xd2\x8b\x34\x90\x03\xf3\x42\x81"
"\x3e\x47\x65\x74\x50\x75\xf2\x81\x7e\x04"
"\x72\x6f\x63\x41\x75\xe9\x8b\x75\x24\x03"
"\xf3\x66\x8b\x14\x56\x8b\x75\x1c\x03\xf3"
"\x8b\x74\x96\xfc\x03\xf3\x33\xff\x57\x68"
"\x61\x72\x79\x41\x68\x4c\x69\x62\x72\x68"
"\x4c\x6f\x61\x64\x54\x53\xff\xd6\x33\xc9"
"\x57\x66\xb9\x33\x32\x51\x68\x75\x73\x65"
"\x72\x54\xff\xd0\x57\x68\x6f\x78\x41\x01"
"\xfe\x4c\x24\x03\x68\x61\x67\x65\x42\x68"
"\x4d\x65\x73\x73\x54\x50\xff\xd6\x57\x68"
"\x72\x6c\x64\x21\x68\x6f\x20\x57\x6f\x68"
"\x48\x65\x6c\x6c\x8b\xcc\x57\x57\x51\x57"
"\xff\xd0\x57\x68\x65\x73\x73\x01\xfe\x4c"
"\x24\x03\x68\x50\x72\x6f\x63\x68\x45\x78"
"\x69\x74\x54\x53\xff\xd6\x57\xff\xd0";
DWORD why_must_this_variable;
BOOL ret = VirtualProtect(
shellcode,
strlen(shellcode),
PAGE_EXECUTE_READWRITE,
&why_must_this_variable
);
if (!ret) {
printf("VirtualProtect\n");
return 0;
}
//printf("strlen(shellcode)=%d\n", strlen(shellcode));
((void (*)(void)) shellcode)();
return 0;
}

pwn全景图

求余数运算反汇编,两者等价。

v5 = 3 * v0 - 0X30 * ((unsigned __int64)(0xAAAAAAAAAAAAAAABLL * (unsigned __int128)(3 * v0) >> 64) >> 5);

v5 = 3 * v0 % 0x30;

Assembly

Intel vs AT&T

  • 操作数顺序不同
  • 寄存器记法有差异
  • 立即数记法有差异
  • 访存寻址计法不同
  • 操作码助记符不同

image.png

程序模板

TITLE Program Template  ; 标题可有可无

include irvine32.inc ; 包含头文件

.data
; 数据区,声明全局变量
val1 dword 10000h
val2 dword 40000h
val3 dword 20000h
finalVal dword ?

.code
; 代码区
main PROC
mov eax, val1 ; start with 10000h
add eax, val2 ; add 40000h
sub eax, val3 ; subtract 20000h
mov finalVal, eax ; store the result (30000h)
call DumpRegs ; display the registers
exit
main ENDP

funcName PROC

ret
funcName ENDP

END main

寄存器

;    16 bits	8 bits	8 bits
eax ax ah al ; 累加器,是很多加、乘法指令的缺省寄存器
ebx bx bh bl ; 基地址寄存器,在内存寻址时存放基地址
ecx cx ch cl ; 计数器,是 rep 和 loop 的内定计数器
edx dx ; 总是用来放整数除法产生的余数
esp sp ; 栈顶指针
ebp bp ; 基址指针
edi di ; 目的变址
esi si ; 源变址
eip ip ; 指令指针,指向下一条指令的内存地址
eflags flags ; 标志

数据类型

var db ?   ; 声明一个字节,未初始化
var db 64 ; 声明一个字节,初始值为 64
db 10 ; 声明一个没有 label 的字节,值为 10
var dw ? ; 2 字节
var dd 40 ; 4 字节
arr dd 1, 2, 3 ; 数组,初始值为 1, 2, 3
arr db 10 dup(?) ; 10个元素的数组,未初始化
arr dd 100 dup(0) ; 100 个元素,初始化为 0
str db 'hello',0 ; 字符串,注意 0 结尾

寻址模式

直接内存寻址

寄存器间接寻址

mov eax, [ebx]  ; 将 ebx 值指示的内存地址中的 4 个字节传送到 eax 中
mov [var], ebx ; 将 ebx 的内容传送到 var 值指示的内存地址中
movsx dest, src ; 8 / 16 bits => 16 / 32 bits,扩展传送

常用指令

mov

mov <reg>, <reg>
mov <reg>, <mem>
mov <mem>, <reg>
mov <reg>, <const>
mov <mem>, <const>

mov byte ptr [var], 5

push

push <reg32>

pop

lea

Load Effective Address

lea <reg32>, <mem>

lea eax, [var] ;将地址 var 放入寄存器 eax 中
lea edi, [ebx+4*esi] ;edi = ebx+4*esi
; 某些编译器会使用 lea 指令来进行算数运算

leave

在32位汇编下相当于:
mov esp,ebp;//将ebp指向(ebp内部应当保存一个地址,所谓指向即这个地址对应的空间)的值赋给esp
pop ebp

leave指令将EBP寄存器的内容复制到ESP寄存器中,以释放分配给该过程的所有堆栈空间。
然后,它从堆栈恢复EBP寄存器的旧值。

ret

push src  ; 将 src 的数据存入栈中,不允许使用立即数寻址方式。
pushad ;通用寄存器全入栈
pop dst ; 用 dst 接收出栈数据,不能使用 cs 段寄存器
popad ; 通用寄存器依次出栈

dumpregs ; 显示所有寄存器信息
dumpmem ; 显示所有内存信息


inc reg/mem ; ++
dec reg/mem ; --

xlat ; 换码指令,默认 al 寄存器?

xchg reg, mem/reg ; 交换两操作数内容
; 两操作数中必须有一个在寄存器中
; 操作数不能为段寄存器和立即数
; 源和目的操作数类型要一致

shl opr, cnt ; 逻辑左移 cnt 位
shr opr, cnt
sal opr, cnt ; 算术左移,同逻辑左移
sar opr, cnt
rol opr, cnt ; 循环左移
ror opr, cnt

call writestring ; 显示 edx 中的值
readstring buffer ; 输入字符串存到 buffer?

; 输入输入函数
readint
; 返回值:cf = 0 => 输入存放在 eax 中,cf = 1 => 输入无效

writeint
; 输出 eax 中的整数

; 类型 ptr 内存操作数或标号

cmp dword ptr [edx + 4*esi], 8 ; 强转后直接能比较

rep stosed ; 重复?

; 函数写完了记得 ret
sub esp, 8
add esp 12 ; 注意回收栈中分配空间
adc ; 进位加法,从进位标志寄存器中读值

控制转移

jmp ;无条件
j[condition] ;条件跳转
cmp
call
ret
JE   ;等于则跳转
JNE ;不等于则跳转

JZ ;为 0 则跳转
JNZ ;不为 0 则跳转

JS ;为负则跳转
JNS ;不为负则跳转

JC ;进位则跳转
JNC ;不进位则跳转

JO ;溢出则跳转
JNO ;不溢出则跳转

JA ;无符号大于则跳转
JNA ;无符号不大于则跳转
JAE ;无符号大于等于则跳转
JNAE ;无符号不大于等于则跳转

JG ;有符号大于则跳转
JNG ;有符号不大于则跳转
JGE ;有符号大于等于则跳转
JNGE ;有符号不大于等于则跳转

JB ;无符号小于则跳转
JNB ;无符号不小于则跳转
JBE ;无符号小于等于则跳转
JNBE ;无符号不小于等于则跳转

JL ;有符号小于则跳转
JNL ;有符号不小于则跳转
JLE ;有符号小于等于则跳转
JNLE ;有符号不小于等于则跳转

JP ;奇偶位置位则跳转
JNP ;奇偶位清除则跳转
JPE ;奇偶位相等则跳转
JPO ;奇偶位不等则跳转

Clang

C 语言的奇技淫巧 https://jin-yang.github.io/post/program-c-tips.html

常用函数

sprintf();

static

静态全局变量:自动初始化为 0,只在声明它的整个文件中可见。

静态函数:只能在声明它的文件当中可见,不能被其他文件使用,降低命名冲突。

Reverse

C++逆向学习三步走 https://bbs.pediy.com/thread-113689.htm

要求

  • 熟悉如操作系统,汇编语言,加解密等相关知识
  • 具有丰富的多种高级语言的编程经验
  • 熟悉多种编译器的编译原理
  • 较强的程序理解和逆向分析能力

常规逆向流程

  1. 使用strings/file/binwalk/IDA等静态分析工具收集信息,并根据这些静态信息进行google/github搜索
  2. 研究程序的保护方法,如代码混淆,保护壳及反调试等技术,并设法破除或绕过保护
  3. 反汇编目标软件,快速定位到关键代码进行分析
  4. 结合动态调试,验证自己的初期猜想,在分析的过程中理清程序功能
  5. 针对程序功能,写出对应脚本,求解出 flag

定位关键代码 tips

  1. 分析控制流

    控制流可以参见 IDA 生成的控制流程图(CFG),沿着分支循环和函数调用,逐块地阅读反汇编代码进行分析。

  2. 利用数据、代码交叉引用

    比如输出的提示字符串,可以通过数据交叉引用找到对应的调用位置,进而找出关键代码。代码交叉引用比如图形界面程序获取用户输入,就可以使用对应的 windowsAPI 函数,我们就可以通过这些 API 函数调用位置找到关键代码。

逆向 tips

  1. 编码风格

    每个程序员的编码风格都有所不同,熟悉开发设计模式的同学能更迅速地分析出函数模块功能

  2. 集中原则

    程序员开发程序时,往往习惯将功能相关的代码或是数据写在同一个地方,而在反汇编代码中也能显示出这一情况,因此在分析时可以查看关键代码附近的函数和数据。

  3. 代码复用

    代码复用情况非常普遍,而最大的源代码仓库 Github 则是最主要的来源。在分析时可以找一些特征(如字符串,代码风格等)在 Github 搜索,可能会发现类似的代码,并据此恢复出分析时缺失的符号信息等。

  4. 七分逆向三分猜

    合理的猜测往往能事半功倍,遇到可疑函数却看不清里面的逻辑,不妨根据其中的蛛丝马迹猜测其功能,并依据猜测继续向下分析,在不断的猜测验证中,或许能帮助你更加接近代码的真相。

  5. 区分代码

    拿到反汇编代码,必须能区分哪些代码是人为编写的,而哪些是编译器自动附加的代码。人为编写的代码中,又有哪些是库函数代码,哪些才是出题人自己写的代码,出题人的代码又经过编译器怎样的优化?我们无须花费时间在出题人以外的代码上,这很重要。如果当你分析半天还在库函数里乱转,那不仅体验极差,也没有丝毫效果。

  6. 耐心

    无论如何,给予足够的时间,总是能将一个程序分析地透彻。但是也不应该过早地放弃分析。相信自己肯定能在抽茧剥丝的过程中突破问题。

动态分析

动态分析的目的在于定位关键代码后,在程序运行的过程中,借由输出信息(寄存器,内存变化,程序输出)等来验证自己的推断或是理解程序功能

主要方法有:调试,符号执行,污点分析

借用系统调用的跟踪工具看一下宏观动作?

  • strace:trace all system call
  • ltrace:trace all library call
  • ptrace
  • dtruss(Mac)

算法和数据结构识别

  • 常用算法识别

如 Tea / XTea / XXTea / IDEA / RC4 / RC5 / RC6 / AES / DES / IDEA / MD5 / SHA256 / SHA1 等加密算法,大数加减乘除、最短路等传统算法

  • 常用数据结构识别

如图、树、哈希表等高级数据结构在汇编代码中的识别。

代码混淆

比如使用OLLVMmovfuscator花指令虚拟化SMC等工具技术对代码进行混淆,使得程序分析十分困难。

那么对应的也有反混淆技术,最主要的目的就是复原控制流。比如模拟执行符号执行

保护壳

保护壳类型有许多,简单的压缩壳可以归类为如下几种

  • unpack -> execute

    直接将程序代码全部解压到内存中再继续执行程序代码

  • unpack -> execute -> unpack -> execute …

    解压部分代码,再边解压边执行

  • unpack -> [decoder | encoded code] -> decode -> execute

    程序代码有过编码,在解压后再运行函数将真正的程序代码解码执行

对于脱壳也有相关的方法,比如单步调试法ESP定律等等

反调试

反调试意在通过检测调试器等方法避免程序被调试分析。比如使用一些 API 函数如IsDebuggerPresent检测调试器,使用SEH异常处理,时间差检测等方法。也可以通过覆写调试端口、自调试等方法进行保护。

非常规逆向思路

非常规逆向题设计的题目范围非常之广,可以是任意架构的任意格式文件。

  • lua / python / java / lua-jit / haskell / applescript / js / solidity / webassembly / etc..
  • firmware / raw bin / etc..
  • chip8 / avr / clemency / risc-v / etc.

但是逆向工程的方法学里不惧怕这些未知的平台格式,遇到这样的非常规题,我们也有一些基本的流程可以通用

前期准备

  • 阅读文档。快速学习平台语言的方法就是去阅读官方文档。
  • 官方工具。官方提供或建议的工具必然是最合适的工具
  • 教程。在逆向方面,也许有许多前辈写出了专门针对该平台语言的逆向教程,因此也可以快速吸收这其中的知识。

找工具

主要找文件解析工具反汇编器调试器反编译器。其中反汇编器是必需的,调试器也包含有相应的反汇编功能,而对于反编译器则要自求多福了,得之我幸失之我命。

找工具总结起来就是:Google 大法好。合理利用 Google 搜索语法,进行关键字搜索可以帮助你更快更好地找到合适工具。

寻找主入口(main函数)

字符串搜索法

栈回溯法

逐步分析法

Stack Overflow

学习环境 https://exploit.education/phoenix/stack-five

视频教程 https://www.youtube.com/watch?v=HSlhY4Uy8SA

手把手教你栈溢出从入门到放弃

https://zhuanlan.zhihu.com/p/25816426

https://zhuanlan.zhihu.com/p/25892385

ctf-wiki https://ctf-wiki.github.io/ctf-wiki/pwn/linux/stackoverflow/basic-rop-zh/#ret2text

Pwn入坑指南 https://www.cnblogs.com/wintrysec/p/10616856.html

熊师傅推荐的题库 https://github.com/scwuaptx/HITCON-Training

视频教程 入门学习路线 https://www.bilibili.com/video/av13427867

发生栈溢出的基本前提:

  • 程序必须向栈上写入数据;
  • 写入的数据大小没有被良好地控制。

Basic

调用约定

  • 实现了层面(底层)的规范
  • 约定了函数之间如何传递参数
  • 约定了函数如何传递返回值

ebp(rbp) 用途:

  • 索引栈上的参数,例如 x86 下,ebp + 8 指向第一个参数
  • 保存栈顶位置 esp(rsp)

常见 x86 调用约定:

  • 调用者负责清理栈上的参数(Caller Clean-up)
    • cdecl
      • 用栈传参
      • 用 eax 保存返回值
    • optlink
  • 被调用者负责清理栈上的参数(Callee Clean-up)
    • stdcall
    • fastcall

需要注意的是,32 位和 64 位程序有以下简单的区别:

  • x86
    • 函数参数函数返回地址的上方
  • x64
    • System V AMD64 ABI (Linux、FreeBSD、macOS 等采用) 中前六个整型或指针参数依次保存在 RDI, RSI, RDX, RCX, R8 和 R9 寄存器中,如果还有更多的参数的话才会保存在栈上。
    • 内存地址不能大于 0x00007FFFFFFFFFFF,6 个字节长度,否则会抛出异常。
    • cdecl 使用寄存器 rdi、rsi、rdx、rcx、r8、r9 传前 6 个,第七个及以上使用栈传递
int callee(int a, int b, int c) {
return a + b + c;
}

int caller(void) {
int ret;

ret = callee(1, 2, 3);
ret += 4;
return ret;
}
pwndbg> disass callee
Dump of assembler code for function callee:
0x000004ed <+0>: push ebp
0x000004ee <+1>: mov ebp,esp
0x000004f0 <+3>: mov edx,DWORD PTR [ebp+0x8]
0x000004f3 <+6>: mov eax,DWORD PTR [ebp+0xc]
0x000004f6 <+9>: add edx,eax
0x000004f8 <+11>: mov eax,DWORD PTR [ebp+0x10]
0x000004fb <+14>: add eax,edx
0x000004fd <+16>: pop ebp
0x000004fe <+17>: ret
End of assembler dump.

pwndbg> disass caller
Dump of assembler code for function caller:
0x000004ff <+0>: push ebp
0x00000500 <+1>: mov ebp,esp
0x00000502 <+3>: sub esp,0x10
0x00000505 <+6>: push 0x3
0x00000507 <+8>: push 0x2
0x00000509 <+10>: push 0x1
0x0000050b <+12>: call 0x4ed <callee>
0x00000510 <+17>: add esp,0xc
0x00000513 <+20>: mov DWORD PTR [ebp-0x4],eax
0x00000516 <+23>: add DWORD PTR [ebp-0x4],0x4
0x0000051a <+27>: mov eax,DWORD PTR [ebp-0x4]
0x0000051d <+30>: leave
0x0000051e <+31>: ret
End of assembler dump.

类型

修改返回地址,让其指向溢出数据中的一段指令(shellcode

修改返回地址,让其指向内存中已有的某个函数(return2libc

修改返回地址,让其指向内存中已有的一段指令(ROP

修改某个被调用函数的地址,让其指向另一个函数(hijack GOT

Format Strings

函数 基本介绍
printf 输出到 stdout
fprintf 输出到指定 FILE 流
vprintf 根据参数列表格式化输出到 stdout
vfprintf 根据参数列表格式化输出到指定 FILE 流
sprintf 输出到字符串
snprintf 输出指定字节数到字符串
vsprintf 根据参数列表格式化输出到字符串
vsnprintf 根据参数列表格式化输出指定字节到字符串
setproctitle 设置 argv
syslog 输出日志
err, verr, warn, vwarn 等 ……

Array Indexing

Bad Seed

Z3 & Symbolic Execution(angr)

ROP

Return Oriented Programming

Partial Overwrite

Stack Pivoting

SIGROP(SROP)

ret2csu

ret2system

Heap Exploitation

Double Frees

Heap Consolidation

Use after Frees

Protostar: heap0

protostar: heap1

protostar: heap2

Heap Grooming

Fastbin Attack

Unsortedbin Attack

Largebin Attack

GLibc Tcache

House of Spirit

House of Lore

House of Force

House of Einherjar

House of Orange

Miscellaneous

Grab Bag

Shell coding

Patching

.NET

Security Protection Mechanism

$checksec fog
[*] '/mnt/hgfs/shared/other/pwn/fog/fog'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled

NX

NX enabled如果这个保护开启就是意味着栈中数据没有执行权限,以前的经常用的call esp或者jmp esp的方法就不能使用,但是可以利用rop这种方法绕过。

关闭:-z execstack
开启:-z noexecstack

开启了的话堆栈会变的可执行,可执行的话可能意味着可以执行shellcode

RELRO

RELRO 会有 Partial RELRO 和F ULL RELRO,若开启 FULL RELRO,意味着无法修改got表,否则能劫持程序流程。

关闭:-z norelro
开启(部分):-z lazy
开启(完全):-z now

Stack (Canary)

如果栈中开启 Canary found,那么就不能用直接用溢出的方法覆盖栈中返回地址,而是要通过改写指针与局部变量、leak canary、overwrite canary 的方法来绕过。

关闭:-fno-stack-protector
启用(只为局部变量中含有 char 数组的函数插入保护代码):-fstack-protector
启用(为所有函数插入保护代码):-fstack-protector-all

没开启的话,栈溢出会变的更加容易

PIE

Position Independent Executable 地址随机化。

没开启的话,程序的基地址就是已知的了(0x400000)

关闭: -no-pie
开启: -pie -fPIC

Linux 平台下还有地址空间分布随机化(ASLR)的机制,即使可执行文件开启了 PIE 保护,还需要系统开启 ASLR 才会真正打乱基址,否则程序运行时依旧会在加载一个固定的基址上(不过和 No PIE 时基址不同)。

我们可以通过修改 /proc/sys/kernel/randomize_va_space 来控制 ASLR 启动与否,具体的选项有:

  • 0,关闭 ASLR,没有随机化。栈、堆、.so 的基地址每次都相同。
  • 1,普通的 ASLR。栈基地址、mmap 基地址、.so 加载基地址都将被随机化,但是堆基地址没有随机化。
  • 2,增强的 ASLR,在 1 的基础上,增加了堆基地址随机化。
sudo bash -c 'echo 0 > /proc/sys/kernel/randomize_va_space'

FORTIFY

FORTIFY_SOURCE 机制对格式化字符串有两个限制

  • 包含%n的格式化字符串不能位于程序内存中的可写地址。

  • 当使用位置参数时,必须使用范围内的所有参数。所以如果要使用%7$x,你必须同时使用1,2,3,4,5和6。

关闭:-D_FORTIFY_SOURCE=0
开启(只会在编译的时候检查):-D_FORTIFY_SOURCE=1 -O1
开启(强检查):-D_FORTIFY_SOURCE=2 -O2

开启的话就是不能用 %n,%hn,%hhn 这种的,%4$p 也不行了。

Bypass

程序没有开启地址随机化:

def debug(addr):
raw_input('debug:')
gdb.attach(r, "b *" + addr)

在程序运行时调用这个函数就可以调试了

程序开启地址随机化:

wordSz = 4
hwordSz = 2
bits = 32
PIE = 0
mypid=0
def leak(address, size):
with open('/proc/%s/mem' % mypid) as mem:
mem.seek(address)
return mem.read(size)

def findModuleBase(pid, mem):
name = os.readlink('/proc/%s/exe' % pid)
with open('/proc/%s/maps' % pid) as maps:
for line in maps:
if name in line:
addr = int(line.split('-')[0], 16)
mem.seek(addr)
if mem.read(4) == "\x7fELF":
bitFormat = u8(leak(addr + 4, 1))
if bitFormat == 2:
global wordSz
global hwordSz
global bits
wordSz = 8
hwordSz = 4
bits = 64
return addr
log.failure("Module's base address not found.")
sys.exit(1)

def debug(addr = 0):
global mypid
mypid = proc.pidof(r)[0]
raw_input('debug:')
with open('/proc/%s/mem' % mypid) as mem:
moduleBase = findModuleBase(mypid, mem)
gdb.attach(r, "set follow-fork-mode parent\nb *" + hex(moduleBase+addr))

由于开启地址随机化之后ida pro打开程序后,显示的是程序的偏移地址,而不是实际的地址,当程序加载后程序的程序的实际地址是:基地址+偏移地址,调用debug函数的时候只要把偏移地址传递进去就好

泄露libc地址和版本的方法

【1】利用格式化字符串漏洞泄露栈中的数据,从而找到libc的某个函数地址,再利用libc-database来判断远程libc的版本,之后再计算出libc的基址,一般做题我喜欢找__libc_start_main的地址

【2】利用write这个函数,pwntools有个很好用的函数DynELF去利用这个函数计算出程序的各种地址,包括函数的基地址,libc的基地址,libc中system的地址

【3】利用printf函数,printf函数输出的时候遇到0x00时候会停止输出,如果输入的时候没有在最后的字节处填充0x00,那么输出的时候就可能泄露栈中的重要数据,比如libc的某个函数地址

简单的栈溢出

程序没有开启任何保护:

方法一:传统的教材思路是把shellcode写入栈中,然后查找程序中或者libc中有没有call esp或者jmp esp,比如这个题目: http://blog.csdn.net/niexinming/article/details/76893510

方法二:但是现代操作系统中libc中会开启地址随机化,所以先寻找程序中system的函数,再布局栈空间,调用gets(.bss),最后调用system(‘/bin/sh’) 比如这个题目:http://blog.csdn.net/niexinming/article/details/78796408

方法三:覆盖虚表方式利用栈溢出漏洞,这个方法是m4x师傅教我的方法,我觉得很巧妙,比如这个题目:http://blog.csdn.net/niexinming/article/details/78144301

开启nx的程序

开启nx之后栈和bss段就只有读写权限,没有执行权限了,所以就要用到rop这种方法拿到系统权限,如果程序很复杂,或者程序用的是静态编译的话,那么就可以使用ROPgadget这个工具很方便的直接生成rop利用链。有时候好多程序不能直接用ROPgadget这个工具直接找到利用链,所以就要手动分析程序来getshell了,比如这两个题目: http://blog.csdn.net/niexinming/article/details/78259866

开启canary的程序

开启canary后就不能直接使用普通的溢出方法来覆盖栈中的函数返回地址了,要用一些巧妙的方法来绕过或者利canary本身的弱点来攻击

【1】利用canary泄露flag,这个方法很巧妙的运用了canary本身的弱点,当__stack_check_fail时,会打印出正在运行中程序的名称,所以,我们只要将__libc_argv[0]覆盖为flag的地址就能将flag打印出来,比如这个题目: http://blog.csdn.net/niexinming/article/details/78522682

【2】利用printf函数泄露一个子进程的Canary,再在另一个子进程栈中伪造Canary就可以绕过Canary的保护了,比如这个题目:http://blog.csdn.net/niexinming/article/details/78681846

开启PIE的程序

【1】利用printf函数尽量多打印一些栈中的数据,根据泄露的地址来计算程序基地址,libc基地址,system地址,比如这篇文章中echo2的wp: http://blog.csdn.net/niexinming/article/details/78512274

【2】利用write泄露程序的关键信息,这样的话可以很方便的用DynELF这个函数了,比如这个文章中的rsbo2的题解:http://blog.csdn.net/niexinming/article/details/78620566

全部保护开启

如果程序的栈可以被完全控制,那么程序的保护全打开也会被攻破,比如这个题目:http://blog.csdn.net/niexinming/article/details/78666941

格式化字符串漏洞

格式化漏洞现在很难在成熟的软件中遇到,但是这个漏洞却很有趣

【1】pwntools有很不错的函数FmtStr和fmtstr_payload来自动计算格式化漏洞的利用点,并且自动生成payload,比如这个题目:http://blog.csdn.net/niexinming/article/details/78699413http://blog.csdn.net/niexinming/article/details/78512274 中echo的题解

【2】格式化漏洞也是信息泄露的好伴侣,比如这个题目中制造格式化字符串漏洞泄露各种数据 http://blog.csdn.net/niexinming/article/details/78768850

uaf漏洞

如果把堆释放之后,没有把指针指针清0,还让指针保存下来,那么就会引发很多问题,比如这个题目 http://blog.csdn.net/niexinming/article/details/78598635

任意位置写

如果程序可以在内存中的任意位置写的话,那么威力绝对很大

【1】虽然只能写一个字节,但是依然可以控制程序的并getshell,比如这个题目 http://blog.csdn.net/niexinming/article/details/78542089

【2】修改got表是个控制程序流程的好办法,很多ctf题目只要能通过各种方法控制got的写入,就可以最终得到胜利,比如这个题目: http://blog.csdn.net/niexinming/article/details/78542089

【3】如果能计算出libc的基地址的话,控制top_chunk指针也是解题的好方法,比如这个题目: http://blog.csdn.net/niexinming/article/details/78759363

Virus

病毒通常会遵循如下相同步骤:

  1. 定位要感染的文件(一直等待直到打开某些东西,或者搜索目录)
  2. 检查某个文件是否已经被感染
  3. 如果已感染,跳过
  4. 保存文件日期/时间
  5. 设置一个跳转跳到我们的代码保存前几个字节
  6. 添加病毒主体代码
  7. 恢复文件日期/时间

DOS

COM 简介

DOS 内存布局

COM 覆盖型病毒

COM 伴随型病毒

COM 寄生型病毒

隐藏技术

变形技术

反跟踪、反调试、反分析

驻留内存

其他

Executable

ELF

ELF (Executable and Linkable Format)文件,也就是在 Linux 中的目标文件,主要有以下三种类型

  • 可重定位文件(Relocatable File),包含由编译器生成的代码以及数据。链接器会将它与其它目标文件链接起来从而创建可执行文件或者共享目标文件。在 Linux 系统中,这种文件的后缀一般为 .o
  • 可执行文件(Executable File),就是我们通常在 Linux 中执行的程序。
  • 共享目标文件(Shared Object File),包含代码和数据,这种文件是我们所称的库文件,一般以 .so 结尾。一般情况下,它有以下两种使用情景:
    • 链接器(Link eDitor, ld)可能会处理它和其它可重定位文件以及共享目标文件,生成另外一个目标文件。
    • 动态链接器(Dynamic Linker)将它与可执行文件以及其它共享目标组合在一起生成进程镜像。

关于 Link eDitor 的命名,https://en.wikipedia.org/wiki/GNU_linker

目标文件由汇编器和链接器创建,是文本程序的二进制形式,可以直接在处理器上运行。那些需要虚拟机才能够执行的程序 (Java) 不属于这一范围。

PE

Tools

pwntools

Pwntools is a python ctf library designed for rapid exploit development. It essentially help us write exploits quickly, and has a lot of useful functionality behind it.

Also one thing to note, pwntools has Python2 and Python3 versions. Atm this course uses the Python2, but I have plans to switch it all over to Python3. Just keep in mind that some things change between Python2 to the Python3 versions, however the changes are relatively small.

Installation

It’s fairly simple process. The installation process is pretty much just using pip:

$    sudo pip install pwn

If you have any problems, google will help a lot.

Using it

So this is going to be an explanation on how you do various things with pwntools. It will only cover a small bit of functionality.

If we want to import it into python:

from pwn import *

Now one thing that pwntools does for us, is it has some nice piping functionality which helps with IO. If we want to connect to the server at github.com (if you have an IP address, just swap out the dns name with the IP address) on port 9000 via tcp:

target = remote("github.com", 9000)

If you want to run a target binary:

target = process("./challenge")

If you want to attach the gdb debugger to a process:

gdb.attach(target)

If we want to attach the gdb debugger to a process, and also immediately pass a command to gdb to set a breakpoint at main:

gdb.attach(target, gdbscript='b *main')

Now for actual I/O. If we want to send the variable x to the target (target can be something like a process, or remote connection established by pwntools):

target.send(x)

If we wanted to send the variable x followed by a newline character appended to the end:

target.sendline(x)

If we wanted to print a single line of text from target:

print target.recvline()

If we wanted to print all text from target up to the string out:

print target.recvuntil("out")

Now one more thing, ELFs store data via least endian, meaning that data is stored with the least significant byte first. In a few situations where we are scanning in an integer, we will need to take this into account. Luckily pwntools will take care of this for us.

To pack the integer y as a least endian QWORD (commonly used for x64):

p64(x)

To pack the integer y as a least endian DWORD (commonly used for x86):

p32(x)

It can also unpack values we get. Let’s say we wanted to unpack a least endian QWORD and get it’s integer value:

u64(x)

To unpack a DWORD:

u32(x)

Lastly if just wanted to interact directly with target:

target.interactive()

This is only a small bit of the functionality pwntools has. You will see a lot more of the functionality later. If you want to see more of pwntools, it has some great docs: http://docs.pwntools.com/en/stable/

  • send(payload) 发送payload
  • sendline(payload) 发送payload,并进行换行(末尾\n
  • sendafter(some_string, payload) 接收到 some_string 后, 发送你的 payload
  • recvn(N) 接受 N(数字) 字符
  • recvline() 接收一行输出
  • recvlines(N) 接收 N(数字) 行输出
  • recvuntil(some_string) 接收到 some_string 为止

IDA Pro

https://xz.aliyun.com/t/4205 IDA Pro7.0使用技巧总结

其他的慢慢看 IDA 权威指南吧

IDA Pro 逆向速参 https://juejin.im/post/6844903550460362766

a:将数据转换为字符串

f5:一键反汇编

esc:回退键,能够倒回上一部操作的视图(只有在反汇编窗口才是这个作用,如果是在其他窗口按下esc,会关闭该窗口)

shift+f12:可以打开string窗口,一键找出所有的字符串,右击setup,还能对窗口的属性进行设置

ctrl+w:保存ida数据库

ctrl+s:选择某个数据段,直接进行跳转

ctrl+鼠标滚轮:能够调节流程视图的大小

x:对着某个函数、变量按该快捷键,可以查看它的交叉引用

g:直接跳转到某个地址

n:更改变量的名称

y:更改变量的类型

/ :在反编译后伪代码的界面中写下注释

\:在反编译后伪代码的界面中隐藏/显示变量和函数的类型描述,有时候变量特别多的时候隐藏掉类型描述看起来会轻松很多

;:在反汇编后的界面中写下注释

ctrl+shift+w:拍摄IDA快照

u:undefine,取消定义函数、代码、数据的定义

配置

Disassembly

OPCODE_BYTES            = 6   // 机器码字节数,默认0
INDENTION = 0 // 指令缩进,默认16,设为0代码会整洁一些
COMMENTS_INDENTION = 30 // 注释缩进,默认40
MAX_TAIL = 16 // 交叉参考的深度,默认16
MAX_XREF_LENGTH = 80 // Maximal length of line with cross-references
MAX_DATALINE_LENGTH = 100 // Data directives (db,dw, etc):
// max length of argument string
SHOW_AUTOCOMMENTS = NO // Display comments for every instruction
// Advanced users will turn this off
// Please note that there is another definition
// for IBM PC below
SHOW_BASIC_BLOCKS = NO // Generate an empty line at the end of a basic block
SHOW_BORDERS = YES // Borders between data/code
SHOW_EMPTYLINES = YES // Generate empty line to make disassembly more readable
SHOW_LINEPREFIXES = YES // Show line prefixes (like 1000:0000)
SHOW_XREFS = 15 // 显示大量的交叉参考信息,默认2
SHOW_ORIGINS = NO // Generate 'org' directives

ASCII strings & names

Options => ASCII String styles

中文

IDA 从 7.0 版本开始正式支持中文字符串的显示,但仍需要配置 ida.cfg。

在 IDA \ CFG 目录下新建一个文件 Chinese.clt,内容如下。(好像默认就有了)

u2000..u206F,
u2F00..u2FDF,
u3000..u303F,
u31C0..u31EF,
u3400..u4DBF,
u4E00..u9FFF,
uF900..uFAFF,
uFE30..uFE4F,
u20000..u2A6DF,
u2A700..u2BA7F,
u2B740..u2B81F,
u2F800..u2FA1F;

导航条

  • 蓝色:.text section

    • 深蓝:用户自己写的函数编译后的代码区
    • 浅蓝:编译器自己添加的函数,像启动函数,异常函数等(我自己猜的,不一定百分百正确)
  • 粉红色:.idata section

    有关输入表的一些数据信息

  • 军绿色:.rdata section

    纯数据,只读

  • 灰色:为了段对齐而留下的空隙

  • 黑色:禁区,不存在任何数据

ghidra

GDB

gdb 还有其他一些小技巧,可以参考awesome-cheatsheets/tools/gdb.txt中的列表。该列表最初由韦神创建,我时不时也会添加一些上去。当然为了方便大家的查阅,这里直接给出汇总表格附录:

启动 GDB

命令 含义 备注
gdb object 正常启动,加载可执行
gdb object core 对可执行 + core 文件进行调试
gdb object pid 对正在执行的进程进行调试
gdb 正常启动,启动后需要 file 命令手动加载
gdb -tui 启用 gdb 的文本界面(或 ctrl-x ctrl-a 更换 CLI/TUI)

帮助信息

命令 含义 备注
help 列出命令分类
help running 查看某个类别的帮助信息
help run 查看命令 run 的帮助
help info 列出查看程序运行状态相关的命令
help info line 列出具体的一个运行状态命令的帮助
help show 列出 GDB 状态相关的命令
help show commands 列出 show 命令的帮助

断点

命令 含义 备注
break main 对函数 main 设置一个断点,可简写为 b main
break 101 对源代码的行号设置断点,可简写为 b 101
break basic.c:101 对源代码和行号设置断点
break basic.c:foo 对源代码和函数名设置断点
break *0x00400448 对内存地址 0x00400448 设置断点
info breakpoints 列出当前的所有断点信息,可简写为 info break
delete 1 按编号删除一个断点
delete 删除所有断点
clear 删除在当前行的断点
clear function 删除函数断点
clear line 删除行号断点
clear basic.c:101 删除文件名和行号的断点
clear basic.c:main 删除文件名和函数名的断点
clear *0x00400448 删除内存地址的断点
disable 2 禁用某断点,但是部删除
enable 2 允许某个之前被禁用的断点,让它生效
rbreak {regexpr} 匹配正则的函数前断点,如 ex_* 将断点 ex_ 开头的函数
tbreak function/line 临时断点
hbreak function/line 硬件断点
ignore {id} {count} 忽略某断点 N-1 次
condition {id} {expr} 条件断点,只有在条件生效时才发生
condition 2 i == 20 2号断点只有在 i == 20 条件为真时才生效
watch {expr} 对变量设置监视点
info watchpoints 显示所有观察点
catch exec 断点在exec事件,即子进程的入口地址

运行程序

命令 含义 备注
run 运行程序
run {args} 以某参数运行程序
run < file 以某文件为标准输入运行程序
run < <(cmd) 以某命令的输出作为标准输入运行程序
run <<< $(cmd) 以某命令的输出作为标准输入运行程序 Here-String
set args {args} ... 设置运行的参数
show args 显示当前的运行参数
cont 继续运行,可简写为 c
step 单步进入(si 执行一行汇编),碰到函数会进去。
step {count} 单步多少次
next 单步跳过(ni 执行一行汇编),碰到函数不会进入。
next {count} 单步多少次
CTRL+C 发送 SIGINT 信号,中止当前运行的程序
attach {process-id} 链接上当前正在运行的进程,开始调试
detach 断开进程链接
finish 结束当前函数的运行
until 持续执行直到代码行号大于当前行号(跳出循环)
until {line} 持续执行直到执行到某行
kill 杀死当前运行的函数

栈帧

命令 含义 备注
bt 打印 backtrace
frame 显示当前运行的栈帧
up 向上移动栈帧(向着 main 函数)
down 向下移动栈帧(远离 main 函数)
info locals 打印帧内的相关变量
info args 打印函数的参数

代码浏览

命令 含义 备注
list 101 显示第 101 行周围 10行代码
list 1,10 显示 1 到 10 行代码
list main 显示函数周围代码
list basic.c:main 显示另外一个源代码文件的函数周围代码
list - 重复之前 10 行代码
list *0x22e4 显示特定地址的代码
cd dir 切换当前目录
pwd 显示当前目录
search {regexpr} 向前进行正则搜索
reverse-search {regexp} 向后进行正则搜索
dir {dirname} 增加源代码搜索路径
dir 复位源代码搜索路径(清空)
show directories 显示源代码路径

浏览数据

命令 含义 备注
print {expression} 打印表达式,并且增加到打印历史
print /x {expression} 十六进制输出,print 可以简写为 p
print array[i]@count 打印数组范围
print $ 打印之前的变量
print *$->next 打印 list
print $1 输出打印历史里第一条
print ::gx 将变量可视范围(scope)设置为全局
print 'basic.c'::gx 打印某源代码里的全局变量,(gdb 4.6)
print /x &main 打印函数地址
x *0x11223344 显示给定地址的内存数据
x /nfu {address} 打印内存数据,n是多少个,f是格式,u是单位大小
x /10xb *0x11223344 按十六进制打印内存地址 0x11223344 处的十个字节
x/x &gx 按十六进制打印变量 gx,x和斜杆后参数可以连写
x/4wx &main 按十六进制打印位于 main 函数开头的四个 long
x/gf &gd1 打印 double 类型
help x 查看关于 x 命令的帮助
info locals 打印本地局部变量
info functions {regexp} 打印函数名称
info variables {regexp} 打印全局变量名称
ptype name 查看类型定义,比如 ptype FILE,查看 FILE 结构体定义
whatis {expression} 查看表达式的类型
set var = {expression} 变量赋值
set *address = value 可将 * 换成 char / short / long 分别设定 1/2/8 byte
set {int}0x600000 = 1337
display {expression} 在单步指令后查看某表达式的值
undisplay 删除单步后对某些值的监控
info display 显示监视的表达式
show values 查看记录到打印历史中的变量的值 (gdb 4.0)
info history 查看打印历史的帮助 (gdb 3.5)

文件操作

命令 含义 备注
file {object} 加载新的可执行文件供调试
file 放弃可执行和符号表信息
symbol-file {object} 仅加载符号表
exec-file {object} 指定用于调试的可执行文件(非符号表)
core-file {core} 加载 core 用于分析

信号控制

命令 含义 备注
info signals 打印信号设置
handle {signo} {actions} 设置信号的调试行为
handle INT print 信号发生时打印信息
handle INT noprint 信号发生时不打印信息
handle INT stop 信号发生时中止被调试程序
handle INT nostop 信号发生时不中止被调试程序
handle INT pass 调试器接获信号,不让程序知道
handle INT nopass 调试起不接获信号
signal signo 继续并将信号转移给程序
signal 0 继续但不把信号给程序

线程调试

命令 含义 备注
info threads 查看当前线程和 id
thread {id} 切换当前调试线程为指定 id 的线程
break {line} thread all 所有线程在指定行号处设置断点
thread apply {id..} cmd 指定多个线程共同执行 gdb 命令
thread apply all cmd 所有线程共同执行 gdb 命令
set schedule-locking ? 调试一个线程时,其他线程是否执行
set non-stop on/off 调试一个线程时,其他线程是否运行
set pagination on/off 调试一个线程时,分页是否停止
set target-async on/off 同步或者异步调试,是否等待线程中止的信息

进程调试

命令 含义 备注
info inferiors 查看当前进程和 id
inferior {id} 切换某个进程
kill inferior {id...} 杀死某个进程
set detach-on-fork on/off 设置当进程调用fork时gdb是否同时调试父子进程
set follow-fork-mode parent/child 设置当进程调用fork时是否进入子进程

汇编调试

命令 含义 备注
info registers 打印普通寄存器
info all-registers 打印所有寄存器
print/x $pc 打印单个寄存器
stepi 指令级别单步进入 si
nexti 指令级别单步跳过 ni
display/i $pc 监控寄存器(每条单步完以后会自动打印值)
x/x &gx 十六进制打印变量
info line 22 打印行号为 22 的内存地址信息
info line *0x2c4e 打印给定内存地址对应的源代码和行号信息
disassemble {addr} 对地址进行反汇编,比如 disassemble 0x2c4e

其他命令

命令 含义 备注
show commands 显示历史命令 (gdb 4.0)
info editing 显示历史命令 (gdb 3.5)
ESC-CTRL-J 切换到 Vi 命令行编辑模式
set history expansion on 允许类 c-shell 的历史
break class::member 在类成员处设置断点
list class:member 显示类成员代码
ptype class 查看类包含的成员 /o可以看成员偏移,类似pahole
print *this 查看 this 指针
define command ... end 定义用户命令
<return> 直接按回车执行上一条指令
shell {command} [args] 执行 shell 命令
source {file} 从文件加载 gdb 命令
quit 退出 gdb

pwndbg

用法特性:https://github.com/pwndbg/pwndbg/blob/dev/FEATURES.md

分屏

peda

git clone https://github.com/longld/peda.git ~/peda
echo "source ~/peda/peda.py" >> ~/.gdbinit

Ollydbg

PE 类工具

masm32

Immunitydebugger

pwndbg

z3

strings

file

binwalk

Reference

https://guyinatuxedo.github.io/

https://adworld.xctf.org.cn/task REVERSE或者PWN或者MOBILE三个方向合计完成任意9题

http://reversing.kr/ 5题

http://pwnable.kr/ 6题

https://pwnable.tw/ 4题

CATALOG
  1. 1. 每天学点新东西
  2. 2. Assembly
    1. 2.1. Intel vs AT&T
    2. 2.2. 程序模板
    3. 2.3. 寄存器
    4. 2.4. 数据类型
    5. 2.5. 寻址模式
      1. 2.5.1. 直接内存寻址
      2. 2.5.2. 寄存器间接寻址
    6. 2.6. 常用指令
      1. 2.6.1. 控制转移
  3. 3. Clang
    1. 3.1. static
  4. 4. Reverse
    1. 4.1. 要求
    2. 4.2. 常规逆向流程
    3. 4.3. 定位关键代码 tips
    4. 4.4. 逆向 tips
    5. 4.5. 动态分析
    6. 4.6. 算法和数据结构识别
    7. 4.7. 代码混淆
    8. 4.8. 保护壳
    9. 4.9. 反调试
    10. 4.10. 非常规逆向思路
      1. 4.10.1. 前期准备
      2. 4.10.2. 找工具
    11. 4.11. 寻找主入口(main函数)
  5. 5. Stack Overflow
    1. 5.1. Basic
      1. 5.1.1. 调用约定
    2. 5.2. 类型
  6. 6. Format Strings
  7. 7. Array Indexing
  8. 8. Bad Seed
  9. 9. Z3 & Symbolic Execution(angr)
  10. 10. ROP
    1. 10.1. Partial Overwrite
    2. 10.2. Stack Pivoting
    3. 10.3. SIGROP(SROP)
    4. 10.4. ret2csu
    5. 10.5. ret2system
  11. 11. Heap Exploitation
    1. 11.1. Double Frees
    2. 11.2. Heap Consolidation
    3. 11.3. Use after Frees
    4. 11.4. Protostar: heap0
    5. 11.5. protostar: heap1
    6. 11.6. protostar: heap2
    7. 11.7. unlink() Exploitation
    8. 11.8. Heap Grooming
    9. 11.9. Fastbin Attack
    10. 11.10. Unsortedbin Attack
    11. 11.11. Largebin Attack
    12. 11.12. GLibc Tcache
    13. 11.13. House of Spirit
    14. 11.14. House of Lore
    15. 11.15. House of Force
    16. 11.16. House of Einherjar
    17. 11.17. House of Orange
    18. 11.18. Miscellaneous
  12. 12. Grab Bag
    1. 12.1. Shell coding
    2. 12.2. Patching
    3. 12.3. .NET
  13. 13. Security Protection Mechanism
    1. 13.1. NX
    2. 13.2. RELRO
    3. 13.3. Stack (Canary)
    4. 13.4. PIE
    5. 13.5. FORTIFY
    6. 13.6. Bypass
      1. 13.6.0.1. 泄露libc地址和版本的方法
      2. 13.6.0.2. 简单的栈溢出
      3. 13.6.0.3. 开启nx的程序
      4. 13.6.0.4. 开启canary的程序
      5. 13.6.0.5. 开启PIE的程序
      6. 13.6.0.6. 全部保护开启
        1. 13.6.0.6.1. 格式化字符串漏洞
        2. 13.6.0.6.2. uaf漏洞
        3. 13.6.0.6.3. 任意位置写
  • 14. Virus
    1. 14.1. DOS
      1. 14.1.1. COM 简介
      2. 14.1.2. COM 覆盖型病毒
      3. 14.1.3. COM 伴随型病毒
      4. 14.1.4. COM 寄生型病毒
    2. 14.2. 隐藏技术
    3. 14.3. 变形技术
    4. 14.4. 反跟踪、反调试、反分析
    5. 14.5. 驻留内存
    6. 14.6. 其他
  • 15. Executable
    1. 15.1. ELF
    2. 15.2. PE
  • 16. Tools
    1. 16.1. pwntools
      1. 16.1.1. Installation
      2. 16.1.2. Using it
    2. 16.2. IDA Pro
      1. 16.2.1. 配置
        1. 16.2.1.1. Disassembly
        2. 16.2.1.2. ASCII strings & names
        3. 16.2.1.3. 中文
      2. 16.2.2. 导航条
    3. 16.3. ghidra
    4. 16.4. GDB
      1. 16.4.1. 启动 GDB
      2. 16.4.2. 帮助信息
      3. 16.4.3. 断点
      4. 16.4.4. 运行程序
      5. 16.4.5. 栈帧
      6. 16.4.6. 代码浏览
      7. 16.4.7. 浏览数据
      8. 16.4.8. 文件操作
      9. 16.4.9. 信号控制
      10. 16.4.10. 线程调试
      11. 16.4.11. 进程调试
      12. 16.4.12. 汇编调试
      13. 16.4.13. 其他命令
    5. 16.5. pwndbg
    6. 16.6. peda
    7. 16.7. Ollydbg
    8. 16.8. PE 类工具
    9. 16.9. masm32
    10. 16.10. Immunitydebugger
    11. 16.11. pwndbg
    12. 16.12. z3
    13. 16.13. strings
    14. 16.14. file
    15. 16.15. binwalk
  • 17. Reference