Xor-Clear: A Jadx plugin for resolving simple string obfuscation patterns.
Why not. I was analyzing code that used this, and the obfuscation was simple enough to reverse, but repetitive enough to be a pain to do manually.
Also, this was a project to learn the Jadx plugin API, which is notoriously undocumented.
Build it with mvn package. In Jadx, go to Plugins -> Install a Plugin, and choose the jar file in the target folder.
The patterns I was analyzing had two methods of obfuscation, technically the same one, just implemented differently.
The first one is this:
char[] cArr = new char[8];
cArr[1] = (char) (7004 ^ 6969);
cArr[0] = (char) (cArr[1] ^ 19);
cArr[2] = (char) (cArr[0] ^ 4);
cArr[3] = (char) (cArr[1] ^ 22);
cArr[4] = (char) (cArr[2] ^ 27);
cArr[6] = (char) (cArr[3] ^ 29);
cArr[7] = (char) (cArr[3] ^ 0);
cArr[5] = (char) (cArr[3] ^ 28);
Intrinsics.checkNotNullParameter(strArr, cArr);It gets deobfuscated into:
Intrinsics.checkNotNullParameter(strArr, "versions");Since the obfuscation is simple, the deobfuscation just follows a specific pattern.
The other method is the same as above, but uses a function for the string that takes a de-XOR value:
private static char[] a(int i) {
char[] cArr = new char[10];
cArr[1] = (char) (23151 ^ i);
cArr[6] = (char) (cArr[1] ^ '@');
cArr[4] = (char) (cArr[6] ^ 3);
cArr[3] = (char) (cArr[4] ^ '_');
cArr[9] = (char) (cArr[1] ^ 'X');
cArr[0] = (char) (cArr[4] ^ 'L');
cArr[8] = (char) (cArr[0] ^ 'O');
cArr[7] = (char) (cArr[9] ^ 6);
cArr[2] = (char) (cArr[6] ^ 'J');
cArr[5] = (char) (cArr[2] ^ 'R');
return cArr;
}Such functions are called with a single unique constant value each. If the argument is identified, the plugin resolves it into this:
@XClear(result = "andr-6.0.6", input = 139614721)
private static char[] a(int i) {
}I'll defend the implementation by saying the Jadx API is undocumented and I didn't want to waste more time on it, this is enough for my needs.