├── .gitignore ├── GPATH ├── GRTAGS ├── GTAGS ├── Makefile ├── README.md ├── TODO ├── bin └── dwarf ├── comment.c ├── dynamic.c ├── example.c ├── frame.c ├── note.c ├── objs └── dwarf ├── parse.c ├── parse.h ├── relocation.c ├── strtab.c ├── symtab.c └── test.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.asm 3 | GRTAGS 4 | GTAGS 5 | GPATH 6 | -------------------------------------------------------------------------------- /GPATH: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rxOred/elfparse/7d3cf2d249f7d39e83b6035c55d11ec0c9f6b7f8/GPATH -------------------------------------------------------------------------------- /GRTAGS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rxOred/elfparse/7d3cf2d249f7d39e83b6035c55d11ec0c9f6b7f8/GRTAGS -------------------------------------------------------------------------------- /GTAGS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rxOred/elfparse/7d3cf2d249f7d39e83b6035c55d11ec0c9f6b7f8/GTAGS -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-g -wall -fPIE -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | - I started this project to get a low level understanding of elf file format. 2 | - This can be used as a small library, but i consider that as a bad idea :) 3 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | 1. Implement functions to patch binaries using relocation entries 2 | 2. Use a dyanmic array for each section 3 | 3. parse debug information 4 | 4. write fucntions to append those arrays 5 | -------------------------------------------------------------------------------- /bin/dwarf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rxOred/elfparse/7d3cf2d249f7d39e83b6035c55d11ec0c9f6b7f8/bin/dwarf -------------------------------------------------------------------------------- /comment.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "parse.h" 3 | #include 4 | 5 | int parse_comment(struct shdr_table *shdr, struct COMMENT *comment, FILE *fh){ 6 | 7 | assert(shdr != NULL); 8 | assert(comment != NULL); 9 | assert(fh != NULL); 10 | comment->comment_index = get_section_index(shdr, ".comment"); 11 | if(comment->comment_index < 0) 12 | return -1; 13 | 14 | comment->comment_offset = shdr->shdr_table[comment->comment_index].sh_offset; 15 | comment->comment_size = shdr->shdr_table[comment->comment_index].sh_size; 16 | comment->comment_entries = comment->comment_size / sizeof(Elf64_Dyn); 17 | 18 | if(fseek(fh, comment->comment_offset, SEEK_SET) < 0) return -1; 19 | 20 | comment->buffer = malloc(comment->comment_size); 21 | if(!comment->buffer){ 22 | 23 | perror("memory allocation error"); 24 | return -1; 25 | } 26 | 27 | memset(comment->buffer, 0, comment->comment_size); 28 | 29 | if(fread(comment->buffer, 1, comment->comment_size, fh) < 0){ 30 | 31 | perror("failed to read file"); 32 | return -1; 33 | } 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /dynamic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "parse.h" 5 | 6 | void free_dynamic(struct DYNAMIC *dyn){ 7 | 8 | if(dyn->dyn != NULL) 9 | free(dyn->dyn); 10 | } 11 | 12 | Elf64_Addr get_dynamic_tag_data(struct DYNAMIC *dyn, int index){ 13 | 14 | switch (dyn->dyn[index].d_tag) { 15 | 16 | case DT_NEEDED: 17 | case DT_PLTRELSZ: 18 | case DT_RELASZ: 19 | case DT_RELAENT: 20 | case DT_STRSZ: 21 | case DT_SYMENT: 22 | case DT_SONAME: 23 | case DT_RELSZ: 24 | case DT_RELENT: 25 | case DT_PLTREL: 26 | return dyn->dyn[index].d_un.d_val; 27 | 28 | case DT_PLTGOT: 29 | case DT_HASH: 30 | case DT_STRTAB: 31 | case DT_SYMTAB: 32 | case DT_RELA: 33 | case DT_INIT: 34 | case DT_FINI: 35 | case DT_REL: 36 | return dyn->dyn[index].d_un.d_ptr; 37 | } 38 | 39 | return -1; 40 | } 41 | 42 | Elf64_Sxword get_dynamic_tag(struct DYNAMIC *dyn, int index){ 43 | 44 | return dyn->dyn[index].d_tag; 45 | } 46 | 47 | /* library search path is an env variable which specifies directories that executable search for shared libraries "LD_LIBRARY_PATH" */ 48 | char **get_lib_search_path(struct shdr_table *shdr, struct DYNAMIC *dyn){ 49 | 50 | char **buffer = NULL; 51 | int no_of_ent = 0; 52 | int j = 0; 53 | for(int i = 0; i < dyn->dynamic_entries; i++){ 54 | 55 | if(dyn->dyn[i].d_tag == DT_RUNPATH){ // or DT_RPATH, but deprecated 56 | 57 | ++no_of_ent; 58 | buffer = realloc(buffer, sizeof(char *) * no_of_ent); 59 | if(!buffer){ 60 | 61 | perror("failed to allocate memory"); 62 | return NULL; 63 | } 64 | 65 | buffer[j] = &shdr->dynstr.strtab_buffer[dyn->dyn[i].d_un.d_val]; 66 | ++j; 67 | } 68 | } 69 | 70 | return buffer; 71 | } 72 | 73 | char **get_lib_list(struct shdr_table *shdr, struct DYNAMIC *dyn){ 74 | 75 | char **buffer = NULL; 76 | int no_of_ent = 0; 77 | int j = 0; 78 | for(int i = 0; i < dyn->dynamic_entries; i++){ 79 | 80 | if(dyn->dyn[i].d_tag == DT_NEEDED || dyn->dyn[i].d_tag == DT_SONAME){ 81 | 82 | ++no_of_ent; 83 | buffer = realloc(buffer, sizeof(char *) * no_of_ent); 84 | if(!buffer){ 85 | 86 | perror("failed to allocate memory"); 87 | return NULL; 88 | } 89 | /* "DT_NEEDED String table offset to name of a needed library" - elf specification (no i lied, its man elf :)) 90 | * So, I assume what it meant by offset is index and string table to be .dynstr 91 | */ 92 | 93 | int index = shdr->shdr_table[dyn->dynamic_index].sh_link; // sh_link of dynamic section specifies an index to section header table. that index refers to string table which dynamic section entries of TYPE DT_NEEDED and DT_NEEDED uses to store its strings 94 | if(index == shdr->dynstr.strtab_index){ 95 | 96 | buffer[j] = &shdr->dynstr.strtab_buffer[dyn->dyn[i].d_un.d_val]; 97 | ++j; 98 | } 99 | else if(index == shdr->strtab.strtab_index){ 100 | 101 | buffer[j] = &shdr->strtab.strtab_buffer[dyn->dyn[i].d_un.d_val]; 102 | ++j; 103 | } 104 | } 105 | } 106 | return buffer; 107 | } 108 | 109 | int parse_dynamic(struct shdr_table *shdr, struct DYNAMIC *dyn, FILE *fh){ 110 | 111 | dyn->dynamic_index = get_section_index(shdr, ".dynamic"); 112 | if(dyn->dynamic_index < 0) 113 | return -1; 114 | 115 | dyn->dynamic_offset = shdr->shdr_table[dyn->dynamic_index].sh_offset; 116 | dyn->dynamic_size = shdr->shdr_table[dyn->dynamic_index].sh_size; 117 | dyn->dynamic_entries = dyn->dynamic_size / sizeof(Elf64_Dyn); 118 | 119 | if(fseek(fh, dyn->dynamic_offset, SEEK_SET) < 0) return -1; 120 | 121 | dyn->dyn = malloc(dyn->dynamic_size); 122 | if(!dyn->dyn){ 123 | 124 | perror("memory allocation error"); 125 | return -1; 126 | } 127 | 128 | memset(dyn->dyn, 0, dyn->dynamic_size); 129 | 130 | if(fread(dyn->dyn, 1, dyn->dynamic_size, fh) < 0){ 131 | 132 | perror("failed to read file"); 133 | return -1; 134 | } 135 | 136 | return 0; 137 | } 138 | -------------------------------------------------------------------------------- /example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "parse.h" 3 | 4 | int main(void){ 5 | 6 | ElfData data; 7 | data.filename = "./dwarf"; 8 | puts("----------------------------------------------"); 9 | printf("filename : %s\n", data.filename); 10 | puts("----------------------------------------------\n"); 11 | 12 | data.fh = open_file(data.filename); 13 | if(data.fh == NULL) return -1; 14 | if(assign_headers(&data) == -1) return -1; 15 | 16 | puts("-----------------------------------------------"); 17 | printf("total entries %d\n", data.shdrtab.shdr_entries); 18 | puts("-----------------------------------------------\n"); 19 | 20 | parse_shstrtab(&data); 21 | 22 | puts("-----------------------------------------------"); 23 | printf("size of shstrtab :%d\t no of shstrtab entries :%d\n", data.shdrtab.shstrtab.strtab_size, data.shdrtab.shstrtab.strtab_entries); 24 | puts("-----------------------------------------------\n"); 25 | 26 | parse_symtab(&data.shdrtab, data.fh); 27 | if(parse_strtab(&data.shdrtab, data.fh) != -1){ 28 | 29 | for(int i = 0; i < data.shdrtab.strtab.strtab_entries; i++){ 30 | 31 | printf("%s\n", data.shdrtab.strtab.strtab_content[i]); 32 | } 33 | } 34 | 35 | parse_dynsym(&data.shdrtab, data.fh); 36 | if(parse_dynstr(&data.shdrtab, data.fh) != -1){ 37 | 38 | printf("%s\n", data.shdrtab.dynstr.strtab_buffer); 39 | } 40 | 41 | puts("-------------------------------------------------"); 42 | for (int i = 0; i < data.shdrtab.shstrtab.strtab_entries; i++){ 43 | 44 | printf("%d\t0x%lx\t%lu\t%s\n", i, data.shdrtab.shdr_table[i].sh_addr, data.shdrtab.shdr_table[i].sh_size, data.shdrtab.shstrtab.strtab_content[i]); 45 | } 46 | puts("------------------------------------------------\n"); 47 | 48 | parse_note_abi_tag(&data.shdrtab, data.fh); 49 | 50 | parse_dynamic(&data.shdrtab, &data.shdrtab.dynamic, data.fh); 51 | get_lib_list(&data.shdrtab, &data.shdrtab.dynamic); 52 | 53 | 54 | 55 | free_all(&data); 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /frame.c: -------------------------------------------------------------------------------- 1 | #include "parse.h" 2 | #include 3 | #include 4 | 5 | int parse_frame(struct shdr_table *shdr, struct FRAME *frame, FILE *fh, const char *section_name){ 6 | 7 | frame->frame_index = get_section_index(shdr, section_name); 8 | if(frame->frame_index == (uint8_t)NOT_FOUND) return NOT_FOUND; 9 | 10 | frame->frame_size = shdr->shdr_table[frame->frame_index].sh_size; 11 | frame->frame_offset = shdr->shdr_table[frame->frame_index].sh_offset; 12 | 13 | frame->buffer = malloc(frame->frame_size); 14 | if(!frame->buffer){ 15 | 16 | perror("Memory allocation error\n"); 17 | return -1; 18 | } 19 | 20 | memset(frame->buffer, 0, frame->frame_size); 21 | 22 | fseek(fh, frame->frame_offset, SEEK_SET); 23 | if(fread(frame->buffer, 1, frame->frame_size, fh) < frame->frame_size){ 24 | 25 | perror("error reading file"); 26 | return -1; 27 | } 28 | 29 | for(int i = 0; i < frame->frame_size; i++){ 30 | 31 | putchar(frame->buffer[i]); 32 | } 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /note.c: -------------------------------------------------------------------------------- 1 | #include "parse.h" 2 | #include 3 | 4 | void free_note(struct NOTETAB *note){ 5 | 6 | if(note->notetab != NULL) 7 | free(note->notetab); 8 | } 9 | 10 | Elf64_Word get_note_type(struct NOTETAB *note, int index){ 11 | 12 | return note->notetab[index].n_type; 13 | } 14 | 15 | Elf64_Word get_note_name_len(struct NOTETAB *note, int index){ 16 | 17 | return note->notetab[index].n_namesz; 18 | } 19 | 20 | Elf64_Word get_note_descriptor_len(struct NOTETAB *note, int index){ 21 | 22 | return note->notetab[index].n_descsz; 23 | } 24 | 25 | int parse_notetab(struct shdr_table *shdr, struct NOTETAB *note, FILE *fh, const char *sectionname){ 26 | 27 | note->notetab_index = get_section_index(shdr, sectionname); 28 | if(note->notetab_index == (uint8_t)NOT_FOUND) 29 | return NOT_FOUND; 30 | 31 | note->notetab_size = shdr->shdr_table[note->notetab_index].sh_size; 32 | note->notetab_entries = note->notetab_size / shdr->shdr_table[note->notetab_index].sh_entsize; 33 | note->notetab_offset = shdr->shdr_table[note->notetab_index].sh_offset; 34 | 35 | note->notetab = malloc(note->notetab_entries * sizeof(Elf64_Nhdr)); 36 | if(!note->notetab){ 37 | 38 | perror("memory allocation failed"); 39 | return -1; 40 | } 41 | memset(note->notetab, 0, note->notetab_entries * sizeof(Elf64_Nhdr)); 42 | 43 | fseek(fh, note->notetab_offset, SEEK_SET); 44 | if(fread(note->notetab, 1, note->notetab_size, fh) < note->notetab_size){ 45 | 46 | perror("failed to read file"); 47 | return -1; 48 | } 49 | 50 | return 0; 51 | } 52 | 53 | int parse_note_abi_tag(struct shdr_table *shdr, FILE *fh){ 54 | 55 | shdr->note_abi_tag.notetab = NULL; 56 | int ret = parse_notetab(shdr, &shdr->note_abi_tag, fh, "note.ABI-tag"); 57 | if(ret == NOT_FOUND){ 58 | 59 | fprintf(stderr, "Section .note.ABI-tag not found\n"); 60 | return NOT_FOUND; 61 | } 62 | else { 63 | 64 | return -1; 65 | } 66 | 67 | return 0; 68 | } 69 | 70 | int parse_note_gnu_property(struct shdr_table *shdr, FILE *fh){ 71 | 72 | shdr->note_gnu_property.notetab = NULL; 73 | int ret = parse_notetab(shdr, &shdr->note_gnu_property, fh, "note.gnu.property"); 74 | if(ret == NOT_FOUND){ 75 | 76 | fprintf(stderr, "Section .note.gnu.property not found\n"); 77 | return -1; 78 | } 79 | else{ 80 | 81 | return -1; 82 | } 83 | 84 | return 0; 85 | } 86 | 87 | int parse_note_gnu_build_id(struct shdr_table *shdr, FILE *fh){ 88 | 89 | shdr->note_gnu_property.notetab = NULL; 90 | int ret = parse_notetab(shdr, &shdr->note_gnu_property, fh, "note.gnu.build.id"); 91 | if(ret == NOT_FOUND){ 92 | 93 | fprintf(stderr, "Section .note.gnu.build-id not found\n"); 94 | return -1; 95 | } 96 | else{ 97 | 98 | return -1; 99 | } 100 | 101 | return 0; 102 | } 103 | -------------------------------------------------------------------------------- /objs/dwarf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rxOred/elfparse/7d3cf2d249f7d39e83b6035c55d11ec0c9f6b7f8/objs/dwarf -------------------------------------------------------------------------------- /parse.c: -------------------------------------------------------------------------------- 1 | #include "parse.h" 2 | #include 3 | #include 4 | 5 | void free_all(ElfData *data){ 6 | 7 | /* 8 | * shstrtab contains details of section header string table. memeber 9 | * strtab_content contains char * pointing to heap where name of every 10 | * section is stored 11 | */ 12 | if(data->shdrtab.shstrtab.strtab_buffer != NULL) 13 | free(data->shdrtab.shstrtab.strtab_buffer); 14 | 15 | /* cleaning array of character pointers which points to section header string table */ 16 | if(data->shdrtab.shstrtab.strtab_content != NULL) 17 | free(data->shdrtab.shstrtab.strtab_content); 18 | 19 | /* cleaning memory where section header table is stored */ 20 | if(data->shdrtab.shdr_table != NULL) 21 | free(data->shdrtab.shdr_table); 22 | 23 | /* cleaning memort where program header table is stored */ 24 | if(data->phdrtab.phdr_table != NULL) 25 | free(data->phdrtab.phdr_table); 26 | 27 | free_note(&data->shdrtab.note_abi_tag); 28 | free_note(&data->shdrtab.note_gnu_build_id); 29 | free_note(&data->shdrtab.note_gnu_property); 30 | 31 | free_symtab(&data->shdrtab.symtab); 32 | free_symtab(&data->shdrtab.dynsym); 33 | 34 | free_strtab(&data->shdrtab.strtab); 35 | free_strtab(&data->shdrtab.dynstr); 36 | 37 | free_dynamic(&data->shdrtab.dynamic); 38 | 39 | free_relocation(&data->shdrtab.rela_debug_arranges); 40 | free_relocation(&data->shdrtab.rela_debug_line); 41 | free_relocation(&data->shdrtab.rela_rodata); 42 | free_relocation(&data->shdrtab.rela_text); 43 | free_relocation(&data->shdrtab.rela_debug_info); 44 | 45 | fclose(data->fh); 46 | } 47 | 48 | int get_no_of_strings(char *buffer, int size){ 49 | 50 | assert(buffer != NULL); 51 | int no_of_strings = 0; 52 | for(int i = 0; i < size; i++){ 53 | 54 | if(buffer[i] == '\0' || buffer[i] == '\n'){ 55 | 56 | no_of_strings++; 57 | } 58 | } 59 | return no_of_strings; 60 | } 61 | 62 | int get_section_index(struct shdr_table *shdr, const char *section_name){ 63 | 64 | assert(shdr != NULL); 65 | assert(section_name != NULL); 66 | 67 | int i; 68 | for (i = 0; i < shdr->shstrtab.strtab_entries; i++){ 69 | 70 | if(shdr->shdr_table[i].sh_name < shdr->shstrtab.strtab_size){ 71 | 72 | char *buf = &shdr->shstrtab.strtab_buffer[shdr->shdr_table[i].sh_name]; 73 | if((buf)) 74 | 75 | if(strcmp(buf, section_name) == 0){ 76 | return i; 77 | } 78 | } 79 | } 80 | return NOT_FOUND; 81 | } 82 | 83 | char **get_strings(struct shdr_table *shdr, int entries){ 84 | 85 | assert(shdr != NULL); 86 | char **parsed_string = malloc(sizeof(char *) * entries); 87 | if(!parsed_string){ 88 | 89 | perror("memory allocation failed"); 90 | return NULL; 91 | } 92 | 93 | memset(parsed_string, 0, sizeof(char *) * entries); 94 | 95 | for (int i = 0; i < entries; i++){ 96 | 97 | char *buf = &shdr->shstrtab.strtab_buffer[shdr->shdr_table[i].sh_name]; 98 | parsed_string[i] = buf; 99 | } 100 | 101 | return parsed_string; 102 | } 103 | 104 | uint32_t get_section_link(struct shdr_table *shdr, const char *sectionname){ 105 | 106 | assert(shdr != NULL); 107 | assert(sectionname != NULL); 108 | int index = get_section_index(shdr, sectionname); 109 | if(index == NOT_FOUND) return NOT_FOUND; 110 | 111 | return shdr->shdr_table[index].sh_link; 112 | } 113 | 114 | uint64_t get_section_address_align(struct shdr_table *shdr, const char *sectionname){ 115 | 116 | assert(shdr != NULL); 117 | assert(sectionname != NULL); 118 | int index = get_section_index(shdr, sectionname); 119 | if(index == NOT_FOUND) return NOT_FOUND; 120 | 121 | return shdr->shdr_table[index].sh_addralign; 122 | } 123 | 124 | uint32_t get_section_index_to_shstr(struct shdr_table *shdr, const char *sectionname){ 125 | 126 | assert(shdr != NULL); 127 | assert(sectionname != NULL); 128 | int index = get_section_index(shdr, sectionname); 129 | if(index == NOT_FOUND) return NOT_FOUND; 130 | 131 | return shdr->shdr_table[index].sh_name; 132 | } 133 | 134 | uint32_t get_section_type(struct shdr_table *shdr, const char *sectionname){ 135 | 136 | assert(shdr != NULL); 137 | assert(sectionname != NULL); 138 | int index = get_section_index(shdr, sectionname); 139 | if(index == NOT_FOUND) return NOT_FOUND; 140 | 141 | return shdr->shdr_table[index].sh_type; 142 | } 143 | 144 | uint32_t get_section_info(struct shdr_table *shdr, const char *sectionname){ 145 | 146 | assert(shdr != NULL); 147 | assert(sectionname != NULL); 148 | int index = get_section_index(shdr, sectionname); 149 | if(index == NOT_FOUND) return NOT_FOUND; 150 | 151 | return shdr->shdr_table[index].sh_info; 152 | } 153 | 154 | uint64_t get_section_flags(struct shdr_table *shdr, const char *sectionname){ 155 | 156 | assert(shdr != NULL); 157 | assert(sectionname != NULL); 158 | int index = get_section_index(shdr, sectionname); 159 | if(index == NOT_FOUND) return NOT_FOUND; 160 | 161 | return shdr->shdr_table[index].sh_flags; 162 | } 163 | 164 | Elf64_Addr get_section_address(struct shdr_table *shdr, const char *sectionname){ 165 | 166 | assert(shdr != NULL); 167 | assert(sectionname != NULL); 168 | int index = get_section_index(shdr, sectionname); 169 | if(index == NOT_FOUND) return NOT_FOUND; 170 | 171 | return shdr->shdr_table[index].sh_addr; 172 | } 173 | 174 | off_t get_section_offset(struct shdr_table *shdr, const char *sectionname){ 175 | 176 | assert(shdr != NULL); 177 | assert(sectionname != NULL); 178 | int index = get_section_index(shdr, sectionname); 179 | if(index == NOT_FOUND) return NOT_FOUND; 180 | 181 | return shdr->shdr_table[index].sh_offset; 182 | } 183 | 184 | uint64_t get_section_entrysize(struct shdr_table *shdr, const char *sectionname){ 185 | 186 | assert(shdr != NULL); 187 | assert(sectionname != NULL); 188 | int index = get_section_index(shdr, sectionname); 189 | if(index == NOT_FOUND) return NOT_FOUND; 190 | 191 | return shdr->shdr_table[index].sh_entsize; 192 | } 193 | 194 | uint64_t get_section_size(struct shdr_table *shdr, const char *sectionname){ 195 | 196 | assert(shdr != NULL); 197 | assert(sectionname != NULL); 198 | int index = get_section_index(shdr, sectionname); 199 | if(index == NOT_FOUND) return NOT_FOUND; 200 | 201 | return shdr->shdr_table[index].sh_size; 202 | } 203 | /* 204 | * this function uses shdr table to parse section names. it stores parsed strings in shstrtab 205 | * structure's strtab_content memeber. this memeber can be used when printing section names and so on 206 | * get_section_index function uses values assigned by this function to track sections. 207 | */ 208 | int parse_shstrtab(ElfData *data){ //should have used struct shdr_table * 209 | 210 | /*get the section header table index to get the string table. ehdr.e_shstrndx containts the index of shstrtab table*/ 211 | assert(data != NULL); 212 | 213 | data->shdrtab.shstrtab.strtab_index = data->elf_header.ehdr.e_shstrndx; 214 | 215 | /*use section header index to access access corresponding section;'s shdr structure and use sh_offset to get the offset of the string table */ 216 | data->shdrtab.shstrtab.strtab_offset = data->shdrtab.shdr_table[data->shdrtab.shstrtab.strtab_index].sh_offset; 217 | 218 | /* seek to that offset */ 219 | fseek(data->fh, data->shdrtab.shstrtab.strtab_offset, SEEK_SET); 220 | 221 | /* set size of the string table using sh_size */ 222 | data->shdrtab.shstrtab.strtab_size = data->shdrtab.shdr_table[data->shdrtab.shstrtab.strtab_index].sh_size; 223 | 224 | /* allocate a buffer with size sh_size, then read shstrtab into that buffer */ 225 | data->shdrtab.shstrtab.strtab_buffer = malloc(data->shdrtab.shstrtab.strtab_size * sizeof(char)); //do not free this, used to get section names.. 226 | if(!data->shdrtab.shstrtab.strtab_buffer){ 227 | 228 | perror("memory allocation failed"); 229 | return -1; 230 | } 231 | 232 | memset(data->shdrtab.shstrtab.strtab_buffer, 0, data->shdrtab.shstrtab.strtab_size * sizeof(char)); 233 | 234 | if(fread(data->shdrtab.shstrtab.strtab_buffer, 1, data->shdrtab.shstrtab.strtab_size, data->fh) < (unsigned long)data->shdrtab.shstrtab.strtab_size){ 235 | 236 | perror("failed read file"); 237 | return -1; 238 | } 239 | /* 240 | * after reading, we need tp get the exact number of strings in that table. this is also possible using something like 241 | * e_shnum, which gives us number of sections. number of sections == no of strings in shstrtab 242 | */ 243 | 244 | #ifdef ___STRENT 245 | data->shdrtab.shstrtab.strtab_entries = data->shdrtab.shdr_entries; 246 | #else 247 | data->shdrtab.shstrtab.strtab_entries = get_no_of_strings(data->shdrtab.shstrtab.strtab_buffer, data->shdrtab.shstrtab.strtab_size); 248 | #endif 249 | 250 | /* read to (char *) buffer , sh_size of bytes from current position (section .strtab offset)) */ 251 | data->shdrtab.shstrtab.strtab_content = get_strings(&data->shdrtab, data->shdrtab.shstrtab.strtab_entries); 252 | 253 | return 0; 254 | } 255 | 256 | int check_elf(FILE *fh){ 257 | 258 | assert(fh != NULL); 259 | uint8_t buf[5]; 260 | 261 | fseek(fh, 0, SEEK_SET); 262 | if(fread(buf, sizeof(uint8_t), 5, fh) < 4){ 263 | 264 | perror("failed to read file"); 265 | return -1; 266 | }; 267 | 268 | if((buf[0] == 0x7f) && (buf[1] == 'E') && (buf[2] == 'L') && (buf[3] == 'F')) 269 | return 0; 270 | else{ 271 | 272 | fprintf(stderr, "not an elf binary\n"); 273 | return -1; 274 | } 275 | return 0; 276 | } 277 | 278 | void init_ptr(struct shdr_table *shdr){ 279 | 280 | assert(shdr != NULL); 281 | /* initialize all not-yet-used pointers to null */ 282 | shdr->shstrtab.strtab_buffer = NULL; 283 | shdr->shstrtab.strtab_content = NULL; 284 | 285 | shdr->dynstr.strtab_buffer = NULL; 286 | shdr->dynstr.strtab_content = NULL; 287 | 288 | shdr->strtab.strtab_buffer = NULL; 289 | shdr->strtab.strtab_content = NULL; 290 | 291 | shdr->dynsym.symtab = NULL; 292 | 293 | shdr->symtab.symtab = NULL; 294 | 295 | shdr->note_abi_tag.notetab = NULL; 296 | 297 | shdr->note_gnu_build_id.notetab = NULL; 298 | 299 | shdr->note_gnu_property.notetab = NULL; 300 | 301 | shdr->dynamic.dyn = NULL; 302 | 303 | shdr->rela_debug_line.relocation = NULL; 304 | shdr->rela_debug_info.relocation = NULL; 305 | shdr->rela_debug_arranges.relocation = NULL; 306 | shdr->rela_rodata.relocation = NULL; 307 | shdr->rela_text.relocation = NULL; 308 | 309 | shdr->comment.buffer = NULL; 310 | } 311 | 312 | /* 313 | * this function reads from the elf file and assign ehdr header and shdr, phdr tables 314 | */ 315 | int assign_headers(ElfData *data){ 316 | 317 | assert(data != NULL); 318 | 319 | if(check_elf(data->fh) == -1) return -1;; 320 | fseek(data->fh, 0, SEEK_SET); 321 | 322 | /* assigning ehdr with data read from the binary */ 323 | data->elf_header.ehdr_size = sizeof(Elf64_Ehdr); 324 | if(fread(&data->elf_header.ehdr, data->elf_header.ehdr_size, 1, data->fh) < 1){ 325 | 326 | perror("failed to read file: "); 327 | return -1; 328 | } 329 | 330 | /* assigning phdr with data read from binary using ehdr->e_phoff */ 331 | if((data->elf_header.ehdr.e_type == ET_EXEC) || (data->elf_header.ehdr.e_type == ET_DYN)){ 332 | 333 | data->phdrtab.phdr_entries = data->elf_header.ehdr.e_phnum; 334 | data->phdrtab.phdr_size = data->phdrtab.phdr_entries * sizeof(Elf64_Phdr); 335 | data->phdrtab.phdr_offset = data->elf_header.ehdr.e_phoff; 336 | 337 | data->phdrtab.phdr_table = malloc(data->phdrtab.phdr_size); 338 | if(!data->phdrtab.phdr_table) { 339 | 340 | perror("memory allocation failed: "); 341 | return -1; 342 | } 343 | 344 | memset(data->phdrtab.phdr_table, 0, data->phdrtab.phdr_size); 345 | 346 | fseek(data->fh, data->phdrtab.phdr_offset, SEEK_SET); //seeking file pointer to position where program header table begins 347 | 348 | if(fread(data->phdrtab.phdr_table, sizeof(Elf64_Phdr), data->phdrtab.phdr_entries, data->fh) < (unsigned long)data->phdrtab.phdr_entries){ //reading from that location to allocated space in heap 349 | perror("failed to read data\n"); 350 | return -1; 351 | } 352 | } 353 | else{ 354 | 355 | fprintf(stderr, "binary file is not an executable file\n"); 356 | } 357 | 358 | /* assigning shdr with data read from binary using ehdr->e_shoff */ 359 | data->shdrtab.shdr_entries = data->elf_header.ehdr.e_shnum; 360 | data->shdrtab.shdr_size = data->shdrtab.shdr_entries * sizeof(Elf64_Shdr); 361 | data->shdrtab.shdr_offset = data->elf_header.ehdr.e_shoff; 362 | 363 | data->shdrtab.shdr_table = malloc(data->shdrtab.shdr_size); //do not free this memory. used througout the code 364 | if(!data->shdrtab.shdr_table) { 365 | 366 | perror("memory allocation failed: "); 367 | return -1; 368 | } 369 | 370 | memset(data->shdrtab.shdr_table, 0, data->shdrtab.shdr_size); 371 | 372 | fseek(data->fh, data->shdrtab.shdr_offset, SEEK_SET); 373 | 374 | if(fread(data->shdrtab.shdr_table, sizeof(Elf64_Shdr), data->shdrtab.shdr_entries, data->fh) < (unsigned long)data->shdrtab.shdr_entries){ 375 | 376 | perror("could not read section header table"); 377 | return -1; 378 | } 379 | 380 | init_ptr(&data->shdrtab); 381 | return 0; 382 | } 383 | 384 | FILE *open_file(const char *filename){ 385 | 386 | assert(filename != NULL); 387 | FILE *local = fopen(filename, "rb"); 388 | if(!local){ 389 | 390 | perror("coud not open binary file"); 391 | return NULL; 392 | } 393 | 394 | return local; 395 | } 396 | -------------------------------------------------------------------------------- /parse.h: -------------------------------------------------------------------------------- 1 | #ifndef PARSE_H 2 | #define PARSE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | struct elf_header{ //elf_header 16 | 17 | Elf64_Ehdr ehdr; /* elf header */ 18 | ssize_t ehdr_size; /* size of the elf header */ 19 | }; 20 | 21 | struct phdr_table{ //phdrtab 22 | 23 | Elf64_Phdr *phdr_table; /* program header table */ 24 | uint8_t phdr_entries; /* no of program headers */ 25 | uint32_t phdr_size; 26 | off_t phdr_offset; 27 | }; 28 | 29 | struct COMMENT{ 30 | 31 | uint8_t comment_index; 32 | uint32_t comment_size; 33 | uint32_t comment_entries; 34 | off_t comment_offset; 35 | char *buffer; 36 | }; 37 | 38 | struct RELOCATION { 39 | 40 | uint8_t relocation_index; 41 | uint32_t relocation_size; 42 | uint32_t relocation_entries; 43 | off_t relocation_offset; 44 | Elf64_Rela *relocation; 45 | }; 46 | 47 | struct DYNAMIC { /* dyanamic section contains an array of Elf64_Dyn structures */ 48 | 49 | uint8_t dynamic_index; 50 | uint32_t dynamic_size; 51 | uint32_t dynamic_entries; 52 | off_t dynamic_offset; 53 | Elf64_Dyn *dyn; 54 | }; 55 | 56 | struct NOTETAB{ 57 | 58 | uint8_t notetab_index; /* index of notetab section from section header table */ 59 | uint32_t notetab_size; /* size of notetab section */ 60 | uint32_t notetab_entries; /* number of entries in notetab section */ 61 | off_t notetab_offset; /* offset of the notetab section from begining of the elf binary */ 62 | Elf64_Nhdr *notetab; /* notetab sectiom contents, an array of type Elf64_Nhdr */ 63 | }; 64 | 65 | struct SYMTAB{ 66 | 67 | uint8_t symtab_index; /* index of symtab section */ 68 | uint32_t symtab_size; /* size of symtab section */ 69 | uint32_t symtab_entries; 70 | off_t symtab_offset; 71 | Elf64_Sym *symtab; /* dynamic symbol table , an array of Elf64_Sym structures*/ 72 | struct STRTAB *strtab; /* pointer to symbol tables string table */ 73 | }; 74 | 75 | struct STRTAB{ //for sections with type strtab 76 | 77 | uint8_t strtab_index; /* index of section which holds section header name string table */ 78 | uint32_t strtab_size; /* string table length */ 79 | uint32_t strtab_entries; /* no of entries in string table, no of section names, or no of 80 | * section names except null section. this is same as shdr_entries - 1 81 | */ 82 | off_t strtab_offset; /* string table offset from begining of the file */ 83 | char *strtab_buffer; 84 | /* 85 | * content and buffer does not points to same chunk of memory therefore buffer can be freed. its useless because we have contents. 86 | */ 87 | char **strtab_content; /* string table data */ 88 | }; 89 | 90 | struct shdr_table{ //shdrtab 91 | 92 | Elf64_Shdr *shdr_table; /* section header table */ 93 | uint32_t shdr_entries; /* no of section headers with that null section*/ 94 | uint32_t shdr_size; /* size of section header table */ 95 | off_t shdr_offset; /* section header table offset */ 96 | 97 | /* 98 | * structures containing each usefull section information 99 | */ 100 | struct STRTAB shstrtab; /* section header table string table */ 101 | struct STRTAB dynstr; /* dynamic section string table */ 102 | struct STRTAB strtab; /* string table */ 103 | struct SYMTAB dynsym; /* dynamic symbol table */ 104 | struct SYMTAB symtab; /* symbol table */ 105 | struct NOTETAB note_abi_tag; /* some additional note sections */ 106 | struct NOTETAB note_gnu_property; 107 | struct NOTETAB note_gnu_build_id; 108 | struct DYNAMIC dynamic; 109 | struct RELOCATION rela_debug_info; 110 | struct RELOCATION rela_debug_arranges; 111 | struct RELOCATION rela_debug_line; 112 | struct RELOCATION rela_rodata; 113 | struct RELOCATION rela_text; 114 | struct COMMENT comment; 115 | 116 | /* TODO make a dynamic array and make sections appendable. */ 117 | /* TODO write fucntions to append those arrays */ 118 | }; 119 | 120 | typedef struct { //data 121 | 122 | char *filename; /* filename of the elf binary */ 123 | FILE *fh; /* file structure to keep read data */ 124 | 125 | /* 126 | * elf header / header table structures 127 | */ 128 | struct elf_header elf_header; 129 | struct phdr_table phdrtab; 130 | struct shdr_table shdrtab; 131 | 132 | } ElfData; 133 | 134 | //write some defines to indicate errors. then return that value instead of exit function. 135 | 136 | #define NOT_FOUND 404 137 | #define NOT_ELF 405 138 | 139 | #define ___STRENT 140 | #define ___PARSE 141 | 142 | // intitial functions 143 | FILE *open_file(const char *filename); 144 | int assign_headers(ElfData *data); 145 | int check_elf(FILE *fh); 146 | void free_all(ElfData *data); 147 | 148 | // get information functions 149 | char **get_strings(struct shdr_table *shdr, int entries); 150 | int get_section_index(struct shdr_table *shdr, const char *section_name); 151 | int get_no_of_strings(char *buffer, int size); 152 | 153 | // program header table functions 154 | 155 | // section header table functions 156 | int parse_shstrtab(ElfData *data); /* this is also an intial function. this function is necessary to parse other information */ 157 | uint32_t get_section_link(struct shdr_table *shdr, const char *sectionname); 158 | uint64_t get_section_address_align(struct shdr_table *shdr, const char *sectionname); 159 | uint32_t get_section_index_to_shstr(struct shdr_table *shdr, const char *sectionname); 160 | uint32_t get_section_type(struct shdr_table *shdr, const char *sectionname); 161 | uint32_t get_section_info(struct shdr_table *shdr, const char *sectionname); 162 | uint64_t get_section_flags(struct shdr_table *shdr, const char *sectionname); 163 | uint64_t get_section_size(struct shdr_table *shdr, const char *sectionname); 164 | Elf64_Addr get_section_address(struct shdr_table *shdr, const char *sectionname); 165 | uint64_t get_section_entrysize(struct shdr_table *shdr, const char *sectionname); 166 | off_t get_section_offset(struct shdr_table *shdr, const char *sectionname); 167 | 168 | // string tables functions 169 | int parse_string_table(struct shdr_table *shdr, struct STRTAB *strtab, FILE *fh, char *section_name); 170 | int parse_dynstr(struct shdr_table *shdr, FILE *fh); 171 | int parse_strtab(struct shdr_table *shdr, FILE *fh); 172 | void free_strtab(struct STRTAB *str); 173 | 174 | // symbol table functions 175 | int parse_symbol_table(struct shdr_table *shdr, struct SYMTAB *symtab, FILE *fh, const char *section_name); 176 | int parse_dynsym(struct shdr_table *shdr, FILE *fh); 177 | int parse_symtab(struct shdr_table *shdr, FILE *fh); 178 | int get_symbol_index(struct SYMTAB *symtab, const char *symname); 179 | int get_symbol_info(struct SYMTAB *symtab, const char *symname); 180 | uint64_t get_symbol_size(struct SYMTAB *symtab, const char *symname); 181 | Elf64_Addr get_symbol_value(struct SYMTAB *symtab, const char *symname); 182 | int get_symbol_visibility(struct SYMTAB *symtab, const char *symname); 183 | uint16_t get_symbol_section(struct SYMTAB *symtab, const char *symname); 184 | void free_symtab(struct SYMTAB *sym); 185 | 186 | //note 187 | int parse_notetab(struct shdr_table *shdr, struct NOTETAB *note, FILE *fh, const char *sectionname); 188 | int parse_note_gnu_build_id(struct shdr_table *shdr, FILE *fh); 189 | int parse_note_gnu_property(struct shdr_table *shdr, FILE *fh); 190 | int parse_note_abi_tag(struct shdr_table *shdr, FILE *fh); 191 | Elf64_Word get_note_type(struct NOTETAB *note, int index); 192 | Elf64_Word get_note_name_len(struct NOTETAB *note, int index); 193 | Elf64_Word get_note_descriptor_len(struct NOTETAB *note, int index); 194 | void free_note(struct NOTETAB *note); 195 | 196 | //dynamic 197 | int parse_dynamic(struct shdr_table *shdr, struct DYNAMIC *dyn, FILE *fh); 198 | char **get_lib_list(struct shdr_table *shdr, struct DYNAMIC *dyn); 199 | char **get_lib_search_path(struct shdr_table *shdr, struct DYNAMIC *dyn); 200 | Elf64_Sxword get_dynamic_tag(struct DYNAMIC *dyn, int index); 201 | Elf64_Addr get_dynamic_tag_data(struct DYNAMIC *dyn, int index); 202 | void free_dynamic(struct DYNAMIC *dyn); 203 | 204 | 205 | //relocation 206 | int parse_relocation(struct shdr_table *shdr, struct RELOCATION *relocation, FILE *fh, const char *sectionname); 207 | int parse_rela_rodata(struct shdr_table *shdr, FILE *fh); 208 | int parse_rela_debug_info(struct shdr_table *shdr, FILE *fh); 209 | int parse_rela_debug_arranges(struct shdr_table *shdr, FILE *fh); 210 | int parse_rela_debug_line(struct shdr_table *shdr, FILE *fh); 211 | int parse_rela_text(struct shdr_table *shdr, FILE *fh); 212 | int free_relocation(struct RELOCATION *relocation); 213 | 214 | #endif 215 | -------------------------------------------------------------------------------- /relocation.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "parse.h" 4 | 5 | void free_relocation(struct RELOCATION *relocation){ 6 | 7 | if(relocation->relocation) 8 | free(relocation->relocation); 9 | } 10 | 11 | /* retrieve address relocation should be affected */ 12 | Elf64_Addr get_relocation_offset(struct RELOCATION *relocation, int index){ 13 | 14 | return relocation->relocation[index].r_offset; 15 | } 16 | 17 | /* retrieve symbol table index with respect to which the relocation must be made */ 18 | Elf64_Word get_relocation_info(struct RELOCATION *relocation, int index){ //can be used when recreating symbols and stuff 19 | 20 | return relocation->relocation[index].r_info; 21 | } 22 | 23 | Elf64_Sword get_relocation_addend(struct RELOCATION *relocation, int index){ 24 | 25 | return relocation->relocation[index].r_addend; 26 | } 27 | 28 | int parse_relocation(struct shdr_table *shdr, struct RELOCATION *relocation, FILE *fh, const char *sectionname){ 29 | 30 | relocation->relocation_index = get_section_index(shdr, sectionname); 31 | if(relocation->relocation_index < 0) 32 | return -1; 33 | 34 | relocation->relocation_offset = shdr->shdr_table[relocation->relocation_index].sh_offset; 35 | relocation->relocation_size = shdr->shdr_table[relocation->relocation_index].sh_size; 36 | relocation->relocation_entries = relocation->relocation_size / sizeof(Elf64_Dyn); 37 | 38 | if(fseek(fh, relocation->relocation_offset, SEEK_SET) < 0) return -1; 39 | 40 | relocation->relocation = malloc(relocation->relocation_size); 41 | if(!relocation->relocation){ 42 | 43 | perror("memory allocation error"); 44 | return -1; 45 | } 46 | 47 | memset(relocation->relocation, 0, relocation->relocation_size); 48 | 49 | if(fread(relocation->relocation, 1, relocation->relocation_size, fh) < 0){ 50 | 51 | perror("failed to read file"); 52 | return -1; 53 | } 54 | 55 | return 0; 56 | } 57 | 58 | int parse_rela_debug_info(struct shdr_table *shdr, FILE *fh){ 59 | 60 | shdr->rela_debug_info.relocation = NULL; 61 | int ret = parse_relocation(shdr, &shdr->rela_debug_info, fh, ".rela.debug_info"); 62 | if(ret == NOT_FOUND){ 63 | 64 | fprintf(stderr, "Section .rela.debug_info not found"); 65 | return -1; 66 | } 67 | 68 | else if(ret == -1) return -1; 69 | 70 | return 0; 71 | } 72 | 73 | int parse_rela_debug_arranges(struct shdr_table *shdr, FILE *fh){ 74 | 75 | shdr->rela_debug_arranges.relocation = NULL; 76 | int ret = parse_relocation(shdr, &shdr->rela_debug_arranges, fh, ".rela.debug_arranges"); 77 | if(ret == NOT_FOUND){ 78 | 79 | fprintf(stderr, "Section .rela.debug_arranges not found"); 80 | return -1; 81 | } 82 | 83 | else if(ret == -1) return -1; 84 | 85 | return 0; 86 | } 87 | 88 | int parse_rela_debug_line(struct shdr_table *shdr, FILE *fh){ 89 | 90 | shdr->rela_debug_line.relocation = NULL; 91 | int ret = parse_relocation(shdr, &shdr->rela_debug_line, fh, ".rela.debug_line"); 92 | if(ret == NOT_FOUND){ 93 | 94 | fprintf(stderr, "Section .rela.debug_line not found"); 95 | return -1; 96 | } 97 | 98 | else if(ret == -1) return -1; 99 | 100 | return 0; 101 | } 102 | 103 | int parse_rela_rodata(struct shdr_table *shdr, FILE *fh){ 104 | 105 | shdr->rela_rodata.relocation = NULL; 106 | int ret = parse_relocation(shdr, &shdr->rela_rodata, fh, ".rela.rodata"); 107 | if(ret == NOT_FOUND){ 108 | 109 | fprintf(stderr, "Section .rela.debug_rodata not found"); 110 | return -1; 111 | } 112 | 113 | else if(ret == -1) return -1; 114 | 115 | return 0; 116 | } 117 | 118 | int parse_rela_text(struct shdr_table *shdr, FILE *fh){ 119 | 120 | shdr->rela_text.relocation = NULL; 121 | int ret = parse_relocation(shdr, &shdr->rela_text, fh, ".rela.text"); 122 | if(ret == NOT_FOUND){ 123 | 124 | fprintf(stderr, "Section .rela.text not found"); 125 | return -1; 126 | } 127 | 128 | else if(ret == -1) return -1; 129 | 130 | return 0; 131 | } 132 | -------------------------------------------------------------------------------- /strtab.c: -------------------------------------------------------------------------------- 1 | #include "parse.h" 2 | #include 3 | #include 4 | 5 | void free_strtab(struct STRTAB *str){ 6 | 7 | if(str->strtab_buffer) 8 | free(str->strtab_buffer); 9 | 10 | if(str->strtab_content) 11 | free(str->strtab_content); 12 | } 13 | 14 | /* 15 | * string table 16 | */ 17 | char **get_strtab_contents(struct SYMTAB *symtab, char *buffer, int entries){ 18 | 19 | assert(symtab != NULL); 20 | assert(buffer != NULL); 21 | 22 | if(!buffer){ 23 | 24 | fprintf(stderr, "buffer is empty. could not parse contents"); 25 | } 26 | 27 | char **parsed_strings = calloc(sizeof(char *), entries); 28 | if(!parsed_strings){ 29 | 30 | perror("memory allocation failed"); 31 | return NULL; 32 | } 33 | 34 | for (int i = 0; i < entries; i++){ 35 | 36 | char *buf = &buffer[symtab->symtab[i].st_name]; 37 | parsed_strings[i] = buf; 38 | } 39 | 40 | return parsed_strings; 41 | } 42 | 43 | int parse_string_table(struct shdr_table *shdr, struct STRTAB *strtab, FILE *fh, char *section_name){ 44 | 45 | assert(fh != NULL); 46 | assert(shdr != NULL); 47 | assert(strtab != NULL); 48 | assert(section_name); 49 | 50 | strtab->strtab_index = get_section_index(shdr, section_name); 51 | if(strtab->strtab_index == (uint8_t)NOT_FOUND) return NOT_FOUND; 52 | 53 | strtab->strtab_offset = shdr->shdr_table[strtab->strtab_index].sh_offset; 54 | strtab->strtab_size = shdr->shdr_table[strtab->strtab_index].sh_size; 55 | 56 | fseek(fh, strtab->strtab_offset, SEEK_SET); 57 | 58 | strtab->strtab_buffer = malloc(strtab->strtab_size); 59 | if(!strtab->strtab_buffer){ 60 | 61 | perror("memory allocation failed"); 62 | return -1; 63 | } 64 | 65 | memset(strtab->strtab_buffer, 0, strtab->strtab_size); 66 | 67 | if(fread(strtab->strtab_buffer, sizeof(char), strtab->strtab_size, fh) < strtab->strtab_size){ 68 | 69 | perror("failed to read file"); 70 | return -1; 71 | } 72 | 73 | strtab->strtab_entries = get_no_of_strings(strtab->strtab_buffer, strtab->strtab_size); 74 | 75 | return 0; 76 | } 77 | 78 | /* 79 | * for dynamic section's string table 80 | */ 81 | int parse_dynstr(struct shdr_table *shdr, FILE *fh){ 82 | 83 | assert(fh != NULL); 84 | assert(shdr != NULL); 85 | if(!shdr->dynsym.strtab) 86 | shdr->dynsym.strtab = &shdr->dynstr; 87 | 88 | shdr->dynstr.strtab_buffer = NULL; 89 | shdr->dynstr.strtab_content = NULL; 90 | 91 | int ret = parse_string_table(shdr, &shdr->dynstr, fh, ".dynstr"); 92 | if(ret == NOT_FOUND){ 93 | 94 | fprintf(stderr, "section .dynstr not found\n"); 95 | return -1; 96 | }else if(ret == -1) return -1; 97 | 98 | shdr->strtab.strtab_content = get_strtab_contents(&shdr->dynsym, shdr->dynstr.strtab_buffer, shdr->dynstr.strtab_entries); 99 | if(!shdr->dynstr.strtab_content) 100 | return -1; 101 | 102 | return 0; 103 | } 104 | 105 | /* 106 | * for main string table 107 | */ 108 | int parse_strtab(struct shdr_table *shdr, FILE *fh){ 109 | 110 | assert(fh != NULL); 111 | assert(shdr != NULL); 112 | if(!shdr->symtab.strtab) 113 | shdr->symtab.strtab = &shdr->strtab; 114 | 115 | shdr->strtab.strtab_buffer = NULL; 116 | shdr->strtab.strtab_content = NULL; 117 | 118 | int ret = parse_string_table(shdr, &shdr->strtab, fh, ".strtab"); 119 | if(ret == NOT_FOUND){ 120 | 121 | fprintf(stderr, "section .strtab not found\n"); 122 | return -1; 123 | }else if(ret == -1) return -1; 124 | 125 | shdr->strtab.strtab_content = get_strtab_contents(&shdr->symtab, shdr->strtab.strtab_buffer, shdr->strtab.strtab_entries); 126 | if(!shdr->strtab.strtab_content) 127 | return -1; 128 | 129 | return 0; 130 | } 131 | -------------------------------------------------------------------------------- /symtab.c: -------------------------------------------------------------------------------- 1 | #include "parse.h" 2 | #include 3 | #include 4 | 5 | void free_symtab(struct SYMTAB *sym){ 6 | 7 | if(sym->symtab) 8 | free(sym->symtab); 9 | } 10 | 11 | int get_symbol_index(struct SYMTAB *symtab, const char *symname){ 12 | 13 | for(int i = 0; i < symtab->symtab_entries; i++){ 14 | 15 | if(strcmp(symtab->strtab->strtab_content[symtab->symtab[i].st_name], symname) == 0) 16 | return i; 17 | } 18 | return NOT_FOUND; 19 | } 20 | 21 | int get_symbol_info(struct SYMTAB *symtab, const char *symname){ 22 | 23 | int index = get_symbol_index(symtab, symname); 24 | if(index == NOT_FOUND){ 25 | 26 | fprintf(stderr, "symbol %s not found\n", symname); 27 | return -1; 28 | } 29 | return symtab->symtab[index].st_info; 30 | } 31 | 32 | uint64_t get_symbol_size(struct SYMTAB *symtab, const char *symname){ 33 | 34 | int index = get_symbol_index(symtab, symname); 35 | if(index == NOT_FOUND){ 36 | 37 | fprintf(stderr, "symbol %s not found\n", symname); 38 | return -1; 39 | } 40 | return symtab->symtab[index].st_size; 41 | } 42 | 43 | Elf64_Addr get_symbol_value(struct SYMTAB *symtab, const char *symname){ 44 | 45 | int index = get_symbol_index(symtab, symname); 46 | if(index == NOT_FOUND){ 47 | 48 | fprintf(stderr, "symbol %s not found\n", symname); 49 | return -1; 50 | } 51 | return symtab->symtab[index].st_value; 52 | } 53 | 54 | int get_symbol_visibility(struct SYMTAB *symtab, const char *symname){ 55 | 56 | int index = get_symbol_index(symtab, symname); 57 | if(index == NOT_FOUND){ 58 | 59 | fprintf(stderr, "symbol %s not found\n", symname); 60 | return -1; 61 | } 62 | return symtab->symtab[index].st_other; 63 | } 64 | 65 | uint16_t get_symbol_section(struct SYMTAB *symtab, const char *symname){ 66 | 67 | int index = get_symbol_index(symtab, symname); 68 | if(index == NOT_FOUND){ 69 | 70 | fprintf(stderr, "symbol %s not found\n", symname); 71 | return -1; 72 | } 73 | return symtab->symtab[index].st_shndx; 74 | } 75 | 76 | int parse_symbol_table(struct shdr_table *shdr, struct SYMTAB *symtab, FILE *fh, const char *section_name){ 77 | 78 | symtab->symtab_index = get_section_index(shdr, section_name); 79 | if(symtab->symtab_index == (uint8_t)NOT_FOUND) return NOT_FOUND; 80 | 81 | symtab->symtab_size = shdr->shdr_table[symtab->symtab_index].sh_size; 82 | symtab->symtab_entries = (symtab->symtab_size / shdr->shdr_table[symtab->symtab_index].sh_entsize); 83 | symtab->symtab_offset = shdr->shdr_table[symtab->symtab_index].sh_offset; 84 | 85 | //use malloc and memset 86 | symtab->symtab = malloc(symtab->symtab_size); 87 | if(!symtab->symtab){ 88 | 89 | perror("memory allocation failed"); 90 | return -1; 91 | } 92 | 93 | memset(symtab->symtab, 0, symtab->symtab_size); 94 | 95 | fseek(fh, symtab->symtab_offset, SEEK_SET); 96 | if(fread(symtab->symtab, 1, symtab->symtab_size, fh) < symtab->symtab_size){ 97 | 98 | perror("error reading file"); 99 | return -1; 100 | } 101 | 102 | return 0; 103 | } 104 | 105 | int parse_dynsym(struct shdr_table *shdr, FILE *fh){ 106 | 107 | shdr->dynsym.symtab = NULL; 108 | int ret = parse_symbol_table(shdr, &shdr->dynsym, fh, ".dynsym"); 109 | if(ret == NOT_FOUND){ 110 | 111 | fprintf(stderr, "Section .dynsym not found\n"); 112 | return -1; 113 | } 114 | else if(ret == -1) return -1; 115 | 116 | return 0; 117 | } 118 | 119 | int parse_symtab(struct shdr_table *shdr, FILE *fh){ 120 | 121 | shdr->symtab.symtab = NULL; 122 | int ret = parse_symbol_table(shdr, &shdr->symtab, fh, ".symtab"); 123 | if(ret == NOT_FOUND){ 124 | 125 | fprintf(stderr, "section .symtab not found\n"); 126 | return -1; 127 | } 128 | else if(ret == -1) return -1; 129 | 130 | return 0; 131 | } 132 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void){ 4 | 5 | printf("hello world"); 6 | return 0; 7 | } 8 | --------------------------------------------------------------------------------