Closed ghost closed 3 years ago
Doesn't look much like regular lambdas. If I had to guess (and it really is a guess), I'd say lambdas back ported to jre7..... (you may find there are no invokedynamic instructions in the bytecode).
I'm afraid there's not much to go on there, I'd need a sample Jar (one that can be legally shared only please!!)
On Tue, 16 Mar 2021, 13:47 Igor Lerinc, @.***> wrote:
CFR version
CFR 0.151 Compiler
unknown, java 8? Description
When decompiling .jar file (decompiled with dex2jar, also tried enjarify, same output), i get multiple $$Lambda$ .class files along with some .class files, but in code clogged with unreadable code. But when i ran in procyon, it decompiled without those $$Lambda$ .class files, and at least got all in one place, in java, even if not perfect. So it must have to do with Java 8 lambda expressions, or whatever it is. Example
this is file content
ls InstanceSettings.java Service.java 'SettingsActivity$$Lambda$14.java' 'SettingsActivity$$Lambda$5.java' SettingsActivity.java 'Provider$$Lambda$1.java' 'SettingsActivity$$Lambda$10.java' 'SettingsActivity$$Lambda$1.java' 'SettingsActivity$$Lambda$6.java' Settings.java 'Provider$$Lambda$2.java' 'SettingsActivity$$Lambda$11.java' 'SettingsActivity$$Lambda$2.java' 'SettingsActivity$$Lambda$7.java' Provider.java 'SettingsActivity$$Lambda$12.java' 'SettingsActivity$$Lambda$3.java' 'SettingsActivity$$Lambda$8.java' RemoteViewsFactory.java 'SettingsActivity$$Lambda$13.java' 'SettingsActivity$$Lambda$4.java' 'SettingsActivity$$Lambda$9.java'
and just a small fraction of code, to see how it looks in code
final class RandomVersePopup$$Lambda$1 implements CompoundButton.OnCheckedChangeListener { private final RadioButton arg$1;
private RandomVersePopup$$Lambda$1(RadioButton radioButton) { this.arg$1 = radioButton; } private static CompoundButton.OnCheckedChangeListener get$Lambda(RadioButton radioButton) { return new RandomVersePopup$$Lambda$1(radioButton); } public static CompoundButton.OnCheckedChangeListener lambdaFactory$(RadioButton radioButton) { return new RandomVersePopup$$Lambda$1(radioButton); } @LambdaForm.Hidden public void onCheckedChanged(CompoundButton compoundButton, boolean bl) { RandomVersePopup.access$lambda$0(this.arg$1, compoundButton, bl); }
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/leibnitz27/cfr/issues/235, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABFXCEF2ASTX2KJ2OK774LDTD5OQTANCNFSM4ZISZQ6A .
bible pentest, example jar.zip
here, is example .jar file, i work closely with developer, denys dolganenko, he asked me to do pentesting on app security (including reverse engeenering), and this is just part, where $$Lambda$ is most commonly happening.
lee, maybe u never heard of retrolambda?
does cfr support retrolambda? or i'm missing some options while decompiling it?
lee, maybe u never heard of retrolambda?
Guess not ;)
I'll have a look.
Oh yeah, that's fairly obvious - so - yes, it does look like a syntactic sugar transpiling (I.e. retrolambda as @Lanchon says)
The reason you see these classes (and the synthetic methods) is that CFR will only remove them if I'm convinced they've been re-sugared; slightly less paranoid folk might ignore classes with $ in them, as they look like synthetic/inner classes. (and if you remove the synthetics without undoing the transform, you're losing a lot of information, which unfortunately I think is what Procyon for example is doing).
I.e. if you look at Profile.java
private void confirmAndDeleteSelectedItems() {
AlertDialog.Builder builder = new AlertDialog.Builder((Context)this);
builder.setTitle(2131297197);
int n = this.getSelectedItemsCount();
if (n == 1) {
builder.setMessage((CharSequence)this.getString(2131296860, new Object[]{((Map)this.itemsData.get(this.getSelectedItemIndex())).get("name")}));
} else {
builder.setMessage((CharSequence)this.getString(2131296861, new Object[]{n}));
}
builder.setNegativeButton(2131296302, null);
builder.setPositiveButton(2131296306, Profiles$$Lambda$6.lambdaFactory$((Profiles)this));
builder.show();
}
Lambda$6's lambdaFactory returns something which eventually generates an anonymous class that calls Profiles.access$lambda$3 -> lambda$confirmAndDeleteSelectedItems$2 -> deleteSelectedItems
builder.setPositiveButton(2131296306, Profiles$$Lambda$6.lambdaFactory$((Profiles)this));
--> is really -->
builder.setPositiveButton(2131296306, () -> deleteSelectedItems());
I'm a bit torn about this one; the problem with bolt-on/transpiling like this is that the source language isn't java (You know what I mean - it's something that's turned into Java, then compiled ;) ), so undoing this actually isn't decompiling ;).
(And it's a dangerous road to start down - for example, I do NOT want to be undoing all of the things that (picking a random one) Project Lombok could do).
Having said that, it's wacky and interesting, so I'll see if there's a nice way of doing it, maybe optionally.
Why is retrolambda being used here? The purpose of it is to make decompilers that don't support indy (and similar) support it - CFR already does so there does not seem to be any need.
The purpose of it is to make decompilers that don't support indy (and similar) support it - CFR already does so there does not seem to be any need.
Compilers, shurely? It exists (IIUC) to allow lambda-containing code to be targetted nicely at pre-invokedynamic jvms.
The interesting thing is that the OUTPUT of retrolambda is a mess of temporary classes, etc. But (as I say above), that's the java that's being compiled, so CFR is faithfully decompiling it. It's just not super useful. ;)
the problem with bolt-on/transpiling like this is that the source language isn't java
project lombok (it still exists?) definitely is a new language. but AFAIR retrolambda takes Java 8 bytecode as input? then reworks the bytecode to be java 7. if this is true, javac + retrol could be simply considered a different java 8 compiler, and then there is a case for better recovery of source.
resugaring is always optional for correctness (and its great to be able to turn it off for lay people -me- to see first hand how desugaring works) , but u seem to always prefer resugaring when possible.
Compilers, shurely? It exists (IIUC) to allow lambda-containing code to be targetted nicely at pre-invokedynamic jvms.
Sorry! I got confused between retrolambda and retroindy.
The interesting thing is that the OUTPUT of retrolambda is a mess of temporary classes, etc. But (as I say above), that's the java that's being compiled, so CFR is faithfully decompiling it. It's just not super useful. ;)
I guess this is a bigger problem. Should CFR be a simple JVM decompiler, or should it be targetted to allow decompilation of specific compilers output (e.g. Java, RetroLambda, Kotlin, Lombok...). At the moment it is targetted for Java and some Kotlin.
The problem is whether it is practical to continue going down this route and add support for every possible compiler, which would have problems with distinguishing between the bytecode of different compilers, maintenance, exploitation (malicious code matching a compiler heuristic to create invalid output for example).
If it were me creating the decompiler it would just plain and simply represent the bytecode. But I think CFR has a different purpose. It is just managing the scope of that purpose.
in my view you are confounding things. you mix alt language compilers with std java compilers. cfr always tried to deco all java compilers (javac and eclipse) while otherwise deco other languages to java. the point here is that javac+retrolambda is a (restricted) std java compiler.
I don't like the idea of undoing this sort of thing automatically (especially not something as complex as this), because I want to actually see the java represented by the bytecode.
That being said, I can imagine given code like the above, it's really useful to see what's really going on - so - there's an EXPLICIT argument sugarretrolambda, (hey, it'll probably never get used, but it's a nice toy to have).
I'm not going to enable this automatically, so I may add something in the future to warn it might be appropriate.
(also the code's a bit of a mess ;) )
Normal
private void confirmAndDeleteSelectedItems() {
AlertDialog.Builder builder = new AlertDialog.Builder((Context)this);
builder.setTitle(2131297197);
int n = this.getSelectedItemsCount();
if (n == 1) {
builder.setMessage((CharSequence)this.getString(2131296860, new Object[]{((Map)this.itemsData.get(this.getSelectedItemIndex())).get("name")}));
} else {
builder.setMessage((CharSequence)this.getString(2131296861, new Object[]{n}));
}
builder.setNegativeButton(2131296302, null);
builder.setPositiveButton(2131296306, Profiles$$Lambda$6.lambdaFactory$((Profiles)this));
builder.show();
}
With --sugarretrolambda true
private void confirmAndDeleteSelectedItems() {
AlertDialog.Builder builder = new AlertDialog.Builder((Context)this);
builder.setTitle(2131297197);
int n = this.getSelectedItemsCount();
if (n == 1) {
builder.setMessage((CharSequence)this.getString(2131296860, new Object[]{this.itemsData.get(this.getSelectedItemIndex()).get(KEY_NAME)}));
} else {
builder.setMessage((CharSequence)this.getString(2131296861, new Object[]{n}));
}
builder.setNegativeButton(2131296302, null);
builder.setPositiveButton(2131296306, (DialogInterface dialogInterface, int n) -> {
this.deleteSelectedItems();
});
builder.show();
}
it's perfect. yeah good call, enabled by default would convert java 7 code to java 8. great!
then again, decompilation is mostly done to understand the code, not to recompile it. and enabled helps understanding...
maybe youll find that sensible defaults are different for analyzing than for roundtripping. a general "roundtrip" option could disable all stuff like this while otherwise defaulting to analysis mode.
CFR version
CFR 0.151
Compiler
unknown, java 8?
Description
When decompiling .jar file (decompiled with dex2jar, also tried enjarify, same output), i get multiple $$Lambda$ .class files along with some .class files, but in code clogged with unreadable code. But when i ran in procyon, it decompiled without those $$Lambda$ .class files, and at least got all in one place, in java, even if not perfect. So it must have to do with Java 8 lambda expressions, or whatever it is.
Example
this is file content
and just a small fraction of code, to see how it looks in code