Patch4Pwn

记录学习到的patch方法.主要针对CTFpwn.
供自己以后忘记的时候查阅…

start

主要来源p4nda

IDA

IDApatch主要是原有的patch功能和添加的插件例如keypatch

keypatch

安装(for mac):
https://github.com/fjh658/keystone-engine
https://github.com/keystone-engine/keypatch

1
2
3
4
5
6
git clone https://github.com/fjh658/keystone-engine.git
cd keystone-engine
git submodule update --init --recursive
sudo python setup.py install --verbose
cp -rf /usr/local/lib/python2.7/site-packages/keystone /Applications/IDA\ Pro\ 7.0/ida.app/Contents/MacOS/python/
brew install cmake

使用

  • control+option+k可以直接打汇编指令也可以用符号.(长度不足补齐nop)
  • 右键可以search 汇编指令

    替换某个函数

    这个还不知道keypatch咋整…如果使用patchpyte过程如下
    例如替换printfputs
    call printf ======>call puts
  • 原来的值 old
  • puts@plt
  • printf@plt
  • new_address:(old+puts-printf)

    缺点

    改变比较有限,不能call 没有plt的函数.不能hook

lief

mac上没装成功ubuntu好像直接pip install lief就可以了
说明文档太长还没去看…
https://lief.quarkslab.com/doc/latest/api/python/elf.html#segment

rude_patch

直接改strtab 例如fmtstr漏洞修复:printf==>puts
(注意这里比较暴力注意其他地方有没有用printf的,是否受影响…)
脚本如下

1
2
3
4
5
6
7
8
9
10
11
# @n132
import lief
import os
name="./main"
binary=lief.parse(name)
for x in binary.imported_symbols:
if x.name=="printf":
x.name="puts"
print "[+]:printf fixed"
binary.write("patched_file")
os.system("chmod +x patched_file")

ADD Seg

主要是增加一个段可以增加编译的hook函数
例如

1
2
3
4
5
6
7
8
9
10
11
12
13
void diy(char *a){
asm(
"mov %rdi,0x68732f6e69622f\n"
"push %rdi\n"
"mov %rdi,%rsp\n"
"xor %rsi,%rsi\n"
"xor %rdx,%rdx\n"
"mov %ral,0x3b\n"
"syscall\n"
);
}

//gcc -Os -nostdlib -nodefaultlibs -fPIC -Wl,-shared hook.c -o hook

编译之后增加到binary里

1
2
3
4
5
import lief
binary=lief.parse("./main")
lib=lief.parse("./hook")
segment_add = binary.add(lib.segments[0])
binary.write("new")

之后确定位置后hook

1
2
3
4
5
6
7
8
9
10
import lief
from pwn import *
def patch_call(file,where,aim,arch = "amd64"):
aim = p32((end - (where + 5 )) & 0xffffffff)
order = '\xe8'+aim#call aim
file.patch_address(where,[ord(i) for i in order])
binary.write("new")
raw_address=
aim_address=
patch_call(binary,raw_address,aim_address)

ADD to .eh_frame

为了防止增加了seg导致binary变化太大.可以直接把较小的hook函数写进.eh_frame
感觉一般来说0x100字节左右的空间很够用了…感觉很好的方法…

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
import lief
from pwn import *
def patch_call(file,where,aim,arch = "amd64"):
aim = p32((aim - (where + 5 )) & 0xffffffff)
order = '\xe8'+aim#call aim
file.patch_address(where,[ord(i) for i in order])
binary.write("new")
binary=lief.parse("../main")
context.arch='amd64'
hook='''
xor rax,rax
xor rsi,rsi
xor rdx,rdx
mov rdi,0x68732f6e69622f
push rdi
mov rdi,rsp
mov al,0x3b
syscall
'''
hook=asm(hook)
en_frame=0x000000000000A18
binary.patch_address(en_frame,[ord(i) for i in hook])
raw_address=0x00000000000092F
aim_address=en_frame
patch_call(binary,raw_address,aim_address)
binary.write("new")

Author: n132!
Link: https://n132.github.io/2019/05/02/2019-05-02-Patch4Pwn/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.