GT-3320 changed manner in which Android ELF APS2 relocation table

is represented within listing.  Corrected Android relocation handling
when sections are not present.
This commit is contained in:
ghidra1 2019-11-22 16:38:14 -05:00
parent 3f6ca95996
commit d68f3697e3
13 changed files with 924 additions and 302 deletions

View file

@ -0,0 +1,157 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.bin;
import java.io.*;
import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.mem.MemoryAccessException;
/**
* <code>MemBufferByteProvider</code> provide a {@link ByteProvider} backed by
* a {@link MemBuffer}.
*/
public class MemBufferByteProvider implements ByteProvider {
private MemBuffer buffer;
/**
* Constructor
* @param buffer memory buffer
*/
public MemBufferByteProvider(MemBuffer buffer) {
this.buffer = buffer;
}
@Override
public File getFile() {
return null;
}
@Override
public String getName() {
return null;
}
@Override
public String getAbsolutePath() {
return null;
}
/**
* Return maximum length since actual length is unknown
* @return maximum possible length
*/
@Override
public long length() {
return Integer.MAX_VALUE;
}
@Override
public boolean isValidIndex(long index) {
if (index < 0 || index > Integer.MAX_VALUE) {
return false;
}
try {
buffer.getByte((int) index);
return true;
}
catch (MemoryAccessException e) {
return false;
}
}
@Override
public void close() throws IOException {
// not applicable
}
@Override
public byte readByte(long index) throws IOException {
if (index < 0 || index > Integer.MAX_VALUE) {
throw new IOException("index out of range");
}
try {
return buffer.getByte((int) index);
}
catch (MemoryAccessException e) {
throw new IOException("index out of range");
}
}
@Override
public byte[] readBytes(long index, long length) throws IOException {
if (index < 0 || (index + length - 1) > Integer.MAX_VALUE) {
throw new IOException("index/length of range");
}
int len = (int) length;
byte[] bytes = new byte[len];
if (buffer.getBytes(bytes, (int) index) != len) {
throw new IOException("index/length of range");
}
return bytes;
}
@Override
public InputStream getInputStream(long index) throws IOException {
if (index < 0 || index > Integer.MAX_VALUE) {
throw new IOException("index out of range");
}
return new MemBufferProviderInputStream((int) index);
}
private class MemBufferProviderInputStream extends InputStream {
private int initialOffset;
private int offset;
MemBufferProviderInputStream(int offset) {
this.offset = offset;
this.initialOffset = offset;
}
@Override
public int read() throws IOException {
byte b = readByte(offset++);
return b & 0xff;
}
@Override
public int read(byte[] b, int off, int len) {
byte[] bytes = new byte[len];
int count = buffer.getBytes(bytes, offset);
System.arraycopy(bytes, 0, b, off, count);
offset += count;
return count;
}
@Override
public int available() {
return (int) length() - offset;
}
@Override
public synchronized void reset() throws IOException {
offset = initialOffset;
}
@Override
public void close() throws IOException {
// not applicable
}
}
}

View file

@ -0,0 +1,89 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.bin.format.elf;
import ghidra.app.plugin.exceptionhandlers.gcc.datatype.AbstractLeb128DataType;
import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsDefinition;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataTypeManager;
/**
* <code>AndroidElfRelocationData</code> provides a dynamic LEB128 data
* component for packed Android ELF Relocation Table.
* See {@link AndroidElfRelocationTableDataType}.
* <br>
* Secondary purpose is to retain the relocation offset associated with a
* component instance. This functionality relies on the 1:1 relationship
* between this dynamic datatype and the single component which references it.
*/
class AndroidElfRelocationData extends AbstractLeb128DataType {
private final long relocationOffset;
/**
* Creates a packed relocation offset data type based upon a signed LEB128
* value.
* @param dtm the data type manager to associate with this data type.
* @param relocationOffset relocation offset associated with component.
*/
AndroidElfRelocationData(DataTypeManager dtm, long relocationOffset) {
super("sleb128", true, dtm);
this.relocationOffset = relocationOffset;
}
@Override
public DataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}
return new AndroidElfRelocationData(dtm, relocationOffset);
}
@Override
public String getMnemonic(Settings settings) {
return name;
}
@Override
public String getDescription() {
return "Android Packed Relocation Data for ELF";
}
@Override
public String getDefaultLabelPrefix() {
return "sleb128";
}
@Override
protected SettingsDefinition[] getBuiltInSettingsDefinitions() {
return null;
}
@Override
public Class<?> getValueClass(Settings settings) {
return Address.class;
}
/**
* Get the relocation offset associated with this data item
* @return the relocation offset associated with this data item
*/
long getRelocationOffset() {
return relocationOffset;
}
}

View file

