GP-1963 added FixElfExternalOffsetDataRelocationScript

This commit is contained in:
ghidra1 2022-04-25 14:43:00 -04:00
parent 5ba11915ae
commit 2a34f206e9
3 changed files with 216 additions and 1 deletions

View file

@ -0,0 +1,206 @@
/* ###
* 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.
*/
//
// With ELF imports performed with Ghidra 10.0 and 10.1 certain data relocations
// which corresponded to symbol pointers with an additional offset produced an
// ERROR bookmark and was not applied. With Ghidra 10.2 such locations now
// get the relocation applied and should utilize a Pointer-Typedef with an
// pointer offset setting. Use of a normal pointer will produce an invalid
// reference which was the original reason we avoided applying the relocation.
//
// This script applies the correct relocaton by modifying the memory bytes
// at all bookmarked locations and applies a WARNING bookmark. If data has been
// applied script will attempt to correct using an offset pointer-typedef.
//
// Script may be constrained by a selection.
//
//@category ELF Relocations
import java.util.Iterator;
import ghidra.app.script.GhidraScript;
import ghidra.app.util.bin.format.elf.relocation.ElfRelocationHandler;
import ghidra.app.util.importer.MessageLog;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.*;
import ghidra.program.model.data.DataUtilities.ClearDataMode;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.DumbMemBufferImpl;
import ghidra.program.model.mem.Memory;
import ghidra.program.model.symbol.*;
import ghidra.util.GhidraDataConverter;
import ghidra.util.Msg;
public class FixElfExternalOffsetDataRelocationScript extends GhidraScript {
private static final String EXT_RELO_BOOKMARK_CATEGORY = "EXTERNAL Relocation";
private static final String EXT_RELO_BOOKMARK_TEXT_PREFIX =
"Unsupported EXTERNAL Data Elf Relocation: External Location =";
@Override
protected void run() throws Exception {
if (currentProgram == null) {
popup("No active program");
return;
}
MessageLog log = new MessageLog(); // throw-away log
Iterator<Bookmark> errorBookmarks =
currentProgram.getBookmarkManager().getBookmarksIterator(BookmarkType.ERROR);
while (errorBookmarks.hasNext()) {
Bookmark b = errorBookmarks.next();
if (EXT_RELO_BOOKMARK_CATEGORY.equals(b.getCategory()) &&
b.getComment().startsWith(EXT_RELO_BOOKMARK_TEXT_PREFIX)) {
if (currentSelection != null && !currentSelection.contains(b.getAddress())) {
continue;
}
try {
if (!updateExternalDataRelocation(b, log)) {
Msg.error(this,
"Failed to update EXTERNAL relocation at " + b.getAddress());
}
}
catch (Exception e) {
Msg.error(this, "Error occured while updating EXTERNAL relocation at " +
b.getAddress() + ": " + e.getMessage());
}
}
}
}
private boolean updateExternalDataRelocation(Bookmark relocErrorBookmark, MessageLog log) throws Exception {
Address address = relocErrorBookmark.getAddress();
String bookmarkComment = relocErrorBookmark.getComment();
int byteSize = address.getAddressSpace().getPointerSize();
int index = bookmarkComment.lastIndexOf("0x");
if (index < 0) {
return false;
}
char signChar = bookmarkComment.charAt(index - 1);
int offset;
try {
offset = Integer.parseInt(bookmarkComment.substring(index + 2), 16);
}
catch (NumberFormatException e) {
return false;
}
if (signChar == '-') {
offset = -offset;
}
else if (signChar != '+') {
return false;
}
Memory memory = currentProgram.getMemory();
DumbMemBufferImpl buf = new DumbMemBufferImpl(memory, address);
Address symbolAddr = PointerDataType.getAddressValue(buf, byteSize, address.getAddressSpace());
if (symbolAddr == null) {
return false; // invalid pointer data
}
String symbolName = bookmarkComment.substring(EXT_RELO_BOOKMARK_TEXT_PREFIX.length(), index - 1).trim();
if (currentProgram.getSymbolTable().getSymbol(symbolName, symbolAddr, null) == null) {
return false; // EXTERNAL block symbol not found at stored address
}
Listing listing = currentProgram.getListing();
Data data = listing.getDataContaining(address);
if (data == null) {
return false; // possible instruction applied
}
DataType dt = data.getDataType();
boolean isDefaultTypeApplied = Undefined.isUndefined(dt);
int componentOffset = (int) address.subtract(data.getAddress());
if (!isDefaultTypeApplied &&
!canFixupStructure(dt, componentOffset, address.getPointerSize())) {
return false; // unsupported datatype applied
}
long newValue = symbolAddr.getOffset() + offset;
GhidraDataConverter converter = GhidraDataConverter.getInstance(buf.isBigEndian());
byte[] bytes = new byte[byteSize];
converter.putValue(newValue, byteSize, bytes, 0);
memory.setBytes(address, bytes);
currentProgram.getBookmarkManager().removeBookmark(relocErrorBookmark);
ElfRelocationHandler.warnExternalOffsetRelocation(currentProgram, address, symbolAddr, symbolName, offset, log);
DataType offsetPtrDt =
currentProgram.getDataTypeManager()
.resolve(new PointerTypedef(null, null, -1, currentProgram.getDataTypeManager(),
offset), null);
if (isDefaultTypeApplied) {
// Replace undefined/default data with offset-pointer
DataUtilities.createData(currentProgram, address, offsetPtrDt, -1, false,
ClearDataMode.CLEAR_ALL_CONFLICT_DATA);
}
else {
Structure s = (Structure) dt;
DataTypeComponent dtc = s.getComponentAt(componentOffset);
if (!offsetPtrDt.isEquivalent(dtc.getDataType())) {
s.replace(dtc.getOrdinal(), offsetPtrDt, -1);
}
ReferenceManager refMgr = currentProgram.getReferenceManager();
Reference ref = refMgr.getPrimaryReferenceFrom(address, 0);
if (ref != null && symbolAddr.equals(ref.getToAddress())) {
// Replace reference with default offset reference
refMgr.delete(ref);
refMgr.addOffsetMemReference(address, symbolAddr, true, offset, RefType.DATA,
SourceType.DEFAULT, 0);
}
}
return true;
}
private boolean canFixupStructure(DataType dt, int componentOffset, int pointerLength) {
if (!(dt instanceof Structure)) {
return false;
}
Structure s = (Structure) dt;
DataTypeComponent dtc = s.getComponentAt(componentOffset);
if (dtc.getLength() != pointerLength) {
return false;
}
DataType cdt = dtc.getDataType();
if (cdt instanceof Pointer) {
return true;
}
// Check for case where structure may already have been modified
if (cdt instanceof TypeDef) {
TypeDef td = (TypeDef) cdt;
if (!(td.getDataType() instanceof Pointer)) {
return false;
}
if (!td.isAutoNamed()) {
return false;
}
return true;
}
return false;
}
}

View file

@ -56,4 +56,9 @@ class OffsetReferenceDB extends MemReferenceDB implements OffsetReference {
return offsetOrShift == ref.getOffset();
}
@Override
public String toString() {
return super.toString() + " Offset: 0x" + Long.toHexString(offsetOrShift);
}
}

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -56,4 +55,9 @@ class ShiftedReferenceDB extends MemReferenceDB implements ShiftedReference {
ShiftedReference ref = (ShiftedReference) obj;
return offsetOrShift == ref.getShift();
}
@Override
public String toString() {
return super.toString() + " Shift: 0x" + Long.toHexString(offsetOrShift);
}
}