* Replace an init/fini function. */
| 396 | * Replace an init/fini function. |
| 397 | */ |
| 398 | intptr_t replaceInitFini(Binary *B, Elf64_Dyn *dyn_fn, |
| 399 | const Elf64_Dyn *dyn_fn_array, size_t dyn_fn_arraysz, |
| 400 | const Elf64_Dyn *dyn_rela, size_t dyn_relasz, intptr_t entry) |
| 401 | { |
| 402 | uint8_t *data = B->patched.bytes; |
| 403 | if (dyn_fn != nullptr) |
| 404 | { |
| 405 | intptr_t old = (intptr_t)dyn_fn->d_un.d_ptr; |
| 406 | dyn_fn->d_un.d_ptr = (Elf64_Addr)entry; |
| 407 | return old; |
| 408 | } |
| 409 | else if (dyn_fn_array != nullptr && dyn_fn_arraysz > 0) |
| 410 | { |
| 411 | intptr_t ptr = (intptr_t)dyn_fn_array->d_un.d_ptr; |
| 412 | intptr_t offset = addrToOffset(B, ptr, ptr); |
| 413 | if (offset < 0) |
| 414 | return INTPTR_MIN; |
| 415 | Elf64_Addr *fns = (Elf64_Addr *)(data + offset); |
| 416 | intptr_t old = (intptr_t)fns[0]; |
| 417 | fns[0] = (Elf64_Addr)entry; |
| 418 | if (dyn_rela != nullptr && dyn_relasz > 0) |
| 419 | { |
| 420 | // fns[0] may be subject to a relocation: |
| 421 | intptr_t rela_ptr = (intptr_t)dyn_rela->d_un.d_ptr; |
| 422 | intptr_t rela_offset = addrToOffset(B, rela_ptr, |
| 423 | rela_ptr + dyn_relasz); |
| 424 | if (rela_offset < 0) |
| 425 | return old; |
| 426 | size_t rela_size = dyn_relasz / sizeof(Elf64_Rela); |
| 427 | Elf64_Rela *rela = (Elf64_Rela *)(B->patched.bytes + rela_offset); |
| 428 | for (size_t i = 0; i < rela_size; i++) |
| 429 | { |
| 430 | if (ELF64_R_TYPE(rela[i].r_info) != R_X86_64_RELATIVE) |
| 431 | continue; |
| 432 | if ((intptr_t)rela[i].r_offset == ptr) |
| 433 | { |
| 434 | old = rela[i].r_addend; |
| 435 | rela[i].r_addend = (Elf64_Addr)entry; |
| 436 | break; |
| 437 | } |
| 438 | } |
| 439 | } |
| 440 | return old; |
| 441 | } |
| 442 | return INTPTR_MIN; |
| 443 | } |
| 444 | |
| 445 | /* |
| 446 | * Emit the (modified) ELF binary. |
no test coverage detected