@ -0,0 +1,195 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.bin.format.elf;
import java.io.IOException;
import java.util.ArrayList;
import ghidra.app.util.bin.*;
import ghidra.app.util.bin.format.elf.AndroidElfRelocationTableDataType.LEB128Info;
import ghidra.docking.settings.Settings;
import ghidra.program.model.data.*;
import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.mem.WrappedMemBuffer;
import ghidra.program.model.scalar.Scalar;
/**
* <code>AndroidElfRelocationGroup</code> provides a dynamic substructure
* component for relocation groups within a packed Android ELF Relocation Table.
* See {@link AndroidElfRelocationTableDataType}.
*/
class AndroidElfRelocationGroup extends DynamicDataType {
// Packed Android APS2 relocation group flags
static final long RELOCATION_GROUPED_BY_INFO_FLAG = 1;
static final long RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG = 2;
static final long RELOCATION_GROUPED_BY_ADDEND_FLAG = 4;
static final long RELOCATION_GROUP_HAS_ADDEND_FLAG = 8;
private final long baseRelocOffset;
AndroidElfRelocationGroup(DataTypeManager dtm, long baseRelocOffset) {
super(CategoryPath.ROOT, "AndroidElfRelocationGroup", dtm);
this.baseRelocOffset = baseRelocOffset;
}
@Override
public DataType clone(DataTypeManager dtm) {
if (dtm == dataMgr) {
return this;
}
return new AndroidElfRelocationGroup(dtm, baseRelocOffset);
}
@Override
public String getDescription() {
return "Android Packed Relocation Entry Group for ELF";
}
@Override
public Object getValue(MemBuffer buf, Settings settings, int length) {
return null;
}
@Override
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
return "";
}
@Override
protected DataTypeComponent[] getAllComponents(MemBuffer buf) {
try {
ByteProvider provider = new MemBufferByteProvider(buf);
BinaryReader reader = new BinaryReader(provider, false);
ArrayList<DataTypeComponent> list = new ArrayList<>();
LEB128Info sleb128 = LEB128Info.parse(reader, true);
long groupSize = sleb128.value;
list.add(sleb128.getComponent(this, list.size(), "group_size", null));
sleb128 = LEB128Info.parse(reader, true);
long groupFlags = sleb128.value;
list.add(sleb128.getComponent(this, list.size(), "group_flags", null));
boolean groupedByInfo = (groupFlags & RELOCATION_GROUPED_BY_INFO_FLAG) != 0;
boolean groupedByDelta = (groupFlags & RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG) != 0;
boolean groupedByAddend = (groupFlags & RELOCATION_GROUPED_BY_ADDEND_FLAG) != 0;
boolean groupHasAddend = (groupFlags & RELOCATION_GROUP_HAS_ADDEND_FLAG) != 0;
long groupOffsetDelta = 0;
if (groupedByDelta) {
sleb128 = LEB128Info.parse(reader, true);
groupOffsetDelta = sleb128.value;
long minOffset = baseRelocOffset + groupOffsetDelta;
String rangeStr = "First relocation offset: 0x" + Long.toHexString(minOffset);
list.add(sleb128.getComponent(this, list.size(), "group_offsetDelta", rangeStr));
}
if (groupedByInfo) {
sleb128 = LEB128Info.parse(reader, true);
list.add(sleb128.getComponent(this, list.size(), "group_info", null));
}
if (groupedByAddend && groupHasAddend) {
sleb128 = LEB128Info.parse(reader, true);
list.add(sleb128.getComponent(this, list.size(), "group_addend", null));
}
long relocOffset = baseRelocOffset;
if (groupedByDelta && groupedByInfo && (!groupHasAddend || groupedByAddend)) {
// no individual relocation entry data
relocOffset += (groupSize - 1) * groupOffsetDelta;
}
else {
for (int i = 0; i < groupSize; i++) {
if (groupedByDelta) {
relocOffset += groupOffsetDelta;
}
else {
sleb128 = LEB128Info.parse(reader, true);
relocOffset += sleb128.value;
DataTypeComponent dtc = new ReadOnlyDataTypeComponent(
new AndroidElfRelocationOffset(dataMgr, relocOffset), this,
sleb128.byteLength, list.size(), sleb128.offset, "reloc_offset_" + i,
null);
list.add(dtc);
}
if (!groupedByInfo) {
sleb128 = LEB128Info.parse(reader, true);
list.add(sleb128.getComponent(this, list.size(), "reloc_info_" + i, null,
relocOffset));
}
if (groupHasAddend && !groupedByAddend) {
sleb128 = LEB128Info.parse(reader, true);
list.add(sleb128.getComponent(this, list.size(), "reloc_addend_" + i, null,
relocOffset));
}
}
}
DataTypeComponent[] comps = new DataTypeComponent[list.size()];
return list.toArray(comps);
}
catch (IOException e) {
return null;
}
}
long getLastRelocationOffset(WrappedMemBuffer buf) {
DataTypeComponent[] comps = getComps(buf);
if ((comps == null) || (comps.length < 3)) {
return -1;
}
Scalar s = (Scalar) comps[0].getDataType().getValue(buf, null, comps[0].getLength());
int groupSize = (int) s.getValue();
DataTypeComponent lastDtc = comps[comps.length - 1];
if ("group_offsetDelta".equals(comps[2].getFieldName())) {
WrappedMemBuffer cbuf = new WrappedMemBuffer(buf, comps[2].getOffset());
s = (Scalar) comps[2].getDataType().getValue(cbuf, null, comps[2].getLength());
long groupOffsetDelta = s.getValue();
if (lastDtc.getFieldName().startsWith("group_")) {
// must compute final offset for group
return baseRelocOffset + (groupSize * groupOffsetDelta);
}
}
if (lastDtc.getFieldName().startsWith("group_")) {
return -1; // unexpected
}
DataType dt = lastDtc.getDataType();
if (dt instanceof AndroidElfRelocationOffset) {
AndroidElfRelocationOffset d = (AndroidElfRelocationOffset) dt;
return d.getRelocationOffset(); // return stashed offset
}
else if (dt instanceof AndroidElfRelocationData) {
AndroidElfRelocationData d = (AndroidElfRelocationData) dt;
return d.getRelocationOffset(); // return stashed offset
}
return -1; // unexpected
}
}

View file

@ -0,0 +1,133 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.bin.format.elf;
import ghidra.app.plugin.exceptionhandlers.gcc.datatype.AbstractLeb128DataType;
import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsDefinition;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.scalar.Scalar;
/**
* <code>AndroidElfRelocationOffset</code> provides a dynamic LEB128 relocation
* offset adjustment component for packed Android ELF Relocation Table groups.
* See {@link AndroidElfRelocationGroup}. The offset adjustment provided
* by the LEB128 memory data is added to the associated baseOffset to obtain
* the corresponding relocation offset/address.
* <br>
* Secondary purpose is to retain the relocation offset associated with a
* component instance. This functionality relies on the 1:1 relationship
* between this dynamic datatype and the single component which references it.
*/
class AndroidElfRelocationOffset extends AbstractLeb128DataType {
private final long baseOffset;
private long relocationOffset;
/**
* Creates a packed relocation offset data type based upon a signed LEB128
* value adjusted by baseOffset.
* @param dtm the data type manager to associate with this data type.
* @param baseOffset base offset to which LEB128 offset data should be added
*/
AndroidElfRelocationOffset(DataTypeManager dtm, long baseOffset) {
super("sleb128_offset", true, dtm);
this.baseOffset = baseOffset;
}
@Override
public DataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}
return new AndroidElfRelocationOffset(dtm, baseOffset);
}
@Override
public String getMnemonic(Settings settings) {
return name;
}
@Override
public String getDescription() {
return "Android Packed Relocation Offset for ELF";
}
@Override
public String getDefaultLabelPrefix() {
return "sleb128";
}
@Override
protected SettingsDefinition[] getBuiltInSettingsDefinitions() {
return null;
}
@Override
public Class<?> getValueClass(Settings settings) {
return Address.class;
}
@Override
public Object getValue(MemBuffer buf, Settings settings, int length) {
Scalar s = (Scalar) super.getValue(buf, settings, length);
if (s == null) {
return null;
}
// assume pointer into physical space associated with buf
AddressSpace space = buf.getAddress().getAddressSpace().getPhysicalSpace();
return space.getAddress(s.getUnsignedValue() + baseOffset);
}
@Override
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
Scalar s = (Scalar) super.getValue(buf, settings, length);
if (s == null) {
return "??";
}
// TODO: not sure what representation to use
StringBuilder b = new StringBuilder();
if (baseOffset != 0) {
b.append("0x");
b.append(Long.toHexString(baseOffset));
b.append(" + ");
}
b.append("0x");
b.append(Long.toHexString(s.getUnsignedValue()));
return b.toString();
}
/**
* Get the stashed relocation offset associated with this data item
* @return the relocation offset associated with this data item
*/
long getRelocationOffset() {
return relocationOffset;
}
/**
* Set the computed relocation offset location associated with this
* component.
* @param relocationOffset stashed relocation offset
*/
void setRelocationOffset(long relocationOffset) {
this.relocationOffset = relocationOffset;
}
}

