GP-2391 added evaluation of return address, allow thunking addresses to externals. Added new arem thunk pattern.

This commit is contained in:
emteere
2022-10-11 18:25:09 -04:00
parent 35b58b3105
commit ca5a6204c3
12 changed files with 490 additions and 85 deletions

View File

@@ -248,7 +248,19 @@
0x01 0xbd </data> <!-- push {r0,r1} ; ldr r0,[dest] ; str r0, [sp, stack[-4]] ; pop {r0,pc} -->
<align mark="0" bits="1"/>
<setcontext name="TMode" value="1"/>
<funcstart validcode="function" thunk="true" /> <!-- must be something defined right before this -->
<funcstart thunk="true" />
</pattern>
<pattern> <!-- Thumb - thunk -->
<data> 0x10 0xb5 <!-- push {r4,lr} -->
0x02 0x4c <!-- ldr r4,[PTR_+0xc] -->
0x24 0x68 <!-- ldr r4,[r4,#0x0] -->
0x01 0x94 <!-- str r4,[sp,#local_4] -->
0x10 0xbd <!-- pop {r4,pc} -->
</data>
<align mark="0" bits="1"/>
<setcontext name="TMode" value="1"/>
<funcstart thunk="true" />
</pattern>
</patternlist>

View File

@@ -132,6 +132,7 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
}
}
return false;
}
@@ -189,7 +190,6 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
// must disassemble right now, because TB flag could get set back at end of blx
doArmThumbDisassembly(program, instr, context, address, instr.getFlowType(),
true, monitor);
return false;
}
return super.evaluateReference(context, instr, pcodeop, address, size, refType);
@@ -211,6 +211,21 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
}
return false;
}
@Override
public boolean evaluateReturn(Varnode retVN, VarnodeContext context, Instruction instruction) {
// check if a return is actually returning, or is branching with a constant PC
if (retVN != null && retVN.isConstant()) {
long offset = retVN.getOffset();
if (offset > 3 && offset != -1) {
// need to override the return to a branch
instruction.setFlowOverride(FlowOverride.BRANCH);
}
}
return false;
}
};
AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
@@ -399,7 +414,12 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
public boolean evaluateDestination(VarnodeContext context, Instruction instruction) {
return instruction.getMinAddress().equals(targetSwitchAddr);
}
@Override
public boolean evaluateReturn(Varnode retVN, VarnodeContext context, Instruction instruction) {
return false;
}
@Override
public Long unknownValue(VarnodeContext context, Instruction instruction,
Varnode node) {

View File

@@ -0,0 +1,110 @@
/* ###
* 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.plugin.core.analysis;
import static org.junit.Assert.*;
import org.junit.*;
import ghidra.app.plugin.core.analysis.AnalysisBackgroundCommand;
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
import ghidra.framework.cmd.Command;
import ghidra.framework.options.Options;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.model.address.AddressSet;
import ghidra.program.model.data.DWordDataType;
import ghidra.program.model.data.DataType;
import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.SourceType;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.test.TestEnv;
public class ArmBranchReturnDetectionTest extends AbstractGhidraHeadedIntegrationTest {
private TestEnv env;
private PluginTool tool;
private Program program;
private ProgramBuilder builder;
@Before
public void setUp() throws Exception {
env = new TestEnv();
tool = env.getTool();
}
@After
public void tearDown() {
if (program != null) {
env.release(program);
}
program = null;
env.dispose();
}
private void analyze() {
// turn off some analyzers
setAnalysisOptions("Stack");
setAnalysisOptions("Embedded Media");
setAnalysisOptions("DWARF");
setAnalysisOptions("Create Address Tables");
AutoAnalysisManager analysisMgr = AutoAnalysisManager.getAnalysisManager(program);
analysisMgr.reAnalyzeAll(null);
Command cmd = new AnalysisBackgroundCommand(analysisMgr, false);
tool.execute(cmd, program);
waitForBusyTool(tool);
}
protected void setAnalysisOptions(String optionName) {
int txId = program.startTransaction("Analyze");
Options analysisOptions = program.getOptions(Program.ANALYSIS_PROPERTIES);
analysisOptions.setBoolean(optionName, false);
program.endTransaction(txId, true);
}
/**
* This tests that a pop to the pc with the lr register is changed to a return
*
* That the thunking function can be found with the constant reference analyzer
*
*/
@Test
public void testDelayArmPopReturn1() throws Exception {
builder = new ProgramBuilder("thunk", ProgramBuilder._ARM);
builder.setBytes("0x00015d9c", "10 b5 03 48 10 bc 01 bc 00 47");
builder.setRegisterValue("TMode", "0x00015d9c", "0x00015d9c", 1);
builder.disassemble("0x00015d9c", 27, true);
builder.createFunction("0x00015d9c");
builder.createLabel("0x00015d9c", "func1");;
program = builder.getProgram();
analyze();
Instruction instruction = program.getListing().getInstructionAt(builder.addr(0x00015da4));
assertNotNull(instruction);
assertTrue("pop turned into return", instruction.getFlowType().isTerminal());
}
}