mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 02:09:44 +02:00
GP-1963 added FixElfExternalOffsetDataRelocationScript
This commit is contained in:
parent
5ba11915ae
commit
2a34f206e9
3 changed files with 216 additions and 1 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue