JEB Developer Tutorial
Delegating and parsing inner data
A plugin (IUnit) should try to achieve high coherence. Examples:
Upon the encounter of inner artifacts, the current parser should delegate the parsing of those artifacts.
This article introduces the concepts of:
Delegation is normally done by calling the processor (IUnitProcessor) process() method. A processor is responsible for managing a set of identifiers (IUnitIdentifier). Every identifier receives a reference to the current project’s processor when their prepare() method is called.
Upon calling IUnitProcessor.process, the caller should provide the current parser as the parent argument. On success, it is the responsibility of the parent unit to register the newly created unit as a child. (Note that if your unit inherits from AbstractUnit, you can simply call the addChild protected method.)
Example (zip parser):
// here `entry` is the zip entry currently being processed
IUnit childUnit = null;
if(!entry.isDirectory()) {
childUnit = unitProcessor.process(entryName, entryData, this);
addChild(childUnit);
}
The above code is an example of loose-coupling delegation: there is no hard-coded dependency on other plugins.
Strong-coupling delegation can be used when a parser needs to be split into several unit components.
Example: DEX parser producing Dalvik units:
childUnit = new DalvikUnit(...)
children.add(childUnit);
Here, we bypassed the IUnitProcessor, and directly created other units of a pre-determined type (DalvikUnit). Strong-coupling should be used with caution, hardcoded dependencies are convenient but potentially hard to deal with when refactoring code.
Soft delegation can be used to avoid the creation of generic units if all identifiers failed.
It can be used for cases where one wants to delegate parsing because they know that a chunk of data may contain data that should be parsed by another unit. (This is in contrast to "regular" delegation, where we know that some input must contain interesting data that should be parsed by some other unit.)
Refer to IUnitProcessor.process(..., softDelegation).
Sometimes, we need to do loose-coupling delegation but want to bypass identification for some reason (e.g., we know that a block must be of this type of data, and is not easily identifiable, for example, it does not contain magic header data). This can be done manually by iterating over the identifiers registered in the IUnitProcessor.
Example:
IUnit target = null;
String targetType = “elf”; // Wanted type
for(IUnitIdentifier ident: unitProcessor.getUnitIdentifiers()) {
if(targetType.equals(ident.getFormatType())) {
target = ident.prepare(name, data, unitProcessor, parent);
break;
}
}
// use `target` …
You may also specify the wantedType in your call to IUnitProcess.process().