/* * Returns the offset of the specified string from within * the given string table. * * entry: * dynsec - Dynamic section descriptor * strsec - Descriptor for string table associated with dynamic section * dyn_strpad - DT_SUNW_STRPAD element from dynamic section * str - String we are looking for. * * exit: * On success, the offset of the given string within the string * table is returned. If the string does not exist within the table, * but there is a valid DT_SUNW_STRPAD reserved section, then we * add the string, and update the dynamic section STRPAD element * to reflect the space we use. * * This routine does not return on failure. */ static GElf_Word dynstr_insert(Cache *dynsec, Cache *strsec, dyn_elt_t *dyn_strpad, const char *str) { GElf_Word ins_off; /* Table offset to 1st reserved byte */ char *s; /* ptr to strings within table */ GElf_Word len; /* Length of str inc. NULL byte */ GElf_Word tail_ign; /* # reserved bytes at end of strtab */ tail_ign = dyn_strpad->seen ? dyn_strpad->dyn.d_un.d_val : 0; /* Does the string already exist in the string table? */ if (sec_findstr(strsec, tail_ign, str, &len)) return (len); /* * The desired string does not already exist. Do we have * room to add it? */ len = strlen(str) + 1; if (!dyn_strpad->seen || (len > dyn_strpad->dyn.d_un.d_val)) msg_fatal("[%d]%s: String table does not have room " "to add string\n", strsec->c_shdr.sh_link, strsec->c_name); /* * We will add the string at the first byte of the reserved NULL * area at the end. The DT_SUNW_STRPAD dynamic element gives us * the size of that reserved space. */ ins_off = strsec->c_shdr.sh_size - tail_ign; s = ((char *)strsec->c_data->d_buf) + ins_off; /* Announce the operation */ msg_debug("[%d]%s[%d]: Using %d/%d byes from reserved area to " "add string: %s\n", strsec->c_shdr.sh_link, strsec->c_name, ins_off, len, (int)dyn_strpad->dyn.d_un.d_val, str); /* * Copy the string into the pad area at the end, and * mark the data area as dirty so libelf will flush our * changes to the string data. */ (void) strncpy(s, str, dyn_strpad->dyn.d_un.d_val); (void) elf_flagdata(strsec->c_data, ELF_C_SET, ELF_F_DIRTY); /* Update the DT_STRPAD dynamic entry */ dyn_strpad->dyn.d_un.d_val -= len; if (gelf_update_dyn(dynsec->c_data, dyn_strpad->ndx, &dyn_strpad->dyn) == 0) msg_elf("gelf_update_dyn"); return (ins_off); }
int main (int argc, char **argv) { if (argc != 2) abort (); elf_version (EV_CURRENT); int fd = open64 (argv[1], O_RDONLY); Elf *stripped = elf_begin (fd, ELF_C_READ, NULL); Elf_Scn *scn = NULL; while ((scn = elf_nextscn (stripped, scn)) != NULL) elf_flagdata (elf_getdata (scn, NULL), ELF_C_SET, ELF_F_DIRTY); }
void saveSharedLibrary::saveMutations(char *textInsn){ memcpy(textData->d_buf, textInsn, textData->d_size); elf_flagdata(textData,ELF_C_SET,ELF_F_DIRTY); }
int main(int argc, char **argv) { int c, ndx; int readonly; int fd; const char *file; const char *runpath; Elf *elf; GElf_Ehdr ehdr; size_t shstrndx, shnum; Elf_Scn *scn; Elf_Data *data; char *shnames = NULL; Cache *cache, *_cache; Cache *dynsec, *strsec; GElf_Word numdyn; dyn_elt_t rpath_elt; dyn_elt_t runpath_elt; dyn_elt_t strpad_elt; dyn_elt_t flags_1_elt; dyn_elt_t null_elt; int changed = 0; opterr = 0; while ((c = getopt(argc, argv, "dr")) != EOF) { switch (c) { case 'd': d_flg = 1; break; case 'r': r_flg = 1; break; case '?': msg_usage(); } } /* * The first plain argument is the file name, and is required. * The second plain argument is the runpath, and is optional. * If no runpath is given, we print the current runpath to stdout * and exit. If it is present, we modify the ELF file to use it. */ argc = argc - optind; argv += optind; if ((argc < 1) || (argc > 2)) msg_usage(); if ((argc == 2) && r_flg) msg_usage(); readonly = (argc == 1) && !r_flg; file = argv[0]; if (!readonly) runpath = argv[1]; if ((fd = open(file, readonly ? O_RDONLY : O_RDWR)) == -1) msg_fatal("unable to open file: %s: %s\n", file, strerror(errno)); (void) elf_version(EV_CURRENT); elf = elf_begin(fd, readonly ? ELF_C_READ : ELF_C_RDWR, NULL); if (elf == NULL) msg_elf("elf_begin"); /* We only handle standalone ELF files */ switch (elf_kind(elf)) { case ELF_K_AR: msg_fatal("unable to edit ELF archive: %s\n", file); break; case ELF_K_ELF: break; default: msg_fatal("unable to edit non-ELF file: %s\n", file); break; } if (gelf_getehdr(elf, &ehdr) == NULL) msg_elf("gelf_getehdr"); if (elf_getshnum(elf, &shnum) == 0) msg_elf("elf_getshnum"); if (elf_getshstrndx(elf, &shstrndx) == 0) msg_elf("elf_getshstrndx"); /* * Obtain the .shstrtab data buffer to provide the required section * name strings. */ if ((scn = elf_getscn(elf, shstrndx)) == NULL) msg_elf("elf_getscn"); if ((data = elf_getdata(scn, NULL)) == NULL) msg_elf("elf_getdata"); shnames = data->d_buf; /* * Allocate a cache to maintain a descriptor for each section. */ if ((cache = malloc(shnum * sizeof (Cache))) == NULL) msg_fatal("unable to allocate section cache: %s\n", strerror(errno)); bzero(cache, sizeof (cache[0])); cache->c_name = ""; _cache = cache + 1; /* * Fill in cache with information for each section, and * locate the dynamic section. */ dynsec = strsec = NULL; for (ndx = 1, scn = NULL; scn = elf_nextscn(elf, scn); ndx++, _cache++) { _cache->c_ndx = ndx; if (gelf_getshdr(scn, &_cache->c_shdr) == NULL) msg_elf("gelf_getshdr"); _cache->c_data = elf_getdata(scn, NULL); _cache->c_name = shnames + _cache->c_shdr.sh_name; if (_cache->c_shdr.sh_type == SHT_DYNAMIC) { dynsec = _cache; numdyn = dynsec->c_shdr.sh_size / dynsec->c_shdr.sh_entsize; msg_debug("[%d]%s: dynamic section\n", ndx, _cache->c_name); } } /* * If we got a dynamic section, locate the string table. * If not, we can't continue. */ if (dynsec == NULL) msg_fatal("file lacks a dynamic section: %s\n", file); strsec = &cache[dynsec->c_shdr.sh_link]; msg_debug("[%d]%s: dynamic string table section\n", strsec->c_ndx, strsec->c_name); /* * History Lesson And Strategy: * * This routine handles both DT_RPATH and DT_RUNPATH entries, altering * either or both if they are present. * * The original SYSV ABI only had DT_RPATH, and the runtime loader used * it to search for things in the following order: * * DT_RPATH, LD_LIBRARY_PATH, defaults * * Solaris did not follow this rule. Environment variables should * supersede everything else, so we have always deviated from the * ABI and and instead search in the order * * LD_LIBRARY_PATH, DT_RPATH, defaults * * Other Unix variants initially followed the ABI, but in recent years * realized that it was a mistake. Hence, DT_RUNPATH was invented, * with the search order: * * LD_LIBRARY_PATH, DT_RUNPATH, defaults * * So for Solaris, DT_RPATH and DT_RUNPATH mean the same thing. If both * are present (which does happen), we set them both to the new * value. If either one is present, we set that one. If neither is * present, and we have a spare DT_NULL slot, we create a DT_RUNPATH. */ /* * Examine the dynamic section to determine the index for * - DT_RPATH * - DT_RUNPATH * - DT_SUNW_STRPAD * - DT_NULL, and whether there are any extra DT_NULL slots */ dyn_elt_init(&rpath_elt); dyn_elt_init(&runpath_elt); dyn_elt_init(&strpad_elt); dyn_elt_init(&flags_1_elt); dyn_elt_init(&null_elt); for (ndx = 0; ndx < numdyn; ndx++) { GElf_Dyn dyn; if (gelf_getdyn(dynsec->c_data, ndx, &dyn) == NULL) msg_elf("gelf_getdyn"); switch (dyn.d_tag) { case DT_NULL: /* * Remember the state of the first DT_NULL. If there * are more than one (i.e. the first one is not * in the final spot), and there is no runpath, then * we will turn the first one into a DT_RUNPATH. */ if (!null_elt.seen) { dyn_elt_save(&null_elt, ndx, &dyn); msg_debug("[%d]%s[%d]: DT_NULL\n", dynsec->c_ndx, dynsec->c_name, ndx); } break; case DT_RPATH: dyn_elt_save(&rpath_elt, ndx, &dyn); msg_debug("[%d]%s[%d]: DT_RPATH: %s\n", dynsec->c_ndx, dynsec->c_name, ndx, DYN_ELT_STRING(&rpath_elt, strsec)); break; case DT_RUNPATH: dyn_elt_save(&runpath_elt, ndx, &dyn); msg_debug("[%d]%s[%d]: DT_RUNPATH: %s\n", dynsec->c_ndx, dynsec->c_name, ndx, DYN_ELT_STRING(&runpath_elt, strsec)); break; case DT_SUNW_STRPAD: dyn_elt_save(&strpad_elt, ndx, &dyn); msg_debug("[%d]%s[%d]: DT_STRPAD: %d\n", dynsec->c_ndx, dynsec->c_name, ndx, (int)strpad_elt.dyn.d_un.d_val); break; case DT_FLAGS_1: dyn_elt_save(&flags_1_elt, ndx, &dyn); break; } } /* * If this is a readonly session, then print the existing * runpath and exit. DT_RPATH and DT_RUNPATH should have * the same value, so we arbitrarily favor DT_RUNPATH. */ if (readonly) { if (runpath_elt.seen) (void) printf("%s\n", DYN_ELT_STRING(&runpath_elt, strsec)); else if (rpath_elt.seen) (void) printf("%s\n", DYN_ELT_STRING(&rpath_elt, strsec)); else msg_debug("ELF file does not have a runpath: %s\n", file); return (0); } /* Edit the file, either to remove the runpath or to add/modify it */ if (r_flg) { if (!(runpath_elt.seen || rpath_elt.seen)) msg_debug("[%d]%s: no runpath found\n", dynsec->c_ndx, dynsec->c_name); else changed = remove_runpath(dynsec, numdyn); } else { changed = new_runpath(runpath, dynsec, numdyn, strsec, &rpath_elt, &runpath_elt, &strpad_elt, &null_elt); } if (changed) { /* * If possible, set the DF_1_EDITED flag, indicating that * this file has been edited after the fact. */ if (flags_1_elt.seen) { flags_1_elt.dyn.d_un.d_val |= DF_1_EDITED; } else if (null_elt.seen && (null_elt.ndx < (numdyn - 1))) { msg_debug("[%d]%s: No existing flags_1 entry to " "modify. Will use extra DT_NULL in slot [%d] \n", dynsec->c_ndx, dynsec->c_name, null_elt.ndx); flags_1_elt.seen = 1; flags_1_elt.ndx = null_elt.ndx; flags_1_elt.dyn.d_tag = DT_FLAGS_1; flags_1_elt.dyn.d_un.d_val = DF_1_EDITED; } if (flags_1_elt.seen) { msg_debug("[%d]%s[%d]: Set DF_1_EDITED flag\n", dynsec->c_ndx, dynsec->c_name, flags_1_elt.ndx); if (gelf_update_dyn(dynsec->c_data, flags_1_elt.ndx, &flags_1_elt.dyn) == 0) msg_elf("gelf_update_dyn"); } /* * Mark the data area as dirty so libelf will flush our * changes to the dynamic section data. */ (void) elf_flagdata(dynsec->c_data, ELF_C_SET, ELF_F_DIRTY); /* Flush the file to disk */ if (elf_update(elf, ELF_C_WRITE) == -1) msg_elf("elf_update"); (void) close(fd); (void) elf_end(elf); } return (0); }
static int replaceAMDILSection(Elf* e, int nStream, MWCALtargetEnum target) { Elf_Scn* scn = NULL; size_t shstrndx = 0; static const int verbose = 0; static const int verboseDebug = 0; /* Get section index of section containing the string table of section names */ if (elf_getshdrstrndx(e, &shstrndx) != 0) { mw_printf("elf_getshdrstrndx failed: %s\n", elf_errmsg(-1)); return 1; } /* Iterate through all the sections */ while ((scn = elf_nextscn(e, scn))) { Elf32_Shdr* shdr; const char* name; /* Get the header for this section */ shdr = elf32_getshdr(scn); if (!shdr) { mw_printf("elf32_getshdr() failed: %s\n", elf_errmsg(-1)); return 1; } /* Look up the name of the section in the string table */ name = elf_strptr(e, shstrndx, shdr->sh_name); if (!name) { mw_printf("elf_strptr() failed: %s\n", elf_errmsg(-1)); return 1; } /* if (strstr(name, ".rodata") != NULL) { Elf_Data* data = elf_getdata(scn, NULL); FILE* f = fopen("rodata_section.bin", "wb"); if (f) { fwrite(data->d_buf, 1, data->d_size, f); fclose(f); } else { perror("Failed to open file"); } size_t roSize; char* r770RO = mwReadFileWithSize("rodata_section_RV770.bin", &roSize); assert(r770RO); data->d_buf = r770RO; data->d_size = roSize; if (!elf_flagdata(data, ELF_C_SET, ELF_F_DIRTY)) { mw_printf("elf_flagdata() failed: %s\n", elf_errmsg(-1)); return 1; } if (!elf_flagscn(scn, ELF_C_SET, ELF_F_DIRTY)) { mw_printf("elf_flagscn() failed: %s\n", elf_errmsg(-1)); return 1; } if (elf_update(e, ELF_C_NULL) < 0) { mw_printf("elf_update(NULL) failed: %s\n", elf_errmsg(-1)); return 1; } } */ if (strstr(name, ".amdil") != NULL) { int uavId; const char* uavComment; Elf_Data* data; data = elf_getdata(scn, NULL); if (!data) { mw_printf("Failed to get data for .amdil section: %s\n", elf_errmsg(-1)); return 1; } if (verbose) { mw_printf("Replacing section data of type %d, off %d align "ZU"\n", data->d_type, (int) data->d_off, data->d_align); } /* Before we overwrite it, there is information we would like to extract */ uavComment = strstr((const char*) data->d_buf, ";uavid:"); if (!uavComment || (sscanf(uavComment, ";uavid:%d\n", &uavId) != 1)) { mw_printf("Error reading uavid from IL comment\n"); uavId = -1; } ilSrc = getILSrc(nStream, target, uavId, &ilSrcLen); if (!ilSrc || (ilSrcLen == 0)) { mw_printf("Failed to get IL source\n"); return 1; } data->d_buf = (void*) ilSrc; data->d_size = ilSrcLen; if (!elf_flagdata(data, ELF_C_SET, ELF_F_DIRTY)) { mw_printf("elf_flagdata() failed: %s\n", elf_errmsg(-1)); return 1; } if (!elf_flagscn(scn, ELF_C_SET, ELF_F_DIRTY)) { mw_printf("elf_flagscn() failed: %s\n", elf_errmsg(-1)); return 1; } /* Don't let libelf rearrange the sections when writing. clBuildProgram() crashes on Windows if you don't do this with some(?) Catalyst versions */ if (!elf_flagelf(e, ELF_C_SET, ELF_F_LAYOUT)) { mw_printf("elf_flagelf() failed: %s\n", elf_errmsg(-1)); return 1; } if (elf_update(e, ELF_C_NULL) < 0) { mw_printf("elf_update(NULL) failed: %s\n", elf_errmsg(-1)); return 1; } } if (verboseDebug) { printf("Section %u %s\n", (unsigned int) elf_ndxscn(scn), name); } } if (elf_update(e, ELF_C_WRITE) < 0) { mw_printf("elf_update(ELF_C_WRITE) failed: %s\n", elf_errmsg(-1)); return 1; } return 0; }
main(int argc, char **argv) { int fd; Elf *elf; Elf32_Ehdr *ehdr; Elf_Scn *scn; Elf_Data *data; Elf32_Half ndx; Elf32_Shdr *shdr; unsigned int *textdata; if (argc != 2) exit(2); assert(!nlist(argv[1], nl)); assert(nl[0].n_value && !(nl[0].n_value & 0x3)); assert(nl[1].n_value && !(nl[1].n_value & 0x3)); assert(nl[2].n_value && !(nl[2].n_value & 0x3)); if (elf_version(EV_CURRENT) == EV_NONE) { fprintf(stderr, "ELF punted! Recompile %s\n", argv[0]); exit(1); } fd = open(argv[1], O_RDWR); if (fd < 0) { perror("open"); exit(1); } elf = elf_begin(fd, ELF_C_RDWR, NULL); ehdr = elf32_getehdr(elf); assert(ehdr); /* want SHT_PROGBITS section named .text */ ndx = ehdr->e_shstrndx; scn = NULL; while ((scn = elf_nextscn(elf, scn))) { char *name = NULL; if ((shdr = elf32_getshdr(scn))) name = elf_strptr(elf, ndx, (size_t) shdr->sh_name); if (!strcmp(name, ".text")) break; } data = elf_getdata(scn, NULL); assert(data && data->d_size && !data->d_off); textdata = (unsigned int *) data->d_buf; /* process */ assert(textdata[nl[0].n_value / 4] == 0x000B000D); textdata[nl[0].n_value / 4] = type_ReturnPcHeader; assert(textdata[nl[1].n_value / 4] == 0x000A000D); assert(textdata[nl[1].n_value / 4 + 1] == 0x000B000D); assert(textdata[nl[1].n_value / 4 + 2] == 0x000B000D); textdata[nl[1].n_value / 4 + 1] = 0x0417FECC; textdata[nl[1].n_value / 4 + 2] = 0x01000000; assert(textdata[nl[2].n_value / 4] == 0x000B000D); textdata[nl[2].n_value / 4] = type_ReturnPcHeader; elf_flagdata(data, ELF_C_SET, ELF_F_DIRTY); elf_update(elf, ELF_C_WRITE); elf_end(elf); }