/// <remarks> /// According to the ELF PPC32 documentation, the .rela.plt and .plt tables /// should contain the same number of entries, even if the individual entry /// sizes are distinct. The entries in .real.plt refer to symbols while the /// entries in .plt are (writeable) pointers. Any caller that jumps to one /// of pointers in the .plt table is a "trampoline", and should be replaced /// in the decompiled code with just a call to the symbol obtained from the /// .real.plt section. /// </remarks> public override void Relocate(Program program) { base.Relocate(program); var rela_plt = loader.GetSectionInfoByName(".rela.plt"); if (rela_plt == null) { return; } var plt = loader.GetSectionInfoByName(".plt"); var relaRdr = loader.CreateReader(rela_plt.FileOffset); var pltRdr = loader.CreateReader(plt.FileOffset); for (int i = 0; i < rela_plt.EntryCount(); ++i) { // Read the .rela.plt entry uint offset; if (!relaRdr.TryReadUInt32(out offset)) { return; } uint info; if (!relaRdr.TryReadUInt32(out info)) { return; } int addend; if (!relaRdr.TryReadInt32(out addend)) { return; } // Read the .plt entry. We don't care about its contents, // only its address. Anyone accessing that address is // trying to access the symbol. uint thunkAddress; if (!pltRdr.TryReadUInt32(out thunkAddress)) { break; } uint sym = info >> 8; string symStr = loader.GetSymbolName(rela_plt.LinkedSection, sym); var addr = plt.Address + (uint)i * 4; program.ImportReferences.Add( addr, new NamedImportReference(addr, null, symStr)); } }
public override void Render(ImageSegment segment, Program program, Formatter formatter) { var entries = shdr.Size / shdr.EntrySize; var symtab = shdr.LinkedSection; var rdr = loader.CreateReader(shdr.FileOffset); for (ulong i = 0; i < entries; ++i) { uint offset; if (!rdr.TryReadUInt32(out offset)) { return; } uint info; if (!rdr.TryReadUInt32(out info)) { return; } int addend; if (!rdr.TryReadInt32(out addend)) { return; } uint sym = info >> 8; string symStr = loader.GetSymbolName(symtab, sym); formatter.Write("{0:X8} {1,3} {2:X8} {3:X8} {4} ({5})", offset, info & 0xFF, sym, addend, symStr, sym); formatter.WriteLine(); } }
public override void Render(ImageSegment segment, Program program, Formatter formatter) { var entries = shdr.EntryCount(); var symtab = shdr.LinkedSection; var rdr = loader.CreateReader(shdr.FileOffset); for (int i = 0; i < entries; ++i) { uint iName; if (!rdr.TryReadUInt32(out iName)) return; uint value; if (!rdr.TryReadUInt32(out value)) return; uint size; if (!rdr.TryReadUInt32(out size)) return; byte info; if (!rdr.TryReadByte(out info)) return; byte other; if (!rdr.TryReadByte(out other)) return; ushort shIndex; if (!rdr.TryReadUInt16(out shIndex)) return; string symStr = loader.GetStrPtr(symtab, iName); string segName = loader.GetSectionName(shIndex); formatter.Write("{0:X4} {1,-40} {2:X8} {3:X8} {4:X2} {5}", i, symStr, value, size, info & 0xFF, segName); formatter.WriteLine(); } }
public override void Render(ImageSegment segment, Program program, Formatter formatter) { var entries = shdr.sh_size / shdr.sh_entsize; var symtab = (int)shdr.sh_link; var rdr = loader.CreateReader(shdr.sh_offset); for (int i = 0; i < entries; ++i) { uint offset; if (!rdr.TryReadUInt32(out offset)) { return; } uint info; if (!rdr.TryReadUInt32(out info)) { return; } uint sym = info >> 8; string symStr = loader.GetSymbolName(symtab, sym); formatter.Write("{0:X8} {1,3} {2:X8} {3}", offset, info & 0xFF, sym, symStr); formatter.WriteLine(); } }
public override void Relocate(Program program) { DumpRela32(loader); foreach (var relSection in loader.Sections.Where(s => s.Type == SectionHeaderType.SHT_RELA)) { var symbols = loader.Symbols[relSection.LinkedSection]; var referringSection = relSection.RelocatedSection; var rdr = loader.CreateReader(relSection.FileOffset); for (uint i = 0; i < relSection.EntryCount(); ++i) { var rela = Elf32_Rela.Read(rdr); var sym = symbols[(int)(rela.r_info >> 8)]; RelocateEntry(program, sym, referringSection, rela); } } }
public override void Render(ImageSegment segment, Program program, Formatter formatter) { var entries = shdr.sh_size / shdr.sh_entsize; var symtab = (int)shdr.sh_link; var rdr = loader.CreateReader(shdr.sh_offset); for (int i = 0; i < entries; ++i) { uint iName; if (!rdr.TryReadUInt32(out iName)) { return; } uint value; if (!rdr.TryReadUInt32(out value)) { return; } uint size; if (!rdr.TryReadUInt32(out size)) { return; } byte info; if (!rdr.TryReadByte(out info)) { return; } byte other; if (!rdr.TryReadByte(out other)) { return; } ushort shIndex; if (!rdr.TryReadUInt16(out shIndex)) { return; } string symStr = loader.GetStrPtr(symtab, iName); string segName = loader.GetSectionName(shIndex); formatter.Write("{0,-40} {1:X8} {2:X8} {3:X2} {4}", symStr, value, size, info & 0xFF, segName); formatter.WriteLine(); } }
protected void DumpRela32(ElfLoader32 loader) { foreach (var section in loader.Sections.Where(s => s.Type == SectionHeaderType.SHT_RELA)) { Debug.Print("RELA: offset {0:X} link section {1}", section.FileOffset, section.LinkedSection.Name); var symbols = loader.Symbols[section.LinkedSection]; var rdr = loader.CreateReader(section.FileOffset); for (uint i = 0; i < section.EntryCount(); ++i) { var rela = Elf32_Rela.Read(rdr); Debug.Print(" off:{0:X8} type:{1,-16} add:{3,-20} {4,3} {2}", rela.r_offset, (SparcRt)(rela.r_info & 0xFF), symbols[(int)(rela.r_info >> 8)].Name, rela.r_addend, (int)(rela.r_info >> 8)); } } }
protected void DumpRela32(ElfLoader32 loader) { foreach (var section in loader.Sections.Where(s => s.Type == SectionHeaderType.SHT_RELA)) { Debug.Print("RELA: offset {0:X} symbol section {1}, relocating in section {2}", section.FileOffset, section.LinkedSection.Name, section.RelocatedSection.Name); var symbols = loader.Symbols[section.LinkedSection]; var rdr = loader.CreateReader(section.FileOffset); for (uint i = 0; i < section.EntryCount(); ++i) { var rela = Elf32_Rela.Read(rdr); Debug.Print(" off:{0:X8} type:{1,-16} add:{3,-20} {4,3} {2}", rela.r_offset, RelocationTypeToString(rela.r_info & 0xFF), symbols[(int)(rela.r_info >> 8)].Name, rela.r_addend, (int)(rela.r_info >> 8)); } } }
public void RelocateOld(Program program) { uint nextFakeLibAddr = ~1u; // See R_386_PC32 below; -1 sometimes used for main for (int i = 1; i < loader.Sections.Count; ++i) { var ps = loader.Sections[i]; if (ps.Type == SectionHeaderType.SHT_REL) { // A section such as .rel.dyn or .rel.plt (without an addend field). // Each entry has 2 words: r_offset and r_info. The r_offset is just the offset from the beginning // of the section (section given by the section header's sh_info) to the word to be modified. // r_info has the type in the bottom byte, and a symbol table index in the top 3 bytes. // A symbol table offset of 0 (STN_UNDEF) means use value 0. The symbol table involved comes from // the section header's sh_link field. var pReloc = loader.CreateReader(ps.FileOffset); ulong size = ps.Size; // NOTE: the r_offset is different for .o files (ET_REL in the e_type header field) than for exe's // and shared objects! uint destNatOrigin = 0; uint destHostOrigin = 0; if (loader.Header.e_type == ElfImageLoader.ET_REL) { var destSection = loader.Sections[i].RelocatedSection; destNatOrigin = destSection.Address.ToUInt32(); destHostOrigin = (uint)destSection.FileOffset; } var symSection = loader.Sections[i].LinkedSection; // associated symbol table var strSection = symSection.LinkedSection; // Section index for the string section assoc with this var pStrSection = strSection.FileOffset; var symOrigin = symSection.FileOffset; var relocR = loader.CreateReader(0); var relocW = loader.CreateWriter(0); for (uint u = 0; u < size; u += 2 * sizeof(uint)) { uint r_offset = pReloc.ReadUInt32(); uint info = pReloc.ReadUInt32(); byte relType = (byte)info; uint symTabIndex = info >> 8; uint pRelWord; // Pointer to the word to be relocated if (loader.Header.e_type == ElfImageLoader.ET_REL) { pRelWord = destHostOrigin + r_offset; } else { if (r_offset == 0) { continue; } var destSec = loader.GetSectionInfoByAddr(r_offset); pRelWord = ~0u; // destSec.uHostAddr - destSec.uNativeAddr + r_offset; destNatOrigin = 0; } uint A, S = 0, P; int nsec; var sym = Elf32_Sym.Load(loader.CreateReader(symOrigin + symTabIndex * Elf32_Sym.Size)); switch (relType) { case 0: // R_386_NONE: just ignore (common) break; case 1: // R_386_32: S + A // Read the symTabIndex'th symbol. S = sym.st_value; if (loader.Header.e_type == ElfImageLoader.ET_REL) { nsec = sym.st_shndx; if (nsec >= 0 && nsec < loader.Sections.Count) { S += loader.Sections[nsec].Address.ToUInt32(); } } A = relocR.ReadUInt32(pRelWord); relocW.WriteUInt32(pRelWord, S + A); break; case 2: // R_386_PC32: S + A - P if (ElfLoader32.ELF32_ST_TYPE(sym.st_info) == ElfLoader.STT_SECTION) { nsec = sym.st_shndx; if (nsec >= 0 && nsec < loader.Sections.Count) { S = loader.Sections[nsec].Address.ToUInt32(); } } else { S = sym.st_value; if (S == 0) { // This means that the symbol doesn't exist in this module, and is not accessed // through the PLT, i.e. it will be statically linked, e.g. strcmp. We have the // name of the symbol right here in the symbol table entry, but the only way // to communicate with the loader is through the target address of the call. // So we use some very improbable addresses (e.g. -1, -2, etc) and give them entries // in the symbol table uint nameOffset = sym.st_name; string pName = loader.ReadAsciiString(pStrSection + nameOffset); // this is too slow, I'm just going to assume it is 0 //S = GetAddressByName(pName); //if (S == (e_type == E_REL ? 0x8000000 : 0)) { S = nextFakeLibAddr--; // Allocate a new fake address loader.AddSymbol(S, pName); //} } else if (loader.Header.e_type == ElfImageLoader.ET_REL) { nsec = sym.st_shndx; if (nsec >= 0 && nsec < loader.Sections.Count) { S += loader.Sections[nsec].Address.ToUInt32(); } } } A = relocR.ReadUInt32(pRelWord); P = destNatOrigin + r_offset; relocW.WriteUInt32(pRelWord, S + A - P); break; case 6: // R_386_GLOB_DAT // This relocation type is used to set a global offset table entry to the address of the // specified symbol. The special relocation type allows one to determine the // correspondence between symbols and global offset table entries. S = sym.st_value; relocW.WriteUInt32(pRelWord, S); break; case 7: case 8: // R_386_RELATIVE break; // No need to do anything with these, if a shared object default: throw new NotSupportedException("Relocation type " + (int)relType + " not handled yet"); } } } } }