Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feature] Direct API Input / dexlib2 compatibility. #1457

Closed
GraxCode opened this issue Apr 21, 2022 · 10 comments
Closed

[feature] Direct API Input / dexlib2 compatibility. #1457

GraxCode opened this issue Apr 21, 2022 · 10 comments

Comments

@GraxCode
Copy link

Describe your idea:
It would be great if the API could also get input directly, without providing a file (maybe an InputStream e.g.), or even better would be making the API work directly with dexlib2 (smali) tree structure.

@skylot
Copy link
Owner

skylot commented Apr 21, 2022

It would be great if the API could also get input directly, without providing a file (maybe an InputStream e.g.)

@GraxCode sure!
I made a commit with custom loading of dex by input stream or byte array. Check test for usage sample:

	@Test
	public void testDirectDexInput() throws IOException {
		try (JadxDecompiler jadx = new JadxDecompiler();
				InputStream in = new FileInputStream(getFileFromSampleDir("hello.dex"))) {
			jadx.addCustomLoad(new DexInputPlugin().loadDexFromInputStream(in, "input"));
			jadx.load();
			for (JavaClass cls : jadx.getClasses()) {
				System.out.println(cls.getCode());
			}
			assertThat(jadx.getClasses(), Matchers.hasSize(1));
		}
	}

"input" here is just a label for loaded dex (optional, can be null).

If this approach and implementation is fine for you, I will merge it into master.

or even better would be making the API work directly with dexlib2 (smali) tree structure.

It is possible to implement ILoadResult for dexlib2 tree structure, but this will require a lot of work (convert all dexlib2 objects into jadx IR counterpart) and I don't think that will improve performance much.

@GraxCode
Copy link
Author

This will definitely make it easier to use and spare me having to create temp files. Does it work for .smali input too? I will need that because it's the best way of inputting dexlib2 data into jadx (dexlib2 -> smali -> jadx)

@skylot
Copy link
Owner

skylot commented Apr 21, 2022

Does it work for .smali input too?

No, only for dex. I thought you will be using dexlib2 -> dex -> jadx 😕
For .smali input jadx use Smali.assemble method internally, which accept smali files only, so I don't see any point to accept input stream in jadx. Maybe I don't understand something, can you describe why you need exactly this pipeline?

@GraxCode
Copy link
Author

Because I want to decompile single classes, and not all classes at the same time, while also considering changes i make to the dexlib2 stuff. I am writing an editor for dalvik code / apk files and need a dynamic decompiler that reflects changes.

@skylot
Copy link
Owner

skylot commented Apr 21, 2022

@GraxCode I see. I can write code for input smali using InputStream, but internally it will use temp files anyway, because I don't see a good way to hack into smali lib and convert smali to dex without temp files. So it looks like your issue should address smali lib in the first place.

@GraxCode
Copy link
Author

No, I don't think that's necessary then. It will be better to stick to the current way. Also I just noticed that the .smali file loader also converts it to a temporary .dex file, so I am doing unneeded steps there.

Current way:
dexlib2 -> convert to smali -> assemble smali to dex -> disassemble again using jadx.

I will change it to:
dexlib2 -> assemble to temporary dex as stream / byte[] -> disassemble with jadx using new API (commit).

So, therefore, the commit you made will be useful for me. Thank you.

@NebelNidas
Copy link
Contributor

NebelNidas commented Apr 10, 2023

I made a commit with custom loading of dex by input stream or byte array.

Can you implement the same thing for the java-input plugin?

Edit: This is how I do it now, but it would be more convenient to have JavaInputPlugin::loadClassFromInputStream instead 😉

skylot added a commit that referenced this issue Apr 10, 2023
@skylot
Copy link
Owner

skylot commented Apr 10, 2023

Can you implement the same thing for the java-input plugin?

@NebelNidas done. Added methods for load from input stream or byte array.

BTW, I notice these lines in your code:

if (fullClassName.contains("$")) {
			errorMessage = "JADX doesn't support decompiling inner classes!";

But jadx do support decompile of inner classes, do you encounter any issue?

@NebelNidas
Copy link
Contributor

NebelNidas commented Apr 12, 2023

Nice, thank you very much :)

[...] But jadx do support decompile of inner classes, do you encounter any issue?

In my initial implementation, it failed because of these lines:

private synchronized ICodeInfo decompile(boolean searchInCache) {
if (isInner()) {
return ICodeInfo.EMPTY;
}

Now it seems to work fine though 😄

@skylot
Copy link
Owner

skylot commented Apr 12, 2023

it failed because of these lines:

I see. Jadx mark class as inner if parent class is found, so inner class moved and code for it generated in that parent class, as a result inner class doesn't have own code.
In your case, only one class decompiling, so jadx will not find parent and class will not be marked as inner.

Anyway, inner class move can be unexpected (related to #1814), so adding option to disable such move can be a good improvement. I will create an issue for that 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants