使用Patchkit和LIEF Patch二进制程序

patchkit

挖个坑, 回头填上

LIEF

修改ELF

修改目标文件的导入符号:

示例程序:

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
puts("/bin/bash");
return EXIT_SUCCESS;
}

那么现在要把puts改成system:

import lief
file = lief.parse("test")
# get puts, system symbol
puts_sym = filter(lambda e: e.name == "puts", file.imported_symbols)[0]
# set puts to system
puts_sym.name = "system"
file.write("test.patch")
print("done")
➜  LIEF_test ./test.patch 
a@ubuntu:~/LIEF_test$ id
uid=1000(a) gid=1000(a) groups=1000(a),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare)

这种方法碰到uaf或者double free之类的很有用, 直接将malloc改为realloc, 这样创建chunk的时候会清空内存, 可以解决很多问题

示例题目:

修改libc

修改libc里的符号, 然后用LD_LIBRARY_PATH加载

import lief

libc = lief.parse('/lib/x86_64-linux-gnu/libc-2.23.so')

# get puts, system symbol
puts_sym = filter(lambda e: e.name == "puts", libc.dynamic_symbols)[0]
system_sym = filter(lambda e: e.name == "system", libc.dynamic_symbols)[0]

# swap them
puts_sym.name = "system"
system_sym.name = "puts"
libc.write("libc.so.6")

然后export LD_LIBRARY_PATH=./:$LD_LIBRARY_PATH即可

但是只能在当前shell中生效, 如果要在所有shell生效, 需要把下述语句写入~/.bash_profile

LD_LIBRARY_PATH=path:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH

如果我们有bash_profile的读写权限的话, 完全可以删掉libc里的system和execve函数, 导致无法用libc getshell

修改库函数

碰到一些无法通过简单修改函数符号表之类的elf, 比如未检查size导致的堆溢出之类的, 我们需要增加一些代码来进行修改

测试程序:

//test.c
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(int argc, char **argv) {
if (argc != 2) {
printf("Usage: %s <a> \n", argv[0]);
exit(-1);
}

int a = atoi(argv[1]);
printf("exp(%d) = %f\n", a, exp(a));
return 0;
}

我们的目标是把exp函数改为我们自定义的hook函数

//hook.c
double hook(double x) {
return x + 100;
}

编译: gcc -Os -nostdlib -nodefaultlibs -fPIC -Wl,-shared hook.c -o hook

jio本:

import lief

libm = lief.parse("/lib/x86_64-linux-gnu/libm-2.23.so")
hook = lief.parse("hook")

segment_added = libm.add(hook.segments[0])

print("Hook inserted at VA: 0x{:06x}".format(segment_added.virtual_address))

exp_symbol = libm.get_symbol("exp")
hook_symbol = hook.get_symbol("hook")

exp_symbol.value = segment_added.virtual_address + hook_symbol.value

libm.write("libm.so.6")

这样就把libc里的exp函数改为我们的hook函数了

修改plt/got表

测试程序:

//test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Damn_YoU_Got_The_Flag
char password[] = "\x18\x3d\x31\x32\x03\x05\x33\x09\x03\x1b\x33\x28\x03\x08\x34\x39\x03\x1a\x30\x3d\x3b";

inline int check(char* input);

int check(char* input) {
for (int i = 0; i < sizeof(password) - 1; ++i) {
password[i] ^= 0x5c;
}
return memcmp(password, input, sizeof(password) - 1);
}

int main(int argc, char **argv) {

if (check(argv[1]) == 0) {
puts("You got it !!");
return EXIT_SUCCESS;
}

puts("Wrong");
return EXIT_FAILURE;
}

这里把memcpy修改为我们自己的memcpy, 把内容打印出来:

//hook.c
#include "arch/x86_64/syscall.c"
#define stdout 1

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

int my_memcmp(const void* lhs, const void* rhs, int n) {
const char msg[] = "Hook add\n";
_write(stdout, msg, sizeof(msg));
_write(stdout, (const char*)lhs, n);
_write(stdout, "\n", 2);
_write(stdout, (const char*)rhs, n);
_write(stdout, "\n", 2);
return 0;
}

jio本:

import lief

crackme = lief.parse("crackme.bin")
hook = lief.parse("hook")

segment_added = crackme.add(hook.segments[0])

my_memcmp = hook.get_symbol("my_memcmp")
my_memcmp_addr = segment_added.virtual_address + my_memcmp.value

crackme.patch_pltgot('memcmp', my_memcmp_addr)
crackme.write("crackme.hooked")

参考

https://bbs.pediy.com/thread-222623.htm