Giter VIP home page Giter VIP logo

dexpatcher-tool's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dexpatcher-tool's Issues

Installation Documentation

Dear All.
First, I am very new to patching world, so please be patient with me.
Usually, if I want to patch apk.

1- Extract dex file from the apk,
2- Use dex2jar in order to see the java code via (jd-gui) [Some time it fails to decode some parts of the Java bite code]
3- locate the method I want to patch - hopefully it decoded via (jd-gui).
4- add/edit the method via Notepad++
5- Decode the apk via apktool 2.4.1 with the "--only-main-classes" decode option.
6- locate the method inside the smali file.
7- Go to http://java2smali.com/ to convert java to smali.
8- Replace the method with the new one.
9- compile and run.

Now I found this project, but honestly, I don't understand how to use it.
I have APK which I want to add an aar to it and call this lib on the apk start... this aar does not belong to the apk, but I want to force it to be included in the APK.

I will be thankful if you redirect me to how to install / use dexpatcher-tool, i believe i am missing something.

target-ing class methods/fields with @DexWrap/@DexEdit

Hi! Thanks so much for this awesome tool!

I'm trying to de-obfuscate and change some proguard obfuscated code. So far I've been trying to make sense of it by renaming methods and fields using target. Things compile fine, but I'm getting runtime errors saying some methods/fields don't exist:

My example class:

// Works
@DexEdit(target = "ro.numedecod.a.e.b", contentOnly = true)
public class b_EncoderInfo {
    
    // Doesn't work
    @DexEdit(target = "g")
    public int g_initialBitrate;
    
    // Also doesn't work
    @DexWrap(target = "a")
    public String a_getDefaultEncoderType() {
        return a_getDefaultEncoderType();
    }
    
    // Works
//    @DexWrap(target = "a")
//    public String a() {
//        return a();
//    }

    // Works
//    @DexEdit(target = "a")
//    private String a_getDefaultEncoderType() { throw null; }
//
//    @DexAdd
//    public String a() {
//        return a_getDefaultEncoderType();
//    }
}

The class targeting works great!

The method targeting works if I manually @DexEdit and @DexAdd, but doesn't work with the @DexWrap helper (even though I think it's meant to be the same).

I can't get the g_initialBitrate field target to work at all.

I was wondering if I'm using dexpatcher properly? Or am I completely in the wrong and there's a better way to annotate obfuscated code?

EmptyMultiDexContainerException while patching multidex application

Hey Lanchon,

i'm struggling a little bit using your command line tool:

Tool version: 1.8.0-alpha4
Setup: Patching a ProGuard obfuscated APK with a non-compiled patch (.java files)
Command: java -jar dexpatcher-1.8.0-alpha4.jar -m -v -o patched.apk ./source.apk patched-app/
Output:

DexPatcher version 1.8.0-alpha4 by Lanchon (https://dexpatcher.github.io/)
info: read './source.apk'
info: read 'patched-app'
fatal: exception: lanchon.multidexlib2.EmptyMultiDexContainerException: patched-app/

The patched-app folder is a standard gradle folder structure, first level contents are:

drwxr-xr-x 6 root root 4096 Feb 20 17:16 app
-rw-r--r-- 1 root root 2378 Feb 20 15:43 build.gradle
drwxr-xr-x 3 root root 4096 Feb 20 12:44 gradle
-rw-r--r-- 1 root root  786 Feb 20 16:23 gradle.properties
-rwxr-xr-x 1 root root 5305 Feb 20 12:44 gradlew
-rw-r--r-- 1 root root 2269 Feb 20 12:44 gradlew.bat
-rw-r--r-- 1 root root  330 Feb 20 12:44 local.properties
-rw-r--r-- 1 root root  865 Feb 20 12:48 patched-app.iml
-rw-r--r-- 1 root root   15 Feb 20 12:44 settings.gradle

DexPatcher does not seem to recognize that the patch is in the folder, tried several different paths (including app, app/src, ...). Am i doing anything wrong? Is dexpatcher capable of processing the patch this was?

Thank you in advance!

apktool and dex2jar tasks should fail on no output

The apktool and dex2jar tasks should fail if for whatever reason no output is produced. This would stop gradle from caching those "results" as valid, if they are ever produced. I observed one instance (that I was not able to reproduce later) in which gradle cached a success of the dex2jar task as producing no output, and a manual reset of the gradle task result cache was required to fix the issue.

Add options for "targetPosition"

Hi

I'm using your tools a lot for many applications.
Recently, I've tried to use the tool for an app that has been compiled with proguard.
As part of the "proguard" process, the files names are changing to a, aa ant etc.
The packages names are also changes to a, aa and etc.

I'm trying to patch a file that is under the package "com.app.c".
But, The app also contains (after the "proguard" process) class named "com.app.c" and I'm getting the error "Error:(1, 1) error: package com.app.c clashes with class of same name".

After many many tries, I've figured that the only way to solve this problem is if you will add a "targetPosition" options to the tag. This will allow me to patch the code in different place (like "com.app.c_") and then to tell the dexpatcher to put this code on "com.app.c".

Many Many thanks for all the great work (and for adding the life-saving "multi-dex" option)
Ysrael

Another request to complete the 'class rewrite' feature

Hi Lanchon,

First, I very appreciate your great job. You've saved me tons of time until now and for this, I'm thanking you.

Now to my suggestion. I've started to use the new 'class rewrite' feature and it's was really helpful. The only problem that left is when I'm trying to wrap some function, that in his signature I have the renamed class.
For example, I've renamed the class aa to class1.
Then I'm trying to wrap the function void function1(class1 input) but now I actually need to wrap the function void function1(aa input) because otherwise, I'm getting the error

Error:type 'com.testapp.class2': target 'com.testapp.bb': virtual method 'function1(com.testapp.class1):void': target 'a': (class2.java:27): target not found

So my request is when you checking for signatures for wrapping functions and etc., test the functions against the renamed names instead of the original names.

Thanks

Unable to map class interface declarations

Hi there,
I've been working on automating the mapping.txt generation for one of my projects lately and have run into an issue with some of the --map-source --map mapping.txt usage. Not sure if it's a bug or a setting I'm missing.

In a situation like

import com.foo.iface;
[noimplements.zip](https://github.com/DexPatcher/dexpatcher-tool/files/4997762/noimplements.zip)

public final class bar extends par implements iface {
    public iface instance$;
}

with com.foo.iface

package com.foo;

public interface iface<P1, P2, R> {
    ...
}

I'm trying to map iface to myface, eg mapping.txt

com.foo.iface -> com.foo.myface
java -jar dexpatcher-1.8.0-beta1.jar --map-source --map mapping.txt --output patched.dex out.dex

Now in patched.dex com.foo.iface class is correctly renamed to com.foo.myface

package com.foo;

public interface myface<P1, P2, R> {
    ...
}

and in the original class, the instance variable type is changed, however the implements details haven't:

import com.foo.iface;
import com.foo.myface;

public final class bar extends par implements iface {
    public myface instance$;
}

Is there a --pre-transform or similar setting I'm missing?
I've attached the reproduction case files listed here if it is a bug / missing feature.

Thanks!
noimplements.zip

Replace the DexTag type with a parameter annotation.

This is an embarrassing mistake. I designed and implemented DexPatcher in a couple of days, and I had never really used Java annotations before.

Because in Java you cannot rename a constructor, if you want to invoke the original constructor from a replacement constructor, you need to add a tag parameter to overload it instead. DexPatcher 1.0.0 recognizes a tag parameter by detecting the specific hardcoded type 'lanchon.dexpatcher.annotation.DexTag', which is bundled in the annotations Jar, and must be included in final executable.

This idiom is typically used to patch a constructor:

@DexEdit
MyClass(String data, DexTag tag) {}

@DexAdd
MyClass(String data) {
  this(filterTheData(data), DexTag.TAG);
  // do more stuff
}

I used a tag type instead of a parameter annotation because I thought that parameter annotations were a Java 1.8 feature, when in fact they are supported in Java 1.7. The downside to this is that an app can easily detect that it has been patched by DexPatcher by checking for this tag type.

To avoid this problem, the tagging mechanism should be changed to a parameter annotation applicable to any type (including primitive types). A suggested name for the annotation is 'DexTagParameter'. Alternatively, the existing 'DexIgnore' annotation could be overloaded for this use.

The end result would look like this:

@DexEdit
MyClass(String data, @DexTagParameter int tag) {}

@DexAdd
MyClass(String data) {
  this(filterTheData(data), 0);
  // do more stuff
}

It might be better if the 'DexTag' name goes unused to guarantee compile time errors in old code. But most code would reference 'DexTag.TAG' anyway, and if not the resulting patch would fail to apply, so this is not hard requirement.

cant get it working

hi

i googled alot and did whatever i found but i still cant patch my target.
can you please record a video or provide step by step image of how to do it? i know its too much to ask but im really stuck and would really appreciate your help.

im using android studio and going by the guide provided in here and here

Implement app bundle support

I'm trying to patch an application that is distributed on the App Bundle format (*.apks).

In order to patch the application, manual work (which is labor intensive and error-prone) needs to be done to merge the apks.

My suggestion is to allow to modify the base apk, package it back to the apks format and let it be installed on the device.

Also, it would be nice to be able to do this inside Android Studio with the gradle plugin.

dexpatcher.jar lib How to use

Note : - I have read all the necessary documentations of this tool before creating this issue.

Earlier i was using this script in linux, now I have seen that .jar version of dexpatcher has been released. Also you said in your forum post that this is independent tool doesn't need any bundle. But problem is how to use it.. the basic filters (options) of setting apk is missing in this jar.
No documentation found for this .jar version. So how to use it basically

Thanks in Advance !

Implement controlled crossing of the virtual/direct method boundary.

In DexPatcher 1.0.0 (and in Dalvik bytecode too) virtual and direct methods inhabit separate worlds, just like instance and static fields do. This correctly stops you from changing an instance field into a static field, or a private instance (ie: direct) method into a public instance (ie: virtual) method.

Allowing those changes would break the binary compatibility of the patched class against the source class (these member types must be accessed using different Dalvik instructions), and would trigger verification errors in the code coming from the source that accesses the patched class (potentially including parts of the class itself).

However, it should be possible to move just the bytecode from an existing method into a new method that crosses the virtual/direct boundary without worrying about method signature compatibility, allowing things like this:

// We should be able to use the private modifier here.
// Right now the best we can do is protected.
// TBD: This could be enabled only when explicitly
// targeting, or when targeting a different method
// name, or via some ad hoc flag.
@DexEdit(target = "method", maybeSetSomeFlag = true)
void private source_method() {}

@DexAdd
void public method() {
  // do stuff
  source_method();
  // do more stuff
}

However implemented, DexPatcher should continue to be able to correctly handle the case in which a class has both direct and instance methods with otherwise the same name and signature. This is invalid in Java source but could potentially be used for obfuscation in bytecode.

EDIT: It seems that such duplication is not allowed neither in Java nor in Dalvik bytecode.

Implement DexAppend.

This very verbose idiom is commonly used to modify methods:

@DexEdit(target = "method")
void source_method() {}

@DexAdd
void method {
  // do stuff before
  source_method();
  // do stuff after
}

To accomplish the same in a more concise fashion, two annotations are proposed: DexWrap and DexAppend. The general case is handled by the companion annotation DexWrap (see #9). However, when the // do stuff before section above is effectively empty and you only want to append code to the method, DexAppend could be used like this:

@DexAppend
void method {
  // do more stuff
}

Contrary to DexWrap, DexAppend can be used to modify constructors and class initializers, which is the main rationale for its existence, and can also code recursions.

In fact, DexAppend works better for class initializers than the verbose idiom it intends to replace. Have a look at the verbose idiom:

@DexEdit(staticConstructorAction = DexAction.ADD)
class MyClass {

  @DexEdit(target = DexTarget.STATIC_CONSTRUCTOR)
  private static void source_static() {}

  static {
    // When this static block is invoked, the patch static fields have
    // already been initialized. Manually invoking the source static
    // constructor initializes the source static fields. The static
    // fields that are declared on both classes are initialized twice,
    // and end up with the values set later by the source.

    source_static();
    // do more stuff
  }

}

In the previous code, the source class initializer is invoked at the beginning of the patch static block, but not at the beginning of the patch class initializer: the compiler prepends code that initializes static fields to the static block when synthesizing the class initializer method.

However, using DexAppend the source class initializer is really invoked right at the beginning of the patched class initializer:

@DexEdit(staticConstructorAction = DexAction.APPEND)
class MyClass {

  static {
    // DexPatcher inlines a call to the source static constructor
    // before any patch code, including synthesized code that
    // initializes the patch static fields. The static fields that
    // are declared on both classes are initialized twice and end
    // up with the values set later by the patch, not the source.

    // do more stuff
  }

}

When DexAppend is implemented, the default for staticConstructorAction should be changed to DexAction.APPEND, as it is the safest way to handle compiler synthesized code that requires static initialization. Also, this default should no longer fail if either or both the source or patch class initializers are missing. And the handling of initializers in static fields should be updated accordingly, along with the warnings they generate.

Crash after patching telephony-common

Hi, thanks for the great tool! Patching services.jar works well, patching telephony-common.jar even in pass-through mode results in a crash. Tried version 1.8.0 as well

Steps to reproduce

  • pass-through patch
java -jar dexpatcher.jar --output classes.dex telephony-common.dex --debug --verbose
DexPatcher version 1.7.0 by Lanchon (https://dexpatcher.github.io/)
info: read 'telephony-common.dex'
debug: read 'telephony-common.dex': 1318 types
debug: read 'telephony-common.dex': dex version '039'
info: write 'classes.dex'
debug: write 'classes.dex': dex version '039'
debug: write 'classes.dex': 1318 types
0 error(s), 0 warning(s)
  • zip classes.dex into telepthony-common.jar
  • push to device
  • reboot
  • crash output attached
    crash.txt

Implement annotations that modify the existing code of source methods.

These annotations would enable replacement of instructions within specific source methods and support stuff like:

  • altering the targets of method calls
  • altering the targets of field accesses
  • replacing field accesses with method calls
  • replacing field reads with constant values
  • etc

how to use this in compile time

Hi, I want to use this lib to modify dex bytecode in compile time, and add gradle plugin like this page. Now question is, where can I add code to use it. Plz help me~

Add/Replace/delete class files in Dex

Is is possible say if I have a class file or jar (without source code) file to replace the classes in the target dex file with my class or group of classes in package in a jar file? Either in the Android Studio Plugin version (the normal way of adding library to project) or standalone version. If the class files are already present as dalvik bytecode in the dex file (determined by same package/class names) they can be automatically replaced or manually deleted in the dex then replaced with the source class/jar before being recompiled/APK'ed for final packaging

Rewrite original anonymous to allow new ones

I've been porting my old (buggy) fully-decompiled / mod / recompiled apk changes to new concise dpx based ones. A lot of my original code makes heavy use of convenient inline / anonymous classes, which are a bit of a pain to have to split out by hand.

One of the tricks I came up with in my previous re-engineering efforts was re-writing the original apk/jar so that the anonymous functions were a little easier to deal with.

Use apktool to extract, then a python script to update all the smali to turn $1 to $Anon1 (and so on) then rebuild. This renames all the anonymous inner classes and the access() functions so can be referenced in a jar and no longer clash with new anonymous functions created by javac

This trick seems to work exceptionally well with Dexpatcher, I've re-written my original APK in this way and now if I set defaultAction to ADD anonymous inner's seem to be working fine.

For reference, this is my basic python script, my target application's code is all in the package com.navdy.* (I didn't want to rewrite classes from other packages)

# java -jar apktool_2.4.0.jar d ../apk/Hud-3080.apk
# python3 ./3080_dupes.py
# java -jar apktool_2.4.0.jar b Hud-3080
# apksigner.bat sign --ks ..\navdy_alelec.jks --out ..\apk\Hud-3080-Anon.apk Hud-3080\dist\Hud-3080.apk

import sys
import os, re
import shutil
import fileinput
from pathlib import Path

for root, dirs, files in os.walk("./Hud-3080"):
   for name in files:

        fpath = os.path.join(root, name)
        fname = origname = Path(fpath)

        if 'com/navdy/' not in fpath:
            continue

        if not fpath.endswith('.smali'):
            continue
       
        print(fname.name)

        if re.search(r'\$\d', fname.name):
            target = fname.with_name(fname.name.replace('$', '$Anon'))            
            print(fname, "->", target)
            fname.rename(target)
            
        else:
            target = fname

        text = target.read_text()
        def add_anon(match):
            return "$Anon" + match.group(1)
        text = re.sub(r'\$(\d+)', add_anon, text)
        target.write_text(text)

I haven't looked into the internals of dexpatcher yet but surely this same trick would be fairly easy to achieve in the dexpatcher tool or the gradle plugin? Is this likely to break something else (other than the general issues to look out for when defaultAction = ADD) ?

Implement DexWrap.

This very verbose idiom is commonly used to modify methods:

@DexEdit(target = "method")
void source_method() {}

@DexAdd
void method() {
  // do stuff
  source_method();
  // do more stuff
}

The DexWrap annotation would accomplish the same in a more concise fashion:

@DexWrap
void method() {
  // do stuff
  method();
  // do more stuff
}

After DexPatcher processing, the recursive 'method()' call would invoke the original source method instead of recurring. (Recursion is not supported with DexWrap; use the verbose form if you need to.)

Unfortunately this would not work with constructors or class initializers, as constructors cannot recursively call themselves using the this(...) syntax, and class initializers can never be explicitly invoked. (But see the proposed companion annotation DexAppend: #10.)

Support configurable package name for DexPatcher annotations.

Add a command line option to the tool to configure the package name for DexPatcher annotations at runtime, to deter rouge apps from intentionally clashing against DexPatcher annotation names. Support for this is already baked into the codebase, only the command line parsing needs to be implemented.

Unable to resume activity ... Service Intent must be explicit

First, I want to thank you all the great work!!

I'm facing a issue, basically I have a application that is running fine, but when I try it to use it on AndroidStudio, running the project I get this error https://paste.kde.org/psfd4kmuk
No Java modification has been made.
I have been reading and it has something to do with Intents and SDK version.
can you check if it's a AndroidStudio/your Tools or my lack of knowledge.

Thanks
Regards, zezadas

Package name manifest

Hi Lanchon

I tried patching app without set package name identifier in manifest file or set the real package name identifier then the compiler show error. But when i set any package name, compiling successful.

Because i need to sign in app with google account so i think the package name must be original.
Can we remain the original package name for the app ?

Thank you so much

core.jar (core-pj.jar) patch support

I noticed in the script that core cannot be patched (yet). I am just curious why such a limitation exists, and if there's any way to work it around, even if manually?
I tried manually patching my core-oj.jar, but after I replaced it in the system, it no longer boots. Given, it is an odexed ROM, but by deleting the odex files I was able to get a services.jar patch to work perfectly.

Thanks!

About haystack: is it possible to patch the individual APKs instead of the framework JARs?

Hi Lanchon. I roughly understand that haystack is patching the "PackageParser" class(the callee) in the framework JAR. But it is very painful to modify the framework:

  1. users need root the phone
  2. the ROM need to be deodexed
  3. different android version need be patched differently

Looks like dexpatcher 1.5 have implemented "cross-class editing". I'm not entirely sure what that is, but could this patch been applied to the individual APK(the caller) that use "PackageParser", utilizing this cross-class editing? If possible, then users can patch the apks on their computers(or in an android app), self-sign the package, and use MicroG on un-rooted phones.

This trick could also be used by app-developers against untrusted close-sourced third-party SDKs. Many SDKs call privileged api and do nasty things, but the app-developer can not change the framework api. If cross-class edit is possible to be used in this way, the app-developer could intercept sensitive calls and protect themselves as well as their users.

--map-source / --unmap-output inner classes

Hi there,
I hope you're doing ok, weathering the storm as it were.

I've just started playing with --map-source, --unmap-output, --map mapping.txt from a master build to port my patches to a new version of the app with wildly different obfuscation.

One the of the main classes being patches has inner (not anon) classes which I also need to patch.
Are these supported at all at the moment?

java -jar "dexpatcher-tool\tool\build\libs\dexpatcher-1.8.0-alpha4.jar" --deanon-source --main-plan "Anon[_Level]" --output Anon\classes.dex classes.dex --map-source --map ../mapping.txt

I've tried:

com.foo.iq4 -> com.foo.NotificationComponent:
     Object a() -> processNotificationAdd
     Object b() -> sendToDevice
     d() -> NotificationMonitor ; inner class attemp

and

com.foo.iq4 -> com.foo.NotificationComponent:
     Object a() -> processNotificationAdd
     Object b() -> sendToDevice

; second inner class attempt
com.foo.iq4$d -> com.foo.NotificationComponent$NotificationMonitor:
     String a -> tag
     String c -> packageName

neither of which seem to work.

In a decompiled copy of the outputted dex I do get iq4.java replace by NotificationComponent.java with all the inner classes now split out as iq4$a.java and so on. iq4$d.java persists with both the mappings as shown above, where I'd prefer it to be NotificationComponent$NotificationMonitor

Thanks in advance, in general this new mapping looks fantastic!

Debugging not possible after dex2jar

I'm using DexPatcher for patching an AAR file because the annotations and programming in Java are more convenient. When translating the dexed patch back into a jar with dex2jar file for AAR the AAR cannot be debugged anymore. What I noticed is:

  • the major version of the class file is only 50 not 51 anymore.
  • The entries LineNumberTable. LocalVariableTable, StackMapTable are not included anymore. Why are these removed?

I tried to set translateDebugInfo = true in the Dex2jarTask task, but this does not change the result

Breaking the direct/virtual method and static/instance field barriers

Up to the current DexPatcher v1.5.0, the tool processes direct and virtual methods of a class separately (and slightly differently), as it does static and instance fields.

The rationale was that an obfuscated class could potentially contain, for instance, two fields with the same name and type, as long as one field was static and the other was instance. This was assumed possible because different sides of the static/instance field barrier are encoded separately in dex files. By processing static and instance fields separately, current DexPatcher allows patching obfuscated code with such duplications. The same goes for methods and their direct/virtual barrier.

The flip side of this segregation is that edits cannot cross the the direct/virtual method and static/instance field barriers. For instance, this is invalid as of now:

Source:

public void method() { /* ... */ }

Patch:

@DexEdit(target = "method")
private void source_method() { throw null; }

@DexAdd
public void method() {
    // ...
    source_method();
    // ...
}

Here we are trying to rename the source method and reduce its visibility. The problem is that in trying to reduce its visibility from 'public' to 'private', we are crossing the direct/virtual method barrier (given that private methods are always direct), and this is forbidden by current DexPatcher. The workaround is reducing the visibility to 'protected' instead.

However, after researching further the Java and Dalvik bytecode formats, it seems that neither allows fields nor methods with the same name and signature on different sides of the barriers. Furthermore, dexlib2 refuses to write dex with such duplicate members, which can be tested using current DexPatcher v1.5.0:

Source:

public class NameClash {
    static int field;
    static void method() {}
}

Patch:

@DexEdit
public class NameClash {
    // This triggers the following exception in dexlib2:
    // org.jf.util.ExceptionWithContext: Multiple definitions for field Ltest/Main$NameClash;->field:I
    @DexAdd
    int field;

    // This triggers the following exception in dexlib2:
    // org.jf.util.ExceptionWithContext: Multiple definitions for method Ltest/Main$NameClash;->method()V
    @DexAdd
    void method() {}
}

Now the plan is to remove the barriers from DexPatcher tool. This is not trivial and involves some sizable changes, and the possibility of introducing bugs cannot be ruled out. The change would be backwards compatible, and would allow cases such as the above reduction of visibility, and would swap the above fatal runtime exceptions in dexlib2 with proper DexPatcher-level errors.

Error: target not found

I would like to patch an overloaded method; the source says:

    /**
     * Equivalent to openDatabase(file.getPath(), password, factory, CREATE_IF_NECESSARY, databaseHook).
     */
    public static SQLiteDatabase openOrCreateDatabase(File file, String password, CursorFactory factory, SQLiteDatabaseHook databaseHook) {
        return openOrCreateDatabase(file, password, factory, databaseHook, null);
    }

    /**
     * Equivalent to openDatabase(path, password, factory, CREATE_IF_NECESSARY, databaseHook).
     */
    public static SQLiteDatabase openOrCreateDatabase(String path, String password, CursorFactory factory, SQLiteDatabaseHook databaseHook) {
        return openDatabase(path, password, factory, CREATE_IF_NECESSARY, databaseHook);
    }

    /**
     * Equivalent to openDatabase(path, password, factory, CREATE_IF_NECESSARY, databaseHook).
     */
    public static SQLiteDatabase openOrCreateDatabase(File file, String password, CursorFactory factory, SQLiteDatabaseHook databaseHook,
                                                      DatabaseErrorHandler errorHandler) {
        return openOrCreateDatabase(file == null ? null : file.getPath(), password, factory, databaseHook, errorHandler);
    }

    public static SQLiteDatabase openOrCreateDatabase(String path, String password, CursorFactory factory, SQLiteDatabaseHook databaseHook,
                                                      DatabaseErrorHandler errorHandler) {
        return openDatabase(path, password == null ? null : password.toCharArray(), factory, CREATE_IF_NECESSARY, databaseHook, errorHandler);
    }

    public static SQLiteDatabase openOrCreateDatabase(String path, char[] password, CursorFactory factory, SQLiteDatabaseHook databaseHook) {
      return openDatabase(path, password, factory, CREATE_IF_NECESSARY, databaseHook);
    }

    public static SQLiteDatabase openOrCreateDatabase(String path, char[] password, CursorFactory factory, SQLiteDatabaseHook databaseHook,
                                                      DatabaseErrorHandler errorHandler) {
        return openDatabase(path, password, factory, CREATE_IF_NECESSARY, databaseHook, errorHandler);
    }

    /**
     * Equivalent to openDatabase(file.getPath(), password, factory, CREATE_IF_NECESSARY).
     */
    public static SQLiteDatabase openOrCreateDatabase(File file, String password, CursorFactory factory) {
        return openOrCreateDatabase(file, password, factory, null);
    }

    /**
     * Equivalent to openDatabase(path, password, factory, CREATE_IF_NECESSARY).
     */
    public static SQLiteDatabase openOrCreateDatabase(String path, String password, CursorFactory factory) {
      return openDatabase(path, password, factory, CREATE_IF_NECESSARY, null);
    }

    /**
     * Equivalent to openDatabase(path, password, factory, CREATE_IF_NECESSARY).
     */
    public static SQLiteDatabase openOrCreateDatabase(String path, char[] password, CursorFactory factory) {
      return openDatabase(path, password, factory, CREATE_IF_NECESSARY, null);
    }

The method is heavily overloaded, and I would like to apply the following patch:

    @DexEdit(target = "openOrCreateDatabase")
    public static SQLiteDatabase source_openOrCreateDatabase(File file, String string2, CursorFactory cursorFactory) {
        throw null;
    }

    @DexAdd
    public static SQLiteDatabase openOrCreateDatabase(File file, String string2, CursorFactory cursorFactory) {
        SQLiteDatabase rv = source_openOrCreateDatabase(file, string2, cursorFactory);
        log("database created");
        return rv;
    }

Dexpatcher says (version 1.6):

dxp-make-patch: done: patch.dex
info: read 'source.dex'
info: read 'patch.dex'
info: type 'net.sqlcipher.database.SQLiteDatabase': direct method '<init>():void': (SQLiteDatabase.java:9): default ignore
error: type 'net.sqlcipher.database.SQLiteDatabase': direct method 'source_openOrCreateDatabase(java.io.File, java.lang.String, net.sqlcipher.database.CursorFactory):net.sqlcipher.database.SQLiteDatabase': target 'openOrCreateDatabase': (SQLiteDatabase.java:12): target not found
info: type 'net.sqlcipher.database.SQLiteDatabase': virtual method 'onAllReferencesReleased():void': (SQLiteDatabase.java:26): default ignore
1 error(s), 0 warning(s)

How can I tell dexpatcher which method to replace?

Android resource compilation failed

Dear all.
I am trying to play with Instagram APK to see how it works.
1- I cloned the samples folder.
2- Open the "patched-app" as a project.
3- replace the APK file with the latest Instagram apk file.
4- Click on debug


Android resource compilation failed
C:\Users\DELL\AndroidStudioProjects\patched-app\app\build\intermediates\dexpatcher\decoded-app\res\values\public.xml:6082: error: resource 'drawable/$avd_hide_password__0' has invalid entry name '$avd_hide_password__0'. Invalid character '$avd_hide_password__0'.
C:\Users\DELL\AndroidStudioProjects\patched-app\app\build\intermediates\dexpatcher\decoded-app\res\values\public.xml:6083: error: resource 'drawable/$avd_hide_password__1' has invalid entry name '$avd_hide_password__1'. Invalid character '$avd_hide_password__1'.
C:\Users\DELL\AndroidStudioProjects\patched-app\app\build\intermediates\dexpatcher\decoded-app\res\values\public.xml:6084: error: resource 'drawable/$avd_hide_password__2' has invalid entry name '$avd_hide_password__2'. Invalid character '$avd_hide_password__2'.
C:\Users\DELL\AndroidStudioProjects\patched-app\app\build\intermediates\dexpatcher\decoded-app\res\values\public.xml:6085: error: resource 'drawable/$avd_show_password__0' has invalid entry name '$avd_show_password__0'. Invalid character '$avd_show_password__0'.
C:\Users\DELL\AndroidStudioProjects\patched-app\app\build\intermediates\dexpatcher\decoded-app\res\values\public.xml:6086: error: resource 'drawable/$avd_show_password__1' has invalid entry name '$avd_show_password__1'. Invalid character '$avd_show_password__1'.
C:\Users\DELL\AndroidStudioProjects\patched-app\app\build\intermediates\dexpatcher\decoded-app\res\values\public.xml:6087: error: resource 'drawable/$avd_show_password__2' has invalid entry name '$avd_show_password__2'. Invalid character '$avd_show_password__2'.
C:\Users\DELL\AndroidStudioProjects\patched-app\app\build\intermediates\dexpatcher\decoded-app\res\values\public.xml: error: file failed to compile.


Please Advice

DexPatcher Tool Roadplan

A NOTE REGARDING CHANGES THAT BREAK BACKWARDS COMPATIBILITY: All backwards breaking changes should be implemented in the DexPatcher 'annotations' package but not in the tool itself. It is ok for the source code of an old patch to fail to compile against a newer 'annotations' package: if a developer upgrades the DexPatcher toolchain she might need to bring the patch source code up to date too. But an old patch binary should continue to apply cleanly using newer versions of the DexPatcher tool. This means that, even though the 'annotations' package might have changed the way of doing things, the tool should recognize and honor both ways, old and new, in the patch binaries it operates upon.

  • Detect default constructors (that could potentially have been added by the compiler) and if they are trivial (ie, no code besides super call) don't error if there is no action defined for them. Allows not having to define and ignore default constructors (if there are no instance initializers in the class). This is a backwards compatible change. done: v1.3.1.

  • Break the direct/virtual method and static/instance field barriers (#19). done: v1.6.0.

  • Add @DexCheck that targets items but does not modify them. It checks that they exist, minimum accessibility, and static- and constructor-ness match. This helps ensure backwards compatibility of new apps to old patches.

  • Add a class checker that checks contents of a class against the source. The only actions allowed within it are @DexIgnore and @DexCheck. Make @DexReplace and @DexCheck invoke the checker if the item they are processing is a class. Add a defaultAction element to those tags, make it default to @DexIgnore for backwards compatibility.

  • In the Gradle plugins, add an option to inhibit the import of the source symbols. This option can be enabled to make sure that every symbol referenced in the patch is also declared in the patch. If they are declared using @DexCheck, then all symbols will be checked at patch time. This is more developer work but makes the patch fail at patch time if applied against a new version of the app that is missing a symbol (instead of producing a patched app that will fail at runtime with link errors). done:
    v0.4.5.

  • The above works if @DexIgnore is not used on any symbol. However trivial default constructor auto-ignore makes it difficult to keep track of all ignores at development time. The patch could be invoking a certain trivial default constructor that is being auto-ignored but also exists in the app, and a new version of the app might not provide it, and this would end up in a runtime link error. To ensure this cannot happen, add a command line option to the tool to disable trivial default constructor auto-ignore. Note that all information regarding application of a patch should always be encoded in the patch itself and never in command line options to the tool. But in this case, the option is not needed to apply the patch; it is only a development time aid. This also involves a Gradle plugin change, of course. done: v1.4.1, v0.4.6.

  • Add @DexWrap (#9). done: v1.3.0.

  • Add @DexAppend (#10) and maybe DexPrepend for symmetry. This is perfect for static constructors but does not really work for instance constructors. done: v1.4.0.

  • Change the way static constructors (SC's) are handled when no action is defined for them, from triggering an error to this strategy (this is a backwards compatible change):

    • if there is no SC in the patch, do nothing.
    • if there is one:
      • if there is no SC in the source, do a @DexAdd.
      • if there is one, do a @DexAppend.

    done: v1.4.0.

  • Have the new way of handling SC's even if a defaultAction is defined for the class. For this, staticConstructorAction could be decoupled from defaultAction in a backwards breaking change (more on this later), or a DexAction.AUTO value could be added. i decided against introducing this semantic change: it does not pull its own usability weight this late in the game.

    UPDATE: i implemented this by adding a DexAction.NONE element value. it can be used for staticConstructorAction, but the motivation was to better support future @DexCheck-style checking of types being replaced or removed. for backwards compatibility, the replace and remove tags when used on types must not @DexCheck the contents of the patch types they are tagging, effectively making @DexIgnore the default action for them. but a saner behavior where DexPatcher forces you to tag every member explicitly can be restored with @DexReplace/DexRemove(defaultAction = DexAction.NONE). so in the end it is...

    done: v1.6.3.

  • Convert staticConstructorAction and defaultAction from an enum type to a nested annotation. This is a backwards breaking change, and a good time to implement the previous change.

  • Remove support for the deprecated DexTag and change Void.class to void.class as the default value of the targetClass element. done: v1.7.0.

  • Regarding @DexEdit on classes where the patch and targeted classes differ (ie: cross-class edits) on today's DexPatcher: If code from the targeted class is used at all to build the resulting bytecode, the bytecode will almost always be invalid in some ways and will trigger a verification exception (due to differences in the types of the this references, constructors, the hierarchy, etc). Additionally, DexPatcher has had an ingrained golden rule where the bytecode ID of injected items will always match that of the items that trigger the injection in the patch. That way it will always be valid to use those items from the patch code: the item in the patch causing the injection serves as the declaration at patch compile-time for the injected item at runtime. This rule was covertly broken by the second gen tags (@DexWrap, @DexPrepend, @DexAppend) which add hidden items behind-the-scenes, and needs to be overtly broken to fix cross-class edits (and to implement contentOnly, see below). Because of this rule, if onlyEditMembers = true is used on cross-class edits, in reality the name of the class (which is its bytecode ID) is also edited (but not other class attributes) to uphold the rule, even though the unhappy name onlyEditMembers suggests otherwise. This means that for cross-class edits, regardless of the value of onlyEditMembers the name of the class is always changed, invalidating the resulting bytecode; so we have verification exceptions again. To fix cross-class edits, when onlyEditMembers = false DexPatcher has to fully rewrite the targeted class (including code) to replace the type of the target with that of the patch before the edit begins, and when onlyEditMembers = true it has to do the reverse (rewrite the patch class to replace the type of the patch with that of the targeted class before the edit begins) and also fully honor the concept of onlyEditMembers by not renaming the class. This is in theory a backwards breaking change for cross-class edits, but AFAIK these edits never worked except for extremely trivial cases that should continue to work under the new semantics. done: v1.5.0.

  • Deprecate the onlyEditMembers element and replace it with contentOnly. This is to allow extending the usage of the element to other tags besides @DexEdit and to other items besides classes. The new tool accepts both the old and new names of the element, so binary patches compiled for an older version of the tool will continue to apply using the new version. However, recompiling the patches will require adapting them to the name change. done: v1.5.0.

  • Add a contentOnly element to @DexReplace. @DexEdit and @DexReplace with contentOnly = true would be valid only for classes and would both cause class rewriting (see above) if cross-class. done: v1.5.0.

  • Add a contentOnly element to all remaining targeting actions except @DexRemove so that the item injected into the patched code is injected at the targeted location instead of at the patch location, as usual. (This breaks the golden rule mentioned above.) For methods, @DexReplace, @DexWrap, @DexPrepend and @DexAppend would be valid with contentOnly = true and would only replace the existing method's code but not its declaration. For packages, only @DexReplace could be valid with contentOnly = true, but the effort is probably not justified. BTW, regular @DexAppend does not work on instance constructors but could be made to work (with a lot of development effort) by targeting constructors with contentOnly = true from a direct non-static method (ie, a private instance method) any non-static method.

  • With @DexCheck in place, allow a patch to be compatible with some changes in the source app:

    • Allow two tags, one targeted and one non-targeted, for each item, such as @DexEdit or @DexIgnore, as alternatives for when the target is found or not.
    • Some method of tallying to verify for example that one and only one of several items are actually targeting must be provided.
    • Special cases such as @DexWrap or @DexAdd must be considered carefully, given that the recursive call in @DexAdd is definitely not what is intended.
    • Syntactic options:
      • Allow more than one tag on the items. But how is tallying handled then?
      • Allow a fallback element on targeting tags of type DexAction (given that non-targeting tags do not currently have elements) or nested annotation. Tallying is possible albeit ugly, via more elements.
      • An annotation such as @DexOption(ifAction=@..., elseAction=@..., id="...", min=1) could take care of tallying-by-id nicely. Id's could be local to the class or global. Nested @DexOption could allow pre-type processing of the patch method to allow the same patch method to apply against similar methods in different version of the source that have changed an argument type.

More to add here:

  • General method rewriting.
  • Support for obfuscated apps in the Gradle plugins.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.