mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-01-09 05:58:00 -05:00
GP-6120_emteere_FixThunkDetectionMarkupPPC64
This commit is contained in:
@@ -64,6 +64,8 @@ data/languages/vsx.sinc||GHIDRA||||END|
|
||||
data/manuals/PowerISA.idx||GHIDRA||||END|
|
||||
data/manuals/PowerPC.idx||GHIDRA||||END|
|
||||
data/patterns/PPC_BE_patterns.xml||GHIDRA||||END|
|
||||
data/patterns/PPC_BE_prepatterns.xml||GHIDRA||||END|
|
||||
data/patterns/PPC_LE_patterns.xml||GHIDRA||||END|
|
||||
data/patterns/PPC_LE_prepatterns.xml||GHIDRA||||END|
|
||||
data/patterns/patternconstraints.xml||GHIDRA||||END|
|
||||
data/ppc64-r2CallStubs.xml||GHIDRA||||END|
|
||||
data/patterns/prepatternconstraints.xml||GHIDRA||||END|
|
||||
|
||||
208
Ghidra/Processors/PowerPC/data/patterns/PPC_BE_prepatterns.xml
Normal file
208
Ghidra/Processors/PowerPC/data/patterns/PPC_BE_prepatterns.xml
Normal file
@@ -0,0 +1,208 @@
|
||||
<patternlist>
|
||||
|
||||
<pattern> <!-- .plt entry thunk -->
|
||||
<data>
|
||||
0xf8410028 <!-- std r2,0x28(r1) -->
|
||||
001111.. ...00010 0xff 0xff <!-- subis rX,r2,0x1 -->
|
||||
0xe9 ........ ........ ........ <!-- ld rX,#(x) -->
|
||||
0x7d 0x.9 0x03 0xa6 <!-- mtctr rX -->
|
||||
0xe8 010..... ........ ........ <!-- ld r2,#(x) -->
|
||||
0x28220000 <!-- cmpldi r2,0 -->
|
||||
0x4c 1..00010 0x04 0x20 <!-- bnectr+ -->
|
||||
010010.. ........ ........ ......00 <!-- b X@plt -->
|
||||
</data>
|
||||
<funcstart thunk="true" section="(?i)(\.plt(\.sec)?)"/> <!-- must be something define before this -->
|
||||
</pattern>
|
||||
|
||||
<pattern> <!-- .plt entry thunk -->
|
||||
<data>
|
||||
0xf8410028 <!-- std r2,0x28(r1) -->
|
||||
0xe9 ........ ........ ........ <!-- ld rX,#(x) -->
|
||||
0x7d 0x.9 0x03 0xa6 <!-- mtctr rX -->
|
||||
0xe8 010..... ........ ........ <!-- ld r2,#(x) -->
|
||||
0x28220000 <!-- cmpldi r2,0 -->
|
||||
0x4c 1..00010 0x04 0x20 <!-- bnectr+ -->
|
||||
010010.. ........ ........ ......00 <!-- b X@plt -->
|
||||
</data>
|
||||
<funcstart thunk="true" section="(?i)(\.plt(\.sec)?)"/> <!-- must be something define before this -->
|
||||
</pattern>
|
||||
|
||||
<pattern>
|
||||
<data>
|
||||
011111.. ...01000 0x02 0xa6 <!-- mfspr rxx, LR -->
|
||||
0x42 1....... 0x00 0x05 <!-- bl +0x4 -->
|
||||
011111.. ...01000 0x02 0xa6 <!-- mfspr rxx,LR -->
|
||||
001111.. ........ 0x.. 0x.. <!-- addis rxx, rxx, 0xxx -->
|
||||
001110.. ........ 0x.. 0x.. <!-- addi rxx, rxx, 0xxx -->
|
||||
011111.. ...01000 0x03 0xa6 <!-- mtspr LR, rxx -->
|
||||
011111.. ...01001 0x03 0xa6 <!-- mtspr CTR, rxx -->
|
||||
0x4e 10000... 0x04 0x20 <!--bctr -->
|
||||
</data>
|
||||
<funcstart thunk="true"/>
|
||||
</pattern>
|
||||
|
||||
<!--
|
||||
Known call stub (i.e., thunk) patterns which
|
||||
utilize a propagated r2 register value in determining the thunked function
|
||||
to which any given call stub branches.
|
||||
|
||||
NOTE: Each pattern must account for all instructions contained within the stub.
|
||||
-->
|
||||
<pattern>
|
||||
<data>
|
||||
0x....823d # addis r12,r2,0x####
|
||||
0x..0041f8 # std r2,0x##(r1)
|
||||
0x....6ce9 # ld r11,0x####(r12)
|
||||
0xa603697d # mtspr CTR,r11
|
||||
0x....4ce8 # ld r2,0x####(r12)
|
||||
0x....6ce9 # ld r11,0x####(r12)
|
||||
0x2004804e # bctr
|
||||
</data>
|
||||
<funcstart thunk="true"/>
|
||||
</pattern>
|
||||
<pattern>
|
||||
<data>
|
||||
0x..0041f8 # std r2,0x##(r1)
|
||||
0x....62e9 # ld r11,0x####(r2)
|
||||
0xa603697d # mtspr CTR,r11
|
||||
0x....62e9 # ld r11,0x####(r2)
|
||||
0x....42e8 # ld r2,0x####(r2)
|
||||
0x2004804e # bctr
|
||||
</data>
|
||||
<funcstart thunk="true"/>
|
||||
</pattern>
|
||||
<pattern>
|
||||
<data>
|
||||
0x..0041f8 # std r2,0x##(r1)
|
||||
0x....82e9 # ld r12,0x####(r2)
|
||||
0xa603897d # mtspr CTR,r12
|
||||
0x2004804e # bctr
|
||||
</data>
|
||||
<funcstart after="defined" thunk="true"/>
|
||||
</pattern>
|
||||
<!-- It is possible that the patterns below always appear inline and not used as a thunk -->
|
||||
<pattern>
|
||||
<data>
|
||||
0x....623d # addis r11,r2,0x####
|
||||
0x....8be9 # ld r12,0x####(r11)
|
||||
0xa603897d # mtspr CTR,r12
|
||||
0x....4be8 # ld r2,0x####(r11)
|
||||
0x2004804e # bctr
|
||||
</data>
|
||||
<possiblefuncstart thunk="true"/>
|
||||
</pattern>
|
||||
<pattern>
|
||||
<data>
|
||||
0x....623d # addis r11,r2,0x####
|
||||
0x....8be9 # ld r12,0x####(r11)
|
||||
0x....6b39 # addi r11,r11,0x####
|
||||
0xa603897d # mtspr CTR,r12
|
||||
0x....4be8 # ld r2,0x####(r11)
|
||||
0x....6be9 # ld r11,0x####(r11)
|
||||
0x2004804e # bctr
|
||||
</data>
|
||||
<possiblefuncstart thunk="true"/>
|
||||
</pattern>
|
||||
<pattern>
|
||||
<data>
|
||||
0x....623d # addis r11,r2,0x####
|
||||
0x....8be9 # ld r12,0x####(r11)
|
||||
0xa603897d # mtspr CTR,r12
|
||||
0x7862827d # xor r2,r12,r12
|
||||
0x14126b7d # add r11,r11,r2
|
||||
0x....4be8 # ld r2,0x####(r11)
|
||||
0x2004804e # bctr
|
||||
</data>
|
||||
<possiblefuncstart thunk="true"/>
|
||||
</pattern>
|
||||
<pattern>
|
||||
<data>
|
||||
0x....623d # addis r11,r2,0x####
|
||||
0x....8be9 # ld r12,0x####(r11)
|
||||
0x....6b39 # addi r11,r11,0x####
|
||||
0xa603897d # mtspr CTR,r12
|
||||
0x7862827d # xor r2,r12,r12
|
||||
0x14126b7d # add r11,r11,r2
|
||||
0x....4be8 # ld r2,0x####(r11)
|
||||
0x....6be9 # ld r11,0x####(r11)
|
||||
0x2004804e # bctr
|
||||
</data>
|
||||
<possiblefuncstart thunk="true"/>
|
||||
</pattern>
|
||||
<pattern>
|
||||
<data>
|
||||
0x..0041f8 # std r2,0x##(r1)
|
||||
0x....623d # addis r11,r2,0x####
|
||||
0x....8be9 # ld r12,0x####(r11)
|
||||
0xa603897d # mtspr CTR,r12
|
||||
0x....4be8 # ld r2,0x####(r11)
|
||||
0x2004804e # bctr
|
||||
</data>
|
||||
<possiblefuncstart thunk="true"/>
|
||||
</pattern>
|
||||
<pattern>
|
||||
<data>
|
||||
0x..0041f8 # std r2,0x##(r1)
|
||||
0x....623d # addis r11,r2,0x####
|
||||
0x....8be9 # ld r12,0x####(r11)
|
||||
0x....6b39 # addi r11,r11,0x####
|
||||
0xa603897d # mtspr CTR,r12
|
||||
0x....4be8 # ld r2,0x####(r11)
|
||||
0x....6be9 # ld r11,0x####(r11)
|
||||
0x2004804e # bctr
|
||||
</data>
|
||||
<possiblefuncstart thunk="true"/>
|
||||
</pattern>
|
||||
<pattern>
|
||||
<data>
|
||||
0x..0041f8 # std r2,0x##(r1)
|
||||
0x....623d # addis r11,r2,0x####
|
||||
0x....8be9 # ld r12,0x####(r11)
|
||||
0xa603897d # mtspr CTR,r12
|
||||
0x7862827d # xor r2,r12,r12
|
||||
0x14126b7d # add r11,r11,r2
|
||||
0x....4be8 # ld r2,0x####(r11)
|
||||
0x2004804e # bctr
|
||||
</data>
|
||||
<possiblefuncstart thunk="true"/>
|
||||
</pattern>
|
||||
<pattern>
|
||||
<data>
|
||||
0x..0041f8 # std r2,0x##(r1)
|
||||
0x....623d # addis r11,r2,0x####
|
||||
0x....8be9 # ld r12,0x####(r11)
|
||||
0x....6b39 # addi r11,r11,0x####
|
||||
0xa603897d # mtspr CTR,r12
|
||||
0x7862827d # xor r2,r12,r12
|
||||
0x14126b7d # add r11,r11,r2
|
||||
0x....4be8 # ld r2,0x####(r11)
|
||||
0x....6be9 # ld r11,0x####(r11)
|
||||
0x2004804e # bctr
|
||||
</data>
|
||||
<possiblefuncstart thunk="true"/>
|
||||
</pattern>
|
||||
<!--
|
||||
The case where call stub performs conditional bnectr followed
|
||||
by relative branch is omitted since this is not a valid thunk
|
||||
scenario.
|
||||
-->
|
||||
<pattern>
|
||||
<data>
|
||||
0x0000823d # addis r12,r2,0x####
|
||||
0x00008ce9 # ld r12,0x####(r12)
|
||||
0xa603897d # mtspr CTR,r12
|
||||
0x2004804e # bctr
|
||||
</data>
|
||||
<possiblefuncstart thunk="true"/>
|
||||
</pattern>
|
||||
<pattern>
|
||||
<data>
|
||||
0x000041f8 # std r2,0x####(r1)
|
||||
0x0000823d # addis r12,r2,0x####
|
||||
0x00008ce9 # ld r12,0x####(r12)
|
||||
0xa603897d # mtspr CTR,r12
|
||||
0x2004804e # bctr
|
||||
</data>
|
||||
<possiblefuncstart thunk="true"/>
|
||||
</pattern>
|
||||
</patternlist>
|
||||
@@ -1,12 +1,52 @@
|
||||
<patternlist>
|
||||
<patternlist>
|
||||
|
||||
<pattern> <!-- .plt entry thunk -->
|
||||
<data>
|
||||
0x280041f8 <!-- std r2,0x28(r1) -->
|
||||
0xff 0xff ...00010 001111.. <!-- subis rX,r2,0x1 -->
|
||||
........ ........ ........ 0xe9 <!-- ld rX,#(x) -->
|
||||
0xa6 0x03 0x.9 0x7d <!-- mtctr rX -->
|
||||
........ ........ 010..... 0xe8 <!-- ld r2,#(x) -->
|
||||
0x00002228 <!-- cmpldi r2,0 -->
|
||||
0x20 0x04 1..00010 0x4c <!-- bnectr+ -->
|
||||
......00 ........ ........ 010010.. <!-- b X@plt -->
|
||||
</data>
|
||||
<funcstart thunk="true" section="(?i)(\.plt(\.sec)?)"/> <!-- must be something define before this -->
|
||||
</pattern>
|
||||
|
||||
<pattern> <!-- .plt entry thunk -->
|
||||
<data>
|
||||
0x280041f8 <!-- std r2,0x28(r1) -->
|
||||
........ ........ ........ 0xe9 <!-- ld rX,#(x) -->
|
||||
0xa6 0x03 0x.9 0x7d <!-- mtctr rX -->
|
||||
........ ........ 010..... 0xe8 <!-- ld r2,#(x) -->
|
||||
0x00002228 <!-- cmpldi r2,0 -->
|
||||
0x20 0x04 1..00010 0x4c <!-- bnectr+ -->
|
||||
......00 ........ ........ 010010.. <!-- b X@plt -->
|
||||
</data>
|
||||
<funcstart thunk="true" section="(?i)(\.plt(\.sec)?)"/> <!-- must be something define before this -->
|
||||
</pattern>
|
||||
|
||||
<pattern> <!-- .plt entry thunk -->
|
||||
<data>
|
||||
0xa6 0x02 ...01000 011111.. <!-- mfspr rxx, LR -->
|
||||
0x05 0x00 1....... 0x42 <!-- bl +0x4 -->
|
||||
0xa6 0x02 ...01000 011111.. <!-- mfspr rxx,LR -->
|
||||
0x.. 0x.. ........ 001111.. <!-- addis rxx, rxx, 0xxx -->
|
||||
0x.. 0x.. ........ 001110.. <!-- addi rxx, rxx, 0xxx -->
|
||||
0xa6 0x03 ...01000 011111.. <!-- mtspr LR, rxx -->
|
||||
0xa6 0x03 ...01001 011111.. <!-- mtspr CTR, rxx -->
|
||||
0x20 0x04 10000... 0x4e <!--bctr -->
|
||||
</data>
|
||||
<funcstart thunk="true"/>
|
||||
</pattern>
|
||||
|
||||
<!--
|
||||
This file contains all known call stub (i.e., thunk) patterns which
|
||||
Known call stub (i.e., thunk) patterns which
|
||||
utilize a propagated r2 register value in determining the thunked function
|
||||
to which any given call stub branches.
|
||||
|
||||
NOTES:
|
||||
1. Each pattern must account for all instructions contained within the stub.
|
||||
2. Only 4-byte instructions are supported (due to pattern flipping for little endian use)
|
||||
NOTE: Each pattern must account for all instructions contained within the stub.
|
||||
-->
|
||||
<pattern>
|
||||
<data>
|
||||
@@ -18,6 +58,7 @@
|
||||
0xe96c.... # ld r11,0x####(r12)
|
||||
0x4e800420 # bctr
|
||||
</data>
|
||||
<funcstart thunk="true"/>
|
||||
</pattern>
|
||||
<pattern>
|
||||
<data>
|
||||
@@ -28,6 +69,7 @@
|
||||
0xe842.... # ld r2,0x####(r2)
|
||||
0x4e800420 # bctr
|
||||
</data>
|
||||
<funcstart thunk="true"/>
|
||||
</pattern>
|
||||
<pattern>
|
||||
<data>
|
||||
@@ -36,6 +78,7 @@
|
||||
0x7d8903a6 # mtspr CTR,r12
|
||||
0x4e800420 # bctr
|
||||
</data>
|
||||
<funcstart after="defined" thunk="true"/>
|
||||
</pattern>
|
||||
<!-- It is possible that the patterns below always appear inline and not used as a thunk -->
|
||||
<pattern>
|
||||
@@ -46,6 +89,7 @@
|
||||
0xe84b.... # ld r2,0x####(r11)
|
||||
0x4e800420 # bctr
|
||||
</data>
|
||||
<possiblefuncstart thunk="true"/>
|
||||
</pattern>
|
||||
<pattern>
|
||||
<data>
|
||||
@@ -57,6 +101,7 @@
|
||||
0xe96b.... # ld r11,0x####(r11)
|
||||
0x4e800420 # bctr
|
||||
</data>
|
||||
<possiblefuncstart thunk="true"/>
|
||||
</pattern>
|
||||
<pattern>
|
||||
<data>
|
||||
@@ -68,6 +113,7 @@
|
||||
0xe84b.... # ld r2,0x####(r11)
|
||||
0x4e800420 # bctr
|
||||
</data>
|
||||
<possiblefuncstart thunk="true"/>
|
||||
</pattern>
|
||||
<pattern>
|
||||
<data>
|
||||
@@ -81,6 +127,7 @@
|
||||
0xe96b.... # ld r11,0x####(r11)
|
||||
0x4e800420 # bctr
|
||||
</data>
|
||||
<possiblefuncstart thunk="true"/>
|
||||
</pattern>
|
||||
<pattern>
|
||||
<data>
|
||||
@@ -91,6 +138,7 @@
|
||||
0xe84b.... # ld r2,0x####(r11)
|
||||
0x4e800420 # bctr
|
||||
</data>
|
||||
<possiblefuncstart thunk="true"/>
|
||||
</pattern>
|
||||
<pattern>
|
||||
<data>
|
||||
@@ -103,6 +151,7 @@
|
||||
0xe96b.... # ld r11,0x####(r11)
|
||||
0x4e800420 # bctr
|
||||
</data>
|
||||
<possiblefuncstart thunk="true"/>
|
||||
</pattern>
|
||||
<pattern>
|
||||
<data>
|
||||
@@ -115,6 +164,7 @@
|
||||
0xe84b.... # ld r2,0x####(r11)
|
||||
0x4e800420 # bctr
|
||||
</data>
|
||||
<possiblefuncstart thunk="true"/>
|
||||
</pattern>
|
||||
<pattern>
|
||||
<data>
|
||||
@@ -129,6 +179,7 @@
|
||||
0xe96b.... # ld r11,0x####(r11)
|
||||
0x4e800420 # bctr
|
||||
</data>
|
||||
<possiblefuncstart thunk="true"/>
|
||||
</pattern>
|
||||
<!--
|
||||
The case where call stub performs conditional bnectr followed
|
||||
@@ -142,6 +193,7 @@
|
||||
0x7d8903a6 # mtspr CTR,r12
|
||||
0x4e800420 # bctr
|
||||
</data>
|
||||
<possiblefuncstart thunk="true"/>
|
||||
</pattern>
|
||||
<pattern>
|
||||
<data>
|
||||
@@ -151,5 +203,6 @@
|
||||
0x7d8903a6 # mtspr CTR,r12
|
||||
0x4e800420 # bctr
|
||||
</data>
|
||||
</pattern>
|
||||
<possiblefuncstart thunk="true"/>
|
||||
</pattern>
|
||||
</patternlist>
|
||||
@@ -0,0 +1,8 @@
|
||||
<patternconstraints>
|
||||
<language id="PowerPC:BE:*:*">
|
||||
<patternfile>PPC_BE_prepatterns.xml</patternfile>
|
||||
</language>
|
||||
<language id="PowerPC:LE:*:*">
|
||||
<patternfile>PPC_LE_prepatterns.xml</patternfile>
|
||||
</language>
|
||||
</patternconstraints>
|
||||
@@ -1,389 +0,0 @@
|
||||
/* ###
|
||||
* 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 java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import generic.jar.ResourceFile;
|
||||
import ghidra.app.cmd.disassemble.DisassembleCommand;
|
||||
import ghidra.app.cmd.function.CreateFunctionCmd;
|
||||
import ghidra.app.cmd.function.CreateThunkFunctionCmd;
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.symbol.RefType;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.program.util.*;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.bytesearch.*;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class PPC64CallStubAnalyzer extends AbstractAnalyzer {
|
||||
|
||||
private static final String NAME = "PPC64 ELF Call Stubs";
|
||||
private static final String DESCRIPTION = "Detect ELF Call Stubs and create thunk function";
|
||||
private static final String PROCESSOR_NAME = "PowerPC";
|
||||
|
||||
private static final String CALL_STUB_PATTERN_FILE = "ppc64-r2CallStubs.xml";
|
||||
|
||||
private static final String UNKNOWN_FUNCTION_NAME = "___UNKNOWN_CALL_STUB___";
|
||||
|
||||
private static boolean patternLoadFailed;
|
||||
private static ArrayList<Pattern> beCallStubPatterns;
|
||||
private static ArrayList<Pattern> leCallStubPatterns;
|
||||
private static int maxPatternLength;
|
||||
|
||||
private Register r2Reg;
|
||||
private Register ctrReg;
|
||||
|
||||
public PPC64CallStubAnalyzer() {
|
||||
super(NAME, DESCRIPTION, AnalyzerType.FUNCTION_ANALYZER);
|
||||
setDefaultEnablement(true);
|
||||
setPriority(AnalysisPriority.FUNCTION_ANALYSIS.before());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAnalyze(Program program) {
|
||||
Language language = program.getLanguage();
|
||||
// TODO: what about 32/64 hybrid case?
|
||||
if (PROCESSOR_NAME.equals(language.getProcessor().toString()) &&
|
||||
language.getLanguageDescription().getSize() == 64 &&
|
||||
patternsLoaded(language.isBigEndian())) {
|
||||
r2Reg = program.getRegister("r2");
|
||||
ctrReg = program.getRegister("CTR");
|
||||
return r2Reg != null && ctrReg != null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static synchronized boolean patternsLoaded(boolean bigEndian) {
|
||||
if (patternLoadFailed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bigEndian) {
|
||||
if (leCallStubPatterns != null) {
|
||||
return true;
|
||||
}
|
||||
if (!patternsLoaded(true)) {
|
||||
return false;
|
||||
}
|
||||
leCallStubPatterns = flipPatterns(beCallStubPatterns);
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
ResourceFile patternFile = Application.getModuleDataFile(CALL_STUB_PATTERN_FILE);
|
||||
|
||||
beCallStubPatterns = new ArrayList<>();
|
||||
Pattern.readPatterns(patternFile, beCallStubPatterns, null);
|
||||
|
||||
maxPatternLength = 0;
|
||||
for (Pattern pattern : beCallStubPatterns) {
|
||||
int len = pattern.getSize();
|
||||
if ((len % 4) != 0) {
|
||||
throw new SAXException("pattern must contain multiple of 4-bytes");
|
||||
}
|
||||
if (len > maxPatternLength) {
|
||||
maxPatternLength = len;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (FileNotFoundException e) {
|
||||
Msg.error(PPC64CallStubAnalyzer.class, "PowerPC resource file not found: " + CALL_STUB_PATTERN_FILE);
|
||||
patternLoadFailed = true;
|
||||
return false;
|
||||
} catch (SAXException | IOException e) {
|
||||
Msg.error(PPC64CallStubAnalyzer.class, "Failed to parse byte pattern file: " + CALL_STUB_PATTERN_FILE, e);
|
||||
patternLoadFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static ArrayList<Pattern> flipPatterns(ArrayList<Pattern> patternlist) {
|
||||
|
||||
ArrayList<Pattern> list = new ArrayList<>();
|
||||
for (Pattern pat : patternlist) {
|
||||
byte[] bytes = flipPatternBytes(pat.getValueBytes());
|
||||
byte[] mask = flipPatternBytes(pat.getMaskBytes());
|
||||
Pattern newPattern = new Pattern(new DittedBitSequence(bytes, mask), pat.getMarkOffset(),
|
||||
pat.getPostRules(), pat.getMatchActions());
|
||||
list.add(newPattern);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private static byte[] flipPatternBytes(byte[] bytes) {
|
||||
for (int i = 0; i < bytes.length; i += 4) {
|
||||
byte b = bytes[i];
|
||||
bytes[i] = bytes[i + 3];
|
||||
bytes[i + 3] = b;
|
||||
b = bytes[i + 1];
|
||||
bytes[i + 1] = bytes[i + 2];
|
||||
bytes[i + 2] = b;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
|
||||
throws CancelledException {
|
||||
|
||||
Memory memory = program.getMemory();
|
||||
Listing listing = program.getListing();
|
||||
ProgramContext programContext = program.getProgramContext();
|
||||
|
||||
SequenceSearchState sequenceSearchState = SequenceSearchState.buildStateMachine(
|
||||
program.getMemory().isBigEndian() ? beCallStubPatterns : leCallStubPatterns);
|
||||
|
||||
monitor.setIndeterminate(false);
|
||||
monitor.setMaximum(set.getNumAddresses());
|
||||
monitor.setProgress(0);
|
||||
int functionCount = 0;
|
||||
|
||||
// each address should correspond to a function
|
||||
for (Function function : listing.getFunctions(set, true)) {
|
||||
|
||||
monitor.checkCancelled();
|
||||
monitor.setProgress(functionCount++);
|
||||
|
||||
Address entryAddr = function.getEntryPoint();
|
||||
boolean isThunk = function.isThunk();
|
||||
|
||||
Match stubMatch = null;
|
||||
if (!isThunk) {
|
||||
stubMatch = matchKnownCallStubs(entryAddr, memory, sequenceSearchState);
|
||||
if (stubMatch == null) {
|
||||
continue; // non-stub
|
||||
}
|
||||
}
|
||||
else if (!thunksUnknownFunction(function)) {
|
||||
continue; // previously resolved thunk
|
||||
}
|
||||
|
||||
RegisterValue r2Value = programContext.getRegisterValue(r2Reg, entryAddr);
|
||||
if (r2Value == null || !r2Value.hasValue()) {
|
||||
if (!isThunk) { // stubMatch is known
|
||||
// Thunk unknown function for future processing once r2 is propagated
|
||||
createThunk(program, entryAddr, stubMatch.getSequenceSize(), getUnknownFunction(
|
||||
program).getEntryPoint());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
int stubLength = stubMatch != null ? stubMatch.getSequenceSize()
|
||||
: (int) function.getBody().getNumAddresses();
|
||||
|
||||
analyzeCallStub(program, function, stubLength, monitor);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Match matchKnownCallStubs(Address addr, Memory memory,
|
||||
SequenceSearchState sequenceSearchState) {
|
||||
byte[] bytes = new byte[maxPatternLength];
|
||||
ArrayList<Match> matches = new ArrayList<>();
|
||||
int cnt = 0;
|
||||
try {
|
||||
cnt = memory.getBytes(addr, bytes);
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
// ignore
|
||||
}
|
||||
if (cnt == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] searchBytes = bytes;
|
||||
if (cnt != bytes.length) {
|
||||
// although rare, shorten searchBytes if unable to fill
|
||||
searchBytes = new byte[cnt];
|
||||
System.arraycopy(bytes, 0, searchBytes, 0, cnt);
|
||||
}
|
||||
|
||||
matches.clear();
|
||||
sequenceSearchState.apply(searchBytes, matches);
|
||||
if (matches.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return matches.get(0);
|
||||
}
|
||||
|
||||
private void createThunk(Program program, Address stubAddr, int stubLength,
|
||||
Address thunkedFunctionAddr) {
|
||||
AddressSet stubBody = new AddressSet(stubAddr, stubAddr.add(stubLength - 1));
|
||||
CreateThunkFunctionCmd cmd = new CreateThunkFunctionCmd(stubAddr, stubBody,
|
||||
thunkedFunctionAddr);
|
||||
cmd.applyTo(program);
|
||||
}
|
||||
|
||||
private void analyzeCallStub(Program program, Function stubFunction, int stubLength,
|
||||
TaskMonitor monitor) throws CancelledException {
|
||||
|
||||
SymbolicPropogator symEval = new SymbolicPropogator(program, false);
|
||||
symEval.setParamRefCheck(false);
|
||||
symEval.setReturnRefCheck(false);
|
||||
symEval.setStoredRefCheck(false);
|
||||
|
||||
Address entryAddr = stubFunction.getEntryPoint();
|
||||
AddressSet stubBody = new AddressSet(entryAddr, entryAddr.add(stubLength - 1));
|
||||
|
||||
ContextEvaluator eval = new ContextEvaluatorAdapter() {
|
||||
|
||||
@Override
|
||||
public boolean followFalseConditionalBranches() {
|
||||
return false; // should never happen - just in case
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, Address address,
|
||||
int size, DataType dataType, RefType refType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean evaluateDestination(VarnodeContext context, Instruction instruction) {
|
||||
|
||||
// We only handle indirect branch through CTR register
|
||||
if (!"bctr".equals(instruction.getMnemonicString())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Change bctr flow to call-return
|
||||
instruction.setFlowOverride(FlowOverride.CALL_RETURN);
|
||||
|
||||
RegisterValue ctrValue = context.getRegisterValue(ctrReg);
|
||||
if (ctrValue != null && ctrValue.hasValue()) {
|
||||
Address destAddr = entryAddr.getNewAddress(
|
||||
ctrValue.getUnsignedValue().longValue());
|
||||
Function destFunction = createDestinationFunction(program, destAddr,
|
||||
instruction.getAddress(), context.getRegisterValue(r2Reg), monitor);
|
||||
if (destFunction != null) {
|
||||
if (!stubFunction.isThunk()) {
|
||||
createThunk(program, entryAddr, stubLength,
|
||||
destFunction.getEntryPoint());
|
||||
}
|
||||
else {
|
||||
stubFunction.setThunkedFunction(destFunction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowAccess(VarnodeContext context, Address address) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
symEval.flowConstants(entryAddr, stubBody, eval, false, monitor);
|
||||
}
|
||||
|
||||
private Function getUnknownFunction(Program program) {
|
||||
|
||||
try {
|
||||
return program.getExternalManager().addExtFunction(Library.UNKNOWN,
|
||||
UNKNOWN_FUNCTION_NAME, null, SourceType.IMPORTED).getFunction();
|
||||
}
|
||||
catch (InvalidInputException | DuplicateNameException e) {
|
||||
throw new AssertException("unexpected", e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean thunksUnknownFunction(Function function) {
|
||||
Function thunkedFunction = function.getThunkedFunction(false);
|
||||
if (thunkedFunction == null || !thunkedFunction.isExternal()) {
|
||||
return false;
|
||||
}
|
||||
return UNKNOWN_FUNCTION_NAME.equals(thunkedFunction.getName());
|
||||
}
|
||||
|
||||
private Function createDestinationFunction(Program program, Address addr, Address flowFromAddr,
|
||||
RegisterValue regValue, TaskMonitor monitor) {
|
||||
|
||||
Listing listing = program.getListing();
|
||||
BookmarkManager bookmarkMgr = program.getBookmarkManager();
|
||||
|
||||
if (!program.getMemory().contains(addr)) {
|
||||
bookmarkMgr.setBookmark(flowFromAddr, BookmarkType.ERROR, "Bad Reference", "No memory for call stub destination at " + addr);
|
||||
return null;
|
||||
}
|
||||
|
||||
Function function = listing.getFunctionAt(addr);
|
||||
|
||||
if (regValue != null && regValue.hasValue()) {
|
||||
ProgramContext programContext = program.getProgramContext();
|
||||
RegisterValue oldValue = programContext.getRegisterValue(regValue.getRegister(), addr);
|
||||
if (oldValue == null || !oldValue.hasValue()) {
|
||||
try {
|
||||
programContext.setRegisterValue(addr, addr, regValue);
|
||||
} catch (ContextChangeException e) {
|
||||
throw new AssertException(e);
|
||||
}
|
||||
if (function != null) {
|
||||
AutoAnalysisManager.getAnalysisManager(program).functionDefined(addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (function != null) {
|
||||
return function;
|
||||
}
|
||||
|
||||
CodeUnit cu = listing.getCodeUnitContaining(addr);
|
||||
if (cu == null) {
|
||||
throw new AssertException("expected code unit in memory");
|
||||
}
|
||||
if (!addr.equals(cu.getMinAddress())) {
|
||||
bookmarkMgr.setBookmark(cu.getMinAddress(), BookmarkType.ERROR, "Code Unit Conflict", "Expected function entry at " + addr + " referenced by call stub from " + flowFromAddr);
|
||||
return null;
|
||||
}
|
||||
if (cu instanceof Data) {
|
||||
Data d = (Data)cu;
|
||||
if (d.isDefined()) {
|
||||
bookmarkMgr.setBookmark(addr, BookmarkType.ERROR, "Code Unit Conflict", "Expected function entry referenced by call stub from " + flowFromAddr);
|
||||
return null;
|
||||
}
|
||||
DisassembleCommand cmd = new DisassembleCommand(addr, null, true);
|
||||
if (!cmd.applyTo(program, monitor)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
CreateFunctionCmd cmd = new CreateFunctionCmd(addr);
|
||||
if (cmd.applyTo(program, monitor)) {
|
||||
return cmd.getFunction();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user