View file

@ -0,0 +1,169 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.bin.format.elf;
import java.io.IOException;
import java.util.ArrayList;
import ghidra.app.plugin.exceptionhandlers.gcc.datatype.SignedLeb128DataType;
import ghidra.app.util.bin.*;
import ghidra.app.util.bin.format.dwarf4.LEB128;
import ghidra.docking.settings.Settings;
import ghidra.program.model.data.*;
import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.mem.WrappedMemBuffer;
import ghidra.util.Msg;
/**
* <code>AndroidElfRelocationTableDataType</code> provides an implementation of
* an Android APS2 packed ELF relocation table.
*/
public class AndroidElfRelocationTableDataType extends DynamicDataType {
public AndroidElfRelocationTableDataType() {
this(null);
}
public AndroidElfRelocationTableDataType(DataTypeManager dtm) {
super(CategoryPath.ROOT, "AndroidElfRelocationTable", dtm);
}
@Override
public DataType clone(DataTypeManager dtm) {
if (dtm == dataMgr) {
return this;
}
return new AndroidElfRelocationTableDataType(dtm);
}
@Override
public String getDescription() {
return "Android Packed Relocation Table for ELF";
}
@Override
public Object getValue(MemBuffer buf, Settings settings, int length) {
return null;
}
@Override
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
return "";
}
static class LEB128Info {
final int offset;
final long value;
final int byteLength;
private LEB128Info(int offset, long value, int byteLength) {
this.offset = offset;
this.value = value;
this.byteLength = byteLength;
}
DataTypeComponent getComponent(DynamicDataType parent, int ordinal, String name,
String comment, long relocOffset) {
return new ReadOnlyDataTypeComponent(
new AndroidElfRelocationData(parent.getDataTypeManager(), relocOffset), parent,
byteLength, ordinal, offset, name, comment);
}
DataTypeComponent getComponent(DynamicDataType parent, int ordinal, String name,
String comment) {
return new ReadOnlyDataTypeComponent(
new SignedLeb128DataType(parent.getDataTypeManager()), parent, byteLength, ordinal,
offset, name, comment);
}
static LEB128Info parse(BinaryReader reader, boolean signed) throws IOException {
long nextPos = reader.getPointerIndex();
long value = LEB128.decode(reader, signed);
long pos = reader.getPointerIndex();
int size = (int) (pos - nextPos);
return new LEB128Info((int) nextPos, value, size);
}
}
@Override
protected DataTypeComponent[] getAllComponents(MemBuffer buf) {
try {
byte[] bytes = new byte[4];
if (buf.getBytes(bytes, 0) != 4 || !"APS2".equals(new String(bytes))) {
return null;
}
ByteProvider provider = new MemBufferByteProvider(buf);
BinaryReader reader = new BinaryReader(provider, false);
ArrayList<DataTypeComponent> list = new ArrayList<>();
// assume APS2 format
list.add(new ReadOnlyDataTypeComponent(StringDataType.dataType, this, 4, 0, 0, "format",
null));
reader.setPointerIndex(4);
LEB128Info sleb128 = LEB128Info.parse(reader, true);
long remainingRelocations = sleb128.value;
list.add(sleb128.getComponent(this, list.size(), "reloc_count", null));
sleb128 = LEB128Info.parse(reader, true);
long baseRelocOffset = sleb128.value;
list.add(sleb128.getComponent(this, list.size(), "reloc_baseOffset", null));
int groupIndex = 0;
long groupRelocOffset = baseRelocOffset;
while (remainingRelocations > 0) {
// NOTE: assumes 2-GByte MemBuffer limit
int offset = (int) reader.getPointerIndex();
long groupSize = LEB128.decode(reader, true);
if (groupSize > remainingRelocations) {
Msg.debug(this, "Group relocation count " + groupSize +
" exceeded total count " + remainingRelocations);
break;
}
AndroidElfRelocationGroup group =
new AndroidElfRelocationGroup(dataMgr, groupRelocOffset);
WrappedMemBuffer groupBuffer = new WrappedMemBuffer(buf, offset);
int groupLength = group.getLength(groupBuffer, -1);
DataTypeComponent dtc = new ReadOnlyDataTypeComponent(group, this, groupLength,
list.size(), offset, "reloc_group_" + groupIndex++, null);
list.add(dtc);
groupRelocOffset = group.getLastRelocationOffset(groupBuffer);
if (groupRelocOffset < 0) {
break;
}
offset += groupLength;
reader.setPointerIndex(offset);
remainingRelocations -= groupSize;
}
DataTypeComponent[] comps = new DataTypeComponent[list.size()];
return list.toArray(comps);
}
catch (IOException e) {
return null;
}
}
}

View file

