#include #include #include typedef unsigned long long uint64; //FMP Ver //SHIFT must be 16KB / 2MB align according to KALSR config #define SHIFT(idx) ((uint64)(idx) * 0x4000) #ifndef R_AARCH64_RELATIVE #define R_AARCH64_RELATIVE 1027 #endif #ifndef R_AARCH64_ABS64 #define R_AARCH64_ABS64 257 #endif /* * The rela section uses the VA * the VA to file offset is: */ uint64 va_to_file; int patch_rela(char *, uint64, uint64, uint64, uint64, uint64, uint64); int main(int argc, char *argv[]){ uint64 rs_offset = 0, re_offset = 0, ds_offset = 0; int index; char *file = NULL; int ret; if (argc != 9) { printf ("\nUsage : \n"); printf ("kaslr_fips vmlinux_file reloc_start_addr reloc_end_addr dynsym_addr index first_fmp_rodata last_fmp_rodata"); printf ("\n"); return -1; } file = argv[1]; rs_offset = atol(argv[2]); re_offset = atol(argv[3]); ds_offset = atol(argv[4]); index = atoi(argv[5]); va_to_file = atol(argv[8]); if( !file || !rs_offset || !re_offset || !ds_offset ) { printf ("kaslr_fips vmlinux_file reloc_start_addr reloc_end_addr dynsym_add\n"); printf ("kaslr_fips index %d\n", index); return -1; } // printf("----- start patching %s with reloc_s %llx reloc_e %llx dynsym_s %llx index %d----\n", file, rs_offset, re_offset, ds_offset, index); ret = patch_rela(file, rs_offset, re_offset, ds_offset, SHIFT(index), atol(argv[6]), atol(argv[7])); if(ret) return ret; // printf("----- end patching %s -----\n", file); return 0; } /* * rela_start: relocation section start in the vmlinux * rela_end * dynsym_start */ int patch_rela(char *file, uint64 rela_start, uint64 rela_end, uint64 dynsym_start, uint64 offset, uint64 first_fmp_rodata, uint64 last_fmp_rodata){ uint64 rs_offset = rela_start - va_to_file; uint64 re_offset = rela_end - va_to_file; uint64 ds_offset = dynsym_start - va_to_file; FILE *fp = NULL; fp = fopen(file, "r+"); if (NULL == fp){ printf ("Unable to open file : %s", file); return -1; } Elf64_Rela rela_entry; Elf64_Sym sym_entry; uint64 addr = 0, value = 0; size_t read_size = 0; for (; rs_offset < re_offset; rs_offset += sizeof(Elf64_Rela)){ //seek and read the rela entry if(0 != fseek(fp, rs_offset, SEEK_SET)){ fclose(fp); return -1; } read_size = fread((void*) &rela_entry, sizeof(rela_entry), 1, fp); if(0 == read_size) continue; /*printf("%llx, %llx\n", ELF64_R_TYPE(rela_entry.r_info), R_AARCH64_RELATIVE);*/ addr = rela_entry.r_offset; if (0x0 == addr) continue; if (!(addr >= first_fmp_rodata && addr <= last_fmp_rodata)) continue; if (ELF64_R_TYPE(rela_entry.r_info) == R_AARCH64_RELATIVE) { value = offset + rela_entry.r_addend; } else if(ELF64_R_TYPE(rela_entry.r_info) == R_AARCH64_ABS64) { uint64 sym_index = ELF64_R_SYM(rela_entry.r_info); uint64 sym_offset = ds_offset + sym_index * (sizeof(Elf64_Sym)); //seek to the start of the symbol table entry if (0 !=fseek(fp, sym_offset, SEEK_SET)){ fclose(fp); return -1; } read_size = fread((void*) &sym_entry, sizeof(sym_entry), 1, fp); if(0 == read_size) continue; value = sym_entry.st_value + rela_entry.r_addend + offset; } else { // printf("Try to patch none supported type %llx\n", (uint64)ELF64_R_TYPE(rela_entry.r_info)); } /*printf("%llx, %llx, %llx, %llx, %llx\n", (uint64) rela_entry.r_offset, */ /*(uint64)rela_entry.r_info, */ /*(uint64)rela_entry.r_addend, */ /*addr - VA_TO_FILE, value);*/ if (0 != fseek(fp, addr - va_to_file, SEEK_SET)){ fclose(fp); return -1; } if (fwrite((const void *) &value, sizeof(uint64), 1, fp) != 1){ fclose(fp); return -1; } } fclose(fp); return 0; }