Commit e1f2c0e6 authored by fangzongwu's avatar fangzongwu

[feat]: merge burstfs syscall_intercept hwk code

parent 3dc856d1
.vscode
\ No newline at end of file
......@@ -62,6 +62,27 @@ set(SYSCALL_INTERCEPT_VERSION_PATCH 0)
set(SYSCALL_INTERCEPT_VERSION
${SYSCALL_INTERCEPT_VERSION_MAJOR}.${SYSCALL_INTERCEPT_VERSION_MINOR}.${SYSCALL_INTERCEPT_VERSION_PATCH})
find_package(OpenSSL REQUIRED)
if(NOT OpenSSL_FOUND)
message("package not find OpenSSL,using pkgConfig find.")
find_package(PkgConfig QUIET)
if(PKG_CONFIG_FOUND)
pkg_search_module(OpenSSL OpenSSL REQUIRED)
endif()
endif()
if(NOT OpenSSL_FOUND)
message(FATAL_ERROR
"Unable to find OpenSSL. Please install pkg-config and OpenSSL development files, e.g.:
sudo apt-get install pkg-config libssl-dev (on Debian, Ubuntu)
or
sudo yum install openssl-devel (on Centos)
If casptone is installed, but cmake didn't manage to find it, there is a slight chance of fixing things by setting some of the following environment variables:
PKG_CONFIG_PATH, CMAKE_PREFIX_PATH, CMAKE_MODULE_PATH")
endif()
if (NOT DEFINED capstone_LIBRARIES AND NOT DEFINED capstone_INCLUDEDIR AND NOT DEFINED capstone_LIBRARIES_PATH)
include(cmake/find_capstone.cmake)
else()
......@@ -90,6 +111,7 @@ set(SOURCES_ASM
src/intercept_wrapper.S)
include_directories(include)
link_directories(${capstone_LIBRARY_DIRS})
......@@ -155,10 +177,10 @@ endif()
target_link_libraries(syscall_intercept_shared
PRIVATE ${CMAKE_DL_LIBS}
"-Wl,--push-state,${CAPSTONE_LINK_MODE} -lcapstone -Wl,--pop-state"
"-Wl,--version-script=${CMAKE_SOURCE_DIR}/version.map")
"-Wl,--version-script=${CMAKE_SOURCE_DIR}/version.map" OpenSSL::Crypto )
target_link_libraries(syscall_intercept_static
INTERFACE ${CMAKE_DL_LIBS} ${capstone_LIBRARIES})
INTERFACE ${CMAKE_DL_LIBS} ${capstone_LIBRARIES} OpenSSL::Crypto)
set_target_properties(syscall_intercept_shared
PROPERTIES VERSION ${SYSCALL_INTERCEPT_VERSION}
......
......@@ -48,8 +48,10 @@
#include <stddef.h>
#include <stdint.h>
struct intercept_disasm_result {
const unsigned char *address;
const unsigned char *address; // = offset + text_start
unsigned long offset; // address referring to text_start
bool is_set;
......@@ -106,7 +108,8 @@ struct intercept_disasm_result {
* These are only valid, when has_ip_relative_opr is true.
*/
int32_t rip_disp;
const unsigned char *rip_ref_addr;
const unsigned char *rip_ref_addr; // = rip + rip_disp
// rip = address + length
#ifndef NDEBUG
const char *mnemonic;
......
......@@ -53,6 +53,7 @@
#include <stdarg.h>
#include <sys/auxv.h>
#include <linux/sched.h>
#include <time.h>
#include "intercept.h"
#include "intercept_log.h"
......@@ -91,13 +92,69 @@ debug_dump(const char *fmt, ...)
if (len <= 0)
return;
char buf[len + 1];
// char buf[len + 1];
// va_start(ap, fmt);
// len = vsprintf(buf, fmt, ap);
// va_end(ap);
// syscall_no_intercept(SYS_write, 2, buf, len);
int time_len = 22;
struct timespec tm;
syscall_no_intercept(SYS_clock_gettime, CLOCK_REALTIME, &tm);
char buf[time_len + len + 1];
va_start(ap, fmt);
len = vsprintf(buf, fmt, ap);
len = vsprintf(buf + time_len, fmt, ap);
va_end(ap);
syscall_no_intercept(SYS_write, 2, buf, len);
sprintf(buf, "%ld.%09ld ", tm.tv_sec, tm.tv_nsec);
syscall_no_intercept(SYS_write, 2, buf, time_len + len);
}
/*
* get_real_path
* Obtain the real path of the object.
*
* The paths resolved are stored in BSS, in the paths variable. The
* returned pointer points into this variable. The next_path
* pointer keeps track of the already "allocated" space inside
* the paths array.
*/
static const char *
get_real_path(const char *path)
{
static char paths[0x10000];
static char *next_path = paths;
static const int path_max = 4096;
if ((next_path >= paths + sizeof(paths) - path_max))
return NULL; /* No more space left */
while (true) {
ssize_t read_size = syscall_no_intercept(SYS_readlink,
path, next_path, path_max - 1);
if (read_size < 0) {
debug_dump("error readlink of %s\n", path);
return NULL;
}
next_path[read_size] = '\0';
if (read_size < path_max - 1) {
// reach the actual file path
break;
}
path = next_path;
}
path = next_path;
next_path += strlen(next_path) + 1;
return path;
}
static void log_header(void);
......@@ -155,6 +212,10 @@ static bool libc_found;
/* address of [vdso] */
static void *vdso_addr;
/* the dir to save text desc */
char *text_desc_save_dir = NULL;
/* save text desc to file or not */
bool text_desc_save_file = false;
/*
* allocate_next_obj_desc
* Handles the dynamic allocation of the struct intercept_desc array.
......@@ -427,6 +488,7 @@ analyze_object(struct dl_phdr_info *info, size_t size, void *data)
patches->base_addr = (unsigned char *)info->dlpi_addr;
patches->path = path;
patches->real_path = get_real_path(path);
find_syscalls(patches);
return 0;
......
......@@ -62,10 +62,12 @@ struct syscall_desc {
};
struct range {
unsigned char *address;
unsigned char *address; // = offset + text_start
unsigned long offset; // address referring to text_start
size_t size;
};
/*
* The patch_list array stores some information on
* whereabouts of patches made to glibc.
......@@ -147,6 +149,9 @@ struct intercept_desc {
/* where the object is in fs */
const char *path;
/* the real path of the object */
const char *real_path;
/*
* Some sections of the library from which information
* needs to be extracted.
......@@ -175,6 +180,8 @@ struct intercept_desc {
struct patch_desc *items;
unsigned count;
size_t jump_table_size;
unsigned char *jump_table;
size_t nop_count;
......
......@@ -40,11 +40,18 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <time.h>
#include <openssl/md5.h>
#include "intercept.h"
#include "intercept_util.h"
#include "disasm_wrapper.h"
#define INTERCEPT_TEXT_DESC "INTERCEPT_TEXT_DESC"
extern bool text_desc_save_file;
extern char *text_desc_save_dir;
/*
* open_orig_file
*
......@@ -674,6 +681,353 @@ allocate_trampoline_table(struct intercept_desc *desc)
desc->next_trampoline = desc->trampoline_table;
}
/*
* get_text_desc_save_path
*/
static void
get_text_desc_save_path(struct intercept_desc *desc, char *desc_save_path)
{
const char *filename = basename(desc->real_path);
if (text_desc_save_dir == NULL) {
sprintf(desc_save_path, "/tmp/%s_%s",
INTERCEPT_TEXT_DESC, filename);
} else {
sprintf(desc_save_path, "%s/%s_%s",
text_desc_save_dir, INTERCEPT_TEXT_DESC, filename);
}
}
/*
* get_text_desc_save_flag
* format: INTERCEPT_TEXT_DESC_filename
*/
static void
get_text_desc_save_flag(struct intercept_desc *desc, char *desc_save_flag)
{
const char *filename = basename(desc->real_path);
sprintf(desc_save_flag, "%s_%s", INTERCEPT_TEXT_DESC, filename);
}
static void
calculate_data_md5(const char *data, size_t length, char *md5)
{
unsigned char md5_hash[MD5_DIGEST_LENGTH];
MD5_CTX mdContext;
MD5_Init(&mdContext);
MD5_Update(&mdContext, data, length);
MD5_Final(md5_hash, &mdContext);
for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
sprintf(&md5[i * 2], "%02x", (unsigned)md5_hash[i]);
}
}
/*
* save text desc to file
* save desc->jump_table && desc->nop_table && desc->items
* format:
* TEXT_DESC_SAVE_FLAG|md5sum|data_length|
* jump_table_size|jump_table|nop_count|nop_table|patches_count|patches
*/
static bool
save_text_desc_to_file(struct intercept_desc *desc)
{
char filepath[4096] = {0};
get_text_desc_save_path(desc, filepath);
debug_dump("save_text_desc_to_file of %s to %s\n",
desc->real_path, filepath);
int fd = syscall_no_intercept(SYS_open, filepath, O_CREAT | O_RDWR,
0644);
if (fd < 0) {
debug_dump("save_text_desc_to_file open %s fail\n", filepath);
return false;
}
int desc_save_flag_len = 0;
char desc_save_flag[256] = {0};
char data_md5sum[MD5_DIGEST_LENGTH * 2 + 1] = {0};
char *data_addr = NULL; // the data address
char *file_addr = NULL; // the file address
unsigned long data_length = 0;
unsigned long file_length = 0;
long data_md5sum_offset = 0; // the data md5sum offset in the file
long data_length_offset = 0; // the data length offset in the file
long data_offset = 0; // the data offset in the file
long data_pos = 0; // the data offset relative to the data address
// 1. seek at the position of the first data character
get_text_desc_save_flag(desc, desc_save_flag);
desc_save_flag_len = strlen(desc_save_flag);
data_md5sum_offset = xlseek(fd, desc_save_flag_len, SEEK_CUR);
data_length_offset = xlseek(fd, sizeof(data_md5sum), SEEK_CUR);
data_offset = xlseek(fd, sizeof(data_length), SEEK_CUR);
// 2. caculate the data length
data_length += sizeof(desc->jump_table_size);
data_length += desc->jump_table_size;
data_length += sizeof(desc->nop_count);
data_length += desc->nop_count * sizeof(struct range);
data_length += sizeof(desc->count);
data_length += desc->count * sizeof(struct patch_desc);
// 3. ftruncate and mmap the file(more convenient to caculate md5)
file_length = data_offset + data_length;
int ret = syscall_no_intercept(SYS_ftruncate, fd, file_length);
if (ret != 0) {
debug_dump("save_text_desc_to_file ftruncate %s fail\n",
filepath);
syscall_no_intercept(SYS_close, fd);
return false;
}
file_addr = xmmap_file(fd, file_length, true);
data_addr = file_addr + data_offset;
debug_dump("save_text_desc_to_file: "
"desc_save_flag: %s, desc_save_flag_len: %d, "
"data_md5sum_offset: %ld, data_length_offset: %ld, "
"data_offset: %ld, data_length: %lu, "
"file_length: %lu, file_addr: %p, data_addr: %p\n",
desc_save_flag, desc_save_flag_len,
data_md5sum_offset, data_length_offset,
data_offset, data_length, file_length, file_addr, data_addr);
// 4. save data
// 4.1. save jump_table_size && jump_table
memcpy(data_addr, &desc->jump_table_size,
sizeof(desc->jump_table_size));
data_pos += sizeof(desc->jump_table_size);
memcpy(data_addr + data_pos, desc->jump_table, desc->jump_table_size);
data_pos += desc->jump_table_size;
// 4.2. save nop_count && nop_table
memcpy(data_addr + data_pos, &desc->nop_count, sizeof(desc->nop_count));
data_pos += sizeof(desc->nop_count);
for (size_t i = 0; i < desc->nop_count; i++) {
struct range *nop = &desc->nop_table[i];
memcpy(data_addr + data_pos, nop, sizeof(struct range));
data_pos += sizeof(struct range);
}
// 4.3. save patch count && patches
memcpy(data_addr + data_pos, &desc->count, sizeof(desc->count));
data_pos += sizeof(desc->count);
for (unsigned i = 0; i < desc->count; i++) {
struct patch_desc *patch = &desc->items[i];
memcpy(data_addr + data_pos, patch, sizeof(struct patch_desc));
data_pos += sizeof(struct patch_desc);
// debug_dump("save desc patches, idx: %d, dst_jmp_patch: %p, "
// "syscall_addr: %p, syscall_offset: %lu\n",
// i, patch->dst_jmp_patch,
// patch->syscall_addr, patch->syscall_offset);
}
// 4. save data -- end
// 5. save data length
memcpy(file_addr + data_length_offset, &data_length,
sizeof(data_length));
// 6. save data md5sum
calculate_data_md5(data_addr, data_length, data_md5sum);
memcpy(file_addr + data_md5sum_offset, data_md5sum,
sizeof(data_md5sum));
// 7. save TEXT_DESC_SAVE_FLAG at the beginning of the file
// after all necessary data have been saved
memcpy(file_addr, desc_save_flag, desc_save_flag_len);
// 8. msync and munmap
xmsync(file_addr, file_length);
xmunmap(file_addr, file_length);
syscall_no_intercept(SYS_close, fd);
debug_dump("save_text_desc_to_file success. "
"jump_table_size: %ld, nop_count: %ld, patch_count: %d, "
"data_length: %lu, data_md5sum: %s\n",
desc->jump_table_size, desc->nop_count, desc->count,
data_length, data_md5sum);
return true;
}
/*
* setup text desc from file
* 1. desc->jump_table setup directly
* 2. desc->nop_table: nop->address = nop->offset + text_start
* 3. desc->items:
* syscall_addr = syscall_offset + (text_start - text_offset)
* ins->addr = ins->offset + text_offset
* ins->rip_ref_addr = ins->rip_disp + ins->rip
* ins->rip = ins->address + ins->length
* format:
* TEXT_DESC_SAVE_FLAG[md5sum]|jump_table_size|jump_table
* |nop_count|nop_table|patch_count|patches
*/
static bool
setup_text_desc_from_file(struct intercept_desc *desc)
{
char filepath[4096] = {0};
get_text_desc_save_path(desc, filepath);
debug_dump("setup_text_desc_from_file of %s "
"at base_addr 0x%016" PRIxPTR " to %s\n",
desc->real_path, (uintptr_t)desc->base_addr, filepath);
int fd = syscall_no_intercept(SYS_open, filepath, O_RDONLY);
if (fd < 0)
return false;
bool result = true;
char desc_save_flag_from_file[256] = {0};
char desc_save_flag[256] = {0};
int desc_save_flag_len = 0;
char data_md5sum_from_file[MD5_DIGEST_LENGTH * 2 + 1] = {0};
char data_md5sum[MD5_DIGEST_LENGTH * 2 + 1] = {0};
char *data_addr = NULL; // the data address
char *file_addr = NULL; // the file address
unsigned long data_length = 0;
unsigned long file_length = 0;
long data_offset = 0; // the data offset in the file
long data_pos = 0; // the data offset relative to the data address
// 1. read and check DESC_SAVE_FLAG
get_text_desc_save_flag(desc, desc_save_flag);
desc_save_flag_len = strlen(desc_save_flag);
syscall_no_intercept(SYS_read, fd, desc_save_flag_from_file,
desc_save_flag_len);
if (strncmp((const char *)desc_save_flag_from_file,
(const char *)desc_save_flag, desc_save_flag_len) != 0) {
result = false;
goto _close;
}
// 2. read data md5sum and data length
long size = syscall_no_intercept(SYS_read, fd, data_md5sum_from_file,
sizeof(data_md5sum_from_file));
if (size != sizeof(data_md5sum_from_file)) {
result = false;
goto _close;
}
size = syscall_no_intercept(SYS_read, fd, &data_length,
sizeof(data_length));
if (size != sizeof(data_length)) {
result = false;
goto _close;
}
// 3. mmap text desc file(more convenient to caculate md5)
data_offset = xlseek(fd, 0, SEEK_CUR);
file_length = data_offset + data_length;
file_addr = xmmap_file(fd, file_length, false);
data_addr = file_addr + data_offset;
debug_dump("setup_text_desc_from_file: data_md5sum_from_file: %s, "
"data_length: %lu, data_offset: %ld, file_length: %lu, "
"file_addr: %p, data_addr: %p\n",
data_md5sum_from_file, data_length, data_offset, file_length,
file_addr, data_addr);
// 4. check data md5sum
calculate_data_md5(data_addr, data_length, data_md5sum);
if (strncmp(data_md5sum_from_file, data_md5sum,
sizeof(data_md5sum_from_file)) != 0) {
result = false;
goto _clean;
}
// 5. read data
// 5.1. read jump_table_size && jump_table
memcpy(&desc->jump_table_size, data_addr,
sizeof(desc->jump_table_size));
data_pos += sizeof(desc->jump_table_size);
memcpy(desc->jump_table, data_addr + data_pos, desc->jump_table_size);
data_pos += desc->jump_table_size;
// 5.2. read nop_count && nop_table,
// setup address with offset
memcpy(&desc->nop_count, data_addr + data_pos, sizeof(desc->nop_count));
data_pos += sizeof(desc->nop_count);
for (size_t i = 0; i < desc->nop_count; i++) {
struct range *nop = &desc->nop_table[i];
memcpy(nop, data_addr + data_pos, sizeof(struct range));
data_pos += sizeof(struct range);
// address = offset + text_start
nop->address = nop->offset + desc->text_start;
}
// 5.3. read patch_count && patches,
// setup syscall_addr with syscall_offset
// setup address with text_start + offset
// setup rip_ref_addr with rip_disp + rip(address + length)
unsigned patch_count = 0;
memcpy(&patch_count, data_addr + data_pos, sizeof(patch_count));
data_pos += sizeof(patch_count);
for (unsigned i = 0; i < patch_count; i++) {
struct patch_desc *patch = add_new_patch(desc);
memcpy(patch, data_addr + data_pos, sizeof(struct patch_desc));
data_pos += sizeof(struct patch_desc);
// syscall_addr = syscall_offset + (text_start - text_offset)
patch->syscall_addr = patch->syscall_offset
+ (desc->text_start - desc->text_offset);
struct intercept_disasm_result *preceding_ins =
&patch->preceding_ins;
struct intercept_disasm_result *preceding_ins_2 =
&patch->preceding_ins_2;
struct intercept_disasm_result *following_ins =
&patch->following_ins;
preceding_ins->address =
desc->text_start + preceding_ins->offset;
preceding_ins->rip_ref_addr = preceding_ins->rip_disp
+ preceding_ins->address + preceding_ins->length;
preceding_ins_2->address =
desc->text_start + preceding_ins_2->offset;
preceding_ins_2->rip_ref_addr = preceding_ins_2->rip_disp
+ preceding_ins_2->address + preceding_ins_2->length;
following_ins->address =
desc->text_start + following_ins->offset;
following_ins->rip_ref_addr = following_ins->rip_disp
+ following_ins->address + following_ins->length;
}
// 5. read data -- end
_clean:
// 6. munmmap
xmunmap(file_addr, file_length);
_close:
syscall_no_intercept(SYS_close, fd);
debug_dump("setup_text_desc_from_file %s. "
"jump_table_size: %ld, nop_count: %ld, patch_count: %d\n",
result == true ? "success" : "fail",
desc->jump_table_size, desc->nop_count, desc->count);
return result;
}
/*
* find_syscalls
* The routine that disassembles a text section. Here is some higher level
......@@ -714,5 +1068,27 @@ find_syscalls(struct intercept_desc *desc)
syscall_no_intercept(SYS_close, fd);
crawl_text(desc);
struct timespec tm1, tm2, tm;
syscall_no_intercept(SYS_clock_gettime, CLOCK_REALTIME, &tm1);
if (text_desc_save_file) {
if (!setup_text_desc_from_file(desc)) {
// crawl text and save it to file if failed to
// setup text desc from file
debug_dump("setup_text_desc_from_file fail.\n");
crawl_text(desc);
save_text_desc_to_file(desc);
}
} else {
crawl_text(desc);
}
syscall_no_intercept(SYS_clock_gettime, CLOCK_REALTIME, &tm2);
tm.tv_sec = tm2.tv_sec - tm1.tv_sec;
tm.tv_nsec = tm2.tv_nsec - tm1.tv_nsec;
debug_dump(
"patch count: %d, crawl cost: %ld.%09ld\n",
desc->count, tm.tv_sec, tm.tv_nsec);
}
......@@ -521,3 +521,38 @@ strerror_no_intercept(long errnum)
return error_strings[errnum];
}
void
xwrite(long fd, void *buffer, size_t size)
{
long result = syscall_no_intercept(SYS_write, fd, buffer, size);
if (result != (long)size)
xabort_errno(syscall_error_code(result), __func__);
}
void *
xmmap_file(int fd, size_t size, bool share)
{
int prot = PROT_READ;
int flags = MAP_PRIVATE;
if (share) {
prot |= PROT_WRITE;
flags = MAP_SHARED;
}
long addr = syscall_no_intercept(SYS_mmap,
NULL, size, prot, flags, fd, (off_t)0);
xabort_on_syserror(addr, __func__);
return (void *) addr;
}
void
xmsync(void *addr, size_t len)
{
long result = syscall_no_intercept(SYS_msync, addr, len, MS_SYNC);
xabort_on_syserror(result, __func__);
}
......@@ -34,6 +34,7 @@
#define INTERCEPT_UTIL_H
#include <stddef.h>
#include <stdbool.h>
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
......@@ -67,6 +68,15 @@ void *xmremap(void *addr, size_t old, size_t new);
*/
void xmunmap(void *addr, size_t len);
/*
* xmmap_file - mapping a file
*
* Not intercepted - does not call libc.
* Always succeeds if returns - aborts the process on failure.
*/
void *xmmap_file(int fd, size_t size, bool share);
/*
* xlseek - no fail lseek
*
......@@ -83,6 +93,20 @@ long xlseek(long fd, unsigned long off, int whence);
*/
void xread(long fd, void *buffer, size_t size);
/*
* xwrite - no fail write
*
* Not intercepted - does not call libc.
* Always succeeds writing size bytes returns - aborts the process on failure.
*/
void xwrite(long fd, void *buffer, size_t size);
/*
* xmsync - no fail xmsync
*/
void xmsync(void *addr, size_t len);
/*
* strerror_no_intercept - returns a pointer to a C string associated with
* an errno value.
......
......@@ -46,7 +46,7 @@ add_executable(asm_pattern asm_pattern.c
$<TARGET_OBJECTS:syscall_intercept_base_asm>)
target_link_libraries(asm_pattern
PRIVATE ${CMAKE_DL_LIBS} ${capstone_LDFLAGS} ${capstone_LIBRARIES})
PRIVATE ${CMAKE_DL_LIBS} ${capstone_LDFLAGS} ${capstone_LIBRARIES} OpenSSL::Crypto)
set(asm_patterns
nosyscall
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment