├── .gdb_history ├── Makefile ├── README.md ├── dsymobf.c ├── libelfmaster.a ├── resolver.c ├── test.c └── test2.c /.gdb_history: -------------------------------------------------------------------------------- 1 | info file 2 | b *0x4640 3 | r 4 | c 5 | q 6 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc -N -static -nostdlib resolver.c -o egg 3 | gcc -g dsymobf.c libelfmaster.a -I /opt/elfmaster/include/ -o dsymobf 4 | gcc -no-pie test.c -s -o test 5 | gcc -no-pie test2.c -s -o test2 -lpthread 6 | clean: 7 | rm -f egg 8 | rm -f test 9 | rm -f test2 10 | rm -f dsymobf 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dsym_obfuscate 2 | PoC for Obfuscating the dynamic symbol table injecting a custom Hash Table to do symbol resolution 3 | courtesy of @elfmaster && @ulexec 4 | -------------------------------------------------------------------------------- /dsymobf.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #define TMP_FILE ".xyz.file" 21 | #define PADDING_SIZE 1024 22 | #ifndef PAGE_SIZE 23 | #define PAGE_SIZE 4096 24 | #endif 25 | #define PAGE_ALIGN(x) (x & ~(PAGE_SIZE - 1)) 26 | #define PAGE_ALIGN_UP(x) (PAGE_ALIGN(x) + PAGE_SIZE) 27 | #define PAGE_ROUND(x) (PAGE_ALIGN_UP(x)) 28 | 29 | #define DYNSTR_MAX_LEN 8192 * 4 30 | 31 | uint32_t dynstr_backup[DYNSTR_MAX_LEN]; 32 | unsigned long int dynstr_len; 33 | 34 | #define MAX_SO_BASENAMES 1024 35 | 36 | struct so_basenames { 37 | char *basename; 38 | uint32_t index; 39 | } so_basenames[MAX_SO_BASENAMES]; 40 | 41 | uint32_t basename_count = 0; 42 | 43 | uint32_t elf_hash(const unsigned char *name) 44 | { 45 | uint32_t h = 0, g; 46 | while (*name) { 47 | h = (h << 4) + *name++; 48 | g = h & 0xf0000000; 49 | if (g) 50 | h ^= g >> 24; 51 | h &= ~g; 52 | } 53 | return h; 54 | } 55 | 56 | bool 57 | set_lazy_binding(elfobj_t *obj) 58 | { 59 | 60 | struct elf_section dynamic; 61 | Elf64_Dyn *dynamic_ptr; 62 | 63 | if (elf_section_by_name(obj, ".dynamic", &dynamic) == false) { 64 | fprintf(stderr, "couldn't find .dynstr section\n"); 65 | return false; 66 | } 67 | 68 | dynamic_ptr = elf_offset_pointer(obj, dynamic.offset); 69 | if (dynamic_ptr == NULL) { 70 | fprintf(stderr, "Unable to locate offset: %#lx\n", dynamic.offset); 71 | return false; 72 | } 73 | 74 | do { 75 | if(dynamic_ptr->d_tag == DT_FLAGS && (dynamic_ptr->d_un.d_val & DF_BIND_NOW)){ 76 | dynamic_ptr->d_un.d_val &= ~DF_BIND_NOW; 77 | } 78 | /*if (dynamic_ptr->d_tag == DT_FLAGS_1 && (dynamic_ptr->d_un.d_val & DF_1_NOW)){ 79 | dynamic_ptr->d_un.d_val &= ~DF_1_NOW; 80 | }*/ 81 | dynamic_ptr++; 82 | } while(dynamic_ptr->d_tag != DT_NULL); 83 | return true; 84 | } 85 | 86 | bool 87 | transform_dynstr_and_zero(elfobj_t *obj) 88 | { 89 | struct elf_section dynstr; 90 | struct elf_section symtab; 91 | struct elf_section reltab; 92 | elf_dynamic_iterator_t iter; 93 | elf_dynamic_entry_t entry; 94 | uint8_t *strtab_ptr; 95 | Elf64_Sym *symtab_ptr; 96 | Elf64_Rela *reltab_ptr; 97 | int i, j, len; 98 | bool res; 99 | 100 | if (elf_section_by_name(obj, ".dynstr", &dynstr) == false) { 101 | fprintf(stderr, "couldn't find .dynstr section\n"); 102 | return false; 103 | } 104 | 105 | strtab_ptr = elf_offset_pointer(obj, dynstr.offset); 106 | if (strtab_ptr == NULL) { 107 | fprintf(stderr, "Unable to locate offset: %#lx\n", dynstr.offset); 108 | return false; 109 | } 110 | if (dynstr.size >= DYNSTR_MAX_LEN) { 111 | fprintf(stderr, ".dynstr too large\n"); 112 | return false; 113 | } 114 | 115 | /* 116 | * Get offsets of imperative string table values for ld.so 117 | */ 118 | if (elf_section_by_name(obj, ".dynsym", &symtab) == false) { 119 | fprintf(stderr, "couldn't find .dynsym section (already stripped)\n"); 120 | goto done; 121 | } 122 | 123 | symtab_ptr = elf_offset_pointer(obj, symtab.offset); 124 | 125 | if (elf_section_by_name(obj, ".rela.plt", &reltab) == false) { 126 | fprintf(stderr, "couldn't find .rela.plt section (already stripped)\n"); 127 | goto done; 128 | } 129 | 130 | reltab_ptr = elf_offset_pointer(obj, reltab.offset); 131 | 132 | j = 0; 133 | for (i = 0; i < reltab.size/sizeof(Elf64_Rela); i++){ 134 | Elf64_Rela *rel = &reltab_ptr[i]; 135 | int symbol_index = ELF64_R_SYM(rel->r_info); 136 | uint32_t hash; 137 | 138 | if (symtab_ptr[symbol_index].st_name == 0) { 139 | continue; 140 | } else if ((symtab_ptr[symbol_index].st_info & 0xf) != STT_FUNC) { 141 | continue; 142 | } else if (!strcmp(&strtab_ptr[symtab_ptr[symbol_index].st_name], "__libc_start_main")) { 143 | printf("[!] Skipping symbol:\t__libc_start_main\n"); 144 | j++; 145 | continue; 146 | } 147 | printf("[*] Hashing symbol:\t%s\n", &strtab_ptr[symtab_ptr[symbol_index].st_name]); 148 | hash = elf_hash(&strtab_ptr[symtab_ptr[symbol_index].st_name]); 149 | *(uint32_t*)&dynstr_backup[j++] = hash; 150 | } 151 | 152 | dynstr_len = j ; 153 | 154 | for (i = 0; i < reltab.size/sizeof(Elf64_Rela); i++){ 155 | Elf64_Rela *rel = &reltab_ptr[i]; 156 | int symbol_index = ELF64_R_SYM(rel->r_info); 157 | uint32_t hash; 158 | 159 | if (symtab_ptr[symbol_index].st_name == 0) { 160 | continue; 161 | } else if ((symtab_ptr[symbol_index].st_info & 0xf) != STT_FUNC) { 162 | continue; 163 | } else if (!strcmp(&strtab_ptr[symtab_ptr[symbol_index].st_name], "__libc_start_main")) { 164 | continue; 165 | } else if (strlen(&strtab_ptr[symtab_ptr[symbol_index].st_name]) <= 1) { 166 | continue; 167 | } 168 | memset(&strtab_ptr[symtab_ptr[symbol_index].st_name], 0, strlen(&strtab_ptr[symtab_ptr[symbol_index].st_name])); 169 | } 170 | 171 | 172 | 173 | done: 174 | return true; 175 | } 176 | 177 | bool 178 | inject_constructor(elfobj_t *obj) 179 | { 180 | int i, j, fd; 181 | size_t old_size = obj->size; 182 | size_t stub_size; 183 | elfobj_t ctor_obj; 184 | elf_error_t error; 185 | unsigned long stub_vaddr; 186 | struct elf_symbol symbol; 187 | struct elf_section ctors; 188 | struct elf_section dynstr; 189 | uint8_t *ptr; 190 | 191 | if (elf_open_object("egg", &ctor_obj, 192 | ELF_LOAD_F_STRICT|ELF_LOAD_F_MODIFY, &error) == false) { 193 | fprintf(stderr, "%s\n", elf_error_msg(&error)); 194 | exit(EXIT_FAILURE); 195 | } 196 | stub_size = ctor_obj.size; 197 | /* 198 | * NOTE: We are directly modifying libelfmaster object's to update 199 | * the program header table. This is not technically correct since 200 | * its not using the libelfmaster API. Eventually libelfmaster will 201 | * support this through accessor functions that are intended to modify 202 | * meanwhile we are still using libelfmaster to speed up the process 203 | * of creating this PoC for symbol and section lookups. 204 | */ 205 | for (i = 0; i < obj->ehdr64->e_phnum; i++) { 206 | if (obj->phdr64[i].p_type == PT_LOAD && 207 | obj->phdr64[i].p_offset == 0) { 208 | obj->phdr64[i].p_flags |= PF_W; 209 | } 210 | if (obj->phdr64[i].p_type == PT_DYNAMIC) { 211 | Elf64_Dyn *dyn = (Elf64_Dyn *)&obj->mem[obj->phdr64[i].p_offset]; 212 | 213 | for (j = 0; dyn[j].d_tag != DT_NULL; j++) { 214 | if (dyn[j].d_tag == DT_VERNEEDNUM) { 215 | dyn[j].d_tag = 0; 216 | } else if (dyn[j].d_tag == DT_VERNEED) { 217 | dyn[j].d_tag = DT_DEBUG; 218 | } 219 | } 220 | } 221 | if (obj->phdr64[i].p_type == PT_NOTE) { 222 | obj->phdr64[i].p_type = PT_LOAD; 223 | obj->phdr64[i].p_vaddr = 0xc000000 + old_size; 224 | obj->phdr64[i].p_filesz = stub_size; 225 | obj->phdr64[i].p_memsz = obj->phdr64[i].p_filesz; 226 | obj->phdr64[i].p_flags = PF_R | PF_X | PF_W; 227 | obj->phdr64[i].p_paddr = obj->phdr64[i].p_vaddr; 228 | obj->phdr64[i].p_offset = old_size; 229 | } 230 | } 231 | /* 232 | * For debugging purposes we can view our injected code 233 | * with objdump by modifying an existing section header 234 | * such as .eh_frame. 235 | */ 236 | #if 0 237 | obj->shdr64[17].sh_size = stub_size; 238 | obj->shdr64[17].sh_addr = 0xc000000 + old_size; 239 | obj->shdr64[17].sh_offset = old_size; 240 | #endif 241 | /* 242 | * Locate .init_array so that we can modify the pointer to 243 | * our injected constructor code 'egg (built from constructor.c)' 244 | */ 245 | if (elf_section_by_name(obj, ".init_array", &ctors) == false) { 246 | printf("Cannot find .init_array\n"); 247 | return false; 248 | } 249 | 250 | /* 251 | * Locate the symbol for the function restore_dynstr in our 252 | * constructor so that we can find out where to hook the .init_array 253 | * function pointer to. 254 | */ 255 | if (elf_symbol_by_name(&ctor_obj, "patch_got", 256 | &symbol) == false) { 257 | printf("cannot find symbol \"patch_got\"\n"); 258 | return false; 259 | } 260 | 261 | /* 262 | * Get a pointer to .init_array function pointer 263 | * so that we can hook it with our constructor 264 | * entry point 'restore_dynstr' 265 | */ 266 | ptr = elf_offset_pointer(obj, ctors.offset); 267 | 268 | /* 269 | * Because of the way that we build the constructor using 'gcc -N' 270 | * it creates a single load segment that is not PAGE aligned, we must 271 | * therefore PAGE align it to get the correct symbol_offset from the beginning 272 | * of the ELF file. 273 | */ 274 | uint64_t symbol_offset = symbol.value - (elf_text_base(&ctor_obj) & ~4095); 275 | uint64_t entry_point = 0xc000000 + old_size + symbol_offset; 276 | 277 | /* 278 | * Set the actual constructor hook with this memcpy. 279 | * i.e. *(uint64_t *)&ptr[0] = entry_point; 280 | */ 281 | memcpy(ptr, &entry_point, sizeof(uint64_t)); 282 | 283 | /* 284 | * Get ready to write out our new final executable 285 | * which includes the constructor code as a 3rd PT_LOAD 286 | * segment 287 | */ 288 | fd = open(TMP_FILE, O_RDWR|O_CREAT|O_TRUNC, S_IRWXU); 289 | if (fd < 0) { 290 | perror("open"); 291 | return false; 292 | } 293 | 294 | /* 295 | * Write out the original binary 296 | */ 297 | if (write(fd, obj->mem, old_size) != old_size) { 298 | perror("write"); 299 | return false; 300 | } 301 | /* 302 | * open 'egg' and find the buffer to store the contents 303 | * of dynstr (It is called dynstr_buf) 304 | */ 305 | if (elf_symbol_by_name(&ctor_obj, "dynstr_buf", 306 | &symbol) == false) { 307 | fprintf(stderr, "Unable to find symbol dynstr_buf in egg binary\n"); 308 | return false; 309 | } 310 | 311 | /* 312 | * Patch egg so it has the .dynstr data in its 313 | * char dynstr_buf[], so that at runtime it can 314 | * restore it into the .dynstr section of the 315 | * target executable that egg is injected into. 316 | */ 317 | ptr = elf_address_pointer(&ctor_obj, symbol.value); 318 | memcpy(ptr, dynstr_backup, dynstr_len * sizeof(uint64_t)); 319 | 320 | /* 321 | * Find dynstr_size variable within egg, and update it with the size 322 | * of the .dynstr section. 323 | */ 324 | if (elf_symbol_by_name(&ctor_obj, "dynstr_size", 325 | &symbol) == false) { 326 | fprintf(stderr, "Unable to find symbol dynstr_size in egg binary\n"); 327 | return false; 328 | } 329 | ptr = elf_address_pointer(&ctor_obj, symbol.value); 330 | memcpy(ptr, &dynstr_len, sizeof(unsigned long int)); 331 | 332 | /*zeroing out string table in egg*/ 333 | if (elf_section_by_name(&ctor_obj, ".strtab", &dynstr) == false) { 334 | fprintf(stderr, "couldn't find .strtab section\n"); 335 | return false; 336 | } 337 | 338 | ptr = elf_offset_pointer(&ctor_obj, dynstr.offset); 339 | if (ptr == NULL) { 340 | fprintf(stderr, "Unable to locate offset: %#lx\n", dynstr.offset); 341 | return false; 342 | } 343 | memset(ptr, 0, dynstr.size); 344 | 345 | /*zeroing out section headers string table in egg*/ 346 | if (elf_section_by_name(&ctor_obj, ".shstrtab", &dynstr) == false) { 347 | fprintf(stderr, "couldn't find .shstrtab section\n"); 348 | return false; 349 | } 350 | 351 | ptr = elf_offset_pointer(&ctor_obj, dynstr.offset); 352 | if (ptr == NULL) { 353 | fprintf(stderr, "Unable to locate offset: %#lx\n", dynstr.offset); 354 | return false; 355 | } 356 | memset(ptr, 0, dynstr.size); 357 | 358 | /* 359 | * Append 'egg' constructor code to the end of the target binary 360 | * the target binary has a PT_LOAD segment with corresponding offset 361 | * and other values pointing to this injected code. 362 | */ 363 | if (write(fd, (char *)ctor_obj.mem, ctor_obj.size) != ctor_obj.size) { 364 | perror("write"); 365 | return false; 366 | } 367 | if (rename(TMP_FILE, obj->path) < 0) { 368 | perror("rename"); 369 | return false; 370 | } 371 | close(fd); 372 | (void) elf_close_object(&ctor_obj); 373 | return true; 374 | } 375 | 376 | int 377 | main(int argc, char **argv) 378 | { 379 | elfobj_t obj; 380 | elf_error_t error; 381 | bool res; 382 | 383 | if (argc < 2) { 384 | fprintf(stderr, "Usage: %s \n", argv[0]); 385 | exit(EXIT_SUCCESS); 386 | } 387 | 388 | if (elf_open_object(argv[1], &obj, 389 | ELF_LOAD_F_STRICT|ELF_LOAD_F_MODIFY, &error) == false) { 390 | fprintf(stderr, "%s\n", elf_error_msg(&error)); 391 | exit(EXIT_FAILURE); 392 | } 393 | 394 | printf("hashing dynstr\n"); 395 | res = transform_dynstr_and_zero(&obj); 396 | 397 | printf("enabling lazy binding\n"); 398 | set_lazy_binding(&obj); 399 | 400 | printf("Injecting constructor.o into %s\n", argv[1]); 401 | res = inject_constructor(&obj); 402 | 403 | printf("Commiting changes to %s\n", obj.path); 404 | elf_close_object(&obj); 405 | } 406 | 407 | 408 | -------------------------------------------------------------------------------- /libelfmaster.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ulexec/elf_dynsym_obfuscation/97723a0ed8fa4d5788f57a751ad7f8f082a38e42/libelfmaster.a -------------------------------------------------------------------------------- /resolver.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define PAGE_SIZE 4096 8 | #define PAGE_ALIGN(k) (((k)+((PAGE_SIZE)-1))&(~((PAGE_SIZE)-1))) 9 | #define PIC_RESOLVE_ADDR(target) (get_rip() - ((char *)&get_rip_label - (char *)target)) 10 | 11 | uint32_t dynstr_buf[8192] __attribute__((section(".data"), aligned(8))) = { [0 ... 8191] = 0}; 12 | unsigned long dynstr_size __attribute__((section(".data"))) = {0}; 13 | unsigned long g_image_base __attribute__((section(".data"))); 14 | 15 | extern unsigned long get_rip_label; 16 | 17 | struct link_map { 18 | Elf64_Addr l_addr; 19 | char * l_name; 20 | Elf64_Dyn *l_ld; 21 | struct link_map *l_next; 22 | struct link_map *l_prev; 23 | }; 24 | 25 | __attribute__((unused)) int _start(void) 26 | { 27 | 28 | return 0; 29 | } 30 | 31 | uint32_t elf_hash(const unsigned char *name) 32 | { 33 | uint32_t h = 0, g; 34 | while (*name) { 35 | h = (h << 4) + *name++; 36 | g = h & 0xf0000000; 37 | if (g) { 38 | h ^= g >> 24; 39 | } 40 | h &= ~g; 41 | } 42 | return h; 43 | } 44 | 45 | uint64_t lookup(uint32_t name_hash, uint32_t *hashtab, Elf64_Sym *symtab, uint8_t *strtab) 46 | { 47 | uint32_t nbuckets; 48 | uint32_t nchains; 49 | uint32_t *buckets; 50 | uint32_t *chains; 51 | uint32_t h; 52 | uint32_t idx; 53 | 54 | nbuckets = hashtab[0]; 55 | nchains = hashtab[1]; 56 | buckets = hashtab + 2; 57 | chains = buckets + nbuckets; 58 | 59 | h = name_hash % nbuckets; 60 | for (idx = buckets[h]; idx != 0; idx = chains[idx]) { 61 | if (elf_hash(symtab[idx].st_name + strtab) == name_hash) 62 | return symtab[idx].st_value; 63 | } 64 | return -1; 65 | } 66 | 67 | uint64_t get_image_base_from_auxv(char **argv) 68 | { 69 | Elf64_auxv_t *auxv; 70 | 71 | /*skip all argv pointers */ 72 | while (*argv++ != NULL); 73 | 74 | /*skip all env pointers */ 75 | while (*argv++ != NULL); 76 | 77 | /*iterating Auxv entries*/ 78 | while (*argv++ != NULL) { 79 | auxv = (Elf64_auxv_t *)argv; 80 | if( auxv->a_type == AT_PHDR) { 81 | return ((auxv->a_un.a_val >> 12) << 12); 82 | } 83 | } 84 | return -1; 85 | } 86 | 87 | uint64_t resolve_symbol_from_module(struct link_map *l_map, uint32_t sym_hash) 88 | { 89 | Elf64_Dyn *dynamic; 90 | Elf64_Sym *sym_table; 91 | uint8_t *str_table = 0; 92 | uint32_t *hash_table = 0; 93 | uint64_t symbol_address = 0; 94 | 95 | /* 96 | * Points to dynamic segment of the shared library 97 | */ 98 | dynamic = l_map->l_ld; 99 | 100 | /* 101 | * Locate .dynstr symbol table, hash lookup, and .dynstr string table 102 | */ 103 | while (dynamic->d_tag != DT_NULL) { 104 | switch (dynamic->d_tag) { 105 | case DT_HASH: 106 | hash_table = (dynamic->d_un.d_ptr < l_map->l_addr) ? 107 | (uint32_t*)((uint8_t*)l_map->l_addr + dynamic->d_un.d_ptr): 108 | (uint32_t*)dynamic->d_un.d_ptr; 109 | break; 110 | case DT_SYMTAB: 111 | sym_table = (dynamic->d_un.d_ptr < l_map->l_addr) ? 112 | (Elf64_Sym*)((uint8_t*)l_map->l_addr + dynamic->d_un.d_ptr): 113 | (Elf64_Sym*)dynamic->d_un.d_ptr; 114 | break; 115 | case DT_STRTAB: 116 | str_table = ((uint64_t)dynamic->d_un.d_ptr < l_map->l_addr) ? 117 | (uint8_t*)((uint8_t*)l_map->l_addr + dynamic->d_un.d_ptr): 118 | (uint8_t*)dynamic->d_un.d_ptr; 119 | break; 120 | } 121 | dynamic++; 122 | } 123 | if (!hash_table || !sym_table || !str_table) { 124 | return -1; 125 | } 126 | symbol_address = lookup(sym_hash, hash_table, sym_table, str_table); 127 | symbol_address = symbol_address == -1 ? symbol_address : (uint64_t)((uint8_t*)symbol_address + l_map->l_addr); 128 | if (symbol_address == l_map->l_addr) { 129 | symbol_address = -1; 130 | } 131 | return symbol_address; 132 | } 133 | 134 | uint64_t * get_got(uint64_t image_base) { 135 | Elf64_Ehdr *ehdr = (Elf64_Ehdr*)image_base; 136 | Elf64_Phdr *phdr = (Elf64_Phdr*)((uint8_t*)image_base + ehdr->e_phoff); 137 | uint64_t *got; 138 | struct link_map *l_map; 139 | 140 | for(int i = 0; i < ehdr->e_phnum; i++) { 141 | if (phdr[i].p_type == PT_DYNAMIC) { 142 | Elf64_Dyn *dyn = (Elf64_Dyn*)phdr[i].p_vaddr; 143 | while(dyn->d_tag != DT_NULL) { 144 | if (dyn->d_tag == DT_PLTGOT) { 145 | got = (uint64_t*)dyn->d_un.d_ptr; 146 | break; 147 | } 148 | dyn++; 149 | } 150 | break; 151 | } 152 | } 153 | return got; 154 | } 155 | 156 | unsigned long get_rip(void) 157 | { 158 | unsigned long ret; 159 | 160 | __asm__ __volatile__ 161 | ( 162 | "call get_rip_label \n" 163 | ".globl get_rip_label \n" 164 | "get_rip_label: \n" 165 | "pop %%rax \n" 166 | "mov %%rax, %0" : "=r"(ret) 167 | ); 168 | return ret; 169 | } 170 | 171 | 172 | /* 173 | * Once the resolver is called the stack and argument context 174 | * is already setup, since our resolver has replaced got[2] 175 | * and control is being transferred there from PLT-0 just the 176 | * same as if dl_runtime_resolve was being invoked. 177 | */ 178 | void resolve_entry (void) 179 | { 180 | uint64_t image_base; 181 | uint64_t *got; 182 | struct link_map *l_map; 183 | uint64_t symbol; 184 | bool skip_entry = false; 185 | uint64_t hash_num; 186 | uint64_t o_rsp; 187 | uint64_t o_rdi; 188 | uint64_t o_rsi; 189 | uint64_t o_rdx; 190 | uint64_t o_rcx; 191 | uint64_t o_r8; 192 | uint64_t o_r9; 193 | uint64_t o_ret; 194 | 195 | /*saving stack and argument context*/ 196 | __asm__ __volatile__( "mov %%rsp, %0" : "=r"(o_rsp)); 197 | __asm__ __volatile__( "mov %%rdi, %0" : "=r"(o_rdi)); 198 | __asm__ __volatile__( "mov %%rsi, %0" : "=r"(o_rsi)); 199 | __asm__ __volatile__( "mov %%rdx, %0" : "=r"(o_rdx)); 200 | __asm__ __volatile__( "mov %%rcx, %0" : "=r"(o_rcx)); 201 | __asm__ __volatile__( "mov %%r8, %0" : "=r"(o_r8)); 202 | __asm__ __volatile__( "mov %%r9, %0" : "=r"(o_r9)); 203 | 204 | /*restoring RTLD's arguments in stack*/ 205 | __asm__ __volatile__( "mov %rbp, %rsp"); 206 | __asm__ __volatile__( "pop %%rax \n" 207 | "pop %%rax \n" 208 | "mov %%rax, %0" : "=r"(l_map)); 209 | __asm__ __volatile__( "pop %%rax \n" 210 | "mov %%rax, %0" : "=r"(hash_num)); 211 | __asm__ __volatile__( "mov %%rsp, %0" : "=r"(o_ret)); 212 | 213 | /*restoring original stack pointer*/ 214 | __asm__ __volatile__( "mov %0, %%rsp" :: "r"(o_rsp)); 215 | 216 | /*Locate the GOT via dynamic segment*/ 217 | got = get_got(g_image_base); 218 | 219 | do { 220 | uint64_t *addr = PIC_RESOLVE_ADDR(dynstr_buf); 221 | symbol = resolve_symbol_from_module(l_map, *(uint32_t*)((uint32_t*)addr+hash_num)); 222 | l_map = l_map->l_next; 223 | } while(symbol == -1); 224 | 225 | /*resolving correspondent symbol GOT entry*/ 226 | /*This line can be deleted and will force the custom resolver to resolve 227 | * an entry every time is called. Good for anti-analysis since the analyst 228 | * would have to track each entry to know what symbol it holds :) */ 229 | *(uint64_t*)&got[3+hash_num] = symbol; 230 | 231 | /*jumping to resolve symbol with adequate arguments and return address*/ 232 | 233 | __asm__ __volatile__( "mov %0, %%rsp" :: "r"(o_ret)); 234 | __asm__ __volatile__( "mov %0, %%rdi" :: "r"(o_rdi)); 235 | __asm__ __volatile__( "mov %0, %%rsi" :: "r"(o_rsi)); 236 | __asm__ __volatile__( "mov %0, %%rdx" :: "r"(o_rdx)); 237 | __asm__ __volatile__( "mov %0, %%rcx" :: "r"(o_rcx)); 238 | __asm__ __volatile__( "mov %0, %%r8" :: "r"(o_r8)); 239 | __asm__ __volatile__( "mov %0, %%r9" :: "r"(o_r9)); 240 | __asm__ __volatile__( "jmpq *%0" :: "r"(symbol)); 241 | } 242 | 243 | int patch_got(int argc, char ** argv) 244 | { 245 | uint64_t image_base; 246 | uint64_t *got; 247 | 248 | if ((image_base = get_image_base_from_auxv(argv)) == -1) { 249 | return -1; 250 | } 251 | g_image_base = image_base; 252 | got = get_got(image_base); 253 | 254 | /*replacing RTLD resolver for our custom one at GOT[2]*/ 255 | *(uint64_t*)&got[2] = PIC_RESOLVE_ADDR(resolve_entry); 256 | return 0; 257 | } 258 | 259 | 260 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(void) 6 | { 7 | FILE *fd = fopen("/etc/passwd", "r"); 8 | printf("Hi\n"); 9 | pause(); 10 | } 11 | 12 | -------------------------------------------------------------------------------- /test2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(void) 7 | { 8 | pthread_attr_t attr; 9 | FILE *fd = fopen("/etc/passwd", "r"); 10 | printf("Hi\n"); 11 | pthread_attr_init(&attr); 12 | pause(); 13 | } 14 | 15 | --------------------------------------------------------------------------------