Modification de la représentation du code intermédiaire à la volée dans Ghidra

Lorsque nous développions le module ghidra nodejs pour l' outil Ghidra , nous nous sommes rendu compte qu'il n'était pas toujours possible d'implémenter correctement l'opcode V8 (le moteur JavaScript utilisé par Node.js) dans le langage d'assemblage SLEIGH. Dans les environnements d'exécution tels que V8, JVM et autres, un seul opcode peut effectuer des actions assez complexes. Pour résoudre ce problème, Ghidra fournit un mécanisme d'injection dynamique de constructions P-code - le langage de représentation intermédiaire de Ghidra. En utilisant ce mécanisme, nous avons pu transformer la sortie du décompilateur à partir de ceci:





Dans ce:





CallRuntime. . . Runtime- V8 (kRuntimeId). (range — -, rangedst — ). SLEIGH, Ghidra , :





, , .





  1. Runtime- kRuntimeId.





  2. , .





  3. .





  4. .





  5. .





, 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. , -!





- , - .





Node.js : , , .








All Articles