1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include <sys/types.h> 20 #include <string> 21 #include <vector> 22 23 #include <android-base/logging.h> 24 #include <elf.h> 25 26 namespace android { 27 namespace elf64 { 28 29 // Section content representation 30 typedef struct { 31 std::vector<char> data; // Raw content of the data section. 32 uint64_t size; // Size of the data section. 33 std::string name; // The name of the section. 34 uint16_t index; // Index of the section. 35 } Elf64_Sc; 36 37 // Class to represent an ELF64 binary. 38 // 39 // An ELF binary is formed by 4 parts: 40 // 41 // - Executable header. 42 // - Program headers (present in executables or shared libraries). 43 // - Sections (.interp, .init, .plt, .text, .rodata, .data, .bss, .shstrtab, etc). 44 // - Section headers. 45 // 46 // ______________________ 47 // | | 48 // | Executable header | 49 // |____________________| 50 // | | 51 // | | 52 // | Program headers | 53 // | | 54 // |____________________| 55 // | | 56 // | | 57 // | Sections | 58 // | | 59 // |____________________| 60 // | | 61 // | | 62 // | Section headers | 63 // | | 64 // |____________________| 65 // 66 // 67 // The structs defined in linux for ELF parts can be found in: 68 // 69 // - /usr/include/elf.h. 70 // - https://elixir.bootlin.com/linux/v5.14.21/source/include/uapi/linux/elf.h#L222 71 class Elf64Binary { 72 public: 73 Elf64_Ehdr ehdr; 74 std::vector<Elf64_Phdr> phdrs; 75 std::vector<Elf64_Shdr> shdrs; 76 std::vector<Elf64_Sc> sections; 77 std::string path; 78 IsElf64()79 bool IsElf64() { return ehdr.e_ident[EI_CLASS] == ELFCLASS64; } 80 81 // Returns the index of the dynamic section header if found, 82 // otherwise it returns -1. 83 // 84 // Note: The dynamic section can be identified by: 85 // 86 // - the section header with name .dynamic 87 // - the section header type SHT_DYNAMIC GetDynamicSectionIndex()88 int GetDynamicSectionIndex() { 89 for (int i = 0; i < shdrs.size(); i++) { 90 if (shdrs.at(i).sh_type == SHT_DYNAMIC) { 91 return i; 92 } 93 } 94 95 return -1; 96 } 97 98 // Populate dynEntries with the entries in the .dynamic section. AppendDynamicEntries(std::vector<Elf64_Dyn> * dynEntries)99 void AppendDynamicEntries(std::vector<Elf64_Dyn>* dynEntries) { 100 int idx = GetDynamicSectionIndex(); 101 102 if (idx == -1) { 103 return; 104 } 105 106 Elf64_Dyn* dynPtr = (Elf64_Dyn*)sections.at(idx).data.data(); 107 int numEntries = sections.at(idx).data.size() / sizeof(*dynPtr); 108 109 for (int j = 0; j < numEntries; j++) { 110 Elf64_Dyn dynEntry; 111 memcpy(&dynEntry, dynPtr, sizeof(*dynPtr)); 112 dynPtr++; 113 114 dynEntries->push_back(dynEntry); 115 } 116 } 117 118 // Set the dynEntries in the .dynamic section. SetDynamicEntries(const std::vector<Elf64_Dyn> * dynEntries)119 void SetDynamicEntries(const std::vector<Elf64_Dyn>* dynEntries) { 120 int idx = GetDynamicSectionIndex(); 121 122 if (idx == -1) { 123 return; 124 } 125 126 Elf64_Dyn* dynPtr = (Elf64_Dyn*)sections.at(idx).data.data(); 127 int numEntries = sections.at(idx).data.size() / sizeof(*dynPtr); 128 129 for (int j = 0; j < dynEntries->size() && j < numEntries; j++) { 130 memcpy(dynPtr, &dynEntries->at(j), sizeof(*dynPtr)); 131 dynPtr++; 132 } 133 } 134 135 // Returns the string at the given offset in the dynamic string table. 136 // If .dynamic or .dynstr sections are not found, it returns an empty string. 137 // If the offset is invalid, it returns an empty string. GetStrFromDynStrTable(Elf64_Xword offset)138 std::string GetStrFromDynStrTable(Elf64_Xword offset) { 139 int idx = GetDynamicSectionIndex(); 140 141 if (idx == -1) { 142 return ""; 143 } 144 145 // Get the index of the string table .dynstr. 146 Elf64_Word dynStrIdx = shdrs.at(idx).sh_link; 147 if (offset >= sections.at(dynStrIdx).data.size()) { 148 return ""; 149 } 150 151 char* st = sections.at(dynStrIdx).data.data(); 152 153 CHECK_NE(nullptr, memchr(&st[offset], 0, sections.at(dynStrIdx).data.size() - offset)); 154 return &st[offset]; 155 } 156 }; 157 158 } // namespace elf64 159 } // namespace android 160