JesusFreke / smali

smali/baksmali
6.29k stars 1.07k forks source link

call interface method which wrong arguments num. #694

Closed huhuang03 closed 5 years ago

huhuang03 commented 5 years ago

apktool -v

Apktool v2.4.0 - a tool for reengineering Android apk files
with smali v2.2.6 and baksmali v2.2.6

I use apktool d xx.apk to dump apk

And has a code snippet.

invoke-interface {v0, v2, v3, v4}, Lcom/xx/xx/plugin/biz/a/a;->d(JLjava/lang/String;)Lcom/xx/xx/ae/l;

Why call with 3 param which accept 2.

And I look around, the v3 has no where assignment.

JesusFreke commented 5 years ago

J (long) is a wide type, which takes 2 registers. Wide values are always in 2 consecutive registers.

Most instructions that have a specific "wide" variant only require the first register of the pair to be specified. But since invoke can accept both narrow and wide arguments, you have to specify both registers. In your case v2 and v3 contain the wide value. You don't see a "set" for v3, because it's implicitly set by something storing a wide value to v2.

melsabagh commented 5 years ago

@JesusFreke Can the two halves of a wide register pair be individually addressed? If not, then what's the point of emitting a register pair in the Smali assembly?

JesusFreke commented 5 years ago

No, the values in the 2 registers cannot be separately referenced. e.g. if you have a wide value in v0 and v1, trying to pass either v0 or v1 to anything expecting a non-wide value is invalid. Or trying to pass v1 to something that expects a wide value will fail.

You can still set either v0 or v1 to a different non-wide value. But in that case, the other half of the wide value becomes unusable.

This isn't a smali language thing, this is a dalvik bytecode thing. For an instruction that only works with wide values, you only have to pass the first register of the pair. For an instruction that can accept both narrow and wide values (i.e. the method arguments in an invoke instruction), you have to specify both registers of the pair.

melsabagh commented 5 years ago

@JesusFreke I understand it's a Dalvik thing, but since that is based on the parameter types of method references used in invoke statements (Smali emits these parameter types anyways) and the halves of a register pair cannot be separately addressed, then what is the point of emitting the register pair in the Smali assembly? In other words, why must the Smali assembly representation be so truthful to the Dalvik bytecode in this regard? If the register pair serves no purpose at the assembly level (not at the Dalvik bytecode level) then perhaps it would make sense to drop the second half register of a wide pair from the assembly output of Smali. This should not hinder reassembling the bytecode from Smali since the parameter types are sufficient to know that a register pair is needed.

JesusFreke commented 5 years ago

Smali is intended to be as close to a 1-to-1 representation of the dalvik bytecode as possible. The goal isn't ease of use. It's an assembly language. It's not going to be easy to use :). But rather, a faithful "human-readable" representation of what's in the dex file.

JesusFreke commented 5 years ago

Say, for example, that there is a dex file that passes an invalid register pair v1, v3 for a wide argument to a method. If the smali language was designed how you describe, how should baksmali handle that? If it ignored the second register of the pair, then it would produce bytecode that doesn't match the input.

Instead, baksmali simply doesn't care. If a register is present in the instruction in the dex file, then that register is present in the instruction in the smali file.

melsabagh commented 5 years ago

I see your point, though why not just report instructions using non-consecutive register pairs for wide types as invalid instead of assembling them anyways? Won't these DEX files fail verification on a live device regardless (e.g., https://android.googlesource.com/platform/art/+/master/runtime/verifier/method_verifier.cc#4099)?

JesusFreke commented 5 years ago

Yes, there are many, many ways for a structurally valid dex file to fail verification. While I agree that it would be useful to perform the types of semantic checks that art's verifier performs, I don't have the time or interest to implement something like that. I've started some work on something like that in the past, but it turned out to be prohibitively time-consuming to implement.

As I already mentioned, one of the primary goals of the smali language is to provide as close to a 1-to-1 representation of the underlying bytecode as possible. The scenario I describe is a structurally valid dex file, and a baksmali<->smali roundtrip of a structurally valid dex file should result in an identical* dex file.

melsabagh commented 5 years ago

Fair enough. Good conversation :-).

JesusFreke commented 5 years ago

And yes, there are other rare corner cases where a roundtrip of a structurally valid, but semantically questionable dex file may not yield an identical dex file :). But that's the goal.