@ -1,96 +0,0 @@
package ghidra.app.util.bin.format.elf;
import java.util.Formatter;
import ghidra.docking.settings.Settings;
import ghidra.program.model.data.BuiltIn;
import ghidra.program.model.data.ByteDataType;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.Dynamic;
import ghidra.program.model.mem.MemBuffer;
public class AndroidPackedRelocationTableDataType extends BuiltIn implements Dynamic {
private ElfRelocation[] relocs;
private int size;
public AndroidPackedRelocationTableDataType() {
this(new ElfRelocation[0], -1);
}
public AndroidPackedRelocationTableDataType(ElfRelocation[] relocs, int length) {
this(relocs, length, null);
}
public AndroidPackedRelocationTableDataType(ElfRelocation[] relocs, int length, DataTypeManager dtm) {
super(null, "AndroidPackedRelocationTable", dtm);
this.relocs = relocs;
this.size = length;
}
@Override
public DataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}
return new AndroidPackedRelocationTableDataType(relocs, size, dtm);
}
@Override
public String getDescription() {
return "Android Packed Relocation Table";
}
@Override
public String getDefaultLabelPrefix() {
return "AndroidPackedRelocationTable";
}
@Override
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
//TODO I think we need to reparse the data here, as the relocs data is not populated
if (relocs.length > 0) {
Formatter formatter = new Formatter();
for(ElfRelocation reloc : relocs) {
formatter.format("%d,%d,%d \n", reloc.getOffset(), reloc.getRelocationInfo(), reloc.getAddend());
}
return formatter.toString();
} else {
return "No relocs present";
}
}
@Override
public int getLength() {
return -1;
}
@Override
public Object getValue(MemBuffer buf, Settings settings, int length) {
return"Value";
}
@Override
public int getLength(MemBuffer buf, int maxLength) {
return size;
}
@Override
public boolean canSpecifyLength() {
return false;
}
@Override
public boolean isDynamicallySized() {
return true;
}
@Override
public DataType getReplacementBaseType() {
return ByteDataType.dataType;
}
}

View file

