From 64126312364cf8ec2f34672553527e1a705d6078 Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Fri, 20 Oct 2023 16:00:43 -0400 Subject: [PATCH] GP-3949 Added FixOldSTVariableStorageScript --- .../FixOldSTVariableStorageScript.java | 174 ++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 Ghidra/Features/Base/ghidra_scripts/FixOldSTVariableStorageScript.java diff --git a/Ghidra/Features/Base/ghidra_scripts/FixOldSTVariableStorageScript.java b/Ghidra/Features/Base/ghidra_scripts/FixOldSTVariableStorageScript.java new file mode 100644 index 0000000000..f6256dc510 --- /dev/null +++ b/Ghidra/Features/Base/ghidra_scripts/FixOldSTVariableStorageScript.java @@ -0,0 +1,174 @@ +/* ### + * 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 fixup script is intended to be run against x86 programs created prior +// to Ghidra 10.0.3 to update old ST0..ST7 floating point register +// locations assigned to function parameters and local variables. The +// address assignment for these registers was changed with Ghidra 10.0.3 +// x86 slaspec change (GP-1228). +// +// This script can be run multiple times without harm +//@category Functions +import java.util.Set; + +import ghidra.app.script.GhidraScript; +import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressSpace; +import ghidra.program.model.lang.Register; +import ghidra.program.model.listing.*; +import ghidra.program.model.pcode.Varnode; +import ghidra.program.model.symbol.*; +import ghidra.util.exception.InvalidInputException; + +public class FixOldSTVariableStorageScript extends GhidraScript { + + private static final int ST_SIZE = 10; + + // See Ghidra/Processors/x86/data/languages/ia.sinc + private static final long OLD_ST_BASE_OFFSET = 0x1000; + private static final long OLD_ST_OFFSET_SPACING = ST_SIZE; // each offset 10-bytes from the previous + + // Must query new ST0 address since it may change again + private static final long NEW_ST_OFFSET_SPACING = 16; // each offset 16-bytes from the previous + + @Override + protected void run() throws Exception { + + if (currentProgram == null || !"x86".equals(currentProgram.getLanguage().getProcessor().toString())) { + popup("Script supports x86 programs only"); + return; + } + + // Spot check new ST0 placement + Register st0 = currentProgram.getRegister("ST0"); + Register st1 = currentProgram.getRegister("ST1"); + if (st0 == null || st1 == null) { + popup("Unsupported x86 language"); + return; + } + + long st0Offset = st0.getAddress().getOffset(); + long st1Offset = st1.getAddress().getOffset(); + if (st0Offset == OLD_ST_BASE_OFFSET || (st1Offset - st0Offset) != NEW_ST_OFFSET_SPACING) { + popup("Unsupported x86 ST register placement"); + return; + } + + STRegisterFixup stRegisterFixup = new STRegisterFixup(st0Offset); + int count = 0; + + SymbolTable symbolTable = currentProgram.getSymbolTable(); + for (Symbol s : symbolTable.getDefinedSymbols()) { + SymbolType type = s.getSymbolType(); + if (type == SymbolType.PARAMETER || type == SymbolType.LOCAL_VAR) { + if (stRegisterFixup.fixupVariableStorage((Variable) s.getObject())) { + ++count; + } + } + else if (type == SymbolType.FUNCTION) { + Function function = (Function) s.getObject(); + if (stRegisterFixup.fixupVariableStorage(function.getReturn())) { + ++count; + } + } + } + + if (count != 0) { + popup("Fixed " + count + " ST register uses"); + } + else { + popup("No old ST register uses were found"); + } + } + + private class STRegisterFixup { + + private Set oldSTVarnodes; // ST0..ST7 + private long newStBaseOffset; + + STRegisterFixup(long newStBaseOffset) { + this.newStBaseOffset = newStBaseOffset; + + AddressSpace registerSpace = currentProgram.getAddressFactory().getRegisterSpace(); + + long oldSTBaseOffset = OLD_ST_BASE_OFFSET; + oldSTVarnodes = Set.of( + new Varnode(registerSpace.getAddress(oldSTBaseOffset), + ST_SIZE), // Old ST0 at 0x1000, now at 0x1106 + new Varnode(registerSpace.getAddress(oldSTBaseOffset + OLD_ST_OFFSET_SPACING), + ST_SIZE), // Old ST1 at 0x100a, now at 0x1116 + new Varnode(registerSpace.getAddress(oldSTBaseOffset + (2 * OLD_ST_OFFSET_SPACING)), + ST_SIZE), // Old ST2 at 0x1014, now at 0x1126 + new Varnode(registerSpace.getAddress(oldSTBaseOffset + (3 * OLD_ST_OFFSET_SPACING)), + ST_SIZE), // Old ST3 at 0x101e, now at 0x1136 + new Varnode(registerSpace.getAddress(oldSTBaseOffset + (4 * OLD_ST_OFFSET_SPACING)), + ST_SIZE), // Old ST4 at 0x1028, now at 0x1146 + new Varnode(registerSpace.getAddress(oldSTBaseOffset + (5 * OLD_ST_OFFSET_SPACING)), + ST_SIZE), // Old ST5 at 0x1032, now at 0x1156 + new Varnode(registerSpace.getAddress(oldSTBaseOffset + (6 * OLD_ST_OFFSET_SPACING)), + ST_SIZE), // Old ST6 at 0x103c, now at 0x1166 + new Varnode(registerSpace.getAddress(oldSTBaseOffset + (7 * OLD_ST_OFFSET_SPACING)), + ST_SIZE) // Old ST7 at 0x1046*, now at 0x1176 // Old ST7 at 0x1046, now at 0x1176 + ); + + } + + private boolean fixupVariableStorage(Variable var) { + VariableStorage varStore = var.getVariableStorage(); + Varnode[] varnodes = varStore.getVarnodes(); + if (fixupStorageVarnodes(varnodes)) { + try { + var.setDataType(var.getDataType(), + new VariableStorage(currentProgram, varnodes), false, var.getSource()); + } + catch (InvalidInputException e) { + throw new AssertionError("Unexpected error for ST register varnode assignment", + e); + } + return true; + } + return false; + } + + private boolean fixupStorageVarnodes(Varnode[] varnodes) { + boolean hasFixup = false; + for (int i = 0; i < varnodes.length; i++) { + Varnode v = getReplacement(varnodes[i]); + if (v != null) { + hasFixup = true; + varnodes[i] = v; + } + } + return hasFixup; + } + + Varnode getReplacement(Varnode v) { + if (!oldSTVarnodes.contains(v)) { + return null; + } + Address regAddr = v.getAddress(); + long stOffset = regAddr.getOffset() - OLD_ST_BASE_OFFSET; + long stIndex = stOffset / OLD_ST_OFFSET_SPACING; + + // Form updated ST varnode + stOffset = newStBaseOffset + (stIndex * NEW_ST_OFFSET_SPACING); + return new Varnode(regAddr.getNewAddress(stOffset), 10); + } + + + } + +}