diff --git a/Ghidra/Features/Base/ghidra_scripts/LocateMemoryAddressesForFileOffset.java b/Ghidra/Features/Base/ghidra_scripts/LocateMemoryAddressesForFileOffset.java new file mode 100644 index 0000000000..c31f620a3f --- /dev/null +++ b/Ghidra/Features/Base/ghidra_scripts/LocateMemoryAddressesForFileOffset.java @@ -0,0 +1,88 @@ +/* ### + * 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. + */ + +//This example script locates a memory address for a file offset. +//Prompt user for a file offset. +//Print the associated memory address to the Ghidra console +//Print the file offset as a Ghidra comment at the memory address in the Ghidra Listing +//If multiple addresses are located, then print the addresses to the console (do not set a +//Ghidra comment) +//@category Examples + +import java.util.Set; + +import ghidra.app.script.GhidraScript; +import ghidra.program.model.address.Address; +import ghidra.program.model.listing.CodeUnit; +import ghidra.program.model.mem.Memory; +import ghidra.util.exception.CancelledException; + +public class LocateMemoryAddressesForFileOffset extends GhidraScript { + + @Override + public void run() throws Exception { + long myFileOffset = getFileOffset(); + Memory mem = currentProgram.getMemory(); + Set
addressSet = mem.locateAddressesForFileOffset(myFileOffset); + if (addressSet.isEmpty()) { + println("No memory address found for: " + Long.toHexString(myFileOffset)); + } + else if (addressSet.size() == 1) { + Address address = addressSet.iterator().next(); + processAddress(address, mem.getBlock(address).getName(), myFileOffset); + + } + //address set size is > 1, file offset matches to multiple addresses. + //Let the user decide which address they want. + else { + println("Possible memory block:address are:"); + for (Address addr : addressSet) { + println(mem.getBlock(addr).getName() + ":" + addr.toString()); + } + } + } + + public long getFileOffset() + throws CancelledException, NumberFormatException, IllegalArgumentException { + String userFileOffset = + askString("File offset", "Please provide a hexadecimal file offset"); + long myFileOffset = 0; + myFileOffset = Long.parseLong(userFileOffset, 16); + if (myFileOffset < 0) { + throw new IllegalArgumentException( + "Offset cannot be a negative value." + userFileOffset); + } + return myFileOffset; + } + + public void processAddress(Address addr, String memBlockName, long fileOffset) { + println("File offset " + Long.toHexString(fileOffset) + + " is associated with memory block:address " + memBlockName + ":" + addr.toString()); + CodeUnit myCodeUnit = currentProgram.getListing().getCodeUnitContaining(addr); + String comment = myCodeUnit.getComment(0); + if (comment == null) { + myCodeUnit.setComment(0, + this.getScriptName() + ": File offset: " + Long.toHexString(fileOffset) + + ", Memory block:address " + memBlockName + ":" + addr.toString()); + } + else { + myCodeUnit.setComment(0, + comment + ", " + this.getScriptName() + ": File offset: " + + Long.toHexString(fileOffset) + ", Memory block:address " + memBlockName + ":" + + addr.toString()); + } + } +} diff --git a/Ghidra/Features/Base/ghidra_scripts/LocateMemoryAddressesForFileOffset.py b/Ghidra/Features/Base/ghidra_scripts/LocateMemoryAddressesForFileOffset.py new file mode 100644 index 0000000000..716cd8041e --- /dev/null +++ b/Ghidra/Features/Base/ghidra_scripts/LocateMemoryAddressesForFileOffset.py @@ -0,0 +1,64 @@ +## ### +# 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. +## +# This example script locates a memory address for a file offset. +#Prompt user for a file offset. +#Print the associated memory address to the Ghidra console +#Print the file offset as a Ghidra comment at the memory address in the Ghidra Listing +#If multiple addresses are located, then print the addresses to the console (do not set a Ghidra comment) +# @category Examples + +import sys +from ghidra.program.model.address import Address +from ghidra.program.model.listing import CodeUnit +from ghidra.program.model.listing import Listing +from ghidra.program.model.mem import Memory +from java.util import Set + +def getFileOffset(): + userFileOffset = askString('File offset', 'Please provide a hexadecimal file offset') + try: + int(userFileOffset,16) + except ValueError: + raise ValueError('Please provide a hexadecimal file offset.') + myFileOffset = long(userFileOffset,16) #specify base 16 since we expect address in hex + if myFileOffset < 0: + raise ValueError('Offset cannot be a negative value.') + return myFileOffset + +def processAddress(addr, memBlockName, fileOffset): + println('File offset ' + hex(fileOffset) + ' is associated with memory block:address ' + memBlockName + ':' + addr.toString()); + myCodeUnit = currentProgram.getListing().getCodeUnitContaining(addr) + comment = myCodeUnit.getComment(0) + if not comment: + myCodeUnit.setComment(0, getScriptName() + ': File offset: ' + hex(fileOffset) + + ', Memory block:address ' + memBlockName + ':'+ addr.toString()) + else: + myCodeUnit.setComment(0, comment + ' ' + getScriptName() + ': File offset: ' + hex(fileOffset) + + ', Memory block:address ' + memBlockName + ':' + addr.toString()) + +myFileOffset = getFileOffset() +mem = currentProgram.getMemory() +addressSet = mem.locateAddressesForFileOffset(myFileOffset) +if addressSet.isEmpty(): + println('No memory address found for: ' + hex(myFileOffset)) +elif addressSet.size() == 1: + address = addressSet.iterator().next() + processAddress(address, mem.getBlock(address).getName(), myFileOffset) +#file offset matches to multiple addresses. Let the user decide which address they want. +else: + println('Possible memory block:address are:') + for addr in addressSet: + println(mem.getBlock(addr).getName() + ":" + addr.toString()) diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/Memory.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/Memory.java index 7e22cc4b9f..e3ed84ab4f 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/Memory.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/Memory.java @@ -17,7 +17,7 @@ package ghidra.program.model.mem; import java.io.IOException; import java.io.InputStream; -import java.util.List; +import java.util.*; import ghidra.framework.store.LockException; import ghidra.program.database.mem.*; @@ -247,9 +247,8 @@ public interface Memory extends AddressSetView { * @throws IllegalArgumentException if invalid block name */ public MemoryBlock createByteMappedBlock(String name, Address start, Address mappedAddress, - long length, ByteMappingScheme byteMappingScheme, boolean overlay) - throws LockException, MemoryConflictException, AddressOverflowException, - IllegalArgumentException; + long length, ByteMappingScheme byteMappingScheme, boolean overlay) throws LockException, + MemoryConflictException, AddressOverflowException, IllegalArgumentException; /** * Create a memory block that uses the bytes located at a different location with a 1:1 @@ -271,8 +270,7 @@ public interface Memory extends AddressSetView { */ default public MemoryBlock createByteMappedBlock(String name, Address start, Address mappedAddress, long length, boolean overlay) throws LockException, - MemoryConflictException, - AddressOverflowException, IllegalArgumentException { + MemoryConflictException, AddressOverflowException, IllegalArgumentException { return createByteMappedBlock(name, start, mappedAddress, length, null, overlay); } @@ -830,4 +828,23 @@ public interface Memory extends AddressSetView { return true; } + /** + * Gets a {@link Set} of {@link Address addresses} that correspond to the given file offset. + * + * @param fileOffset the file offset that will be used to locate the corresponding memory + * addresses + * @return a {@link Set} of {@link Address}es that are associated with the provided file offset + */ + public default Set locateAddressesForFileOffset(long fileOffset) { + Set set = new HashSet<>(); + for (MemoryBlock memBlock : getBlocks()) { + for (MemoryBlockSourceInfo info : memBlock.getSourceInfos()) { + Address addr = info.locateAddressForFileOffset(fileOffset); + if (addr != null) { + set.add(addr); + } + } + } + return set; + } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemoryBlockSourceInfo.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemoryBlockSourceInfo.java index 8cfe596307..8917dc71bb 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemoryBlockSourceInfo.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemoryBlockSourceInfo.java @@ -59,16 +59,17 @@ public interface MemoryBlockSourceInfo { Optional