@ -90,26 +90,35 @@ public class ElfDynamicType {
"Size in bytes of DT_FINI_ARRAY", ElfDynamicValueType.VALUE);
public static ElfDynamicType DT_RUNPATH = addDefaultDynamicType(29, "DT_RUNPATH",
"Library search path (string ref)", ElfDynamicValueType.STRING);
// see DF_ constants for flag definitions
public static ElfDynamicType DT_FLAGS = addDefaultDynamicType(30, "DT_FLAGS",
"Flags for the object being loaded", ElfDynamicValueType.VALUE);
public static ElfDynamicType DT_ENCODING = addDefaultDynamicType(32, "DT_ENCODING",
"Start of encoded range", ElfDynamicValueType.VALUE);
// public static ElfDynamicType DT_PREINIT_ARRAY = addDefaultDynamicType(32, "DT_PREINIT_ARRAY", "Array with addresses of preinit fct", ElfDynamicValueType.VALUE);
public static final int DF_ORIGIN = 0x1; // $ORIGIN processing required
public static final int DF_SYMBOLIC = 0x2; // Symbolic symbol resolution required
public static final int DF_TEXTREL = 0x4; // Text relocations exist
public static final int DF_BIND_NOW = 0x8; // Non-lazy binding required
public static final int DF_STATIC_TLS = 0x10; // Object uses static TLS scheme
// glibc and BSD disagree for DT_ENCODING
// public static ElfDynamicType DT_ENCODING = addDefaultDynamicType(32, "DT_ENCODING",
// "Start of encoded range", ElfDynamicValueType.VALUE);
public static ElfDynamicType DT_PREINIT_ARRAY = addDefaultDynamicType(32, "DT_PREINIT_ARRAY",
"Array with addresses of preinit fct", ElfDynamicValueType.VALUE);
public static ElfDynamicType DT_PREINIT_ARRAYSZ = addDefaultDynamicType(33,
"DT_PREINIT_ARRAYSZ", "Size in bytes of DT_PREINIT_ARRAY", ElfDynamicValueType.VALUE);
// OS-specific range: 0x6000000d - 0x6ffff000
public static ElfDynamicType DT_ANDROID_REL =
addDefaultDynamicType(0x6000000F, "DT_ANDROID_REL", "Address of Rel relocs", ElfDynamicValueType.ADDRESS);
public static ElfDynamicType DT_ANDROID_RELSZ = addDefaultDynamicType(0x60000010, "DT_ANDROID_RELSZ",
"Total size of Rel relocs", ElfDynamicValueType.VALUE);
public static ElfDynamicType DT_ANDROID_RELA =
addDefaultDynamicType(0x60000011, "DT_ANDROID_RELA", "Address of Rela relocs", ElfDynamicValueType.ADDRESS);
public static ElfDynamicType DT_ANDROID_RELASZ = addDefaultDynamicType(0x60000012, "DT_ANDROID_RELASZ",
"Total size of Rela relocs", ElfDynamicValueType.VALUE);
public static ElfDynamicType DT_ANDROID_REL = addDefaultDynamicType(0x6000000F,
"DT_ANDROID_REL", "Address of Rel relocs", ElfDynamicValueType.ADDRESS);
public static ElfDynamicType DT_ANDROID_RELSZ = addDefaultDynamicType(0x60000010,
"DT_ANDROID_RELSZ", "Total size of Rel relocs", ElfDynamicValueType.VALUE);
public static ElfDynamicType DT_ANDROID_RELA = addDefaultDynamicType(0x60000011,
"DT_ANDROID_RELA", "Address of Rela relocs", ElfDynamicValueType.ADDRESS);
public static ElfDynamicType DT_ANDROID_RELASZ = addDefaultDynamicType(0x60000012,
"DT_ANDROID_RELASZ", "Total size of Rela relocs", ElfDynamicValueType.VALUE);
// Value Range (??): 0x6ffffd00 - 0x6ffffdff
@ -168,8 +177,23 @@ public class ElfDynamicType {
addDefaultDynamicType(0x6ffffff9, "DT_RELACOUNT", "", ElfDynamicValueType.VALUE);
public static ElfDynamicType DT_RELCOUNT =
addDefaultDynamicType(0x6ffffffa, "DT_RELCOUNT", "", ElfDynamicValueType.VALUE);
// see DF_1_ constants for flag definitions
public static ElfDynamicType DT_FLAGS_1 =
addDefaultDynamicType(0x6ffffffb, "DT_FLAGS_1", "State flags", ElfDynamicValueType.VALUE);
public static final int DF_1_NOW = 0x1;
public static final int DF_1_GLOBAL = 0x2;
public static final int DF_1_GROUP = 0x4;
public static final int DF_1_NODELETE = 0x8;
public static final int DF_1_LOADFLTR = 0x10;
public static final int DF_1_INITFIRST = 0x20;
public static final int DF_1_NOOPEN = 0x40;
public static final int DF_1_ORIGIN = 0x80;
public static final int DF_1_DIRECT = 0x100;
public static final int DF_1_INTERPOSE = 0x400;
public static final int DF_1_NODEFLIB = 0x800;
public static ElfDynamicType DT_VERDEF = addDefaultDynamicType(0x6ffffffc, "DT_VERDEF",
"Address of version definition table", ElfDynamicValueType.ADDRESS);
public static ElfDynamicType DT_VERDEFNUM = addDefaultDynamicType(0x6ffffffd, "DT_VERDEFNUM",

View file

@ -23,6 +23,7 @@ import generic.continues.GenericFactory;
import ghidra.app.util.bin.*;
import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader;
import ghidra.app.util.bin.format.Writeable;
import ghidra.app.util.bin.format.elf.ElfRelocationTable.TableFormat;
import ghidra.app.util.bin.format.elf.extend.ElfExtensionFactory;
import ghidra.app.util.bin.format.elf.extend.ElfLoadAdapter;
import ghidra.program.model.data.*;
@ -339,13 +340,13 @@ public class ElfHeader implements StructConverter, Writeable {
parseDynamicRelocTable(relocationTableList, ElfDynamicType.DT_RELA,
ElfDynamicType.DT_RELAENT, ElfDynamicType.DT_RELASZ, true);
// Android versions
parseDynamicRelocTable(relocationTableList, ElfDynamicType.DT_ANDROID_REL, ElfDynamicType.DT_RELENT,
parseDynamicRelocTable(relocationTableList, ElfDynamicType.DT_ANDROID_REL, null,
ElfDynamicType.DT_ANDROID_RELSZ, false);
parseDynamicRelocTable(relocationTableList, ElfDynamicType.DT_ANDROID_RELA,
ElfDynamicType.DT_RELAENT, ElfDynamicType.DT_ANDROID_RELASZ, true);
parseDynamicRelocTable(relocationTableList, ElfDynamicType.DT_ANDROID_RELA, null,
ElfDynamicType.DT_ANDROID_RELASZ, true);
parseJMPRelocTable(relocationTableList);
@ -364,7 +365,9 @@ public class ElfHeader implements StructConverter, Writeable {
try {
int sectionHeaderType = section.getType();
if (sectionHeaderType == ElfSectionHeaderConstants.SHT_REL ||
sectionHeaderType == ElfSectionHeaderConstants.SHT_RELA) {
sectionHeaderType == ElfSectionHeaderConstants.SHT_RELA ||
sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_REL ||
sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_RELA) {
for (ElfRelocationTable relocTable : relocationTableList) {
if (relocTable.getFileOffset() == section.getOffset()) {
@ -380,55 +383,24 @@ public class ElfHeader implements StructConverter, Writeable {
sectionToBeRelocated != null ? sectionToBeRelocated.getNameAsString()
: "PT_LOAD";
ElfSectionHeader symbolTableSection = getLinkedSection(link,
ElfSectionHeaderConstants.SHT_DYNSYM, ElfSectionHeaderConstants.SHT_SYMTAB);
ElfSymbolTable symbolTable = getSymbolTable(symbolTableSection);
boolean addendTypeReloc = (sectionHeaderType == ElfSectionHeaderConstants.SHT_RELA);
Msg.debug(this,
"Elf relocation table section " + section.getNameAsString() +
" linked to symbol table section " + symbolTableSection.getNameAsString() +
" affecting " + relocaBaseName);
if (section.getOffset() < 0) {
return;
ElfSectionHeader symbolTableSection;
if (link == 0) {
// dynamic symbol table assumed when link section value is 0
symbolTableSection = getSection(ElfSectionHeaderConstants.dot_dynsym);
}
else {
symbolTableSection = getLinkedSection(link,
ElfSectionHeaderConstants.SHT_DYNSYM, ElfSectionHeaderConstants.SHT_SYMTAB);
}
relocationTableList.add(ElfRelocationTable.createElfRelocationTable(reader, this,
section, section.getOffset(), section.getAddress(), section.getSize(),
section.getEntrySize(), addendTypeReloc, symbolTable, sectionToBeRelocated));
}
else if (sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_REL ||
sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_RELA) {
for (ElfRelocationTable relocTable : relocationTableList) {
if (relocTable.getFileOffset() == section.getOffset()) {
return; // skip reloc table previously parsed as dynamic entry
}
}
int link = section.getLink(); // section index of associated symbol table
int info = section.getInfo(); // section index of section to which relocations apply (relocation offset base)
ElfSectionHeader sectionToBeRelocated = info != 0 ? getLinkedSection(info) : null;
String relocaBaseName =
sectionToBeRelocated != null ? sectionToBeRelocated.getNameAsString()
: "PT_LOAD";
// For some Android binaries, the symbols table section is not referenced by the link value. Instead
// we can just reference the main dynamic symbol table.
ElfSectionHeader symbolTableSection = (link != 0)
? getLinkedSection(link, ElfSectionHeaderConstants.SHT_DYNSYM, ElfSectionHeaderConstants.SHT_SYMTAB)
: getSection(ElfSectionHeaderConstants.dot_dynsym);
ElfSymbolTable symbolTable = getSymbolTable(symbolTableSection);
if (symbolTable == null) {
throw new NotFoundException("Referenced symbol section not found.");
throw new NotFoundException("Referenced relocation symbol section not found.");
}
boolean addendTypeReloc = (sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_RELA);
boolean addendTypeReloc =
(sectionHeaderType == ElfSectionHeaderConstants.SHT_RELA ||
sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_RELA);
Msg.debug(this,
"Elf relocation table section " + section.getNameAsString() +
@ -439,9 +411,18 @@ public class ElfHeader implements StructConverter, Writeable {
return;
}
relocationTableList.add(ElfRelocationTable.createAndroidElfRelocationTable(reader, this,
section, section.getOffset(), section.getAddress(), section.getSize(),
section.getEntrySize(), addendTypeReloc, symbolTable, sectionToBeRelocated));
ElfRelocationTable.TableFormat format = TableFormat.DEFAULT;
if (sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_REL ||
sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_RELA) {
format = TableFormat.ANDROID;
}
ElfRelocationTable relocTable = ElfRelocationTable.createElfRelocationTable(reader,
this, section, section.getOffset(), section.getAddress(), section.getSize(),
section.getEntrySize(), addendTypeReloc, symbolTable, sectionToBeRelocated,
format);
relocationTableList.add(relocTable);
}
}
catch (NotFoundException e) {
@ -513,13 +494,20 @@ public class ElfHeader implements StructConverter, Writeable {
}
long relocTableOffset = relocTableLoadHeader.getOffset(relocTableAddr);
long tableEntrySize = dynamicTable.getDynamicValue(relocEntrySizeType);
long tableEntrySize =
relocEntrySizeType != null ? dynamicTable.getDynamicValue(relocEntrySizeType) : -1;
long tableSize = dynamicTable.getDynamicValue(relocTableSizeType);
relocationTableList.add(ElfRelocationTable.createElfRelocationTable(reader, this, null,
relocTableOffset, relocTableAddr, tableSize, tableEntrySize, addendTypeReloc,
dynamicSymbolTable, null));
ElfRelocationTable.TableFormat format = TableFormat.DEFAULT;
if (relocTableAddrType == ElfDynamicType.DT_ANDROID_REL ||
relocTableAddrType == ElfDynamicType.DT_ANDROID_RELA) {
format = TableFormat.ANDROID;
}
ElfRelocationTable relocTable = ElfRelocationTable.createElfRelocationTable(reader,
this, null, relocTableOffset, relocTableAddr, tableSize, tableEntrySize,
addendTypeReloc, dynamicSymbolTable, null, format);
relocationTableList.add(relocTable);
}
catch (NotFoundException e) {
// ignore - skip (required dynamic table value is missing)
@ -1581,6 +1569,9 @@ public class ElfHeader implements StructConverter, Writeable {
* @return the symbol table associated to the specified section header
*/
public ElfSymbolTable getSymbolTable(ElfSectionHeader symbolTableSection) {
if (symbolTableSection == null) {
return null;
}
for (int i = 0; i < symbolTables.length; i++) {
if (symbolTables[i].getFileOffset() == symbolTableSection.getOffset()) {
return symbolTables[i];

View file

@ -101,30 +101,7 @@ public class ElfRelocation implements ByteArrayConverter, StructConverter {
/**
* GenericFactory construction and initialization method for a ELF representative
* relocation entry (entry data will be 0)
* @param factory instantiation factory.
* @param elfHeader ELF header
* @param relocationIndex index of entry in relocation table
* @param withAddend true if if RELA entry with addend, else false
* @return ELF relocation object
*/
static ElfRelocation createElfRelocation(GenericFactory factory, ElfHeader elfHeader,
int relocationIndex, boolean withAddend) {
Class<? extends ElfRelocation> elfRelocationClass = getElfRelocationClass(elfHeader);
ElfRelocation elfRelocation = (ElfRelocation) factory.create(elfRelocationClass);
try {
elfRelocation.initElfRelocation(null, elfHeader, relocationIndex, withAddend);
}
catch (IOException e) {
// absence of reader should prevent any IOException from occurring
throw new AssertException("unexpected IO error", e);
}
return elfRelocation;
}
/**
* GenericFactory construction and initialization method for a ELF relocation entry
* relocation entry
* @param reader binary reader positioned at start of relocation entry.
* @param elfHeader ELF header
* @param relocationIndex index of entry in relocation table
@ -133,15 +110,20 @@ public class ElfRelocation implements ByteArrayConverter, StructConverter {
* @param r_info The info value for the entry
* @param r_addend The addend for the entry
* @return ELF relocation object
* @throws IOException
*/
static ElfRelocation createElfRelocation(FactoryBundledWithBinaryReader reader,
ElfHeader elfHeader, int relocationIndex, boolean withAddend, long r_offset, long r_info, long r_addend) throws IOException {
static ElfRelocation createElfRelocation(GenericFactory factory, ElfHeader elfHeader,
int relocationIndex, boolean withAddend, long r_offset, long r_info, long r_addend) {
Class<? extends ElfRelocation> elfRelocationClass = getElfRelocationClass(elfHeader);
ElfRelocation elfRelocation =
(ElfRelocation) reader.getFactory().create(elfRelocationClass);
elfRelocation.initElfRelocation(elfHeader, relocationIndex, withAddend, r_offset, r_info, r_addend);
ElfRelocation elfRelocation = (ElfRelocation) factory.create(elfRelocationClass);
try {
elfRelocation.initElfRelocation(elfHeader, relocationIndex, withAddend, r_offset,
r_info, r_addend);
}
catch (IOException e) {
// absence of reader should prevent any IOException from occurring
throw new AssertException("unexpected IO error", e);
}
return elfRelocation;
}
@ -193,12 +175,12 @@ public class ElfRelocation implements ByteArrayConverter, StructConverter {
* @param r_addend The addend for the entry
* @throws IOException
*/
protected void initElfRelocation(ElfHeader elfHeader, int relocationTableIndex,
protected void initElfRelocation(ElfHeader elfHeader, int relocationTableIndex,
boolean withAddend, long r_offset, long r_info, long r_addend) throws IOException {
this.is32bit = elfHeader.is32Bit();
this.relocationIndex = relocationTableIndex;
this.hasAddend = withAddend;
if (is32bit) {
this.r_offset = r_offset & Conv.INT_MASK;
this.r_info = r_info & Conv.INT_MASK;

View file

@ -33,6 +33,12 @@ import ghidra.util.Msg;
*/
public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter {
public enum TableFormat {
DEFAULT, ANDROID;
}
private TableFormat format;
private ElfSectionHeader sectionToBeRelocated;
private ElfSymbolTable symbolTable;
@ -61,28 +67,19 @@ public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter {
* @param addendTypeReloc true if addend type relocation table
* @param symbolTable associated symbol table
* @param sectionToBeRelocated or null for dynamic relocation table
* @param format table format
* @return Elf relocation table object
* @throws IOException
*/
static ElfRelocationTable createElfRelocationTable(FactoryBundledWithBinaryReader reader,
ElfHeader header, ElfSectionHeader relocTableSection, long fileOffset, long addrOffset,
long length, long entrySize, boolean addendTypeReloc, ElfSymbolTable symbolTable,
ElfSectionHeader sectionToBeRelocated) throws IOException {
ElfSectionHeader sectionToBeRelocated, TableFormat format) throws IOException {
ElfRelocationTable elfRelocationTable =
(ElfRelocationTable) reader.getFactory().create(ElfRelocationTable.class);
elfRelocationTable.initElfRelocationTable(reader, header, relocTableSection, fileOffset,
addrOffset, length, entrySize, addendTypeReloc, symbolTable, sectionToBeRelocated);
return elfRelocationTable;
}
static ElfRelocationTable createAndroidElfRelocationTable(FactoryBundledWithBinaryReader reader,
ElfHeader header, ElfSectionHeader relocTableSection, long fileOffset, long addrOffset,
long length, long entrySize, boolean addendTypeReloc, ElfSymbolTable symbolTable,
ElfSectionHeader sectionToBeRelocated) throws IOException {
ElfRelocationTable elfRelocationTable =
(ElfRelocationTable) reader.getFactory().create(ElfRelocationTable.class);
elfRelocationTable.initAndroidElfRelocationTable(reader, header, relocTableSection, fileOffset,
addrOffset, length, entrySize, addendTypeReloc, symbolTable, sectionToBeRelocated);
addrOffset, length, entrySize, addendTypeReloc, symbolTable, sectionToBeRelocated,
format);
return elfRelocationTable;
}
@ -95,7 +92,7 @@ public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter {
private void initElfRelocationTable(FactoryBundledWithBinaryReader reader, ElfHeader header,
ElfSectionHeader relocTableSection, long fileOffset, long addrOffset, long length,
long entrySize, boolean addendTypeReloc, ElfSymbolTable symbolTable,
ElfSectionHeader sectionToBeRelocated) throws IOException {
ElfSectionHeader sectionToBeRelocated, TableFormat format) throws IOException {
this.relocTableSection = relocTableSection;
this.fileOffset = fileOffset;
@ -105,6 +102,7 @@ public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter {
this.addendTypeReloc = addendTypeReloc;
this.elfHeader = header;
this.factory = reader.getFactory();
this.format = format;
this.sectionToBeRelocated = sectionToBeRelocated;
this.symbolTable = symbolTable;
@ -112,12 +110,12 @@ public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter {
long ptr = reader.getPointerIndex();
reader.setPointerIndex(fileOffset);
List<ElfRelocation> relocList = new ArrayList<ElfRelocation>();
int nRelocs = (int) (length / entrySize);
for (int relocationIndex = 0; relocationIndex < nRelocs; ++relocationIndex) {
relocList.add(ElfRelocation.createElfRelocation(reader, header, relocationIndex,
addendTypeReloc));
List<ElfRelocation> relocList;
if (format == TableFormat.ANDROID) {
relocList = parseAndroidRelocations(reader);
}
else {
relocList = parseStandardRelocations(reader);
}
reader.setPointerIndex(ptr);
@ -126,79 +124,65 @@ public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter {
relocList.toArray(relocs);
}
private void initAndroidElfRelocationTable(FactoryBundledWithBinaryReader reader, ElfHeader header,
ElfSectionHeader relocTableSection, long fileOffset, long addrOffset, long length,
long entrySize, boolean addendTypeReloc, ElfSymbolTable symbolTable,
ElfSectionHeader sectionToBeRelocated) throws IOException {
private List<ElfRelocation> parseStandardRelocations(FactoryBundledWithBinaryReader reader)
throws IOException {
this.relocTableSection = relocTableSection;
this.fileOffset = fileOffset;
this.addrOffset = addrOffset;
this.length = length;
this.entrySize = entrySize;
this.addendTypeReloc = addendTypeReloc;
this.elfHeader = header;
this.factory = reader.getFactory();
List<ElfRelocation> relocations = new ArrayList<>();
int nRelocs = (int) (length / entrySize);
for (int relocationIndex = 0; relocationIndex < nRelocs; ++relocationIndex) {
relocations.add(ElfRelocation.createElfRelocation(reader, elfHeader, relocationIndex,
addendTypeReloc));
}
return relocations;
}
this.sectionToBeRelocated = sectionToBeRelocated;
this.symbolTable = symbolTable;
long ptr = reader.getPointerIndex();
reader.setPointerIndex(fileOffset);
private List<ElfRelocation> parseAndroidRelocations(FactoryBundledWithBinaryReader reader)
throws IOException {
String identifier = reader.readNextAsciiString(4);
if (!"APS2".equals(identifier)) {
Msg.error(this, "Invalid indentifier value for Android packed relocation table: " + identifier);
return;
throw new IOException("Unsupported Android relocation table format");
}
List<ElfRelocation> relocList = parseAndroidRelocations(reader, header);
reader.setPointerIndex(ptr);
relocs = new ElfRelocation[relocList.size()];
relocList.toArray(relocs);
}
private List<ElfRelocation> parseAndroidRelocations(FactoryBundledWithBinaryReader reader, ElfHeader header) {
List<ElfRelocation> relocations = new ArrayList<>();
try {
long RELOCATION_GROUPED_BY_INFO_FLAG = 1;
long RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG = 2;
long RELOCATION_GROUPED_BY_ADDEND_FLAG = 4;
long RELOCATION_GROUP_HAS_ADDEND_FLAG = 8;
try {
int relocationIndex = 0;
long remainingRelocations = LEB128.decode(reader, true);
long offset = LEB128.decode(reader, true);
long addend = 0;
while (remainingRelocations > 0) {
long groupSize = LEB128.decode(reader, true);
if (groupSize > remainingRelocations) {
Msg.warn(this, "Group relocation count " + groupSize + " exceeded total count " + remainingRelocations);
Msg.warn(this, "Group relocation count " + groupSize +
" exceeded total count " + remainingRelocations);
break;
}
long groupFlags = LEB128.decode(reader, true);
boolean groupedByInfo = (groupFlags & RELOCATION_GROUPED_BY_INFO_FLAG) != 0;
boolean groupedByDelta = (groupFlags & RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG) != 0;
boolean groupedByAddend = (groupFlags & RELOCATION_GROUPED_BY_ADDEND_FLAG) != 0;
boolean groupHasAddend = (groupFlags & RELOCATION_GROUP_HAS_ADDEND_FLAG) != 0;
boolean groupedByInfo =
(groupFlags & AndroidElfRelocationGroup.RELOCATION_GROUPED_BY_INFO_FLAG) != 0;
boolean groupedByDelta = (groupFlags &
AndroidElfRelocationGroup.RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG) != 0;
boolean groupedByAddend =
(groupFlags & AndroidElfRelocationGroup.RELOCATION_GROUPED_BY_ADDEND_FLAG) != 0;
boolean groupHasAddend =
(groupFlags & AndroidElfRelocationGroup.RELOCATION_GROUP_HAS_ADDEND_FLAG) != 0;
long groupOffsetDelta = groupedByDelta ? LEB128.decode(reader, true) : 0;
long groupRInfo = groupedByInfo ? LEB128.decode(reader, true) : 0;
if (groupedByAddend && groupHasAddend) {
addend += LEB128.decode(reader, true);
}
for (int i = 0; i < groupSize; i++) {
offset += groupedByDelta ? groupOffsetDelta : LEB128.decode(reader, true);
long info = groupedByInfo ? groupRInfo : LEB128.decode(reader, true);
long rAddend = 0;
if (groupHasAddend) {
if (!groupedByAddend) {
@ -206,27 +190,22 @@ public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter {
}
rAddend = addend;
}
try {
relocations.add(ElfRelocation.createElfRelocation(reader, header, relocationIndex, addendTypeReloc,
offset, info, rAddend));
} catch (IOException e) {
Msg.error(this, "Error creating relocation entry");
}
relocationIndex++;
relocations.add(ElfRelocation.createElfRelocation(reader.getFactory(),
elfHeader, relocationIndex++, addendTypeReloc, offset, info, rAddend));
}
if (!groupHasAddend) {
addend = 0;
}
remainingRelocations -= groupSize;
}
} catch (IOException e) {
}
catch (IOException e) {
Msg.error(this, "Error reading relocations.", e);
}
return relocations;
}
@ -267,9 +246,6 @@ public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter {
return symbolTable;
}
/**
* @see ghidra.app.util.bin.ByteArrayConverter#toBytes(ghidra.util.DataConverter)
*/
@Override
public byte[] toBytes(DataConverter dc) {
byte[] bytes = new byte[relocs.length * relocs[0].sizeof()];
@ -311,18 +287,14 @@ public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter {
return (int) entrySize;
}
/**
* @see ghidra.app.util.bin.StructConverter#toDataType()
*/
@Override
public DataType toDataType() {
if (relocTableSection.getType() == ElfSectionHeaderConstants.SHT_ANDROID_REL ||
relocTableSection.getType() == ElfSectionHeaderConstants.SHT_ANDROID_RELA ) {
return new AndroidPackedRelocationTableDataType(relocs, (int) length);
if (format == TableFormat.ANDROID) {
return new AndroidElfRelocationTableDataType();
}
ElfRelocation relocationRepresentative =
ElfRelocation.createElfRelocation(factory, elfHeader, -1, addendTypeReloc);
ElfRelocation.createElfRelocation(factory, elfHeader, -1, addendTypeReloc, 0, 0, 0);
DataType relocEntryDataType = relocationRepresentative.toDataType();
return new ArrayDataType(relocEntryDataType, (int) (length / entrySize), (int) entrySize);
}

View file

@ -90,7 +90,8 @@ public class ElfLoader extends AbstractLibrarySupportLoader {
}
@Override
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options, Program program) {
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options,
Program program) {
if (options != null) {
String validationErrorStr = ElfLoaderOptionsFactory.validateOptions(loadSpec, options);
if (validationErrorStr != null) {
@ -143,7 +144,8 @@ public class ElfLoader extends AbstractLibrarySupportLoader {
@Override
public void load(ByteProvider provider, LoadSpec loadSpec, List<Option> options,
Program program, TaskMonitor monitor, MessageLog log) throws IOException {
Program program, TaskMonitor monitor, MessageLog log)
throws IOException, CancelledException {
try {
GenericFactory factory = MessageLogContinuesFactory.create(log);
@ -153,10 +155,6 @@ public class ElfLoader extends AbstractLibrarySupportLoader {
catch (ElfException e) {
throw new IOException(e.getMessage());
}
catch (CancelledException e) {
// TODO: Caller should properly handle CancelledException instead
throw new IOException(e.getMessage());
}
}
@Override

View file

@ -158,9 +158,9 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
elf.getLoadAdapter().processElf(this, monitor);
processRelocations(monitor);
processEntryPoints(monitor);
processImports(monitor);
processRelocations(monitor);
monitor.setMessage("Processing PLT/GOT ...");
elf.getLoadAdapter().processGotPlt(this, monitor);
@ -469,17 +469,19 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
}
// process dynamic entry points
createDynamicEntryPoints(ElfDynamicType.DT_INIT, null, monitor);
createDynamicEntryPoints(ElfDynamicType.DT_INIT, null, "_INIT_", monitor);
createDynamicEntryPoints(ElfDynamicType.DT_INIT_ARRAY, ElfDynamicType.DT_INIT_ARRAYSZ,
monitor);
createDynamicEntryPoints(ElfDynamicType.DT_FINI, null, monitor);
"_INIT_", monitor);
createDynamicEntryPoints(ElfDynamicType.DT_PREINIT_ARRAY, ElfDynamicType.DT_PREINIT_ARRAYSZ,
"_PREINIT_", monitor);
createDynamicEntryPoints(ElfDynamicType.DT_FINI, null, "_FINI_", monitor);
createDynamicEntryPoints(ElfDynamicType.DT_FINI_ARRAY, ElfDynamicType.DT_FINI_ARRAYSZ,
monitor);
"_FINI_", monitor);
}
private void createDynamicEntryPoints(ElfDynamicType dynamicEntryType,
ElfDynamicType entryArraySizeType, TaskMonitor monitor) {
ElfDynamicType entryArraySizeType, String baseName, TaskMonitor monitor) {
ElfDynamicTable dynamicTable = elf.getDynamicTable();
if (dynamicTable == null) {
@ -502,8 +504,6 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
long arraySize = dynamicTable.getDynamicValue(entryArraySizeType);
long elementCount = arraySize / dt.getLength();
String baseName = dynamicEntryType.name.startsWith("DT_INIT") ? "_INIT_" : "_FINI_";
for (int i = 0; i < elementCount; i++) {
Address addr = entryArrayAddr.add(i * dt.getLength());
Data data = createData(addr, dt);
@ -512,6 +512,9 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
}
Scalar value = (Scalar) data.getValue();
if (value != null) {
if (i != 0 && value.getValue() == 0) {
continue;
}
long funcAddrOffset = elf.adjustAddressForPrelink(value.getValue());
Address funcAddr = createEntryFunction(baseName + i, funcAddrOffset, monitor);
if (funcAddr != null) {

View file

@ -64,7 +64,6 @@ public abstract class DynamicDataType extends BuiltIn implements Dynamic {
* their data context. A null value is acceptable to indicate that a memory
* context is not available. DataTypes that need a context will return -1
* if the context is null.
* @return the number of components that make up this data prototype
* - if this is an Array, return the number of elements in the array.
* - if this datatype is a subcomponent of another datatype and it
@ -78,7 +77,7 @@ public abstract class DynamicDataType extends BuiltIn implements Dynamic {
return -1;
}
private DataTypeComponent[] getComps(MemBuffer buf) {
protected DataTypeComponent[] getComps(MemBuffer buf) {
Address addr = buf.getAddress();
DataTypeComponent[] comps = map.get(addr);
if (comps == null) {
@ -150,6 +149,12 @@ public abstract class DynamicDataType extends BuiltIn implements Dynamic {
}
/**
* Get all dynamic components associated with the specified MemBuffer
* @param buf memory buffer positioned at start of data type instance
* @return all components or null if memory data is not valid for this
* data type.
*/
protected abstract DataTypeComponent[] getAllComponents(MemBuffer buf);
@Override