mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 09:49:23 +02:00
GP-5411 Added plt thunk patterns, pre-fill of edit thunk GUI, loosened
thunk address calculation for more complicated thunks
This commit is contained in:
parent
c2533aaf6e
commit
208f6f3ed1
4 changed files with 127 additions and 33 deletions
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -15,6 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.cmd.function;
|
package ghidra.app.cmd.function;
|
||||||
|
|
||||||
|
import static ghidra.program.model.symbol.RefType.*;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
@ -732,36 +734,66 @@ public class CreateThunkFunctionCmd extends BackgroundCommand<Program> {
|
||||||
FlowType flowType, boolean checkForSideEffects, HashSet<Varnode> setRegisters,
|
FlowType flowType, boolean checkForSideEffects, HashSet<Varnode> setRegisters,
|
||||||
HashSet<Varnode> usedRegisters) {
|
HashSet<Varnode> usedRegisters) {
|
||||||
|
|
||||||
// conditional jumps can't be thunks.
|
// conditional jumps/call terminators can't be thunks,
|
||||||
// any other flow, not good
|
// unless not checkingForSideEffects and just trying to get possible thunk address.
|
||||||
Address flowingAddr = null;
|
|
||||||
if ((flowType.isJump() || flowType.equals(RefType.COMPUTED_CALL_TERMINATOR) ||
|
boolean isJump = flowType.isJump();
|
||||||
flowType.equals(RefType.CALL_TERMINATOR)) && !flowType.isConditional()) {
|
boolean isCall = flowType.isCall();
|
||||||
// program counter should be assumed to be used
|
boolean isConditional = flowType.isConditional();
|
||||||
|
|
||||||
// assume PC is used when considering registers that have been set
|
// only jump/call are allowed
|
||||||
Register PC = program.getLanguage().getProgramCounter();
|
if (!(isJump || isCall)) {
|
||||||
if (PC != null) {
|
return null;
|
||||||
usedRegisters.add(new Varnode(PC.getAddress(), PC.getMinimumByteSize()));
|
}
|
||||||
|
|
||||||
|
// no conditional jumps allowed
|
||||||
|
if (isJump && isConditional) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isCall) {
|
||||||
|
// Any conditional call considered as having side-effects
|
||||||
|
if (isConditional && checkForSideEffects) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
setRegisters.removeAll(usedRegisters);
|
// CALL_TERMINATOR, COMPUTED_CALL_TERMINATOR
|
||||||
|
else if (!flowType.isTerminal()) {
|
||||||
// check that the setRegisters are all hidden, meaning don't care.
|
if (flowType == COMPUTED_CALL ||
|
||||||
for (Iterator<Varnode> iterator = setRegisters.iterator(); iterator.hasNext();) {
|
flowType == UNCONDITIONAL_CALL) {
|
||||||
Varnode rvnode = iterator.next();
|
// consider any simple call having side-effects
|
||||||
Register reg = program.getRegister(rvnode);
|
if (checkForSideEffects) {
|
||||||
// the register pcode access could have fallen in the middle of a valid register
|
return null;
|
||||||
// thus no register will exist at the varnode
|
}
|
||||||
if (reg != null && reg.isHidden()) {
|
|
||||||
iterator.remove();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// program counter should be assumed to be used
|
||||||
|
// assume PC is used when considering registers that have been set
|
||||||
|
Register PC = program.getLanguage().getProgramCounter();
|
||||||
|
if (PC != null) {
|
||||||
|
usedRegisters.add(new Varnode(PC.getAddress(), PC.getMinimumByteSize()));
|
||||||
|
}
|
||||||
|
setRegisters.removeAll(usedRegisters);
|
||||||
|
|
||||||
// if not checking for sideEffect registers set, or there are no side-effects
|
// check that the setRegisters are all hidden, meaning don't care.
|
||||||
if (!checkForSideEffects || setRegisters.size() == 0) {
|
for (Iterator<Varnode> iterator = setRegisters.iterator(); iterator.hasNext();) {
|
||||||
flowingAddr = getFlowingAddress(program, instr);
|
Varnode rvnode = iterator.next();
|
||||||
|
Register reg = program.getRegister(rvnode);
|
||||||
|
// the register pcode access could have fallen in the middle of a valid register
|
||||||
|
// thus no register will exist at the varnode
|
||||||
|
if (reg != null && reg.isHidden()) {
|
||||||
|
iterator.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Address flowingAddr = null;
|
||||||
|
|
||||||
|
// if not checking for sideEffect registers set, or there are no side-effects
|
||||||
|
if (!checkForSideEffects || setRegisters.size() == 0) {
|
||||||
|
flowingAddr = getFlowingAddress(program, instr);
|
||||||
|
}
|
||||||
|
|
||||||
return flowingAddr;
|
return flowingAddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -72,22 +72,30 @@ class EditThunkFunctionAction extends ProgramContextAction {
|
||||||
if (func == null) {
|
if (func == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Address funcEntry = func.getEntryPoint();
|
||||||
|
|
||||||
Function refFunc = func.getThunkedFunction(false);
|
Function refFunc = func.getThunkedFunction(false);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Symbol refSymbol = (refFunc == null ? null : refFunc.getSymbol());
|
||||||
|
|
||||||
// Prompt for function referenced by thunk
|
// Prompt for function referenced by thunk
|
||||||
ThunkReferenceAddressDialog dialog = new ThunkReferenceAddressDialog(funcPlugin.getTool());
|
ThunkReferenceAddressDialog dialog = new ThunkReferenceAddressDialog(funcPlugin.getTool());
|
||||||
dialog.showDialog(program, func.getEntryPoint(),
|
dialog.showDialog(program, funcEntry, refSymbol);
|
||||||
refFunc != null ? refFunc.getSymbol() : null);
|
|
||||||
Symbol referencedSymbol = dialog.getSymbol();
|
Symbol referencedSymbol = dialog.getSymbol();
|
||||||
Address referencedFunctionAddr = dialog.getAddress();
|
Address referencedFunctionAddr = dialog.getAddress();
|
||||||
|
|
||||||
CreateThunkFunctionCmd cmd;
|
CreateThunkFunctionCmd cmd;
|
||||||
if (referencedSymbol != null) {
|
if (referencedSymbol != null) {
|
||||||
cmd = new CreateThunkFunctionCmd(func.getEntryPoint(), null, referencedSymbol);
|
cmd = new CreateThunkFunctionCmd(funcEntry, null, referencedSymbol);
|
||||||
}
|
}
|
||||||
else if (referencedFunctionAddr != null) {
|
else if (referencedFunctionAddr != null) {
|
||||||
cmd = new CreateThunkFunctionCmd(func.getEntryPoint(), null, referencedFunctionAddr);
|
cmd = new CreateThunkFunctionCmd(funcEntry, null, referencedFunctionAddr);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return; // cancelled
|
return; // cancelled
|
||||||
|
|
|
@ -36,4 +36,31 @@
|
||||||
<possiblefuncstart validcode="function" label="__get_pc_thunk_lr" /> <!-- must be a function here -->
|
<possiblefuncstart validcode="function" label="__get_pc_thunk_lr" /> <!-- must be a function here -->
|
||||||
</pattern>
|
</pattern>
|
||||||
|
|
||||||
|
<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 after="defined" thunk="true"/> <!-- 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 after="defined" thunk="true"/> <!-- must be something define before this -->
|
||||||
|
</pattern>
|
||||||
|
|
||||||
</patternlist>
|
</patternlist>
|
||||||
|
|
|
@ -35,5 +35,32 @@
|
||||||
<data>0x21 0x00 0x80 0x4e</data> <!-- blrl -->
|
<data>0x21 0x00 0x80 0x4e</data> <!-- blrl -->
|
||||||
<possiblefuncstart validcode="function" label="__get_pc_thunk_lr" /> <!-- must be a function here -->
|
<possiblefuncstart validcode="function" label="__get_pc_thunk_lr" /> <!-- must be a function here -->
|
||||||
</pattern>
|
</pattern>
|
||||||
|
|
||||||
|
<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 after="defined" thunk="true"/> <!-- 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 after="defined" thunk="true"/> <!-- must be something define before this -->
|
||||||
|
</pattern>
|
||||||
|
|
||||||
</patternlist>
|
</patternlist>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue