diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CreateThunkFunctionCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CreateThunkFunctionCmd.java index 5d5c5f7d76..52ea98aa69 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CreateThunkFunctionCmd.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CreateThunkFunctionCmd.java @@ -635,6 +635,8 @@ public class CreateThunkFunctionCmd extends BackgroundCommand { // keep going if flow target is right below, allow only a simple branch. if (isLocalBranch(listing, instr, flowType)) { + Address[] flows = instr.getFlows(); + instr = listing.getInstructionAt(flows[0]); continue; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/NewFunctionStackAnalysisCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/NewFunctionStackAnalysisCmd.java index 48923d0106..dc8e7dc79f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/NewFunctionStackAnalysisCmd.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/NewFunctionStackAnalysisCmd.java @@ -583,6 +583,9 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand { if (local_offset == offset) { return opIndex; } + if ((local_offset & 0xffff) == offset) { + return opIndex; + } } } return -1; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java index 2dd4fe4e2b..3e946e49a0 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java @@ -247,6 +247,7 @@ public abstract class CompositeEditorPanel { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/AnalyzeStackRefsAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/AnalyzeStackRefsAction.java index eceefb4643..0b528814d8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/AnalyzeStackRefsAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/AnalyzeStackRefsAction.java @@ -104,13 +104,8 @@ class AnalyzeStackRefsAction extends ListingContextAction { doParameterAnalysis = options.getBoolean("Create Param Variables", doParameterAnalysis); BackgroundCommand cmd = null; - if (doNewStackAnalysis) { - cmd = new NewFunctionStackAnalysisCmd(funcSet, doParameterAnalysis, doLocalAnalysis, + cmd = new NewFunctionStackAnalysisCmd(funcSet, doParameterAnalysis, doLocalAnalysis, true); - } - else { - cmd = new FunctionStackAnalysisCmd(funcSet, doParameterAnalysis, doLocalAnalysis, true); - } funcPlugin.execute(program, cmd); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/EditThunkFunctionAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/EditThunkFunctionAction.java index a9f0313745..3f2254cdff 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/EditThunkFunctionAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/EditThunkFunctionAction.java @@ -74,15 +74,17 @@ class EditThunkFunctionAction extends ProgramContextAction { } Address funcEntry = func.getEntryPoint(); - Function refFunc = func.getThunkedFunction(false); + Function refFunc = func.getThunkedFunction(false); + Symbol refSymbol = null; if (refFunc == null) { // if not already thunked, fill in a possible value from functions instructions Address thunkAddr = CreateThunkFunctionCmd.getThunkedAddr(program, funcEntry, false); if (thunkAddr != null) { - refFunc = functionMgr.getFunctionAt(thunkAddr); + refSymbol = program.getSymbolTable().getPrimarySymbol(thunkAddr); } - } - Symbol refSymbol = (refFunc == null ? null : refFunc.getSymbol()); + } else { + refSymbol = refFunc.getSymbol(); + } // Prompt for function referenced by thunk ThunkReferenceAddressDialog dialog = new ThunkReferenceAddressDialog(funcPlugin.getTool()); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/StackVariableAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/StackVariableAnalyzer.java index 120fc422a6..9f2d61bba8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/StackVariableAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/StackVariableAnalyzer.java @@ -17,14 +17,12 @@ package ghidra.app.plugin.core.function; import java.util.*; -import ghidra.app.cmd.function.FunctionStackAnalysisCmd; import ghidra.app.cmd.function.NewFunctionStackAnalysisCmd; import ghidra.app.services.*; import ghidra.app.util.importer.MessageLog; import ghidra.framework.cmd.BackgroundCommand; import ghidra.framework.options.Options; import ghidra.program.model.address.*; -import ghidra.program.model.lang.*; import ghidra.program.model.listing.Function; import ghidra.program.model.listing.Program; import ghidra.util.Msg; @@ -41,7 +39,6 @@ public class StackVariableAnalyzer extends AbstractAnalyzer { protected static final int MAX_THREAD_COUNT_OPTION_DEFAULT_VALUE = 2; protected int maxThreadCount = MAX_THREAD_COUNT_OPTION_DEFAULT_VALUE; - private boolean doNewStackAnalysis = true; private boolean doCreateLocalStackVars = true; private boolean doCreateStackParams = false; @@ -80,14 +77,8 @@ public class StackVariableAnalyzer extends AbstractAnalyzer { final TaskMonitor monitor) throws CancelledException { BackgroundCommand cmd; - if (doNewStackAnalysis) { - cmd = new NewFunctionStackAnalysisCmd(new AddressSet(start, start), doCreateStackParams, doCreateLocalStackVars, + cmd = new NewFunctionStackAnalysisCmd(new AddressSet(start, start), doCreateStackParams, doCreateLocalStackVars, false); - } - else { - cmd = new FunctionStackAnalysisCmd(new AddressSet(start, start), doCreateStackParams, doCreateLocalStackVars, - false); - } cmd.applyTo(program, monitor); return EMPTY_ADDRESS_SET; @@ -120,23 +111,8 @@ public class StackVariableAnalyzer extends AbstractAnalyzer { } } -// private boolean useOldStackAnalysisByDefault(Program program) { -// Language language = program.getLanguage(); -// if (language.getProcessor().equals(Processor.findOrPossiblyCreateProcessor("x86"))) { -// if (language.getLanguageDescription().getSize() == 16) { -// // Prefer using old stack analysis for x86 16-bit with segmented addresses -// return true; -// } -// } -// return false; -// } - @Override public void registerOptions(Options options, Program program) { - options.registerOption(GhidraLanguagePropertyKeys.USE_NEW_FUNCTION_STACK_ANALYSIS, - true, null, - "Use General Stack Reference Propogator (This works best on most processors)"); - options.registerOption("Create Local Variables", doCreateLocalStackVars, null, "Create Function Local stack variables and references"); @@ -149,10 +125,6 @@ public class StackVariableAnalyzer extends AbstractAnalyzer { @Override public void optionsChanged(Options options, Program program) { - doNewStackAnalysis = - options.getBoolean(GhidraLanguagePropertyKeys.USE_NEW_FUNCTION_STACK_ANALYSIS, - true); - doCreateLocalStackVars = options.getBoolean("Create Local Variables", doCreateLocalStackVars); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/FunctionsXmlMgr.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/FunctionsXmlMgr.java index c1dc17aebb..5c23c666d4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/FunctionsXmlMgr.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/FunctionsXmlMgr.java @@ -228,7 +228,7 @@ class FunctionsXmlMgr { parser.end(element); FunctionPurgeAnalysisCmd purgeAnalysisCmd = new FunctionPurgeAnalysisCmd(functions); purgeAnalysisCmd.applyTo(program, monitor); - FunctionStackAnalysisCmd stackAnalysisCmd = new FunctionStackAnalysisCmd(functions, true); + NewFunctionStackAnalysisCmd stackAnalysisCmd = new NewFunctionStackAnalysisCmd(functions, true); stackAnalysisCmd.applyTo(program, monitor); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java index 951a251f3a..f73db0bd27 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java @@ -886,6 +886,15 @@ public class SymbolicPropogator { } vContext.copy(out, in[0], mustClearAll, evaluator); break; + + case PcodeOp.SEGMENTOP: + // treat like a copy for now, and extend the size as if segment had been applied + Varnode vval = context.getValue(in[2], evaluator); + if (context.isSymbolicSpace(vval.getSpace())) { + vval = vContext.createVarnode(vval.getOffset(), vval.getSpace(), out.getSize()); + } + vContext.putValue(out, vval, mustClearAll); + break; case PcodeOp.LOAD: Varnode memVal = null; @@ -1843,7 +1852,7 @@ public class SymbolicPropogator { for (int i = 1; i < ins.length; i++) { Varnode vval = context.getValue(ins[i], evaluator); if (vval == null || !context.isConstant(vval)) { - return null; + return checkSegmentCallOther(payload, instr, ins, out); } inputs.add(vval); } @@ -1867,6 +1876,29 @@ public class SymbolicPropogator { return null; } + private PcodeOp[] checkSegmentCallOther(InjectPayload payload, Instruction instr, Varnode[] ins, Varnode out) { + if (!payload.getName().equals("segment_pcode")) { + return null; + } + if (ins.length != 3) { + return null; + } + Varnode vval = context.getValue(ins[2], evaluator); + if (vval == null) { + return null; + } + if (!context.isSymbolicSpace(vval.getSpace())) { + return null; + } + if (!context.isRegister(ins[1])) { + return null; + } + // morph segment into COPY as long as still symbolic + PcodeOp[] newop = new PcodeOp[1]; + newop[0] = new PcodeOp(instr.getAddress(), 1, PcodeOp.SEGMENTOP, ins, out); + return newop; + } + private InjectPayload findPcodeInjection(Program prog, PcodeInjectLibrary snippetLibrary, long callOtherIndex) { InjectPayload payload = injectPayloadCache.get(callOtherIndex); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/AbstractListingMergeManagerTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/AbstractListingMergeManagerTest.java index cf8a14ba2f..05af19cd2e 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/AbstractListingMergeManagerTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/AbstractListingMergeManagerTest.java @@ -35,7 +35,7 @@ import docking.test.AbstractDockingTest; import docking.widgets.dialogs.ReadTextDialog; import ghidra.app.cmd.disassemble.DisassembleCommand; import ghidra.app.cmd.function.CreateFunctionCmd; -import ghidra.app.cmd.function.FunctionStackAnalysisCmd; +import ghidra.app.cmd.function.NewFunctionStackAnalysisCmd; import ghidra.app.merge.AbstractMergeTest; import ghidra.app.merge.ProgramMultiUserMergeManager; import ghidra.app.merge.tool.ListingMergePanel; @@ -364,7 +364,7 @@ public abstract class AbstractListingMergeManagerTest extends AbstractMergeTest // TODO For thunk functions need to call thunk analyzer here before // stack analysis occurs } - FunctionStackAnalysisCmd analyzeCmd = new FunctionStackAnalysisCmd(addr, true); + NewFunctionStackAnalysisCmd analyzeCmd = new NewFunctionStackAnalysisCmd(addr, true); assertTrue("Failed to analyze stack for " + name + " @ " + addr, analyzeCmd.applyTo(program)); } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/SymbolMergeManager3Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/SymbolMergeManager3Test.java index d6b8bb3a2f..a4e12f09c3 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/SymbolMergeManager3Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/SymbolMergeManager3Test.java @@ -4,9 +4,9 @@ * 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. @@ -22,7 +22,7 @@ import org.junit.Test; import ghidra.app.cmd.disassemble.DisassembleCommand; import ghidra.app.cmd.function.CreateFunctionCmd; -import ghidra.app.cmd.function.FunctionStackAnalysisCmd; +import ghidra.app.cmd.function.NewFunctionStackAnalysisCmd; import ghidra.program.database.ProgramDB; import ghidra.program.database.ProgramModifierListener; import ghidra.program.model.address.Address; @@ -154,7 +154,7 @@ public class SymbolMergeManager3Test extends AbstractListingMergeManagerTest { functionCmd.applyTo(program)); Function newFunction = program.getFunctionManager().getFunctionAt(addr); assertNotNull(newFunction); - FunctionStackAnalysisCmd analyzeCmd = new FunctionStackAnalysisCmd(addr, true); + NewFunctionStackAnalysisCmd analyzeCmd = new NewFunctionStackAnalysisCmd(addr, true); assertTrue("Failed to analyze stack for " + name + " @ " + addr, analyzeCmd.applyTo(program)); } diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/cmd/function/FunctionStackAnalysisCmdTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/cmd/function/FunctionStackAnalysisCmdTest.java new file mode 100644 index 0000000000..105948a613 --- /dev/null +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/cmd/function/FunctionStackAnalysisCmdTest.java @@ -0,0 +1,239 @@ +/* ### + * 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.cmd.function; + +import static org.junit.Assert.*; + +import java.math.BigInteger; + +import org.junit.Test; + +import generic.test.AbstractGenericTest; +import ghidra.app.plugin.core.analysis.ConstantPropagationAnalyzer; +import ghidra.app.plugin.core.analysis.ConstantPropagationContextEvaluator; +import ghidra.app.plugin.core.function.StackVariableAnalyzer; +import ghidra.program.database.ProgramBuilder; +import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressSet; +import ghidra.program.model.lang.Register; +import ghidra.program.model.lang.RegisterValue; +import ghidra.program.model.listing.*; +import ghidra.program.model.mem.MemoryBlock; +import ghidra.program.model.pcode.Varnode; +import ghidra.program.model.symbol.Reference; +import ghidra.program.model.symbol.ReferenceIterator; +import ghidra.program.util.SymbolicPropogator.Value; +import ghidra.util.task.TaskMonitor; + +/** + * quick and dirty test of the ProgramContextImpl just to see + * if the values are being set for specified address range. + * The ProgramContextPlugin will be a more complete test + * program, with a gui interface to specify the values and + * select/highlight an address range. + */ +public class FunctionStackAnalysisCmdTest extends AbstractGenericTest { + + private ProgramBuilder builder; + private Program program; + + private StackVariableAnalyzer analyzer; + + public FunctionStackAnalysisCmdTest() { + super(); + } + + public void do16bitTest(String processor) throws Exception { + + builder = new ProgramBuilder("ProtectedMode", processor); + + /** + * undefined __cdecl16near FUN_1000_00cc() + 1000:00cc 45 0 INC BP + 1000:00cd 55 0 PUSH BP + 1000:00ce 8b ec 002 MOV BP,SP + 1000:00d0 56 002 PUSH SI + 1000:00d1 57 004 PUSH DI + 1000:00d2 8a 46 f0 006 MOV AL,byte ptr [BP + local_12] + 1000:00d5 b4 4c 006 MOV AH,0x4c + 1000:00d7 8b 56 08 006 MOV DX,word ptr [BP + Stack[0x6]] + 1000:00da 8b 46 06 006 MOV AX,word ptr [BP + Stack[0x4]] + 1000:00dd ff 76 08 006 PUSH word ptr [BP + Stack[0x6]] + 1000:00e0 ff 76 ee 008 PUSH word ptr [BP + local_14] + 1000:00e3 83 7e 06 00 00a CMP word ptr [BP + Stack[0x4]],0x0 + 1000:00e7 dd 46 04 00a FLD double ptr [BP + Stack[0x2]] + 1000:00ea 07 00a POP ES + 1000:00eb c3 008 RET + + */ + builder.setBytes("0x1000:00cc", + "45 55 8b ec 56 57 8a 46 f0 b4 4c 8b 56 08 8b 46 06 ff 76 08 ff 76 ee 83 7e 06 00 dd 46 04 07 c3"); + + builder.disassemble("0x1000:0x00CC", 48); + + analyzer = new StackVariableAnalyzer(); + + program = builder.getProgram(); + program.startTransaction("Test"); + + Address codeStart = addr("0x1000:0x00CC"); + Listing listing = program.getListing(); + assertNotNull("Bad instruction disassembly", listing.getInstructionAt(codeStart)); + + builder.createFunction("0x1000:0x00cc"); + + Instruction instr = listing.getInstructionAt(addr("0x1000:0x00d2")); + assertNoOperandReference(0, instr); + assertNoOperandReference(1, instr); + + AddressSet addressSet = new AddressSet(codeStart, codeStart.add(48)); + analyze(addressSet); + + assertNoOperandReference(0, instr); + assertOperandReferenceTo(1, instr, addr("stack:0x0").subtract(0x12)); + + instr = listing.getInstructionAt(addr("0x1000:0x00d7")); + assertNoOperandReference(0, instr); + assertOperandReferenceTo(1, instr, addr("stack:0x6")); + + instr = listing.getInstructionAt(addr("0x1000:0x00da")); + assertNoOperandReference(0, instr); + assertOperandReferenceTo(1, instr, addr("stack:0x4")); + + instr = listing.getInstructionAt(addr("0x1000:0x00dd")); + assertNoOperandReference(1, instr); + assertOperandReferenceTo(0, instr, addr("stack:0x6")); + + instr = listing.getInstructionAt(addr("0x1000:0x00e0")); + assertNoOperandReference(1, instr); + assertOperandReferenceTo(0, instr, addr("stack:0x0").subtract(0x14)); + + instr = listing.getInstructionAt(addr("0x1000:0x00e3")); + assertNoOperandReference(1, instr); + assertOperandReferenceTo(0, instr, addr("stack:0x4")); + + instr = listing.getInstructionAt(addr("0x1000:0x00e7")); + assertOperandReferenceTo(0, instr, addr("stack:0x2")); + } + + @Test + public void testOperandRef_x86ProtectedMode() throws Exception { + do16bitTest("x86:LE:16:Protected Mode"); + } + + @Test + public void testOperandRef_x86RealMode() throws Exception { + do16bitTest("x86:LE:16:Real Mode"); + } + + @Test + public void testMIPS64() throws Exception { + builder = new ProgramBuilder("MIPS", "MIPS:LE:32:default"); + + /** + * undefined FUN_9d010b2c() + 9d010b2c c0 ff bd 27 0 addiu sp,sp,-0x40 + 9d010b30 24 00 b0 af 040 sw s0,local_1c(sp) + 9d010b34 01 a0 10 3c 040 lui s0,0xa001 + 9d010b38 40 5c 02 26 040 addiu v0,s0,0x5c40 + 9d010b3c 14 00 42 8c 040 lw v0,0x14(v0)=>DAT_a0015c54 + 9d010b40 3c 00 bf af 040 sw ra,local_4(sp) + 9d010b44 31 00 43 2c 040 sltiu v1,v0,0x31 + 9d010b48 38 00 b5 af 040 sw s5,local_8(sp) + 9d010b4c 34 00 b4 af 040 sw s4,local_c(sp) + 9d010b50 30 00 b3 af 040 sw s3,local_10(sp) + 9d010b54 2c 00 b2 af 040 sw s2,local_14(sp) + 9d010b58 b7 05 60 10 040 beq v1,zero,switchD_9d010b74 + 9d010b5c 28 00 b1 af _sw s1,local_18(sp) + 9d010b60 01 9d 03 3c 040 lui v1,0x9d01 + 9d010b64 80 10 02 00 040 sll v0,v0,0x2 + 9d010b68 7c 0b 63 24 040 addiu v1,v1,0xb7c + 9d010b6c 21 10 62 00 040 addu v0,v1,v0 + 9d010b70 00 00 42 8c 040 lw v0,0x0(v0) + 9d010b74 08 00 40 00 040 jr v0 + + */ + String funcStartAddrString = "0x9d010b2c"; + builder.setBytes(funcStartAddrString, + "c0 ff bd 27 24 00 b0 af 01 a0 10 3c 40 5c 02 26 14 00 42 8c 3c 00 bf af 31 00 43 2c 38 00 b5 af 34 " + + "00 b4 af 30 00 b3 af 2c 00 b2 af b7 05 60 10 28 00 b1 af 01 9d 03 3c 80 10 02 00 7c 0b 63 24 21 " + + "10 62 00 00 00 42 8c 08 00 40 00"); + + builder.disassemble(funcStartAddrString, 72); + + analyzer = new StackVariableAnalyzer(); + + program = builder.getProgram(); + program.startTransaction("Test"); + + Address codeStart = addr(funcStartAddrString); + Listing listing = program.getListing(); + assertNotNull("Bad instruction disassembly", listing.getInstructionAt(codeStart)); + + builder.createFunction(funcStartAddrString); + + Instruction instr = listing.getInstructionAt(addr("0x9d010b30")); + assertNoOperandReference(0, instr); + assertNoOperandReference(1, instr); + + AddressSet addressSet = new AddressSet(codeStart, codeStart.add(72)); + analyze(addressSet); + + assertNoOperandReference(0, instr); + assertOperandReferenceTo(1, instr, addr("stack:0x0").subtract(0x1c)); + + // should not create any memory refs, is stack analyzer + instr = listing.getInstructionAt(addr("0x9d010b3c")); + assertNoOperandReference(0, instr); + assertNoOperandReference(1, instr); + + instr = listing.getInstructionAt(addr("0x9d010b40")); + assertNoOperandReference(0, instr); + assertOperandReferenceTo(1, instr, addr("stack:0x0").subtract(4)); + + instr = listing.getInstructionAt(addr("0x9d010b48")); + assertNoOperandReference(0, instr); + assertOperandReferenceTo(1, instr, addr("stack:0x0").subtract(8)); + + instr = listing.getInstructionAt(addr("0x9d010b4c")); + assertNoOperandReference(0, instr); + assertOperandReferenceTo(1, instr, addr("stack:0x0").subtract(12)); + + // delay slot stack reference case + instr = listing.getInstructionAt(addr("0x9d010b5c")); + assertNoOperandReference(0, instr); + assertOperandReferenceTo(1, instr, addr("stack:0x0").subtract(0x18)); + } + + private void assertNoOperandReference(int opIndex, Instruction instr) { + Reference[] refs = instr.getOperandReferences(opIndex); + assertEquals("No reference on operand " + opIndex, 0, refs.length); + } + + private void assertOperandReferenceTo(int opIndex, Instruction instr, Address to) { + Reference[] refs = instr.getOperandReferences(opIndex); + assertEquals("Operand " + opIndex + " num refs", 1, refs.length); + assertEquals("Operand " + opIndex + " Ref Check", to, refs[0].getToAddress()); + } + + private void analyze(AddressSet addrs) throws Exception { + analyzer.added(program, addrs, TaskMonitor.DUMMY, null); + } + + private Address addr(String address) { + return builder.addr(address); + } +} diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/analysis/DecompilerSwitchAnalyzer.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/analysis/DecompilerSwitchAnalyzer.java index 48f44d5e0b..af699b90ab 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/analysis/DecompilerSwitchAnalyzer.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/analysis/DecompilerSwitchAnalyzer.java @@ -433,8 +433,8 @@ public class DecompilerSwitchAnalyzer extends AbstractAnalyzer { if (fixupFunc.hasNoReturn()) { return fixupFunc; } - return null; } + return null; } } diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/net/ApplicationKeyStore.java b/Ghidra/Framework/Generic/src/main/java/ghidra/net/ApplicationKeyStore.java index cea30ea79d..d9985d392d 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/net/ApplicationKeyStore.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/net/ApplicationKeyStore.java @@ -4,9 +4,9 @@ * 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. @@ -32,7 +32,7 @@ import ghidra.util.Msg; * X.509 form (*.pem, *.crt, *.cer, *.der) or Java JKS (*.jks) form, while keystores * for client/server may be in a PKCS12 form (*.p12, *.pks, *.pfx) or Java JKS (*.jks) form. */ -class ApplicationKeyStore { +public class ApplicationKeyStore { private ApplicationKeyStore() { // no instantiation - static methods only @@ -48,7 +48,7 @@ class ApplicationKeyStore { * @throws NoSuchAlgorithmException * @throws CertificateException */ - static KeyStore getCertificateStoreInstance(String cacertsPath) + public static KeyStore getCertificateStoreInstance(String cacertsPath) throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException { int certCount = 0; @@ -103,7 +103,7 @@ class ApplicationKeyStore { * @throws NoSuchAlgorithmException * @throws CertificateException */ - static KeyStore getKeyStoreInstance(String keystorePath, char[] pwd) + public static KeyStore getKeyStoreInstance(String keystorePath, char[] pwd) throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException { File keystoreFile = new File(keystorePath); @@ -122,6 +122,35 @@ class ApplicationKeyStore { return ks; } + /** + * Attempt to detect PKI KeyStore type ("JKS" or "PKCS12") for the specified file. + * @param keystorePath key store file path + * @return "JKS", "PKCS12" or null + * @throws IOException if file read error occurs + */ + public static String detectKeyStoreType(String keystorePath) throws IOException { + try (FileInputStream fis = new FileInputStream(keystorePath)) { + byte[] header = new byte[4]; + int read = fis.read(header); + if (read < 4) { + return null; + } + + // Check for JKS magic number: FEEDFEED + if ((header[0] & 0xFF) == 0xFE && (header[1] & 0xFF) == 0xED && + (header[2] & 0xFF) == 0xFE && (header[3] & 0xFF) == 0xED) { + return "JKS"; + } + + // Check for PKCS12: starts with 0x30 0x82 + if ((header[0] & 0xFF) == 0x30 && (header[1] & 0xFF) == 0x82) { + return "PKCS12"; + } + + return null; + } + } + /** * Extract Common Name (CN) from specified principal subject Distinguished Name (DN) * @param subject X.509 certificate subject @@ -180,7 +209,7 @@ class ApplicationKeyStore { * Log all X509 certificates contained within array * @param x509Certs array of certificates */ - static void logCerts(X509Certificate[] x509Certs) { + public static void logCerts(X509Certificate[] x509Certs) { for (X509Certificate x509Cert : x509Certs) { logCert(null, x509Cert); } diff --git a/Ghidra/Processors/PowerPC/data/patterns/PPC_BE_patterns.xml b/Ghidra/Processors/PowerPC/data/patterns/PPC_BE_patterns.xml index d69520f08d..2937da4e7b 100644 --- a/Ghidra/Processors/PowerPC/data/patterns/PPC_BE_patterns.xml +++ b/Ghidra/Processors/PowerPC/data/patterns/PPC_BE_patterns.xml @@ -73,4 +73,18 @@ + + + 011111.. ...01000 0x02 0xa6 + 0x42 1....... 0x00 0x05 + 011111.. ...01000 0x02 0xa6 + 001111.. ........ 0x.. 0x.. + 001110.. ........ 0x.. 0x.. + 011111.. ...01000 0x03 0xa6 + 011111.. ...01001 0x03 0xa6 + 0x4e 10000... 0x04 0x20 + + + + diff --git a/Ghidra/Processors/PowerPC/data/patterns/PPC_LE_patterns.xml b/Ghidra/Processors/PowerPC/data/patterns/PPC_LE_patterns.xml index 6e4e7b739e..8d22aafcf5 100644 --- a/Ghidra/Processors/PowerPC/data/patterns/PPC_LE_patterns.xml +++ b/Ghidra/Processors/PowerPC/data/patterns/PPC_LE_patterns.xml @@ -73,4 +73,18 @@ + + + 0xa6 0x02 ...01000 011111.. + 0x05 0x00 1....... 0x42 + 0xa6 0x02 ...01000 011111.. + 0x.. 0x.. ........ 001111.. + 0x.. 0x.. ........ 001110.. + 0xa6 0x03 ...01000 011111.. + 0xa6 0x03 ...01001 011111.. + 0x20 0x04 10000... 0x4e + + + + diff --git a/Ghidra/Processors/SuperH/data/languages/superh.sinc b/Ghidra/Processors/SuperH/data/languages/superh.sinc index a342834246..44c9fdefc5 100644 --- a/Ghidra/Processors/SuperH/data/languages/superh.sinc +++ b/Ghidra/Processors/SuperH/data/languages/superh.sinc @@ -2307,8 +2307,7 @@ define pcodeop Sleep_Standby; :bclr "#"imm3_00_02, rn_04_07 is opcode_08_15=0b10000110 & rn_04_07 & opcode_03_03=0b0 & imm3_00_02 { - local b = *:1 (rn_04_07); - *:1 (rn_04_07) = b & (~(1 << imm3_00_02)); + rn_04_07 = rn_04_07 & (~(1 << imm3_00_02)); } # BLD.B #imm3, @(disp12,Rn) 0011nnnn0iii1001 0011dddddddddddd (imm of (disp+Rn)) → T diff --git a/GhidraBuild/LaunchSupport/src/main/java/ghidra/launch/LaunchProperties.java b/GhidraBuild/LaunchSupport/src/main/java/ghidra/launch/LaunchProperties.java index c3822b9d9e..efac026caf 100644 --- a/GhidraBuild/LaunchSupport/src/main/java/ghidra/launch/LaunchProperties.java +++ b/GhidraBuild/LaunchSupport/src/main/java/ghidra/launch/LaunchProperties.java @@ -193,10 +193,10 @@ public class LaunchProperties { text = text.replaceAll("\\$\\{" + key + "\\}", value.replace("\\", "\\\\")); } catch (IllegalArgumentException e) { - throw new ParseException( - "Error expanding environment variable in %s (env %s=%s) -- %s".formatted(text, - key, value, e.getMessage()), - 0); + String msg = + String.format("Error expanding environment variable in %s (env %s=%s) -- %s", + text, key, value, e.getMessage()); + throw new ParseException(msg, 0); } } return text;