mirror of
https://github.com/ttttupup/wxhelper.git
synced 2024-11-05 09:59:23 +08:00
feat: script
This commit is contained in:
parent
c49eaf9203
commit
36ecd7e349
23
app/base/src/include/function_resolver.h
Normal file
23
app/base/src/include/function_resolver.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#ifndef BASE_FUNCTION_RESOLVER_H_
|
||||||
|
#define BASE_FUNCTION_RESOLVER_H_
|
||||||
|
namespace base {
|
||||||
|
class FunctionResolver {
|
||||||
|
public:
|
||||||
|
explicit FunctionResolver(uint64_t base_addr) : base_addr_(base_addr) {}
|
||||||
|
|
||||||
|
template <typename FuncType>
|
||||||
|
FuncType ResolveFunction(uint64_t offset) {
|
||||||
|
return reinterpret_cast<FuncType>(base_addr_ + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint64_t base_addr_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename FuncType>
|
||||||
|
auto CastFunction(FunctionResolver& resolver, uint64_t offset) {
|
||||||
|
return resolver.ResolveFunction<FuncType>(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace base
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
236
script/ghidra_script/GraphFunctionFactory.java
Normal file
236
script/ghidra_script/GraphFunctionFactory.java
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.commons.collections4.BidiMap;
|
||||||
|
import org.apache.commons.collections4.bidimap.DualHashBidiMap;
|
||||||
|
|
||||||
|
import edu.uci.ics.jung.graph.Graph;
|
||||||
|
import generic.stl.Pair;
|
||||||
|
import ghidra.graph.GDirectedGraph;
|
||||||
|
import ghidra.graph.GEdge;
|
||||||
|
import ghidra.graph.jung.JungDirectedGraph;
|
||||||
|
import ghidra.program.model.address.AddressSetView;
|
||||||
|
import ghidra.program.model.block.BasicBlockModel;
|
||||||
|
import ghidra.program.model.block.CodeBlock;
|
||||||
|
import ghidra.program.model.block.CodeBlockIterator;
|
||||||
|
import ghidra.program.model.block.CodeBlockModel;
|
||||||
|
import ghidra.program.model.block.CodeBlockReference;
|
||||||
|
import ghidra.program.model.block.CodeBlockReferenceIterator;
|
||||||
|
import ghidra.program.model.block.graph.CodeBlockVertex;
|
||||||
|
import ghidra.program.model.listing.Function;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.model.symbol.FlowType;
|
||||||
|
import ghidra.util.exception.CancelledException;
|
||||||
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
|
public class GraphFunctionFactory {
|
||||||
|
|
||||||
|
public static Pair<GDirectedGraph<FunctionVertex, FunctionEdge>, BidiMap<CodeBlock, FunctionVertex>> createGraph(
|
||||||
|
Function f, TaskMonitor monitor) throws CancelledException {
|
||||||
|
if (monitor == null) {
|
||||||
|
monitor = TaskMonitor.DUMMY;
|
||||||
|
}
|
||||||
|
|
||||||
|
JungDirectedGraph<FunctionVertex, FunctionEdge> graph = new JungDirectedGraph<>();
|
||||||
|
|
||||||
|
BidiMap<CodeBlock, FunctionVertex> vertices = createVertices(f, monitor);
|
||||||
|
for (FunctionVertex v : vertices.values()) {
|
||||||
|
graph.addVertex(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
Collection<FunctionEdge> edges = createdEdges(vertices, monitor);
|
||||||
|
for (FunctionEdge e : edges) {
|
||||||
|
graph.addEdge(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// this must be done after the edges are added to the graph
|
||||||
|
for (FunctionVertex vertex : vertices.values()) {
|
||||||
|
vertex.setType(getVertexType(graph, vertex));
|
||||||
|
}
|
||||||
|
return new Pair<GDirectedGraph<FunctionVertex, FunctionEdge>, BidiMap<CodeBlock, FunctionVertex>>(graph,
|
||||||
|
vertices);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BidiMap<CodeBlock, FunctionVertex> createVertices(Function f, TaskMonitor monitor)
|
||||||
|
throws CancelledException {
|
||||||
|
|
||||||
|
BidiMap<CodeBlock, FunctionVertex> vertices = new DualHashBidiMap<>();
|
||||||
|
Program p = f.getProgram();
|
||||||
|
CodeBlockModel blockModel = new BasicBlockModel(p);
|
||||||
|
|
||||||
|
AddressSetView addresses = f.getBody();
|
||||||
|
CodeBlockIterator iterator = blockModel.getCodeBlocksContaining(addresses, monitor);
|
||||||
|
monitor.initialize(addresses.getNumAddresses());
|
||||||
|
|
||||||
|
for (; iterator.hasNext();) {
|
||||||
|
CodeBlock codeBlock = iterator.next();
|
||||||
|
|
||||||
|
FlowType flowType = codeBlock.getFlowType();
|
||||||
|
boolean isEntry = isEntry(codeBlock);
|
||||||
|
|
||||||
|
FunctionVertex vertex = new FunctionVertex(codeBlock, flowType, isEntry);
|
||||||
|
|
||||||
|
vertices.put(codeBlock, vertex);
|
||||||
|
|
||||||
|
long blockAddressCount = codeBlock.getNumAddresses();
|
||||||
|
long currentProgress = monitor.getProgress();
|
||||||
|
monitor.setProgress(currentProgress + blockAddressCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return vertices;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Collection<FunctionEdge> createdEdges(BidiMap<CodeBlock, FunctionVertex> vertices,
|
||||||
|
TaskMonitor monitor) throws CancelledException {
|
||||||
|
|
||||||
|
List<FunctionEdge> edges = new ArrayList<>();
|
||||||
|
for (FunctionVertex startVertex : vertices.values()) {
|
||||||
|
Collection<FunctionEdge> vertexEdges = getEdgesForStartVertex(vertices, startVertex, monitor);
|
||||||
|
|
||||||
|
edges.addAll(vertexEdges);
|
||||||
|
}
|
||||||
|
|
||||||
|
return edges;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Collection<FunctionEdge> getEdgesForStartVertex(BidiMap<CodeBlock, FunctionVertex> blockToVertexMap,
|
||||||
|
FunctionVertex startVertex, TaskMonitor monitor) throws CancelledException {
|
||||||
|
|
||||||
|
List<FunctionEdge> edges = new ArrayList<>();
|
||||||
|
CodeBlock codeBlock = blockToVertexMap.getKey(startVertex);
|
||||||
|
CodeBlockReferenceIterator destinations = codeBlock.getDestinations(monitor);
|
||||||
|
for (; destinations.hasNext();) {
|
||||||
|
CodeBlockReference reference = destinations.next();
|
||||||
|
CodeBlock destinationBlock = reference.getDestinationBlock();
|
||||||
|
FunctionVertex destinationVertex = blockToVertexMap.get(destinationBlock);
|
||||||
|
if (destinationVertex == null) {
|
||||||
|
continue;// no vertex means the code block is not in our function
|
||||||
|
}
|
||||||
|
|
||||||
|
edges.add(new FunctionEdge(startVertex, destinationVertex, reference.getFlowType()));
|
||||||
|
}
|
||||||
|
return edges;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static VertexType getVertexType(Graph<FunctionVertex, FunctionEdge> graph, FunctionVertex v) {
|
||||||
|
|
||||||
|
boolean isEntry = v.isEntry();
|
||||||
|
boolean isExit = false;
|
||||||
|
|
||||||
|
FlowType flowType = v.getFlowType();
|
||||||
|
if (flowType.isTerminal()) {
|
||||||
|
isExit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Collection<FunctionEdge> outs = graph.getOutEdges(v);
|
||||||
|
if (outs == null || outs.isEmpty()) {
|
||||||
|
isExit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
VertexType type = VertexType.BODY;
|
||||||
|
if (isEntry) {
|
||||||
|
if (isExit) {
|
||||||
|
type = VertexType.SINGLETON;
|
||||||
|
} else {
|
||||||
|
type = VertexType.ENTRY;
|
||||||
|
}
|
||||||
|
} else if (isExit) {
|
||||||
|
type = VertexType.EXIT;
|
||||||
|
}
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isEntry(CodeBlock codeBlock) {
|
||||||
|
boolean isSource = true;
|
||||||
|
try {
|
||||||
|
CodeBlockReferenceIterator iter = codeBlock.getSources(TaskMonitor.DUMMY);
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
isSource = false;
|
||||||
|
if (iter.next().getFlowType().isCall()) {
|
||||||
|
// any calls into a code block will make it an 'entry'
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (CancelledException e) {
|
||||||
|
// will never happen, because I don't have a monitor
|
||||||
|
}
|
||||||
|
return isSource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FunctionVertex extends CodeBlockVertex {
|
||||||
|
|
||||||
|
private VertexType type = VertexType.BODY;
|
||||||
|
private FlowType flowType;
|
||||||
|
private boolean isEntry;
|
||||||
|
|
||||||
|
public FunctionVertex(CodeBlock codeBlock, FlowType flowType, boolean isEntry) {
|
||||||
|
super(codeBlock);
|
||||||
|
this.flowType = flowType;
|
||||||
|
this.isEntry = isEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEntry() {
|
||||||
|
return isEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FlowType getFlowType() {
|
||||||
|
return flowType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VertexType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(VertexType type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FunctionEdge implements GEdge<FunctionVertex> {
|
||||||
|
|
||||||
|
private FunctionVertex start;
|
||||||
|
private FunctionVertex end;
|
||||||
|
private FlowType flowType;
|
||||||
|
|
||||||
|
public FunctionEdge(FunctionVertex start, FunctionVertex end, FlowType flowType) {
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
this.flowType = flowType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FlowType getFlowType() {
|
||||||
|
return flowType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FunctionVertex getStart() {
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FunctionVertex getEnd() {
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum VertexType {
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
BODY,
|
||||||
|
ENTRY,
|
||||||
|
EXIT,
|
||||||
|
GROUP,
|
||||||
|
SINGLETON;
|
||||||
|
//@formatter:on
|
||||||
|
|
||||||
|
public boolean isEntry() {
|
||||||
|
return this == ENTRY || this == SINGLETON;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isExit() {
|
||||||
|
return this == EXIT || this == SINGLETON;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
139
script/ghidra_script/RenameScript.java
Normal file
139
script/ghidra_script/RenameScript.java
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
/* ###
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// 根据一些日志类的相关函数的引用来获取当前函数的函数名
|
||||||
|
// 输入被调用函数的地址和可以作为函数名称的参数的位置
|
||||||
|
//
|
||||||
|
//@category Functions
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import ghidra.app.decompiler.DecompInterface;
|
||||||
|
import ghidra.app.decompiler.DecompileOptions;
|
||||||
|
import ghidra.app.decompiler.DecompileResults;
|
||||||
|
import ghidra.app.script.GhidraScript;
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.listing.CodeUnit;
|
||||||
|
import ghidra.program.model.listing.Data;
|
||||||
|
import ghidra.program.model.listing.Function;
|
||||||
|
import ghidra.program.model.pcode.HighFunction;
|
||||||
|
import ghidra.program.model.pcode.PcodeOp;
|
||||||
|
import ghidra.program.model.pcode.PcodeOpAST;
|
||||||
|
import ghidra.program.model.pcode.Varnode;
|
||||||
|
import ghidra.program.model.symbol.Reference;
|
||||||
|
import ghidra.program.model.symbol.ReferenceIterator;
|
||||||
|
import ghidra.program.model.symbol.ReferenceManager;
|
||||||
|
import ghidra.program.model.symbol.SourceType;
|
||||||
|
import ghidra.util.StringUtilities;
|
||||||
|
|
||||||
|
public class RenameScript extends GhidraScript {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void run() throws Exception {
|
||||||
|
Address askAddress = askAddress("输入函数地址", "引用的函数地址");
|
||||||
|
int askInt = askInt("输入参数位置", "函数名称的参数位置");
|
||||||
|
DecompInterface decompiler = getDecompInterface();
|
||||||
|
|
||||||
|
ReferenceIterator referenceIterator = currentProgram.getReferenceManager().getReferencesTo(askAddress);
|
||||||
|
for (Reference ref : referenceIterator) {
|
||||||
|
monitor.checkCancelled();
|
||||||
|
Address fromAddress = ref.getFromAddress();
|
||||||
|
Function functionContaining = currentProgram.getFunctionManager().getFunctionContaining(fromAddress);
|
||||||
|
if (null == functionContaining) {
|
||||||
|
println("no found function: " + fromAddress.toString());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DecompileResults res = decompiler.decompileFunction(functionContaining, 30, null);
|
||||||
|
if (!res.decompileCompleted()) {
|
||||||
|
println("decompile error: " + res.getErrorMessage());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
HighFunction highFunction = res.getHighFunction();
|
||||||
|
Iterator<PcodeOpAST> pcodeOps = highFunction.getPcodeOps();
|
||||||
|
|
||||||
|
while (pcodeOps.hasNext()) {
|
||||||
|
monitor.checkCancelled();
|
||||||
|
PcodeOpAST opAST = pcodeOps.next();
|
||||||
|
int opcode = opAST.getOpcode();
|
||||||
|
if (PcodeOp.CALL == opcode || PcodeOp.CALLIND == opcode || PcodeOp.CALLOTHER == opcode) {
|
||||||
|
Varnode input0 = opAST.getInput(0);
|
||||||
|
boolean contains = input0.contains(askAddress);
|
||||||
|
if (!contains) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Varnode inputVarnode = opAST.getInput(askInt);
|
||||||
|
String nameString = null;
|
||||||
|
if (inputVarnode.isUnique()) {
|
||||||
|
nameString = getUniqueValue(inputVarnode);
|
||||||
|
|
||||||
|
} else if (inputVarnode.isConstant()) {
|
||||||
|
nameString = getConstact(inputVarnode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StringUtilities.isAllBlank(nameString)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String name = nameString.replace(" ", "");
|
||||||
|
println("find function :" + name);
|
||||||
|
SourceType signatureSource = functionContaining.getSignatureSource();
|
||||||
|
if (signatureSource.isLowerPriorityThan(SourceType.USER_DEFINED)) {
|
||||||
|
functionContaining.setName(name, SourceType.USER_DEFINED);
|
||||||
|
currentProgram.getListing().setComment(functionContaining.getEntryPoint(), CodeUnit.POST_COMMENT,
|
||||||
|
"script rename: " + name);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private DecompInterface getDecompInterface() {
|
||||||
|
DecompInterface decompiler = new DecompInterface();
|
||||||
|
DecompileOptions decompileOptions = new DecompileOptions();
|
||||||
|
decompiler.setOptions(decompileOptions);
|
||||||
|
decompiler.openProgram(currentProgram);
|
||||||
|
return decompiler;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getConstact(Varnode input3) {
|
||||||
|
Address address2 = input3.getAddress();
|
||||||
|
Address address3 = toAddr(address2.getOffset());
|
||||||
|
Data dataAt2 = getDataAt(address3);
|
||||||
|
if (null != dataAt2) {
|
||||||
|
if (dataAt2.hasStringValue()) {
|
||||||
|
return dataAt2.getValue().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getUniqueValue(Varnode input3) {
|
||||||
|
PcodeOp def = input3.getDef();
|
||||||
|
Varnode[] inputs = def.getInputs();
|
||||||
|
if (null != inputs && inputs.length > 0) {
|
||||||
|
if (inputs[0].isConstant()) {
|
||||||
|
Address address2 = inputs[0].getAddress();
|
||||||
|
Address address3 = toAddr(address2.getOffset());
|
||||||
|
Data dataAt2 = currentProgram.getListing().getDataAt(address3);
|
||||||
|
if (null != dataAt2) {
|
||||||
|
if (dataAt2.hasStringValue()) {
|
||||||
|
return dataAt2.getValue().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user