Saat kami mengembangkan modul ghidra nodejs untuk alat Ghidra , kami menyadari bahwa tidak selalu mungkin untuk mengimplementasikan opcode V8 dengan benar (mesin JavaScript yang digunakan oleh Node.js) dalam bahasa assembly SLEIGH. Dalam lingkungan runtime seperti V8, JVM, dan lainnya, satu opcode dapat melakukan tindakan yang cukup kompleks. Untuk mengatasi masalah ini, Ghidra menyediakan mekanisme injeksi dinamis dari konstruksi P-code - bahasa representasi perantara Ghidra. Dengan menggunakan mekanisme ini, kami dapat mengubah keluaran decompiler dari ini:
Di dalam:
CallRuntime. . . Runtime- V8 (kRuntimeId). (range โ -, rangedst โ ). SLEIGH, Ghidra , :
, , .
Runtime- kRuntimeId.
, .
.
.
.
, SLEIGH, , . , ( -) ( ) , p-code, Ghidra. ?
(slaspec) , CallRuntimeCallOther. , ( โ ), , Ghidra Java , Java , p-code , Java.
, .
SLEIGH
CallRuntime . SLEIGH Ghidra v8.
:
define pcodeop CallRuntimeCallOther;
:
:CallRuntime [kRuntimeId], range^rangedst is op = 0x53; kRuntimeId; range; rangedst {
CallRuntimeCallOther(2, 0);
}
, , 0x53, CallRuntime
CallRuntimeCallOther
2 0. (CallRuntime
) (CallWithSpread
, CallUndefinedReceiver
. .).
, : V8_PcodeInjectLibrary. ghidra.program.model.lang.PcodeInjectLibrary
p-code .
V8_PcodeInjectLibrary
:
package v8_bytecode;
import โฆ
public class V8_PcodeInjectLibrary extends PcodeInjectLibrary {
public V8_PcodeInjectLibrary(SleighLanguage l) {
}
}
V8_PcodeInjectLibrary
, Ghidra, pcodeInjectLibraryClass
pspec, Ghidra , p-code.
<?xml version="1.0" encoding="UTF-8"?>
<processor_spec>
<programcounter register="pc"/>
<properties>
<property key="pcodeInjectLibraryClass" value="v8_bytecode.V8_PcodeInjectLibrary"/>
</properties>
</processor_spec>
CallRuntimeCallOther
cspec. Ghidra V8_PcodeInjectLibrary
, cspec-.
<callotherfixup targetop="CallRuntimeCallOther">
<pcode dynamic="true">
<input name="outsize"/>
</pcode>
</callotherfixup>
(, , ) .
HashSet, . โ language. CallRuntimeCallOther
, , .
public class V8_PcodeInjectLibrary extends PcodeInjectLibrary {
private Set<String> implementedOps;
private SleighLanguage language;
public V8_PcodeInjectLibrary(SleighLanguage l) {
super(l);
language = l;
String translateSpec = language.buildTranslatorTag(language.getAddressFactory(),
getUniqueBase(), language.getSymbolTable());
PcodeParser parser = null;
try {
parser = new PcodeParser(translateSpec);
}
catch (JDOMException e1) {
e1.printStackTrace();
}
implementedOps = new HashSet<>();
implementedOps.add("CallRuntimeCallOther");
}
}
Ghidra getPayload
V8_PcodeInjectLibrary
CallRuntimeCallOther
, V8_InjectCallVariadic
( ) .
@Override
/**
* This method is called by DecompileCallback.getPcodeInject.
*/
public InjectPayload getPayload(int type, String name, Program program, String context) {
if (type == InjectPayload.CALLMECHANISM_TYPE) {
return null;
}
if (!implementedOps.contains(name)) {
return super.getPayload(type, name, program, context);
}
V8_InjectPayload payload = null;
switch (name) {
case ("CallRuntimeCallOther"):
payload = new V8_InjectCallVariadic("", language, 0);
break;
default:
return super.getPayload(type, name, program, context);
}
return payload;
}
p-code
p-code V8_InjectCallVariadic. .
package v8_bytecode;
import โฆ
public class V8_InjectCallVariadic extends V8_InjectPayload {
public V8_InjectCallVariadic(String sourceName, SleighLanguage language, long uniqBase) {
super(sourceName, language, uniqBase);
}
// . RUNTIMETYPE
int INTRINSICTYPE = 1;
int RUNTIMETYPE = 2;
int PROPERTYTYPE = 3;
@Override
public PcodeOp[] getPcode(Program program, InjectContext context) {
}
@Override
public String getName() {
return "InjectCallVariadic";
}
}
, getPcode
pCode V8_PcodeOpEmitter
pCode ( ).
V8_PcodeOpEmitter pCode = new V8_PcodeOpEmitter(language, context.baseAddr, uniqueBase);
context ( ) , .
Address opAddr = context.baseAddr;
:
Instruction instruction = program.getListing().getInstructionAt(opAddr);
context
, SLEIGH.
Integer funcType = (int) context.inputlist.get(0).getOffset();
Integer receiver = (int) context.inputlist.get(1).getOffset();
Pcode.
//
if (funcType != PROPERTYTYPE) {
// kRuntimeId โ
Integer index = (int) instruction.getScalar(0).getValue();
// Pcode cpool pCode V8_PcodeOpEmitter. .
pCode.emitAssignVarnodeFromPcodeOpCall("call_target", 4, "cpool", "0", "0x" + opAddr.toString(), index.toString(),
funcType.toString());
}
โฆ
// ยซ ยป
Object[] tOpObjects = instruction.getOpObjects(2);
// get caller args count to save only necessary ones
Object[] opObjects;
Register recvOp = null;
if (receiver == 1) {
โฆ
}
else {
opObjects = new Object[tOpObjects.length];
System.arraycopy(tOpObjects, 0, opObjects, 0, tOpObjects.length);
}
//
try {
callerParamsCount = program.getListing().getFunctionContaining(opAddr).getParameterCount();
}
catch(Exception e) {
callerParamsCount = 0;
}
// aN . , Ghidra
Integer callerArgIndex = 0;
for (; callerArgIndex < callerParamsCount; callerArgIndex++) {
pCode.emitPushCat1Value("a" + callerArgIndex);
}
// aN
Integer argIndex = opObjects.length;
for (Object o: opObjects) {
argIndex--;
Register currentOp = (Register)o;
pCode.emitAssignVarnodeFromVarnode("a" + argIndex, currentOp.toString(), 4);
}
//
pCode.emitVarnodeCall("call_target", 4);
//
while (callerArgIndex > 0) {
callerArgIndex--;
pCode.emitPopCat1Value("a" + callerArgIndex);
}
// P-Code
return pCode.getPcodeOps();
V8_PcodeOpEmitter (https://github.com/PositiveTechnologies/ghidra_nodejs/blob/main/src/main/java/v8_bytecode/V8_PcodeOpEmitter.java), JVM. p-code . .
emitAssignVarnodeFromPcodeOpCall(String varnodeName, int size, String pcodeop, String... args)
Varnode โ p-code, , p-code. , โ Varnode.
. p-code pcodeop
args
varnodeName
:
varnodeName = pcodeop(args[0], args[1], โฆ);
emitPushCat1Value(String valueName) emitPopCat1Value (String valueName)
p-code push pop Varnode valueName
.
emitAssignVarnodeFromVarnode (String varnodeOutName, String varnodeInName, int size)
p-code varnodeOutName = varnodeInName
emitVarnodeCall (String target, int size)
P-Code target.
Ghidra. p-code โ bytenode Node.JS. github.com. , -!
- , - .