├── .gitignore
├── .idea
├── .name
├── codeStyles
│ ├── Project.xml
│ └── codeStyleConfig.xml
├── compiler.xml
├── copyright
│ ├── Default.xml
│ └── profiles_settings.xml
├── dictionaries
│ └── rod.xml
├── gradle.xml
├── jarRepositories.xml
├── misc.xml
├── uiDesigner.xml
└── vcs.xml
├── .travis.yml
├── LICENSE.txt
├── NOTICE.txt
├── README.md
├── README.txt
├── annotation
├── build.gradle
└── src
│ └── main
│ └── java
│ └── lanchon
│ └── dexpatcher
│ └── annotation
│ ├── DexAction.java
│ ├── DexAdd.java
│ ├── DexAppend.java
│ ├── DexEdit.java
│ ├── DexIgnore.java
│ ├── DexPrepend.java
│ ├── DexRemove.java
│ ├── DexReplace.java
│ ├── DexTarget.java
│ └── DexWrap.java
├── build.gradle
├── check-copyright.gradle
├── configure-artifacts.gradle
├── configure-publishing.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
├── test
├── build.gradle
├── compose-mapping.txt
├── encode-mapping.txt
├── mapping.txt
├── patch
│ ├── build.gradle
│ └── src
│ │ └── main
│ │ └── java
│ │ └── test
│ │ ├── Main.java
│ │ ├── info
│ │ └── package-info.java
│ │ ├── rec
│ │ ├── Rec.java
│ │ ├── inner
│ │ │ └── RecInner.java
│ │ └── package-info.java
│ │ └── target
│ │ └── package-info.java
├── run-dex-via-adb
├── run-patched-dex-via-adb
├── shell-test
├── shell-test-diff
├── shell-test-ref.txt
├── shell-test-set-ref
├── shell-test.config
├── source
│ ├── build.gradle
│ └── src
│ │ └── main
│ │ └── java
│ │ └── test
│ │ ├── Main.java
│ │ ├── info
│ │ └── package-info.java
│ │ ├── nonrec
│ │ ├── NonRec.java
│ │ └── inner
│ │ │ └── NonRecInner.java
│ │ └── rec
│ │ ├── Rec.java
│ │ └── inner
│ │ └── RecInner.java
└── template-mapping-ref.txt
└── tool
├── about
└── lib
│ ├── commons-cli-LICENSE.txt
│ ├── dexlib2-NOTICE.txt
│ ├── guava-COPYING.txt
│ └── multidexlib2-NOTICE.txt
├── build.gradle
└── src
└── main
└── java
└── lanchon
└── dexpatcher
├── Configuration.java
├── Main.java
├── MapReader.java
├── Parser.java
├── Processor.java
├── core
├── Action.java
├── ActionParser.java
├── Context.java
├── DexPatcher.java
├── Marker.java
├── PatchException.java
├── PatcherAnnotation.java
├── logger
│ ├── BasicLogger.java
│ └── Logger.java
├── model
│ ├── BasicClassDef.java
│ ├── BasicDexFile.java
│ ├── BasicField.java
│ ├── BasicMethod.java
│ └── BasicMethodImplementation.java
├── patcher
│ ├── AbstractPatcher.java
│ ├── ActionBasedPatcher.java
│ ├── AnnotatableSetPatcher.java
│ ├── ClassSetPatcher.java
│ ├── FieldSetPatcher.java
│ ├── MemberSetPatcher.java
│ ├── MethodSetPatcher.java
│ └── PackagePatcher.java
└── util
│ ├── AccessFlagLogger.java
│ ├── DexUtils.java
│ ├── ElementalTypeRewriter.java
│ ├── Id.java
│ ├── InvalidTypeDescriptorException.java
│ ├── Label.java
│ ├── SimpleTypeRewriter.java
│ ├── Target.java
│ ├── TemplateMapFileWriter.java
│ └── TypeName.java
└── transform
├── BaseLogger.java
├── MemberLogger.java
├── TransformLogger.java
├── anonymizer
├── DexAnonymizer.java
└── TypeAnonymizer.java
├── codec
├── BinaryClassNameRewriter.java
├── DexCodec.java
├── DexCodecModule.java
├── StringCodec.java
├── decoder
│ ├── DexDecoder.java
│ └── StringDecoder.java
└── encoder
│ ├── BasicDexEncoder.java
│ ├── BasicStringEncoder.java
│ ├── CopyStringBuilder.java
│ ├── DefaultIgnoredHintTypes.java
│ ├── EncoderConfiguration.java
│ ├── EncoderDexMap.java
│ ├── ReservedWords.java
│ ├── StringEscaper.java
│ ├── StringEscaperConfiguration.java
│ ├── TypeClassifier.java
│ ├── TypeHintMapper.java
│ └── TypeInfoMapper.java
├── mapper
├── DexMapperModule.java
├── MapFileReader.java
├── PatchRewriterModule.java
└── map
│ ├── DexMap.java
│ ├── DexMaps.java
│ ├── LoggingDexMap.java
│ └── builder
│ ├── CompositeMapBuilder.java
│ ├── DexMapping.java
│ ├── InverseMapBuilder.java
│ └── MapBuilder.java
└── util
├── DexVisitor.java
└── wrapper
├── WrapperAnnotation.java
├── WrapperAnnotationElement.java
├── WrapperClassDef.java
├── WrapperField.java
├── WrapperFieldReference.java
├── WrapperMethod.java
├── WrapperMethodReference.java
└── WrapperRewriterModule.java
/.gitignore:
--------------------------------------------------------------------------------
1 | /.gradle/
2 | /.idea/workspace.xml
3 | /.idea/libraries
4 |
5 | /build/
6 | /annotation/build/
7 | /tool/build/
8 | /test/build/
9 | /test/source/build/
10 | /test/patch/build/
11 |
12 | /gradle.properties
13 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | dexpatcher-tool
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/copyright/Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/dictionaries/rod.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | annotatable
5 | anonymization
6 | anonymized
7 | anonymizer
8 | anonymizing
9 | balerdi
10 | dalvik
11 | deanon
12 | deanonymization
13 | deanonymize
14 | deanonymized
15 | deanonymizer
16 | deobfuscated
17 | dexlib
18 | dexpatcher
19 | lanchon
20 | multidexlib
21 | nano
22 | opcode
23 | opcodes
24 | precalculated
25 | reanon
26 | reanonymize
27 | reanonymized
28 | reanonymizer
29 | reanonymizing
30 | smali
31 |
32 |
33 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
25 |
26 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | os: linux
2 | dist: xenial
3 | language: java
4 | jdk: openjdk8
5 |
6 | script:
7 | - ./gradlew clean build portableTest shellTest --stacktrace
8 |
9 | before_cache:
10 | - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
11 | - rm -fr $HOME/.gradle/caches/*/plugin-resolution/
12 |
13 | cache:
14 | directories:
15 | - $HOME/.gradle/caches/
16 | - $HOME/.gradle/wrapper/
17 |
--------------------------------------------------------------------------------
/NOTICE.txt:
--------------------------------------------------------------------------------
1 | ********************************************************************
2 | DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | (GNU General Public License version 3 or later)
4 | ********************************************************************
5 | DexPatcher uses dexlib2 (part of smali) by Ben Gruver (JesusFreke).
6 | Many thanks to him for repeatedly helping me in #smali on freenode.
7 |
8 | DexPatcher also uses other free software libraries. Please see the
9 | LIB-LICENSE folder for details.
10 | ********************************************************************
11 | DexPatcher is free software: you can redistribute it and/or modify
12 | it under the terms of the GNU General Public License as published
13 | by the Free Software Foundation, either version 3 of the License,
14 | or (at your option) any later version.
15 |
16 | DexPatcher is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU General Public License for more details.
20 |
21 | You should have received a copy of the GNU General Public License
22 | along with DexPatcher. If not, see .
23 | ********************************************************************
24 | LICENSING NOTE: Recent versions of DexPatcher no longer require that
25 | users bundle the DexPatcher annotations with every patch (although
26 | continuing to do so has no ill effects). The DexPatcher licensing
27 | terms no longer impose licensing restrictions on patches, as long as
28 | users refrain from bundling the DexPatcher annotations with them.
29 | In particular, DexPatcher patches are no longer considered to be
30 | derivative works of DexPatcher and thus are no longer automatically
31 | covered by the GPL. Legals aside, the DexPatcher project urges you
32 | not to use copyright laws to introduce artificial scarcity in the
33 | world. Please give back to the community: share your work.
34 | ********************************************************************
35 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DexPatcher-tool
2 | ### Android Dalvik bytecode patcher.
3 |
4 | [](https://travis-ci.org/DexPatcher/dexpatcher-tool)
5 |
6 | https://dexpatcher.github.io/
7 |
8 | DexPatcher is free software. (GPLv3+)
9 |
--------------------------------------------------------------------------------
/README.txt:
--------------------------------------------------------------------------------
1 | ===============
2 | DexPatcher-tool
3 | ===============
4 |
5 | Android Dalvik bytecode patcher.
6 | https://dexpatcher.github.io/
7 |
8 | DexPatcher is free software. (GPLv3+)
9 |
--------------------------------------------------------------------------------
/annotation/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | plugins {
12 | id 'java-library'
13 | id 'maven-publish'
14 | id 'signing'
15 | }
16 |
17 | group = parent.group
18 | version = parent.version
19 |
20 | ext.mainArtifact = 'dexpatcher-annotation'
21 | ext.artifactName = 'DexPatcher-annotation'
22 |
23 | sourceCompatibility = '1.6'
24 | def jdk = findProperty('JDK6_HOME') ?: '/usr/lib/jvm/java-6-openjdk-amd64'
25 | def jdk_rt = new File(jdk, 'jre/lib/rt.jar')
26 | if (jdk_rt.exists()) compileJava.options.bootstrapClasspath = files(jdk_rt)
27 |
28 | apply from: '../configure-artifacts.gradle'
29 |
30 | apply from: '../configure-publishing.gradle'
31 |
32 | publishing {
33 | publications {
34 | dexpatcherAnnotation(MavenPublication) {
35 | artifactId = mainArtifact
36 | from components.java
37 | pom {
38 | name = artifactName
39 | configurePom it
40 | }
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/annotation/src/main/java/lanchon/dexpatcher/annotation/DexAction.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.annotation;
12 |
13 | @DexIgnore
14 | public enum DexAction {
15 | ADD,
16 | EDIT,
17 | REPLACE,
18 | REMOVE,
19 | IGNORE,
20 | WRAP,
21 | PREPEND,
22 | APPEND,
23 |
24 | NONE,
25 | UNDEFINED;
26 | }
27 |
--------------------------------------------------------------------------------
/annotation/src/main/java/lanchon/dexpatcher/annotation/DexAdd.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.annotation;
12 |
13 | import java.lang.annotation.Documented;
14 | import java.lang.annotation.ElementType;
15 | import java.lang.annotation.Retention;
16 | import java.lang.annotation.RetentionPolicy;
17 | import java.lang.annotation.Target;
18 |
19 | @DexIgnore
20 | @Documented
21 | @Retention(RetentionPolicy.RUNTIME)
22 | @Target({
23 | ElementType.PACKAGE,
24 | ElementType.TYPE,
25 | ElementType.CONSTRUCTOR,
26 | ElementType.METHOD,
27 | ElementType.FIELD
28 | })
29 | public @interface DexAdd {}
30 |
--------------------------------------------------------------------------------
/annotation/src/main/java/lanchon/dexpatcher/annotation/DexAppend.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.annotation;
12 |
13 | import java.lang.annotation.Documented;
14 | import java.lang.annotation.ElementType;
15 | import java.lang.annotation.Retention;
16 | import java.lang.annotation.RetentionPolicy;
17 | import java.lang.annotation.Target;
18 |
19 | @DexIgnore
20 | @Documented
21 | @Retention(RetentionPolicy.RUNTIME)
22 | @Target({
23 | ElementType.METHOD
24 | })
25 | public @interface DexAppend {
26 | String target() default "";
27 | }
28 |
--------------------------------------------------------------------------------
/annotation/src/main/java/lanchon/dexpatcher/annotation/DexEdit.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.annotation;
12 |
13 | import java.lang.annotation.Documented;
14 | import java.lang.annotation.ElementType;
15 | import java.lang.annotation.Retention;
16 | import java.lang.annotation.RetentionPolicy;
17 | import java.lang.annotation.Target;
18 |
19 | @DexIgnore
20 | @Documented
21 | @Retention(RetentionPolicy.RUNTIME)
22 | @Target({
23 | ElementType.TYPE,
24 | ElementType.CONSTRUCTOR,
25 | ElementType.METHOD,
26 | ElementType.FIELD
27 | })
28 | public @interface DexEdit {
29 | String target() default "";
30 | Class> targetClass() default void.class;
31 | DexAction staticConstructorAction() default DexAction.UNDEFINED;
32 | DexAction defaultAction() default DexAction.UNDEFINED;
33 | boolean contentOnly() default false;
34 | }
35 |
--------------------------------------------------------------------------------
/annotation/src/main/java/lanchon/dexpatcher/annotation/DexIgnore.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.annotation;
12 |
13 | import java.lang.annotation.Documented;
14 | import java.lang.annotation.ElementType;
15 | import java.lang.annotation.Retention;
16 | import java.lang.annotation.RetentionPolicy;
17 | import java.lang.annotation.Target;
18 |
19 | @DexIgnore
20 | @Documented
21 | @Retention(RetentionPolicy.RUNTIME)
22 | @Target({
23 | ElementType.PACKAGE,
24 | ElementType.TYPE,
25 | ElementType.CONSTRUCTOR,
26 | ElementType.METHOD,
27 | ElementType.FIELD,
28 | ElementType.PARAMETER
29 | })
30 | public @interface DexIgnore {}
31 |
--------------------------------------------------------------------------------
/annotation/src/main/java/lanchon/dexpatcher/annotation/DexPrepend.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.annotation;
12 |
13 | import java.lang.annotation.Documented;
14 | import java.lang.annotation.ElementType;
15 | import java.lang.annotation.Retention;
16 | import java.lang.annotation.RetentionPolicy;
17 | import java.lang.annotation.Target;
18 |
19 | @DexIgnore
20 | @Documented
21 | @Retention(RetentionPolicy.RUNTIME)
22 | @Target({
23 | ElementType.METHOD
24 | })
25 | public @interface DexPrepend {
26 | String target() default "";
27 | }
28 |
--------------------------------------------------------------------------------
/annotation/src/main/java/lanchon/dexpatcher/annotation/DexRemove.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.annotation;
12 |
13 | import java.lang.annotation.Documented;
14 | import java.lang.annotation.ElementType;
15 | import java.lang.annotation.Retention;
16 | import java.lang.annotation.RetentionPolicy;
17 | import java.lang.annotation.Target;
18 |
19 | @DexIgnore
20 | @Documented
21 | @Retention(RetentionPolicy.RUNTIME)
22 | @Target({
23 | ElementType.PACKAGE,
24 | ElementType.TYPE,
25 | ElementType.CONSTRUCTOR,
26 | ElementType.METHOD,
27 | ElementType.FIELD
28 | })
29 | public @interface DexRemove {
30 | String target() default "";
31 | Class> targetClass() default void.class;
32 | boolean recursive() default false;
33 | }
34 |
--------------------------------------------------------------------------------
/annotation/src/main/java/lanchon/dexpatcher/annotation/DexReplace.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.annotation;
12 |
13 | import java.lang.annotation.Documented;
14 | import java.lang.annotation.ElementType;
15 | import java.lang.annotation.Retention;
16 | import java.lang.annotation.RetentionPolicy;
17 | import java.lang.annotation.Target;
18 |
19 | @DexIgnore
20 | @Documented
21 | @Retention(RetentionPolicy.RUNTIME)
22 | @Target({
23 | ElementType.PACKAGE,
24 | ElementType.TYPE,
25 | ElementType.CONSTRUCTOR,
26 | ElementType.METHOD
27 | })
28 | public @interface DexReplace {
29 | String target() default "";
30 | Class> targetClass() default void.class;
31 | boolean contentOnly() default false;
32 | boolean recursive() default false;
33 | }
34 |
--------------------------------------------------------------------------------
/annotation/src/main/java/lanchon/dexpatcher/annotation/DexTarget.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.annotation;
12 |
13 | @DexIgnore
14 | public final class DexTarget {
15 | public static final String STATIC_CONSTRUCTOR = "";
16 | public static final String CONSTRUCTOR = "";
17 | private DexTarget() {}
18 | }
19 |
--------------------------------------------------------------------------------
/annotation/src/main/java/lanchon/dexpatcher/annotation/DexWrap.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.annotation;
12 |
13 | import java.lang.annotation.Documented;
14 | import java.lang.annotation.ElementType;
15 | import java.lang.annotation.Retention;
16 | import java.lang.annotation.RetentionPolicy;
17 | import java.lang.annotation.Target;
18 |
19 | @DexIgnore
20 | @Documented
21 | @Retention(RetentionPolicy.RUNTIME)
22 | @Target({
23 | ElementType.METHOD
24 | })
25 | public @interface DexWrap {
26 | String target() default "";
27 | }
28 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | plugins {
12 | id 'base'
13 | }
14 |
15 | group = 'com.github.lanchon.dexpatcher'
16 | version = '1.8.0-beta1'
17 |
18 | apply from: 'check-copyright.gradle'
19 |
20 | wrapper.distributionType = Wrapper.DistributionType.ALL
21 |
--------------------------------------------------------------------------------
/check-copyright.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | task checkCopyrightNotice {
12 | dependsOn { subprojects*.tasks.build }
13 | def notice = "Copyright 2015-${new java.text.SimpleDateFormat('yyyy').format(new Date())}"
14 | def checkNotice = { noticeFile ->
15 | if (!file(noticeFile).text.contains(notice)) {
16 | System.err.println "******************************** WARNING ********************************"
17 | System.err.println "Expired copyright notice: ${noticeFile}"
18 | System.err.println "***************************************************************************"
19 | }
20 | }
21 | doLast {
22 | checkNotice 'NOTICE.txt'
23 | }
24 | }
25 |
26 | build {
27 | dependsOn checkCopyrightNotice
28 | }
29 |
--------------------------------------------------------------------------------
/configure-artifacts.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | java {
12 | withJavadocJar()
13 | withSourcesJar()
14 | }
15 |
16 | processResources {
17 | from(rootDir) {
18 | include 'README.txt'
19 | include 'NOTICE.txt'
20 | include 'LICENSE.txt'
21 | into 'META-INF/about'
22 | }
23 | }
24 |
25 | def sharedManifest = manifest {
26 | attributes(
27 | 'Implementation-Title': artifactName,
28 | 'Implementation-Version': version
29 | )
30 | }
31 |
32 | tasks.withType(Jar).configureEach {
33 | archiveBaseName.set mainArtifact
34 | manifest.from sharedManifest
35 | reproducibleFileOrder = true
36 | preserveFileTimestamps = false
37 | duplicatesStrategy = DuplicatesStrategy.FAIL
38 | }
39 |
--------------------------------------------------------------------------------
/configure-publishing.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | ext.configurePom = { pom ->
12 | pom.description = 'Android Dalvik bytecode patcher.'
13 | pom.url = 'https://github.com/DexPatcher/dexpatcher-tool'
14 | pom.organization {
15 | name = 'DexPatcher'
16 | url = 'https://dexpatcher.github.io/'
17 | }
18 | pom.licenses {
19 | license {
20 | name = 'GNU General Public License (version 3 or later)'
21 | url = 'https://www.gnu.org/licenses/gpl.txt'
22 | }
23 | }
24 | pom.developers {
25 | developer {
26 | name = 'Lanchon'
27 | url = 'https://github.com/Lanchon'
28 | }
29 | }
30 | pom.scm {
31 | connection = 'scm:git:git://github.com/DexPatcher/dexpatcher-tool.git'
32 | developerConnection = 'scm:git:ssh://github.com:DexPatcher/dexpatcher-tool.git'
33 | url = 'https://github.com/DexPatcher/dexpatcher-tool'
34 | }
35 | }
36 |
37 | publishing {
38 | repositories {
39 | maven {
40 | name = 'local'
41 | url = rootProject.layout.buildDirectory.dir('repository')
42 | }
43 | if (project.hasProperty('publishing.url')) {
44 | maven {
45 | name = 'remote'
46 | url = project.getProperty('publishing.url')
47 | credentials {
48 | username = project.getProperty('publishing.username')
49 | password = project.getProperty('publishing.password')
50 | }
51 | }
52 | }
53 | }
54 | }
55 |
56 | signing {
57 | if (project.hasProperty('signing.secretKeyRingFile')) {
58 | sign publishing.publications
59 | }
60 | }
61 |
62 | assemble.dependsOn publishAllPublicationsToLocalRepository
63 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DexPatcher/dexpatcher-tool/e301fb823a857e684c1dd4503a92fee30f966785/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-all.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
34 |
35 | @rem Find java.exe
36 | if defined JAVA_HOME goto findJavaFromJavaHome
37 |
38 | set JAVA_EXE=java.exe
39 | %JAVA_EXE% -version >NUL 2>&1
40 | if "%ERRORLEVEL%" == "0" goto init
41 |
42 | echo.
43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
44 | echo.
45 | echo Please set the JAVA_HOME variable in your environment to match the
46 | echo location of your Java installation.
47 |
48 | goto fail
49 |
50 | :findJavaFromJavaHome
51 | set JAVA_HOME=%JAVA_HOME:"=%
52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
53 |
54 | if exist "%JAVA_EXE%" goto init
55 |
56 | echo.
57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
58 | echo.
59 | echo Please set the JAVA_HOME variable in your environment to match the
60 | echo location of your Java installation.
61 |
62 | goto fail
63 |
64 | :init
65 | @rem Get command-line arguments, handling Windows variants
66 |
67 | if not "%OS%" == "Windows_NT" goto win9xME_args
68 |
69 | :win9xME_args
70 | @rem Slurp the command line arguments.
71 | set CMD_LINE_ARGS=
72 | set _SKIP=2
73 |
74 | :win9xME_args_slurp
75 | if "x%~1" == "x" goto execute
76 |
77 | set CMD_LINE_ARGS=%*
78 |
79 | :execute
80 | @rem Setup the command line
81 |
82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
83 |
84 | @rem Execute Gradle
85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
86 |
87 | :end
88 | @rem End local scope for the variables with windows NT shell
89 | if "%ERRORLEVEL%"=="0" goto mainEnd
90 |
91 | :fail
92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
93 | rem the _cmd.exe /c_ return code!
94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
95 | exit /b 1
96 |
97 | :mainEnd
98 | if "%OS%"=="Windows_NT" endlocal
99 |
100 | :omega
101 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | include ':annotation', ':tool', ':test', ':test:source', ':test:patch'
12 |
--------------------------------------------------------------------------------
/test/compose-mapping.txt:
--------------------------------------------------------------------------------
1 | test.Main$ObfuscatedDbRecord -> test.Main$DbRecord
2 | java.lang.String obfuscatedPut(test.Main$ObfuscatedDbRecord) -> put
3 | test.Main$ObfuscatedDbRecord obfuscatedGet(java.lang.String) -> get
4 | test.Main$ObfuscatedDbRecord[] obfuscatedGetAllRecords() -> getAllRecords
5 | test.Main$ObfuscatedDbRecord obfuscatedParentRecord -> parentRecord
6 |
--------------------------------------------------------------------------------
/test/encode-mapping.txt:
--------------------------------------------------------------------------------
1 | test.Main$ObfuscatedClassForEncodingWithMap -> test.EncodedClass
2 | int obfuscatedField -> field
3 | void obfuscatedMethod() -> method
4 | void obfuscatedMethodWithArg(test.Main$ObfuscatedClassForEncodingWithMap) -> methodWithArg
5 |
--------------------------------------------------------------------------------
/test/mapping.txt:
--------------------------------------------------------------------------------
1 | test.Main$ObfuscatedThing -> test.Main$Thing:
2 | int obfuscatedField -> field
3 | .int obfuscatedField -> weirdField ; the type of this field is the class named 'int' in the default package
4 | void obfuscatedMethod() -> someMethod
5 | float[][] obfuscatedMethod2(int, .java.lang.String, java.lang.Object[]) -> anotherMethodWithArgs
6 | void yetAnotherObfuscatedMethod(test.Main$ObfuscatedThing[]) -> makeFriendsWithOtherThings
7 | int obfuscatedFieldForTargeting -> targetedField
8 | void obfuscatedMethodForTargeting() -> targetedMethod
9 |
10 | test.Main$ObfuscatedClassForTargeting -> test.Main$TargetedClass
11 | int obfuscatedField -> field
12 | void obfuscatedMethod() -> method
13 | void obfuscatedMethodWithArg(test.Main$ObfuscatedClassForTargeting) -> methodWithArg
14 | int obfuscatedFieldForTargeting -> targetedField
15 | void obfuscatedMethodForTargeting() -> targetedMethod
16 |
17 | /test.Main$DbRecord -> test.Main$User
18 | java.lang.String /put(/test.Main$DbRecord) -> put
19 | /test.Main$DbRecord /get(java.lang.String) -> get
20 | /test.Main$DbRecord[] /getAllRecords() -> getAllUsers
21 | /test.Main$DbRecord /parentRecord -> parentUser
22 |
--------------------------------------------------------------------------------
/test/patch/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | plugins {
12 | id 'java'
13 | }
14 |
15 | dependencies {
16 | compileOnly project(':annotation')
17 | }
18 |
--------------------------------------------------------------------------------
/test/patch/src/main/java/test/info/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | @DexReplace
12 | package test.info;
13 |
14 | import lanchon.dexpatcher.annotation.*;
15 |
--------------------------------------------------------------------------------
/test/patch/src/main/java/test/rec/Rec.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package test.rec;
12 |
13 | public class Rec {}
14 |
--------------------------------------------------------------------------------
/test/patch/src/main/java/test/rec/inner/RecInner.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package test.rec.inner;
12 |
13 | public class RecInner {}
14 |
--------------------------------------------------------------------------------
/test/patch/src/main/java/test/rec/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | @DexRemove(recursive = true)
12 | package test.rec;
13 |
14 | import lanchon.dexpatcher.annotation.*;
15 |
--------------------------------------------------------------------------------
/test/patch/src/main/java/test/target/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | @DexRemove(target = "test.nonrec")
12 | package test.target;
13 |
14 | import lanchon.dexpatcher.annotation.*;
15 |
--------------------------------------------------------------------------------
/test/run-dex-via-adb:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | run-dex-via-adb() {
6 | local dexFile="$1"
7 | local mainClass="$2"
8 | echo "--- prepare $dexFile ---"
9 | rm -rf build/run-via-adb
10 | mkdir build/run-via-adb
11 | cp "$dexFile" build/run-via-adb/classes.dex
12 | cd build/run-via-adb
13 | zip run-via-adb.zip classes.dex
14 | cd ../..
15 | adb push build/run-via-adb/run-via-adb.zip /sdcard/run-via-adb.zip
16 | rm -rf build/run-via-adb
17 | echo "--- run $dexFile ---"
18 | adb shell dalvikvm -cp /sdcard/run-via-adb.zip "$mainClass"
19 | echo "--- end $dexFile ---"
20 | echo
21 | }
22 |
23 | run-dex-via-adb "$@"
24 |
--------------------------------------------------------------------------------
/test/run-patched-dex-via-adb:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | ./run-dex-via-adb build/patched.dex test.Main
3 |
--------------------------------------------------------------------------------
/test/shell-test:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | source shell-test.config
6 |
7 | run() {
8 | echo -n "\$"
9 | printf " %q" "$@"
10 | echo
11 | "run-$@"
12 | local ret="$?"
13 | echo
14 | return "$ret"
15 | }
16 |
17 | dex-jar() {
18 | name="$1"
19 | jar=$name/build/libs/$name.jar
20 | dex=build/$name.dex.zip
21 | run d8 --no-desugaring --output $dex $jar
22 | #run dex2jar --force --output $name-dex2jar.jar $dex
23 | }
24 |
25 | cat-file() {
26 | file="$1"
27 | echo "--- cat $file ---"
28 | cat $file
29 | echo "--- end $file ---"
30 | echo
31 | }
32 |
33 | run-jar() {
34 | jar="$1"
35 | echo "--- run $jar ---"
36 | run-java -cp $jar test.Main
37 | echo "--- end $jar ---"
38 | echo
39 | }
40 |
41 | mkdir -p build
42 |
43 | dex-jar source
44 | dex-jar patch
45 |
46 | run dexpatcher --help
47 | run dexpatcher build/source.dex.zip build/patch.dex.zip --output build/patched.dex\
48 | --create-map build/template-mapping.txt\
49 | --map-source --unmap-output --map mapping.txt --compose-map compose-mapping.txt\
50 | --encode-source --encode-map encode-mapping.txt --escape-non-ascii --encode-reserved-chars\
51 | --encode-obfuscated-classes --obfuscated-classes '.*OBF' --encode-class-hints\
52 | --encode-obfuscated-members --obfuscated-members '.*OBF' --encode-member-hints\
53 | --deanon-source --reanon-output --main-plan Anon[_Level] --deanon-patches-alt --no-reanon-errors\
54 | --decode-patches --no-decode-errors\
55 | --debug "$@"
56 |
57 | run sha1sum build/patched.dex
58 |
59 | #cat-file build/template-mapping.txt
60 | run sha1sum build/template-mapping.txt
61 |
62 | if "$RUN_RELEASE_PATCH_TEST"; then
63 |
64 | run dexpatcher build/source.dex.zip build/patch.dex.zip --output build/patched-release.dex\
65 | --unmap-patches --map mapping.txt --compose-map compose-mapping.txt\
66 | --encode-source --encode-map encode-mapping.txt --escape-non-ascii --encode-reserved-chars\
67 | --encode-obfuscated-classes --obfuscated-classes '.*OBF' --encode-class-hints\
68 | --encode-obfuscated-members --obfuscated-members '.*OBF' --encode-member-hints\
69 | --reanon-patches --main-plan Anon[_Level] --deanon-patches-alt --no-reanon-errors\
70 | --decode-patches --no-decode-errors\
71 | --quiet "$@"
72 |
73 | #run sha1sum build/patched-release.dex
74 | run cmp --quiet build/patched.dex build/patched-release.dex || {
75 | echo "error: patched-release.dex differs from patched.dex"
76 | exit 1
77 | }
78 |
79 | fi
80 |
81 | run dex2jar --force --output build/patched-dex2jar.jar build/patched.dex
82 |
83 | run-jar source/build/libs/source.jar
84 | run-jar build/patched-dex2jar.jar
85 |
--------------------------------------------------------------------------------
/test/shell-test-diff:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | mkdir -p build
6 |
7 | ./shell-test "$@" &>build/shell-test-out.txt || {
8 | echo "error: shell-test: execution failed"
9 | echo
10 | echo "====== full output ======"
11 | echo
12 | cat build/shell-test-out.txt
13 | echo
14 | exit 1
15 | }
16 |
17 | diff shell-test-ref.txt build/shell-test-out.txt &>/dev/null || {
18 | echo "error: shell-test: unexpected output"
19 | #echo
20 | #echo "====== full output ======"
21 | #echo
22 | #cat build/shell-test-out.txt
23 | #echo
24 |
25 | sedcmd='s|\(Main\.java\:[0-9]+\)\:|\(Main\.java\:\<\?\>\)\:|g'
26 | sed -r "$sedcmd" shell-test-ref.txt >build/shell-test-ref-filtered.txt
27 | sed -r "$sedcmd" build/shell-test-out.txt >build/shell-test-out-filtered.txt
28 |
29 | echo
30 | echo "====== diff output ======"
31 | echo
32 | diff build/shell-test-ref-filtered.txt build/shell-test-out-filtered.txt --color=always -U8 && {
33 | echo "info: shell-test: only source code line numbers differ"
34 | } || true
35 | echo
36 | exit 2
37 | }
38 |
--------------------------------------------------------------------------------
/test/shell-test-set-ref:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | mkdir -p build
6 |
7 | ./shell-test "$@" &> build/shell-test-out.txt
8 |
9 | cp build/shell-test-out.txt shell-test-ref.txt
10 | cp build/template-mapping.txt template-mapping-ref.txt
11 |
--------------------------------------------------------------------------------
/test/shell-test.config:
--------------------------------------------------------------------------------
1 | # Tool Path Configuration
2 |
3 | run-java() { java "$@"; }
4 | run-d8() { run-java -cp 'build/tools/r8/*' 'com.android.tools.r8.D8' "$@"; }
5 | run-dex2jar() { run-java -cp 'build/tools/dex2jar/*' 'com.googlecode.dex2jar.tools.Dex2jarCmd' "$@"; }
6 |
7 | run-dexpatcher() { run-java -jar ../tool/build/libs/dexpatcher-[0-9]*.jar "$@"; }
8 |
9 | run-sha1sum() { sha1sum "$@"; }
10 | run-cmp() { cmp "$@"; }
11 |
12 | RUN_RELEASE_PATCH_TEST=true
13 |
--------------------------------------------------------------------------------
/test/source/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | plugins {
12 | id 'java'
13 | }
14 |
--------------------------------------------------------------------------------
/test/source/src/main/java/test/info/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | @Deprecated
12 | package test.info;
13 |
--------------------------------------------------------------------------------
/test/source/src/main/java/test/nonrec/NonRec.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package test.nonrec;
12 |
13 | public class NonRec {}
14 |
--------------------------------------------------------------------------------
/test/source/src/main/java/test/nonrec/inner/NonRecInner.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package test.nonrec.inner;
12 |
13 | public class NonRecInner {}
14 |
--------------------------------------------------------------------------------
/test/source/src/main/java/test/rec/Rec.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package test.rec;
12 |
13 | public class Rec {}
14 |
--------------------------------------------------------------------------------
/test/source/src/main/java/test/rec/inner/RecInner.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package test.rec.inner;
12 |
13 | public class RecInner {}
14 |
--------------------------------------------------------------------------------
/tool/about/lib/dexlib2-NOTICE.txt:
--------------------------------------------------------------------------------
1 | The majority of smali/baksmali is written and copyrighted by me (Ben Gruver)
2 | and released under the following license:
3 |
4 | *******************************************************************************
5 | Copyright (c) 2010 Ben Gruver (JesusFreke)
6 | All rights reserved.
7 |
8 | Redistribution and use in source and binary forms, with or without
9 | modification, are permitted provided that the following conditions
10 | are met:
11 | 1. Redistributions of source code must retain the above copyright
12 | notice, this list of conditions and the following disclaimer.
13 | 2. Redistributions in binary form must reproduce the above copyright
14 | notice, this list of conditions and the following disclaimer in the
15 | documentation and/or other materials provided with the distribution.
16 | 3. The name of the author may not be used to endorse or promote products
17 | derived from this software without specific prior written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 | *******************************************************************************
30 |
31 |
32 | Unless otherwise stated in the code/commit message, any changes with the
33 | committer of bgruv@google.com is copyrighted by Google Inc. and released
34 | under the following license:
35 |
36 | *******************************************************************************
37 | Copyright 2011, Google Inc.
38 | All rights reserved.
39 |
40 | Redistribution and use in source and binary forms, with or without
41 | modification, are permitted provided that the following conditions are
42 | met:
43 |
44 | * Redistributions of source code must retain the above copyright
45 | notice, this list of conditions and the following disclaimer.
46 | * Redistributions in binary form must reproduce the above
47 | copyright notice, this list of conditions and the following disclaimer
48 | in the documentation and/or other materials provided with the
49 | distribution.
50 | * Neither the name of Google Inc. nor the names of its
51 | contributors may be used to endorse or promote products derived from
52 | this software without specific prior written permission.
53 |
54 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
55 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
56 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
57 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
58 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
59 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
60 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
61 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
62 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
63 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
64 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
65 | *******************************************************************************
66 |
67 |
68 | Various portions of the code are taken from the Android Open Source Project,
69 | and are used in accordance with the following license:
70 |
71 | *******************************************************************************
72 | Copyright (C) 2007 The Android Open Source Project
73 |
74 | Licensed under the Apache License, Version 2.0 (the "License");
75 | you may not use this file except in compliance with the License.
76 | You may obtain a copy of the License at
77 |
78 | http://www.apache.org/licenses/LICENSE-2.0
79 |
80 | Unless required by applicable law or agreed to in writing, software
81 | distributed under the License is distributed on an "AS IS" BASIS,
82 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
83 | See the License for the specific language governing permissions and
84 | limitations under the License.
85 | *******************************************************************************
--------------------------------------------------------------------------------
/tool/about/lib/multidexlib2-NOTICE.txt:
--------------------------------------------------------------------------------
1 | ********************************************************************
2 | multidexlib2 - Copyright 2015-2020 Rodrigo Balerdi
3 | (GNU General Public License version 3 or later)
4 | ********************************************************************
5 | multidexlib2 is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published
7 | by the Free Software Foundation, either version 3 of the License,
8 | or (at your option) any later version.
9 |
10 | multidexlib2 is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with multidexlib2. If not, see .
17 | ********************************************************************
18 |
--------------------------------------------------------------------------------
/tool/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | plugins {
12 | id 'java-library'
13 | id 'com.github.johnrengelman.shadow' version '5.2.0'
14 | id 'maven-publish'
15 | id 'signing'
16 | }
17 |
18 | group = parent.group
19 | version = parent.version
20 |
21 | ext.mainArtifact = 'dexpatcher-tool'
22 | ext.artifactName = 'DexPatcher-tool'
23 |
24 | def fatArtifact = 'dexpatcher'
25 |
26 | sourceCompatibility = '1.7'
27 | def jdk = findProperty('JDK7_HOME') ?: '/usr/lib/jvm/java-7-openjdk-amd64'
28 | def jdk_rt = new File(jdk, 'jre/lib/rt.jar')
29 | if (jdk_rt.exists()) compileJava.options.bootstrapClasspath = files(jdk_rt)
30 |
31 | repositories {
32 | jcenter()
33 |
34 | // Use local version of multidexlib2:
35 | maven {
36 | url = '../../multidexlib2/build/repository'
37 | }
38 | }
39 |
40 | def dexlib2Version = '2.3.4'
41 | def multidexlib2VersionSuffix = '.r2'
42 |
43 | def multidexlib2Version = dexlib2Version + multidexlib2VersionSuffix
44 |
45 | dependencies {
46 | implementation 'commons-cli:commons-cli:1.4'
47 | implementation 'com.github.lanchon.dexpatcher:multidexlib2:' + multidexlib2Version
48 | api 'org.smali:dexlib2:' + dexlib2Version
49 | }
50 |
51 | compileJava {
52 | options.compilerArgs << '-Xlint:unchecked' << '-Xlint:deprecation'
53 | }
54 |
55 | apply from: '../configure-artifacts.gradle'
56 |
57 | def versionFile = layout.buildDirectory.file('version-file/version')
58 |
59 | task createVersionFile {
60 | inputs.property 'version', version
61 | outputs.file versionFile
62 | doLast {
63 | versionFile.get().asFile.text = version
64 | }
65 | }
66 |
67 | processResources {
68 | dependsOn createVersionFile
69 | from(versionFile) {
70 | into 'lanchon/dexpatcher'
71 | }
72 | }
73 |
74 | // The Shadow plugin erroneously unpacks nested jars.
75 | // The issue can be worked around by double-jarring the jars.
76 | task shadowBugWorkaround(type: Jar) {
77 | destinationDirectory.set layout.buildDirectory.dir('shadow-bug-workaround')
78 | archiveBaseName.set 'nested-content'
79 | from jar
80 | from tasks.getByPath(':annotation:jar')
81 | }
82 |
83 | shadowJar {
84 | archiveBaseName.set fatArtifact
85 | archiveClassifier.set null
86 | manifest {
87 | attributes(
88 | 'Main-Class': 'lanchon.dexpatcher.Main'
89 | )
90 | }
91 | exclude '*.txt'
92 | exclude 'META-INF/*.txt'
93 | exclude 'META-INF/maven/**'
94 | from('about') {
95 | into 'META-INF/about'
96 | }
97 | //from jar
98 | //from tasks.getByPath(':annotation:jar')
99 | from shadowBugWorkaround
100 | }
101 |
102 | assemble.dependsOn shadowJar
103 |
104 | apply from: '../configure-publishing.gradle'
105 |
106 | publishing {
107 | publications {
108 | dexpatcherTool(MavenPublication) {
109 | artifactId = mainArtifact
110 | from components.java
111 | pom {
112 | name = artifactName
113 | configurePom it
114 | }
115 | }
116 | dexpatcher(MavenPublication) {
117 | artifactId = fatArtifact
118 | artifact shadowJar
119 | artifact javadocJar
120 | artifact sourcesJar
121 | pom {
122 | name = artifactName + ' (Fat JAR)'
123 | configurePom it
124 | }
125 | }
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/Configuration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher;
12 |
13 | import java.util.Collections;
14 |
15 | import lanchon.dexpatcher.Processor.PreTransform;
16 | import lanchon.dexpatcher.core.Context;
17 | import lanchon.dexpatcher.core.logger.Logger;
18 | import lanchon.dexpatcher.transform.anonymizer.TypeAnonymizer;
19 | import lanchon.dexpatcher.transform.codec.StringCodec;
20 | import lanchon.dexpatcher.transform.codec.encoder.EncoderConfiguration;
21 | import lanchon.multidexlib2.DexIO;
22 |
23 | public class Configuration {
24 |
25 | public String sourceFile;
26 | public Iterable patchFiles = Collections.emptyList();
27 |
28 | public int apiLevel;
29 |
30 | public boolean multiDex;
31 | public int multiDexJobs = 1;
32 |
33 | public int maxDexPoolSize = DexIO.DEFAULT_MAX_DEX_POOL_SIZE;
34 |
35 | public String annotationPackage = Context.DEFAULT_ANNOTATION_PACKAGE;
36 | public boolean constructorAutoIgnoreDisabled;
37 |
38 | public String patchedFile;
39 | public String templateMapFile;
40 | public boolean dryRun;
41 |
42 | public Logger.Level logLevel = Context.DEFAULT_LOG_LEVEL;
43 |
44 | public String sourceCodeRoot;
45 | public boolean timingStats;
46 |
47 | // Code transform options:
48 |
49 | public boolean mapSource;
50 | public boolean deanonSource;
51 | public boolean deanonSourceAlternate;
52 | public boolean encodeSource;
53 | public boolean decodeSource;
54 | public boolean reanonSource;
55 | public boolean unmapSource;
56 |
57 | public boolean deanonPatches;
58 | public boolean deanonPatchesAlternate;
59 | public boolean decodePatches;
60 | public boolean reanonPatches;
61 | public boolean unmapPatches;
62 |
63 | public boolean decodeOutput;
64 | public boolean reanonOutput;
65 | public boolean unmapOutput;
66 |
67 | public Iterable mapFiles;
68 | public boolean invertMap;
69 | public Iterable composeMapFiles;
70 | public boolean invertComposeMap;
71 |
72 | public String mainAnonymizationPlan = TypeAnonymizer.DEFAULT_MAIN_ANONYMIZATION_PLAN;
73 | public String alternateAnonymizationPlan = TypeAnonymizer.DEFAULT_ALTERNATE_ANONYMIZATION_PLAN;
74 | public boolean treatReanonymizeErrorsAsWarnings;
75 |
76 | public String codeMarker = StringCodec.DEFAULT_CODE_MARKER;
77 | public Iterable encodeMapFiles;
78 | public boolean invertEncodeMap;
79 | public EncoderConfiguration encoderConfiguration = new EncoderConfiguration();
80 | public boolean treatDecodeErrorsAsWarnings;
81 |
82 | public PreTransform preTransform = Processor.DEFAULT_PRE_TRANSFORM;
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/Main.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher;
12 |
13 | import java.io.BufferedReader;
14 | import java.io.IOException;
15 | import java.io.InputStream;
16 | import java.io.InputStreamReader;
17 | import java.util.Locale;
18 |
19 | import lanchon.dexpatcher.core.logger.BasicLogger;
20 | import lanchon.dexpatcher.core.logger.Logger;
21 |
22 | import org.apache.commons.cli.ParseException;
23 |
24 | import static lanchon.dexpatcher.core.logger.Logger.Level.*;
25 |
26 | public class Main {
27 |
28 | public static void main(String[] args) {
29 | Locale.setDefault(Locale.ROOT);
30 | int value = runWithUsage(args);
31 | System.exit(value);
32 | }
33 |
34 | public static int runWithUsage(String[] args) {
35 | if (args.length == 0) {
36 | Parser.printUsage();
37 | return 2;
38 | } else {
39 | return run(args);
40 | }
41 | }
42 |
43 | public static int run(String[] args) {
44 | return run(args, new BasicLogger());
45 | }
46 |
47 | public static int run(String[] args, Logger logger) {
48 | try {
49 | boolean success = runWithExceptions(args, logger);
50 | return success ? 0 : 1;
51 | } catch (ParseException e) {
52 | logger.log(FATAL, e.getMessage());
53 | return 2;
54 | } catch (Exception e) {
55 | if (logger.isLogging(DEBUG)) {
56 | logger.log(FATAL, "exception:", e);
57 | } else {
58 | logger.log(FATAL, "exception: " + e);
59 | }
60 | return 3;
61 | } finally {
62 | logger.flush();
63 | }
64 | }
65 |
66 | public static boolean runWithExceptions(String[] args, Logger logger) throws ParseException, IOException {
67 | try {
68 | Configuration config = Parser.parseCommandLine(args);
69 | if (config == null) return true;
70 | logger.log(NONE, getHeader());
71 | return Processor.processFiles(logger, config);
72 | } finally {
73 | logger.flush();
74 | }
75 | }
76 |
77 | public static String getVersion() {
78 | final String FILE = "version";
79 | try (InputStream is = Main.class.getResourceAsStream(FILE)) {
80 | return new BufferedReader(new InputStreamReader(is)).readLine().trim();
81 | } catch (IOException e) {
82 | return "";
83 | }
84 | }
85 |
86 | public static String getHeader() {
87 | return "DexPatcher version " + Main.getVersion() + " by Lanchon (https://dexpatcher.github.io/)";
88 | }
89 |
90 | private Main() {}
91 |
92 | }
93 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/MapReader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher;
12 |
13 | import java.io.File;
14 | import java.io.IOException;
15 |
16 | import lanchon.dexpatcher.core.logger.Logger;
17 | import lanchon.dexpatcher.transform.mapper.MapFileReader;
18 | import lanchon.dexpatcher.transform.mapper.map.DexMap;
19 | import lanchon.dexpatcher.transform.mapper.map.builder.CompositeMapBuilder;
20 | import lanchon.dexpatcher.transform.mapper.map.builder.DexMapping;
21 | import lanchon.dexpatcher.transform.mapper.map.builder.InverseMapBuilder;
22 | import lanchon.dexpatcher.transform.mapper.map.builder.MapBuilder;
23 |
24 | import static lanchon.dexpatcher.core.logger.Logger.Level.*;
25 |
26 | public final class MapReader {
27 |
28 | public static boolean readMapPair(Iterable mapFiles, DexMap inverseComposeMap, boolean invertMap,
29 | DexMapping directMap, DexMapping inverseMap, Logger logger) throws IOException {
30 | return readMapPair(mapFiles, inverseComposeMap, invertMap ? inverseMap : directMap, invertMap ? directMap : inverseMap,
31 | logger);
32 | }
33 |
34 | public static boolean readMapPair(Iterable mapFiles, DexMap inverseComposeMap, DexMapping directMap,
35 | MapBuilder inverseMap, Logger logger) throws IOException {
36 | // The direct map is needed to read the inverse map. (It will be discarded if not needed further.)
37 | if (directMap == null) {
38 | if (inverseMap == null) return true;
39 | directMap = new DexMapping();
40 | }
41 | MapBuilder directMapBuilder = CompositeMapBuilder.of(directMap, inverseComposeMap);
42 | boolean success = readMap(mapFiles, directMapBuilder, logger);
43 | // Read the inverse map only if needed. (It is more memory efficient to read it again from disk.)
44 | if (inverseMap != null && (success || !Processor.ABORT_ON_EARLY_ERRORS)) {
45 | MapBuilder inverseMapBuilder = new InverseMapBuilder(inverseMap, directMap);
46 | inverseMapBuilder = CompositeMapBuilder.of(inverseMapBuilder, inverseComposeMap);
47 | success = readMap(mapFiles, inverseMapBuilder, logger) && success;
48 | }
49 | return success;
50 | }
51 |
52 | public static boolean readMap(Iterable mapFiles, MapBuilder mapBuilder, Logger logger) throws IOException {
53 | int errors = logger.getMessageCount(FATAL) + logger.getMessageCount(ERROR);
54 | for (String mapFile : mapFiles) {
55 | MapFileReader.read(new File(mapFile), true, mapBuilder, logger);
56 | }
57 | return (errors == (logger.getMessageCount(FATAL) + logger.getMessageCount(ERROR)));
58 | }
59 |
60 | private MapReader() {}
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/core/Action.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.core;
12 |
13 | import java.util.Locale;
14 |
15 | import org.jf.dexlib2.iface.value.EnumEncodedValue;
16 |
17 | public enum Action {
18 |
19 | ADD("DexAdd", false),
20 | EDIT("DexEdit", true),
21 | REPLACE("DexReplace", false),
22 | REMOVE("DexRemove", true),
23 | IGNORE("DexIgnore", true),
24 | WRAP("DexWrap", false),
25 | PREPEND("DexPrepend", false),
26 | APPEND("DexAppend", false),
27 |
28 | NONE(null, false);
29 |
30 | public static final String NAME_UNDEFINED = "UNDEFINED";
31 |
32 | private final String className;
33 | private final String label;
34 | private final boolean ignoresCode;
35 |
36 | Action(String className, boolean ignoresCode) {
37 | this.className = className;
38 | label = name().toLowerCase(Locale.ROOT);
39 | this.ignoresCode = ignoresCode;
40 | }
41 |
42 | public String getClassName() {
43 | return className;
44 | }
45 |
46 | public String getLabel() {
47 | return label;
48 | }
49 |
50 | public boolean ignoresCode() {
51 | return ignoresCode;
52 | }
53 |
54 | public PatchException invalidAction() {
55 | return new PatchException("invalid action (" + label + ")");
56 | }
57 |
58 | public static Action fromEnumEncodedValue(EnumEncodedValue value) {
59 | String s = value.getValue().getName();
60 | if (NAME_UNDEFINED.equals(s)) return null;
61 | return Action.valueOf(s);
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/core/ActionParser.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.core;
12 |
13 | import java.util.Collections;
14 | import java.util.HashMap;
15 | import java.util.Map;
16 |
17 | import lanchon.dexpatcher.core.util.TypeName;
18 |
19 | public class ActionParser {
20 |
21 | private final String annotationPackage;
22 | private final Map actionMap;
23 |
24 | public ActionParser(String annotationPackage) {
25 | this.annotationPackage = annotationPackage;
26 | if (annotationPackage == null) {
27 | actionMap = Collections.emptyMap();
28 | } else {
29 | Action[] actions = Action.values();
30 | int sizeFactor = 4;
31 | actionMap = new HashMap<>(sizeFactor * actions.length);
32 | for (Action action : actions) {
33 | String actionTypeDescriptor = getTypeDescriptor(action);
34 | if (actionTypeDescriptor != null) actionMap.put(actionTypeDescriptor, action);
35 | }
36 | }
37 | }
38 |
39 | public String getAnnotationPackage() {
40 | return annotationPackage;
41 | }
42 |
43 | public boolean isDisabled() {
44 | return annotationPackage == null;
45 | }
46 |
47 | private String getTypeDescriptor(Action action) {
48 | String className = action.getClassName();
49 | if (className == null) return null;
50 | if (!annotationPackage.isEmpty()) className = annotationPackage + '.' + className;
51 | return TypeName.toClassDescriptor(className);
52 | }
53 |
54 | public Action parseTypeDescriptor(String typeDescriptor) {
55 | return actionMap.get(typeDescriptor);
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/core/Context.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.core;
12 |
13 | import java.io.File;
14 |
15 | import lanchon.dexpatcher.core.logger.BasicLogger;
16 | import lanchon.dexpatcher.core.logger.Logger;
17 |
18 | import static lanchon.dexpatcher.core.logger.Logger.Level.*;
19 |
20 | public class Context {
21 |
22 | public static final String DEFAULT_ANNOTATION_PACKAGE = "lanchon.dexpatcher.annotation";
23 | public static final Logger.Level DEFAULT_LOG_LEVEL = WARN;
24 |
25 | public static class Builder {
26 |
27 | private final Logger logger;
28 | private String annotationPackage = DEFAULT_ANNOTATION_PACKAGE;
29 | private boolean constructorAutoIgnoreDisabled;
30 | private String sourceCodeRoot;
31 |
32 | public Builder() {
33 | this(DEFAULT_LOG_LEVEL);
34 | }
35 |
36 | public Builder(Logger.Level logLevel) {
37 | this(new BasicLogger());
38 | logger.setLogLevel(logLevel);
39 | }
40 |
41 | public Builder(Logger logger) {
42 | this.logger = logger;
43 | }
44 |
45 | public Builder setAnnotationPackage(String value) {
46 | annotationPackage = value;
47 | return this;
48 | }
49 |
50 | public Builder setConstructorAutoIgnoreDisabled(boolean value) {
51 | constructorAutoIgnoreDisabled = value;
52 | return this;
53 | }
54 |
55 | public Builder setSourceCodeRoot(String value) {
56 | sourceCodeRoot = value;
57 | return this;
58 | }
59 |
60 | public Context build() {
61 | return new Context(logger, annotationPackage, constructorAutoIgnoreDisabled, sourceCodeRoot);
62 | }
63 |
64 | }
65 |
66 | private final Logger logger;
67 | private final ActionParser actionParser;
68 | private final boolean constructorAutoIgnoreDisabled;
69 | private final String sourceCodeRoot;
70 |
71 | private Context(Logger logger, String annotationPackage, boolean constructorAutoIgnoreDisabled,
72 | String sourceCodeRoot) {
73 | this.logger = logger;
74 | actionParser = new ActionParser(annotationPackage);
75 | this.constructorAutoIgnoreDisabled = constructorAutoIgnoreDisabled;
76 | if (sourceCodeRoot != null && !sourceCodeRoot.isEmpty() && !sourceCodeRoot.endsWith(File.separator)) {
77 | sourceCodeRoot += File.separator;
78 | }
79 | this.sourceCodeRoot = sourceCodeRoot;
80 | }
81 |
82 | public Logger getLogger() {
83 | return logger;
84 | }
85 |
86 | public ActionParser getActionParser() {
87 | return actionParser;
88 | }
89 |
90 | public boolean isConstructorAutoIgnoreDisabled() {
91 | return constructorAutoIgnoreDisabled;
92 | }
93 |
94 | public String getSourceCodeRoot() {
95 | return sourceCodeRoot;
96 | }
97 |
98 | }
99 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/core/DexPatcher.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.core;
12 |
13 | import java.util.Collection;
14 | import java.util.Collections;
15 | import java.util.LinkedHashSet;
16 | import java.util.Set;
17 |
18 | import lanchon.dexpatcher.core.model.BasicDexFile;
19 | import lanchon.dexpatcher.core.patcher.PackagePatcher;
20 |
21 | import org.jf.dexlib2.Opcodes;
22 | import org.jf.dexlib2.iface.ClassDef;
23 | import org.jf.dexlib2.iface.DexFile;
24 |
25 | public class DexPatcher {
26 |
27 | public static DexFile process(Context context, DexFile sourceDex, DexFile patchDex) {
28 | return process(context, sourceDex, patchDex, sourceDex.getOpcodes());
29 | }
30 |
31 | public static DexFile process(Context context, DexFile sourceDex, DexFile patchDex, Opcodes opcodes) {
32 | Set extends ClassDef> sourceClasses = sourceDex.getClasses();
33 | Set extends ClassDef> patchClasses = patchDex.getClasses();
34 | PackagePatcher patcher = new PackagePatcher(context);
35 | Collection patchedClasses = patcher.process(sourceClasses, sourceClasses.size(),
36 | patchClasses, patchClasses.size());
37 | return new BasicDexFile(opcodes, Collections.unmodifiableSet(new LinkedHashSet<>(patchedClasses)));
38 | }
39 |
40 | private DexPatcher() {}
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/core/Marker.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.core;
12 |
13 | import lanchon.dexpatcher.core.util.TypeName;
14 |
15 | public class Marker {
16 |
17 | // Annotation Elements
18 |
19 | public static final String ELEM_TARGET = "target";
20 | public static final String ELEM_TARGET_CLASS = "targetClass";
21 | public static final String ELEM_STATIC_CONSTRUCTOR_ACTION = "staticConstructorAction";
22 | public static final String ELEM_DEFAULT_ACTION = "defaultAction";
23 | public static final String ELEM_CONTENT_ONLY = "contentOnly";
24 | public static final String ELEM_RECURSIVE = "recursive";
25 |
26 | public static final String ELEM_ONLY_EDIT_MEMBERS = "onlyEditMembers"; // deprecated
27 |
28 | // Actions
29 |
30 | private static final String DEXPATCHER_PREFIX = "__$";
31 |
32 | public static final String WRAP_SOURCE_SUFFIX = DEXPATCHER_PREFIX + "wrapSource";
33 | public static final String PREPEND_SOURCE_SUFFIX = DEXPATCHER_PREFIX + "prependSource";
34 | public static final String PREPEND_PATCH_SUFFIX = DEXPATCHER_PREFIX + "prependPatch";
35 | public static final String APPEND_SOURCE_SUFFIX = DEXPATCHER_PREFIX + "appendSource";
36 | public static final String APPEND_PATCH_SUFFIX = DEXPATCHER_PREFIX + "appendPatch";
37 |
38 | public static final String SPECIAL_METHOD_PREFIX = DEXPATCHER_PREFIX;
39 |
40 | // Dalvik
41 |
42 | public static final String TYPE_VOID = "V";
43 | public static final String TYPE_INNER_CLASS = TypeName.toClassDescriptor("dalvik.annotation.InnerClass");
44 | public static final String ELEM_ACCESS_FLAGS = "accessFlags";
45 | public static final String NAME_VOID = "void";
46 | public static final String NAME_STATIC_CONSTRUCTOR = "";
47 | public static final String NAME_INSTANCE_CONSTRUCTOR = "";
48 | public static final String NAME_PACKAGE_INFO = "package-info";
49 |
50 | private Marker() {}
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/core/PatchException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.core;
12 |
13 | @SuppressWarnings("serial")
14 | public class PatchException extends Exception {
15 |
16 | public PatchException(String message) {
17 | super(message);
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/core/logger/BasicLogger.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.core.logger;
12 |
13 | import java.io.PrintStream;
14 | import java.io.PrintWriter;
15 |
16 | public class BasicLogger extends Logger {
17 |
18 | private final PrintWriter out;
19 | private final PrintWriter err;
20 |
21 | public BasicLogger() {
22 | this(System.out, System.err);
23 | }
24 |
25 | public BasicLogger(PrintStream out) {
26 | this(out, null);
27 | }
28 |
29 | public BasicLogger(PrintWriter out) {
30 | this(out, null);
31 | }
32 |
33 | public BasicLogger(PrintStream out, PrintStream err) {
34 | this(new PrintWriter(out, true), err != null ? new PrintWriter(err, true) : null);
35 | }
36 |
37 | public BasicLogger(PrintWriter out, PrintWriter err) {
38 | this.out = out;
39 | this.err = err;
40 | flush();
41 | }
42 |
43 | @Override
44 | protected void doLog(Level level, String message, Throwable throwable) {
45 | boolean isError = false;
46 | switch (level) {
47 | case ERROR:
48 | case FATAL:
49 | isError = true;
50 | case DEBUG:
51 | case INFO:
52 | case WARN:
53 | message = level.getLabel() + ": " + message;
54 | case NONE:
55 | break;
56 | default:
57 | throw new AssertionError("Unexpected log level");
58 | }
59 | if (isError && err != null) {
60 | out.flush();
61 | err.println(message);
62 | if (throwable != null) throwable.printStackTrace(err);
63 | err.flush();
64 | } else {
65 | out.println(message);
66 | if (throwable != null) {
67 | throwable.printStackTrace(out);
68 | out.flush();
69 | }
70 | }
71 | }
72 |
73 | @Override
74 | public void flush() {
75 | out.flush();
76 | if (err != null) err.flush();
77 | }
78 |
79 | @Override
80 | public void close() {
81 | out.close();
82 | if (err != null) err.close();
83 | }
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/core/logger/Logger.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.core.logger;
12 |
13 | import java.io.Closeable;
14 | import java.io.Flushable;
15 |
16 | import static lanchon.dexpatcher.core.logger.Logger.Level.*;
17 |
18 | public abstract class Logger implements Flushable, Closeable {
19 |
20 | public enum Level {
21 |
22 | DEBUG("debug"),
23 | INFO("info"),
24 | WARN("warning"),
25 | ERROR("error"),
26 | FATAL("fatal"),
27 | NONE("none");
28 |
29 | private final String label;
30 |
31 | Level(String label) {
32 | this.label = label;
33 | }
34 |
35 | public String getLabel() {
36 | return label;
37 | }
38 |
39 | }
40 |
41 | private Level logLevel;
42 | private int logLevelOrdinal;
43 | private int isLoggingOrdinal;
44 | private int[] counts;
45 |
46 | public Logger() {
47 | setLogLevel(DEBUG);
48 | clearMessageCounts();
49 | }
50 |
51 | public final void log(Level level, String message) {
52 | log(level, message, null);
53 | }
54 |
55 | public final void log(Level level, String message, Throwable throwable) {
56 | if (message == null) throw new NullPointerException("message");
57 | int levelOrdinal = level.ordinal();
58 | counts[levelOrdinal]++;
59 | if (levelOrdinal >= logLevelOrdinal) doLog(level, message, throwable);
60 | }
61 |
62 | public Level getLogLevel() {
63 | return logLevel;
64 | }
65 |
66 | public void setLogLevel(Level logLevel) {
67 | this.logLevel = logLevel;
68 | logLevelOrdinal = logLevel.ordinal();
69 | isLoggingOrdinal = Math.min(logLevelOrdinal, WARN.ordinal());
70 | }
71 |
72 | public final boolean isLogging(Level level) {
73 | return level.ordinal() >= isLoggingOrdinal;
74 | }
75 |
76 | public int getMessageCount(Level level) {
77 | return counts[level.ordinal()];
78 | }
79 |
80 | public void clearMessageCounts() {
81 | counts = new int[Level.values().length];
82 | }
83 |
84 | public boolean hasNotLoggedErrors() {
85 | int errors = getMessageCount(FATAL) + getMessageCount(ERROR);
86 | return errors == 0;
87 | }
88 |
89 | public void logErrorAndWarningCounts() {
90 | int errors = getMessageCount(FATAL) + getMessageCount(ERROR);
91 | int warnings = getMessageCount(WARN);
92 | //if (errors != 0 || warnings != 0) {
93 | log(NONE, errors + " error(s), " + warnings + " warning(s)");
94 | //}
95 | }
96 |
97 | protected abstract void doLog(Level level, String message, Throwable throwable);
98 |
99 | public abstract void flush();
100 | public abstract void close();
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/core/model/BasicClassDef.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.core.model;
12 |
13 | import java.util.List;
14 | import java.util.Set;
15 |
16 | import com.google.common.collect.Iterables;
17 | import org.jf.dexlib2.base.reference.BaseTypeReference;
18 | import org.jf.dexlib2.iface.Annotation;
19 | import org.jf.dexlib2.iface.ClassDef;
20 | import org.jf.dexlib2.iface.Field;
21 | import org.jf.dexlib2.iface.Method;
22 | import org.jf.dexlib2.util.FieldUtil;
23 | import org.jf.dexlib2.util.MethodUtil;
24 |
25 | public class BasicClassDef extends BaseTypeReference implements ClassDef {
26 |
27 | private final String type;
28 | private final int accessFlags;
29 | private final String superclass;
30 | private final List interfaces;
31 | private final String sourceFile;
32 | private final Set extends Annotation> annotations;
33 | private final Iterable extends Field> fields;
34 | private final Iterable extends Field> staticFields;
35 | private final Iterable extends Field> instanceFields;
36 | private final Iterable extends Method> methods;
37 | private final Iterable extends Method> directMethods;
38 | private final Iterable extends Method> virtualMethods;
39 |
40 | public BasicClassDef(
41 | String type,
42 | int accessFlags,
43 | String superclass,
44 | List interfaces,
45 | String sourceFile,
46 | Set extends Annotation> annotations,
47 | Iterable extends Field> fields,
48 | Iterable extends Method> methods
49 | ) {
50 | this.type = type;
51 | this.accessFlags = accessFlags;
52 | this.superclass = superclass;
53 | this.interfaces = interfaces;
54 | this.sourceFile = sourceFile;
55 | this.annotations = annotations;
56 | this.fields = fields;
57 | this.staticFields = Iterables.filter(fields, FieldUtil.FIELD_IS_STATIC);
58 | this.instanceFields = Iterables.filter(fields, FieldUtil.FIELD_IS_INSTANCE);
59 | this.methods = methods;
60 | this.directMethods = Iterables.filter(methods, MethodUtil.METHOD_IS_DIRECT);
61 | this.virtualMethods = Iterables.filter(methods, MethodUtil.METHOD_IS_VIRTUAL);
62 | }
63 |
64 | public BasicClassDef(
65 | String type,
66 | int accessFlags,
67 | String superclass,
68 | List interfaces,
69 | String sourceFile,
70 | Set extends Annotation> annotations,
71 | Iterable extends Field> staticFields,
72 | Iterable extends Field> instanceFields,
73 | Iterable extends Method> directMethods,
74 | Iterable extends Method> virtualMethods
75 | ) {
76 | this.type = type;
77 | this.accessFlags = accessFlags;
78 | this.superclass = superclass;
79 | this.interfaces = interfaces;
80 | this.sourceFile = sourceFile;
81 | this.annotations = annotations;
82 | this.fields = Iterables.concat(staticFields, instanceFields);
83 | this.staticFields = staticFields;
84 | this.instanceFields = instanceFields;
85 | this.methods = Iterables.concat(directMethods, virtualMethods);
86 | this.directMethods = directMethods;
87 | this.virtualMethods = virtualMethods;
88 | }
89 |
90 | @Override
91 | public String getType() {
92 | return type;
93 | }
94 |
95 | @Override
96 | public int getAccessFlags() {
97 | return accessFlags;
98 | }
99 |
100 | @Override
101 | public String getSuperclass() {
102 | return superclass;
103 | }
104 |
105 | @Override
106 | public List getInterfaces() {
107 | return interfaces;
108 | }
109 |
110 | @Override
111 | public String getSourceFile() {
112 | return sourceFile;
113 | }
114 |
115 | @Override
116 | public Set extends Annotation> getAnnotations() {
117 | return annotations;
118 | }
119 |
120 | @Override
121 | public Iterable extends Field> getFields() {
122 | return fields;
123 | }
124 |
125 | @Override
126 | public Iterable extends Field> getStaticFields() {
127 | return staticFields;
128 | }
129 |
130 | @Override
131 | public Iterable extends Field> getInstanceFields() {
132 | return instanceFields;
133 | }
134 |
135 | @Override
136 | public Iterable extends Method> getMethods() {
137 | return methods;
138 | }
139 |
140 | @Override
141 | public Iterable extends Method> getDirectMethods() {
142 | return directMethods;
143 | }
144 |
145 | @Override
146 | public Iterable extends Method> getVirtualMethods() {
147 | return virtualMethods;
148 | }
149 |
150 | }
151 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/core/model/BasicDexFile.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.core.model;
12 |
13 | import java.util.Set;
14 |
15 | import org.jf.dexlib2.Opcodes;
16 | import org.jf.dexlib2.iface.ClassDef;
17 | import org.jf.dexlib2.iface.DexFile;
18 |
19 | public class BasicDexFile implements DexFile {
20 |
21 | private final Opcodes opcodes;
22 | private final Set extends ClassDef> classes;
23 |
24 | public BasicDexFile(
25 | Opcodes opcodes,
26 | Set extends ClassDef> classes
27 | ) {
28 | this.opcodes = opcodes;
29 | this.classes = classes;
30 | }
31 |
32 | @Override
33 | public Opcodes getOpcodes() {
34 | return opcodes;
35 | }
36 |
37 | @Override
38 | public Set extends ClassDef> getClasses() {
39 | return classes;
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/core/model/BasicField.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.core.model;
12 |
13 | import java.util.Set;
14 |
15 | import org.jf.dexlib2.base.reference.BaseFieldReference;
16 | import org.jf.dexlib2.iface.Annotation;
17 | import org.jf.dexlib2.iface.Field;
18 | import org.jf.dexlib2.iface.value.EncodedValue;
19 |
20 | public class BasicField extends BaseFieldReference implements Field {
21 |
22 | private final String definingClass;
23 | private final String name;
24 | private final String type;
25 | private final int accessFlags;
26 | private final EncodedValue initialValue;
27 | private final Set extends Annotation> annotations;
28 |
29 | public BasicField(
30 | String definingClass,
31 | String name,
32 | String type,
33 | int accessFlags,
34 | EncodedValue initialValue,
35 | Set extends Annotation> annotations
36 | ) {
37 | this.definingClass = definingClass;
38 | this.name = name;
39 | this.type = type;
40 | this.accessFlags = accessFlags;
41 | this.initialValue = initialValue;
42 | this.annotations = annotations;
43 | }
44 |
45 | @Override
46 | public String getDefiningClass() {
47 | return definingClass;
48 | }
49 |
50 | @Override
51 | public String getName() {
52 | return name;
53 | }
54 |
55 | @Override
56 | public String getType() {
57 | return type;
58 | }
59 |
60 | @Override
61 | public int getAccessFlags() {
62 | return accessFlags;
63 | }
64 |
65 | @Override
66 | public EncodedValue getInitialValue() {
67 | return initialValue;
68 | }
69 |
70 | @Override
71 | public Set extends Annotation> getAnnotations() {
72 | return annotations;
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/core/model/BasicMethod.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.core.model;
12 |
13 | import java.util.List;
14 | import java.util.Set;
15 |
16 | import org.jf.dexlib2.base.reference.BaseMethodReference;
17 | import org.jf.dexlib2.iface.Annotation;
18 | import org.jf.dexlib2.iface.Method;
19 | import org.jf.dexlib2.iface.MethodImplementation;
20 | import org.jf.dexlib2.iface.MethodParameter;
21 |
22 | public class BasicMethod extends BaseMethodReference implements Method {
23 |
24 | private final String definingClass;
25 | private final String name;
26 | private final List extends MethodParameter> parameters;
27 | private final String returnType;
28 | private final int accessFlags;
29 | private final Set extends Annotation> annotations;
30 | private final MethodImplementation methodImplementation;
31 |
32 | public BasicMethod(
33 | String definingClass,
34 | String name,
35 | List extends MethodParameter> parameters,
36 | String returnType,
37 | int accessFlags,
38 | Set extends Annotation> annotations,
39 | MethodImplementation methodImplementation
40 | ) {
41 | this.definingClass = definingClass;
42 | this.name = name;
43 | this.parameters = parameters;
44 | this.returnType = returnType;
45 | this.accessFlags = accessFlags;
46 | this.annotations = annotations;
47 | this.methodImplementation = methodImplementation;
48 | }
49 |
50 | @Override
51 | public String getDefiningClass() {
52 | return definingClass;
53 | }
54 |
55 | @Override
56 | public String getName() {
57 | return name;
58 | }
59 |
60 | @Override
61 | public List extends MethodParameter> getParameters() {
62 | return parameters;
63 | }
64 |
65 | @Override
66 | public String getReturnType() {
67 | return returnType;
68 | }
69 |
70 | @Override
71 | public int getAccessFlags() {
72 | return accessFlags;
73 | }
74 |
75 | @Override
76 | public Set extends Annotation> getAnnotations() {
77 | return annotations;
78 | }
79 |
80 | @Override
81 | public MethodImplementation getImplementation() {
82 | return methodImplementation;
83 | }
84 |
85 | @Override
86 | public List extends CharSequence> getParameterTypes() {
87 | return parameters;
88 | }
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/core/model/BasicMethodImplementation.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.core.model;
12 |
13 | import java.util.List;
14 |
15 | import org.jf.dexlib2.iface.ExceptionHandler;
16 | import org.jf.dexlib2.iface.MethodImplementation;
17 | import org.jf.dexlib2.iface.TryBlock;
18 | import org.jf.dexlib2.iface.debug.DebugItem;
19 | import org.jf.dexlib2.iface.instruction.Instruction;
20 |
21 | public class BasicMethodImplementation implements MethodImplementation {
22 |
23 | private final int registerCount;
24 | private final Iterable extends Instruction> instructions;
25 | private final List extends TryBlock extends ExceptionHandler>> tryBlocks;
26 | private final Iterable extends DebugItem> debugItems;
27 |
28 | public BasicMethodImplementation(
29 | int registerCount,
30 | Iterable extends Instruction> instructions,
31 | List extends TryBlock extends ExceptionHandler>> tryBlocks,
32 | Iterable extends DebugItem> debugItems
33 | ) {
34 | this.registerCount = registerCount;
35 | this.instructions = instructions;
36 | this.tryBlocks = tryBlocks;
37 | this.debugItems = debugItems;
38 | }
39 |
40 | @Override
41 | public int getRegisterCount() {
42 | return registerCount;
43 | }
44 |
45 | @Override
46 | public Iterable extends Instruction> getInstructions() {
47 | return instructions;
48 | }
49 |
50 | @Override
51 | public List extends TryBlock extends ExceptionHandler>> getTryBlocks() {
52 | return tryBlocks;
53 | }
54 |
55 | @Override
56 | public Iterable extends DebugItem> getDebugItems() {
57 | return debugItems;
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/core/patcher/ActionBasedPatcher.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.core.patcher;
12 |
13 | import lanchon.dexpatcher.core.Action;
14 | import lanchon.dexpatcher.core.Context;
15 | import lanchon.dexpatcher.core.PatchException;
16 |
17 | import static lanchon.dexpatcher.core.logger.Logger.Level.*;
18 |
19 | public abstract class ActionBasedPatcher extends AbstractPatcher {
20 |
21 | public interface ActionContext {
22 | Action getAction();
23 | }
24 |
25 | protected ActionBasedPatcher(Context context) {
26 | super(context);
27 | }
28 |
29 | protected ActionBasedPatcher(AbstractPatcher> parent) {
30 | super(parent);
31 | }
32 |
33 | // Implementation
34 |
35 | @Override
36 | protected void onPatch(String patchId, T patch) throws PatchException {
37 | C actionContext = getActionContext(patchId, patch);
38 | onPrepare(patchId, patch, actionContext);
39 | Action action = actionContext.getAction();
40 | if (isLogging(DEBUG)) log(DEBUG, action.getLabel());
41 | switch (action) {
42 | case ADD:
43 | onAdd(patchId, patch, actionContext);
44 | break;
45 | case EDIT:
46 | onEdit(patchId, patch, actionContext);
47 | break;
48 | case REPLACE:
49 | onReplace(patchId, patch, actionContext);
50 | break;
51 | case REMOVE:
52 | onRemove(patchId, patch, actionContext);
53 | break;
54 | case IGNORE:
55 | onIgnore(patchId, patch, actionContext);
56 | break;
57 | case WRAP:
58 | onWrap(patchId, patch, actionContext);
59 | break;
60 | case PREPEND:
61 | onSplice(patchId, patch, actionContext, Action.PREPEND);
62 | break;
63 | case APPEND:
64 | onSplice(patchId, patch, actionContext, Action.APPEND);
65 | break;
66 | default:
67 | throw new AssertionError("Unexpected action");
68 | }
69 | }
70 |
71 | // Intermediate Handlers
72 |
73 | protected void onAdd(String patchId, T patch, C actionContext) throws PatchException {
74 | T patched = onSimpleAdd(patch, actionContext);
75 | addPatched(patch, patched);
76 | }
77 |
78 | protected void onEdit(String patchId, T patch, C actionContext) throws PatchException {
79 | String targetId = getTargetId(patchId, patch, actionContext);
80 | boolean inPlace = patchId.equals(targetId);
81 | T target = findTarget(targetId, inPlace);
82 | T patched = onSimpleEdit(patch, actionContext, target, inPlace);
83 | addPatched(patch, patched);
84 | }
85 |
86 | protected void onReplace(String patchId, T patch, C actionContext) throws PatchException {
87 | String targetId = getTargetId(patchId, patch, actionContext);
88 | boolean inPlace = patchId.equals(targetId);
89 | T target = findTarget(targetId, false);
90 | T patched = onSimpleReplace(patch, actionContext, target, inPlace);
91 | addPatched(patch, patched);
92 | }
93 |
94 | protected void onRemove(String patchId, T patch, C actionContext) throws PatchException {
95 | String targetId = getTargetId(patchId, patch, actionContext);
96 | T target = findTarget(targetId, false);
97 | onSimpleRemove(patch, actionContext, target);
98 | }
99 |
100 | protected void onIgnore(String patchId, T patch, C actionContext) throws PatchException {}
101 |
102 | protected void onWrap(String patchId, T patch, C actionContext) throws PatchException {
103 | throw Action.WRAP.invalidAction();
104 | }
105 |
106 | protected void onSplice(String patchId, T patch, C actionContext, Action action) throws PatchException {
107 | throw action.invalidAction();
108 | }
109 |
110 | // Handlers
111 |
112 | protected abstract C getActionContext(String patchId, T patch) throws PatchException;
113 | protected void onPrepare(String patchId, T patch, C actionContext) throws PatchException {}
114 | protected abstract String getTargetId(String patchId, T patch, C actionContext) throws PatchException;
115 |
116 | protected abstract T onSimpleAdd(T patch, C actionContext);
117 | protected abstract T onSimpleEdit(T patch, C actionContext, T target, boolean inPlace);
118 | protected abstract T onSimpleReplace(T patch, C actionContext, T target, boolean inPlace);
119 | protected void onSimpleRemove(T patch, C actionContext, T target) {}
120 |
121 | }
122 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/core/patcher/AnnotatableSetPatcher.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.core.patcher;
12 |
13 | import java.io.File;
14 | import java.util.Set;
15 |
16 | import lanchon.dexpatcher.core.Action;
17 | import lanchon.dexpatcher.core.Context;
18 | import lanchon.dexpatcher.core.PatchException;
19 | import lanchon.dexpatcher.core.PatcherAnnotation;
20 | import lanchon.dexpatcher.core.logger.Logger;
21 | import lanchon.dexpatcher.core.util.AccessFlagLogger;
22 |
23 | import org.jf.dexlib2.iface.Annotatable;
24 | import org.jf.dexlib2.iface.Annotation;
25 | import org.jf.dexlib2.iface.ClassDef;
26 |
27 | import static lanchon.dexpatcher.core.logger.Logger.Level.*;
28 |
29 | public abstract class AnnotatableSetPatcher extends ActionBasedPatcher {
30 |
31 | private ClassDef sourceFileClass;
32 | private String sourceFileName;
33 |
34 | protected AnnotatableSetPatcher(Context context) {
35 | super(context);
36 | }
37 |
38 | protected AnnotatableSetPatcher(AnnotatableSetPatcher> parent) {
39 | super(parent);
40 | sourceFileClass = parent.sourceFileClass;
41 | sourceFileName = parent.sourceFileName;
42 | }
43 |
44 | // Debug Info
45 |
46 | protected void setSourceFileClass(ClassDef sourceFileClass) {
47 | this.sourceFileClass = sourceFileClass;
48 | sourceFileName = null;
49 | }
50 |
51 | protected String getSourceFileName() {
52 | // Parse debug information lazily.
53 | if (sourceFileClass != null) {
54 | sourceFileName = sourceFileClass.getSourceFile();
55 | if (sourceFileName != null && getContext().getSourceCodeRoot() != null) {
56 | String type = sourceFileClass.getType();
57 | int i = type.lastIndexOf('/');
58 | if (i >= 1) {
59 | String path = type.substring(1, i + 1).replace('/', File.separatorChar);
60 | sourceFileName = path + sourceFileName;
61 | }
62 | }
63 | sourceFileClass = null;
64 | }
65 | return sourceFileName;
66 | }
67 |
68 | protected int getSourceFileLine() {
69 | return 0;
70 | }
71 |
72 | // Logging
73 |
74 | protected void log(Logger.Level level, String message) {
75 | if (isLogging(level)) {
76 | String name = getSourceFileName();
77 | if (name != null) {
78 | int line = getSourceFileLine();
79 | String root = getContext().getSourceCodeRoot();
80 | if (root != null) {
81 | String ls = System.lineSeparator();
82 | message += ls + '\t' + root + name + ":" + line;
83 | } else {
84 | message = "(" + name + ":" + line + "): " + message;
85 | }
86 | }
87 | super.log(level, message);
88 | }
89 | }
90 |
91 | protected final boolean shouldLogTarget(String patchId, String targetId) {
92 | return !patchId.equals(targetId);
93 | }
94 |
95 | protected final void extendLogPrefixWithTargetLabel(String targetLabel) {
96 | extendLogPrefix("target '" + targetLabel + "'");
97 | }
98 |
99 | // Implementation
100 |
101 | @Override
102 | protected PatcherAnnotation getActionContext(String patchId, T patch) throws PatchException {
103 | Set extends Annotation> rawAnnotations = patch.getAnnotations();
104 | PatcherAnnotation annotation = PatcherAnnotation.parse(getContext().getActionParser(), rawAnnotations);
105 | if (annotation == null) annotation = new PatcherAnnotation(getDefaultAction(patchId, patch), rawAnnotations);
106 | return annotation;
107 | }
108 |
109 | // Access Flags Logging
110 |
111 | private void logAccessFlags(String item, int oldFlags, int newFlags, boolean keepInterface,
112 | boolean ensureInterface, boolean keepImplementation, Logger.Level warningLevel) {
113 | new AccessFlagLogger(item, oldFlags, newFlags) {
114 | @Override
115 | protected void log(Logger.Level level, String message) {
116 | AnnotatableSetPatcher.this.log(level, message);
117 | }
118 | }.allFlags(this, keepInterface, ensureInterface, keepImplementation, warningLevel);
119 | }
120 |
121 | @Override
122 | protected T onSimpleEdit(T patch, PatcherAnnotation annotation, T target, boolean inPlace) {
123 | int oldFlags = getAccessFlags(target);
124 | int newFlags = getAccessFlags(patch);
125 | if (inPlace) {
126 | String item = "edited " + getItemLabel();
127 | logAccessFlags(item, oldFlags, newFlags, true, false,
128 | true, WARN);
129 | } else {
130 | String item = "renamed " + getItemLabel();
131 | logAccessFlags(item, oldFlags, newFlags, false, false,
132 | true, WARN);
133 | }
134 | return patch;
135 | }
136 |
137 | @Override
138 | protected void onEffectiveReplacement(String id, T patch, T patched, T original, boolean inPlaceEdit) {
139 | // Avoid duplicated messages if not renaming.
140 | if (!inPlaceEdit) {
141 | int oldFlags = getAccessFlags(original);
142 | int newFlags = getAccessFlags(patched);
143 | String item = "replaced " + getItemLabel();
144 | logAccessFlags(item, oldFlags, newFlags, true, false,
145 | false, WARN);
146 | }
147 | }
148 |
149 | // Handlers
150 |
151 | protected abstract String getItemLabel();
152 | protected abstract int getAccessFlags(T item);
153 | protected abstract Action getDefaultAction(String patchId, T patch) throws PatchException;
154 |
155 | }
156 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/core/patcher/FieldSetPatcher.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.core.patcher;
12 |
13 | import lanchon.dexpatcher.core.Action;
14 | import lanchon.dexpatcher.core.PatchException;
15 | import lanchon.dexpatcher.core.PatcherAnnotation;
16 | import lanchon.dexpatcher.core.model.BasicField;
17 | import lanchon.dexpatcher.core.util.Id;
18 | import lanchon.dexpatcher.core.util.Label;
19 |
20 | import org.jf.dexlib2.iface.Field;
21 | import org.jf.dexlib2.iface.value.EncodedValue;
22 | import org.jf.dexlib2.util.FieldUtil;
23 |
24 | import static lanchon.dexpatcher.core.PatcherAnnotation.*;
25 | import static lanchon.dexpatcher.core.logger.Logger.Level.*;
26 | import static org.jf.dexlib2.AccessFlags.*;
27 |
28 | public class FieldSetPatcher extends MemberSetPatcher {
29 |
30 | public FieldSetPatcher(ClassSetPatcher parent, PatcherAnnotation annotation) {
31 | super(parent, annotation);
32 | }
33 |
34 | // Logging
35 |
36 | @Override
37 | protected void setupLogPrefix(String id, Field item, Field patch, Field patched) {
38 | setupLogPrefix(getItemLabel() + " '" + Label.ofField(item) + "'");
39 | }
40 |
41 | // Implementation
42 |
43 | @Override
44 | protected final String getId(Field item) {
45 | return Id.ofField(item);
46 | }
47 |
48 | @Override
49 | protected String getItemLabel() {
50 | return "field";
51 | }
52 |
53 | @Override
54 | protected void onPrepare(String patchId, Field patch, PatcherAnnotation annotation) throws PatchException {
55 | if (annotation.getAction() == Action.REPLACE) throw invalidAnnotation(Action.REPLACE);
56 | super.onPrepare(patchId, patch, annotation);
57 | }
58 |
59 | @Override
60 | protected String getTargetId(String patchId, Field patch, PatcherAnnotation annotation) {
61 | String target = annotation.getTarget();
62 | String targetId = (target != null) ? Id.ofField(patch, target) : patchId;
63 | if (shouldLogTarget(patchId, targetId)) {
64 | extendLogPrefixWithTargetLabel(Label.ofTargetMember(target));
65 | }
66 | return targetId;
67 | }
68 |
69 | @Override
70 | protected Field onSimpleAdd(Field patch, PatcherAnnotation annotation) {
71 |
72 | EncodedValue value = filterInitialValue(patch, null);
73 |
74 | return new BasicField(
75 | patch.getDefiningClass(),
76 | patch.getName(),
77 | patch.getType(),
78 | patch.getAccessFlags(),
79 | value,
80 | annotation.getFilteredAnnotations());
81 |
82 | }
83 |
84 | @Override
85 | protected Field onSimpleEdit(Field patch, PatcherAnnotation annotation, Field target, boolean inPlace) {
86 |
87 | // Use the static field initializer value in source only
88 | // if not renaming, given that the static constructor in
89 | // source would only initialize it if not renamed.
90 | // This makes behavior predictable across compilers.
91 | EncodedValue value = inPlace ? target.getInitialValue() : null;
92 | value = filterInitialValue(patch, value);
93 |
94 | onSimpleRemove(patch, annotation, target);
95 |
96 | Field patched = new BasicField(
97 | patch.getDefiningClass(),
98 | patch.getName(),
99 | patch.getType(),
100 | patch.getAccessFlags(),
101 | value,
102 | annotation.getFilteredAnnotations());
103 |
104 | return super.onSimpleEdit(patched, annotation, target, inPlace);
105 |
106 | }
107 |
108 | @Override
109 | protected Field onSimpleReplace(Field patch, PatcherAnnotation annotation, Field target, boolean inPlace) {
110 | throw new AssertionError("Replace field");
111 | }
112 |
113 | @Override
114 | protected void onSimpleRemove(Field patch, PatcherAnnotation annotation, Field target) {
115 | if (FieldUtil.isStatic(target)) {
116 | if (FINAL.isSet(target.getAccessFlags())) {
117 | log(WARN, "original value of final static field is likely to be embedded in code");
118 | }
119 | }
120 | }
121 |
122 | // Helpers
123 |
124 | private EncodedValue filterInitialValue(Field patch, EncodedValue value){
125 | if (FieldUtil.isStatic(patch)) {
126 | // Use the static field initializer values in patch if and
127 | // only if the static constructor code in patch is being used.
128 | // This makes behavior more predictable across compilers.
129 | Action action = resolvedStaticConstructorAction;
130 | if (/* action != Action.NONE && */ action.ignoresCode()) {
131 | log(WARN, "static field will not be initialized as specified in patch because code of static constructor of class is being discarded");
132 | return value;
133 | } else {
134 | EncodedValue patchValue = patch.getInitialValue();
135 | return (patchValue != null) ? patchValue : value;
136 | }
137 | } else {
138 | // Instance fields should never have initializer values.
139 | EncodedValue patchValue = patch.getInitialValue();
140 | if (patchValue != null) {
141 | log(ERROR, "unexpected instance field initializer value in patch");
142 | }
143 | return (patchValue != null) ? patchValue : value;
144 | }
145 | }
146 |
147 | }
148 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/core/patcher/MemberSetPatcher.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.core.patcher;
12 |
13 | import lanchon.dexpatcher.core.Action;
14 | import lanchon.dexpatcher.core.Marker;
15 | import lanchon.dexpatcher.core.PatchException;
16 | import lanchon.dexpatcher.core.PatcherAnnotation;
17 |
18 | import org.jf.dexlib2.iface.Member;
19 |
20 | import static lanchon.dexpatcher.core.PatcherAnnotation.*;
21 | import static lanchon.dexpatcher.core.logger.Logger.Level.*;
22 |
23 | public abstract class MemberSetPatcher extends AnnotatableSetPatcher {
24 |
25 | protected final Action explicitStaticConstructorAction;
26 | protected final Action resolvedStaticConstructorAction; // not null
27 | protected final Action explicitDefaultAction;
28 | protected final Action resolvedDefaultAction; // not null
29 |
30 | public MemberSetPatcher(ClassSetPatcher parent, PatcherAnnotation annotation) {
31 | super(parent);
32 | Action defaultAction = Action.NONE;
33 | Action sca = annotation.getStaticConstructorAction();
34 | Action da = annotation.getDefaultAction();
35 | explicitStaticConstructorAction = sca;
36 | explicitDefaultAction = da;
37 | resolvedDefaultAction = (da != null) ? da : defaultAction;
38 | resolvedStaticConstructorAction = (sca != null) ? sca : resolvedDefaultAction;
39 | }
40 |
41 | // Implementation
42 |
43 | @Override
44 | protected int getAccessFlags(T item) {
45 | return item.getAccessFlags();
46 | }
47 |
48 | @Override
49 | protected Action getDefaultAction(String patchId, T patch) throws PatchException {
50 | if (resolvedDefaultAction == Action.NONE) throw new PatchException("no action defined");
51 | log(INFO, "default " + resolvedDefaultAction.getLabel());
52 | return resolvedDefaultAction;
53 | }
54 |
55 | @Override
56 | protected void onPrepare(String patchId, T patch, PatcherAnnotation annotation) throws PatchException {
57 | if (annotation.getTargetClass() != null) throw invalidElement(Marker.ELEM_TARGET_CLASS);
58 | if (annotation.getStaticConstructorAction() != null) throw invalidElement(Marker.ELEM_STATIC_CONSTRUCTOR_ACTION);
59 | if (annotation.getDefaultAction() != null) throw invalidElement(Marker.ELEM_DEFAULT_ACTION);
60 | if (annotation.getContentOnly()) throw invalidElement(Marker.ELEM_CONTENT_ONLY);
61 | if (annotation.getRecursive()) throw invalidElement(Marker.ELEM_RECURSIVE);
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/core/patcher/PackagePatcher.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.core.patcher;
12 |
13 | import lanchon.dexpatcher.core.Context;
14 | import lanchon.dexpatcher.core.Marker;
15 | import lanchon.dexpatcher.core.PatchException;
16 | import lanchon.dexpatcher.core.PatcherAnnotation;
17 | import lanchon.dexpatcher.core.util.DexUtils;
18 | import lanchon.dexpatcher.core.util.Id;
19 | import lanchon.dexpatcher.core.util.Label;
20 | import lanchon.dexpatcher.core.util.Target;
21 |
22 | import org.jf.dexlib2.iface.ClassDef;
23 |
24 | import static lanchon.dexpatcher.core.PatcherAnnotation.*;
25 | import static lanchon.dexpatcher.core.logger.Logger.Level.*;
26 |
27 | public class PackagePatcher extends ClassSetPatcher {
28 |
29 | private boolean processingPackage;
30 |
31 | public PackagePatcher(Context context) {
32 | super(context);
33 | }
34 |
35 | // Implementation
36 |
37 | @Override
38 | protected void onPrepare(String patchId, ClassDef patch, PatcherAnnotation annotation) throws PatchException {
39 | processingPackage = DexUtils.isPackageId(patchId);
40 | if (!processingPackage) {
41 | super.onPrepare(patchId, patch, annotation);
42 | return;
43 | }
44 | if (annotation.getTargetClass() != null) throw invalidElement(Marker.ELEM_TARGET_CLASS);
45 | if (annotation.getContentOnly()) throw invalidElement(Marker.ELEM_CONTENT_ONLY);
46 | }
47 |
48 | @Override
49 | protected void onReplace(String patchId, ClassDef patch, PatcherAnnotation annotation) throws PatchException {
50 | if (!processingPackage) {
51 | super.onReplace(patchId, patch, annotation);
52 | return;
53 | }
54 | String targetId = getPackageTargetId(patchId, patch, annotation);
55 | boolean recursive = annotation.getRecursive();
56 | if (isLogging(DEBUG)) log(DEBUG, recursive ? "replace package recursive" : "replace package non-recursive");
57 | removePackage(targetId, recursive);
58 | ClassDef patched = onSimpleAdd(patch, annotation);
59 | addPatched(patch, patched);
60 | }
61 |
62 | @Override
63 | protected void onRemove(String patchId, ClassDef patch, PatcherAnnotation annotation) throws PatchException {
64 | if (!processingPackage) {
65 | super.onRemove(patchId, patch, annotation);
66 | return;
67 | }
68 | String targetId = getPackageTargetId(patchId, patch, annotation);
69 | boolean recursive = annotation.getRecursive();
70 | if (isLogging(DEBUG)) log(DEBUG, recursive ? "remove package recursive" : "remove package non-recursive");
71 | removePackage(targetId, recursive);
72 | }
73 |
74 | private String getPackageTargetId(String patchId, ClassDef patch, PatcherAnnotation annotation) throws PatchException {
75 | String target = annotation.getTarget();
76 | String targetId = (target != null) ? Id.ofClass(Target.resolvePackageDescriptor(target)) : patchId;
77 | if (!DexUtils.isPackageId(targetId)) throw new PatchException("target is not a package");
78 | if (shouldLogTarget(patchId, targetId)) {
79 | extendLogPrefixWithTargetLabel(Label.fromClassId(targetId));
80 | }
81 | return targetId;
82 | }
83 |
84 | private void removePackage(String targetId, boolean recursive) throws PatchException {
85 | int prefixLength = targetId.length() - (Marker.NAME_PACKAGE_INFO.length() + 1);
86 | String prefix = targetId.substring(0, prefixLength);
87 | for (String id: getSourceMap().keySet()) {
88 | if (id.startsWith(prefix) && (recursive || id.indexOf('/', prefixLength) < 0) && id.endsWith(";")) {
89 | try {
90 | addTarget(id, false);
91 | if (isLogging(DEBUG)) log(DEBUG, "remove type '" + Label.fromClassId(id) + "'");
92 | } catch (PatchException e) {
93 | log(ERROR, "already targeted type '" + Label.fromClassId(id) + "'");
94 | }
95 | }
96 | }
97 | }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/core/util/DexUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.core.util;
12 |
13 | import java.util.Iterator;
14 |
15 | import lanchon.dexpatcher.core.Marker;
16 |
17 | import org.jf.dexlib2.Opcode;
18 | import org.jf.dexlib2.iface.Annotation;
19 | import org.jf.dexlib2.iface.AnnotationElement;
20 | import org.jf.dexlib2.iface.ClassDef;
21 | import org.jf.dexlib2.iface.Method;
22 | import org.jf.dexlib2.iface.MethodImplementation;
23 | import org.jf.dexlib2.iface.instruction.Instruction;
24 | import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
25 | import org.jf.dexlib2.iface.reference.MethodReference;
26 | import org.jf.dexlib2.iface.value.EncodedValue;
27 | import org.jf.dexlib2.iface.value.IntEncodedValue;
28 |
29 | import static org.jf.dexlib2.AccessFlags.*;
30 |
31 | public class DexUtils {
32 |
33 | public static boolean isClassDescriptor(String descriptor) {
34 | int l = descriptor.length();
35 | return l >= 2 && descriptor.charAt(0) == 'L' && descriptor.charAt(l - 1) == ';';
36 | }
37 |
38 | private static final String PACKAGE_DESCRIPTOR_SUFFIX = '/' + Marker.NAME_PACKAGE_INFO + ';';
39 | private static final String PACKAGE_DESCRIPTOR_DEFAULT = 'L' + Marker.NAME_PACKAGE_INFO + ';';
40 |
41 | public static boolean isPackageDescriptor(String descriptor) {
42 | return (descriptor.endsWith(PACKAGE_DESCRIPTOR_SUFFIX) && descriptor.charAt(0) == 'L') ||
43 | descriptor.equals(PACKAGE_DESCRIPTOR_DEFAULT);
44 | }
45 |
46 | public static boolean isPackageId(String id) {
47 | return DexUtils.isPackageDescriptor(Id.toClassDescriptor(id));
48 | }
49 |
50 | // Access Flags
51 |
52 | public static int getClassAccessFlags(ClassDef classDef) {
53 | int f = classDef.getAccessFlags();
54 | for (Annotation a : classDef.getAnnotations()) {
55 | if (Marker.TYPE_INNER_CLASS.equals(a.getType())) {
56 | for (AnnotationElement e : a.getElements()) {
57 | if (Marker.ELEM_ACCESS_FLAGS.equals(e.getName())) {
58 | EncodedValue v = e.getValue();
59 | if (v instanceof IntEncodedValue) {
60 | f |= ((IntEncodedValue) v).getValue();
61 | }
62 | }
63 | }
64 | }
65 | }
66 | return f;
67 | }
68 |
69 | // Constructors
70 |
71 | public static boolean isStaticConstructor(Method method) {
72 | int flags = method.getAccessFlags();
73 | return CONSTRUCTOR.isSet(flags) && STATIC.isSet(flags) &&
74 | isStaticConstructorReference(method);
75 | }
76 |
77 | public static boolean isStaticConstructorReference(MethodReference method) {
78 | return Marker.NAME_STATIC_CONSTRUCTOR.equals(method.getName()) &&
79 | Marker.TYPE_VOID.equals(method.getReturnType()) &&
80 | method.getParameterTypes().isEmpty();
81 | }
82 |
83 | public static boolean isInstanceConstructor(Method method) {
84 | int flags = method.getAccessFlags();
85 | return CONSTRUCTOR.isSet(flags) && !STATIC.isSet(flags) &&
86 | isInstanceConstructorReference(method);
87 | }
88 |
89 | public static boolean isInstanceConstructorReference(MethodReference method) {
90 | return Marker.NAME_INSTANCE_CONSTRUCTOR.equals(method.getName()) &&
91 | Marker.TYPE_VOID.equals(method.getReturnType());
92 | }
93 |
94 | public static boolean isDefaultConstructor(Method method) {
95 | return isInstanceConstructor(method) &&
96 | method.getParameterTypes().isEmpty();
97 | }
98 |
99 | public static boolean hasTrivialConstructorImplementation(Method method) {
100 | // Precondition: isDefaultConstructor(...) returns true.
101 | MethodImplementation implementation = method.getImplementation();
102 | if (implementation.getRegisterCount() != 1 || !implementation.getTryBlocks().isEmpty()) return false;
103 | Iterator extends Instruction> iterator = implementation.getInstructions().iterator();
104 | if (!iterator.hasNext()) return false;
105 | {
106 | Instruction instruction = iterator.next();
107 | if (instruction.getOpcode() != Opcode.INVOKE_DIRECT) return false;
108 | MethodReference reference = (MethodReference) ((ReferenceInstruction) instruction).getReference();
109 | if (!Marker.NAME_INSTANCE_CONSTRUCTOR.equals(reference.getName())) return false;
110 | if (method.getDefiningClass().equals(reference.getDefiningClass())) return false;
111 | }
112 | if (!iterator.hasNext()) return false;
113 | {
114 | Instruction instruction = iterator.next();
115 | if (instruction.getOpcode() != Opcode.RETURN_VOID) return false;
116 | }
117 | if (iterator.hasNext()) return false;
118 | return true;
119 | }
120 |
121 | private DexUtils() {}
122 |
123 | }
124 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/core/util/ElementalTypeRewriter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.core.util;
12 |
13 | import org.jf.dexlib2.rewriter.Rewriter;
14 |
15 | public abstract class ElementalTypeRewriter implements Rewriter {
16 |
17 | @Override
18 | public String rewrite(String value) {
19 | int length = value.length();
20 | if (length == 0 || value.charAt(0) != '[') return rewriteElementalType(value);
21 | int start = 1;
22 | while (start < length && value.charAt(start) == '[') start++;
23 | String elementalType = value.substring(start);
24 | String rewrittenElementalType = rewriteElementalType(elementalType);
25 | if (rewrittenElementalType.equals(elementalType)) return value;
26 | StringBuilder sb = new StringBuilder(start + rewrittenElementalType.length());
27 | sb.append(value, 0, start).append(rewrittenElementalType);
28 | return sb.toString();
29 | }
30 |
31 | public abstract String rewriteElementalType(String elementalType);
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/core/util/Id.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.core.util;
12 |
13 | import lanchon.dexpatcher.core.Marker;
14 |
15 | import org.jf.dexlib2.iface.ClassDef;
16 | import org.jf.dexlib2.iface.reference.FieldReference;
17 | import org.jf.dexlib2.iface.reference.MethodReference;
18 |
19 | public class Id {
20 |
21 | public static final String STATIC_CONSTRUCTOR = Marker.NAME_STATIC_CONSTRUCTOR + "..V";
22 |
23 | public static String ofClass(ClassDef classDef) {
24 | return ofClass(classDef.getType());
25 | }
26 |
27 | public static String ofClass(String descriptor) {
28 | return descriptor;
29 | }
30 |
31 | public static String toClassDescriptor(String id) {
32 | return id;
33 | }
34 |
35 | public static String ofField(FieldReference field) {
36 | return ofField(field.getType(), field.getName());
37 | }
38 |
39 | public static String ofField(FieldReference field, String name) {
40 | return ofField(field.getType(), name);
41 | }
42 |
43 | public static String ofField(String type, String name) {
44 | return name + '.' + type;
45 | }
46 |
47 | public static String ofMethod(MethodReference method) {
48 | return ofMethod(method.getParameterTypes(), method.getReturnType(), method.getName());
49 | }
50 |
51 | public static String ofMethod(MethodReference method, String name) {
52 | return ofMethod(method.getParameterTypes(), method.getReturnType(), name);
53 | }
54 |
55 | public static String ofMethod(Iterable extends CharSequence> parameterTypes, String returnType, String name) {
56 | StringBuilder sb = new StringBuilder();
57 | sb.append(name).append('.');
58 | for (CharSequence parameterType : parameterTypes) sb.append(parameterType);
59 | sb.append('.').append(returnType);
60 | return sb.toString();
61 | }
62 |
63 | private Id() {}
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/core/util/InvalidTypeDescriptorException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.core.util;
12 |
13 | import lanchon.dexpatcher.core.PatchException;
14 |
15 | public class InvalidTypeDescriptorException extends PatchException {
16 |
17 | protected final String descriptorType;
18 | protected final String descriptor;
19 |
20 | public InvalidTypeDescriptorException(String descriptorType, String descriptor) {
21 | super("Invalid " + descriptorType + " type descriptor (" + descriptor + ")");
22 | this.descriptorType = descriptorType;
23 | this.descriptor = descriptor;
24 | }
25 |
26 | public String getDescriptorType() {
27 | return descriptorType;
28 | }
29 |
30 | public String getDescriptor() {
31 | return descriptor;
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/core/util/Label.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.core.util;
12 |
13 | import org.jf.dexlib2.iface.ClassDef;
14 | import org.jf.dexlib2.iface.reference.FieldReference;
15 | import org.jf.dexlib2.iface.reference.MethodReference;
16 |
17 | public class Label {
18 |
19 | public static String fromClassDescriptor(String descriptor) {
20 | try {
21 | return TypeName.fromClassDescriptor(descriptor);
22 | } catch (InvalidTypeDescriptorException e) {
23 | return "[class-type:" + descriptor + "]";
24 | }
25 | }
26 |
27 | public static String fromFieldDescriptor(String descriptor) {
28 | try {
29 | return TypeName.fromFieldDescriptor(descriptor);
30 | } catch (InvalidTypeDescriptorException e) {
31 | return "[field-type:" + descriptor + "]";
32 | }
33 | }
34 |
35 | public static String fromReturnDescriptor(String descriptor) {
36 | try {
37 | return TypeName.fromReturnDescriptor(descriptor);
38 | } catch (InvalidTypeDescriptorException e) {
39 | return "[return-type:" + descriptor + "]";
40 | }
41 | }
42 |
43 | public static String ofClass(ClassDef classDef) {
44 | return fromClassDescriptor(classDef.getType());
45 | }
46 |
47 | public static String fromClassId(String id) {
48 | return fromClassDescriptor(Id.toClassDescriptor(id));
49 | }
50 |
51 | public static String ofTargetMember(String name) {
52 | return name;
53 | }
54 |
55 | public static String ofField(FieldReference field) {
56 | return ofField(field, field.getName());
57 | }
58 |
59 | public static String ofField(FieldReference field, String name) {
60 | return name + ':' + fromFieldDescriptor(field.getType());
61 | }
62 |
63 | public static String ofMethod(MethodReference method) {
64 | return ofMethod(method, method.getName());
65 | }
66 |
67 | public static String ofMethod(MethodReference method, String name) {
68 | return ofMethod(method.getParameterTypes(), method.getReturnType(), name);
69 | }
70 |
71 | public static String ofMethod(Iterable extends CharSequence> parameterTypes, String returnType, String name) {
72 | StringBuilder sb = new StringBuilder();
73 | sb.append(name).append('(');
74 | boolean first = true;
75 | for (CharSequence parameterType : parameterTypes) {
76 | if (!first) sb.append(", ");
77 | sb.append(fromFieldDescriptor(parameterType.toString()));
78 | first = false;
79 | }
80 | sb.append("):").append(fromReturnDescriptor(returnType));
81 | return sb.toString();
82 | }
83 |
84 | private Label() {}
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/core/util/SimpleTypeRewriter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.core.util;
12 |
13 | import org.jf.dexlib2.iface.ClassDef;
14 | import org.jf.dexlib2.rewriter.DexRewriter;
15 | import org.jf.dexlib2.rewriter.Rewriter;
16 | import org.jf.dexlib2.rewriter.RewriterModule;
17 | import org.jf.dexlib2.rewriter.Rewriters;
18 |
19 | public class SimpleTypeRewriter {
20 |
21 | public static RewriterModule getModule(final String fromDescriptor, final String toDescriptor) {
22 | return new RewriterModule() {
23 | @Override
24 | public Rewriter getTypeRewriter(Rewriters rewriters) {
25 | return new ElementalTypeRewriter() {
26 | @Override
27 | public String rewriteElementalType(String elementalType) {
28 | return elementalType.equals(fromDescriptor) ? toDescriptor : elementalType;
29 | }
30 | };
31 | }
32 | };
33 | }
34 |
35 | public static ClassDef renameClass(ClassDef classDef, String toClassDescriptor) {
36 | RewriterModule rewriterModule = getModule(classDef.getType(), toClassDescriptor);
37 | return new DexRewriter(rewriterModule).getClassDefRewriter().rewrite(classDef);
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/core/util/Target.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.core.util;
12 |
13 | import lanchon.dexpatcher.core.Marker;
14 |
15 | public class Target {
16 |
17 | public static String resolveDescriptor(String baseDescriptor, String target)
18 | throws InvalidTypeDescriptorException {
19 | // Precondition: target is a non-zero length string.
20 | return DexUtils.isPackageDescriptor(baseDescriptor) ?
21 | Target.resolvePackageDescriptor(target) :
22 | Target.resolveClassDescriptor(baseDescriptor, target);
23 | }
24 |
25 | public static String resolveClassDescriptor(String baseDescriptor, String target)
26 | throws InvalidTypeDescriptorException {
27 | // Precondition: target is a non-zero length string.
28 | if (!DexUtils.isClassDescriptor(target)) {
29 | String baseName = TypeName.fromClassDescriptor(baseDescriptor);
30 | target = TypeName.toClassDescriptor(resolveClassName(baseName, target));
31 | }
32 | return target;
33 | }
34 |
35 | private static String resolveClassName(String baseName, String target) {
36 | int targetDot = target.indexOf('.');
37 | if (targetDot < 0) {
38 | // If target is not fully qualified:
39 | int baseNameEnd = baseName.lastIndexOf('.');
40 | if (target.indexOf('$') < 0) {
41 | // If target is not a qualified nested type:
42 | baseNameEnd = Math.max(baseNameEnd, baseName.lastIndexOf('$'));
43 | }
44 | if (baseNameEnd >= 0) {
45 | target = baseName.substring(0, baseNameEnd + 1) + target;
46 | }
47 | }
48 | return target;
49 | }
50 |
51 | public static String resolvePackageDescriptor(String target) {
52 | // Precondition: target is a non-zero length string.
53 | if (!DexUtils.isClassDescriptor(target)) {
54 | if (target.startsWith(".")) target = target.substring(1);
55 | target = (target.isEmpty()) ? Marker.NAME_PACKAGE_INFO : target + '.' + Marker.NAME_PACKAGE_INFO;
56 | target = TypeName.toClassDescriptor(target);
57 | }
58 | return target;
59 | }
60 |
61 | private Target() {}
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/core/util/TemplateMapFileWriter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.core.util;
12 |
13 | import java.io.BufferedWriter;
14 | import java.io.File;
15 | import java.io.FileOutputStream;
16 | import java.io.IOException;
17 | import java.io.OutputStream;
18 | import java.io.OutputStreamWriter;
19 | import java.io.PrintWriter;
20 | import java.io.Writer;
21 | import java.nio.charset.StandardCharsets;
22 |
23 | import org.jf.dexlib2.iface.ClassDef;
24 | import org.jf.dexlib2.iface.DexFile;
25 | import org.jf.dexlib2.iface.Field;
26 | import org.jf.dexlib2.iface.Method;
27 |
28 | public class TemplateMapFileWriter {
29 |
30 | private static String MEMBER_INDENTATION = " ";
31 |
32 | public static void write(File file, DexFile dexFile, String prefix) throws IOException {
33 | try (OutputStream outputStream = new FileOutputStream(file)) {
34 | Writer writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);
35 | write(writer, dexFile, prefix);
36 | }
37 | }
38 |
39 | public static void write(Writer writer, DexFile dexFile, String prefix) throws IOException {
40 | write(new BufferedWriter(writer), dexFile, prefix);
41 | }
42 |
43 | public static void write(BufferedWriter writer, DexFile dexFile, String prefix) throws IOException {
44 | write(new PrintWriter(writer), dexFile, prefix);
45 | }
46 |
47 | public static void write(PrintWriter writer, DexFile dexFile, String prefix) throws IOException {
48 | if (prefix == null) prefix = "";
49 | for (ClassDef classDef : dexFile.getClasses()) {
50 | String classDescriptor = classDef.getType();
51 | //if (DexUtils.isPackageDescriptor(classDescriptor)) continue;
52 | String className = Label.fromClassDescriptor(classDescriptor);
53 | writer.print(prefix);
54 | writer.print(className);
55 | writer.print(" -> ");
56 | writer.print(className);
57 | writer.print(":");
58 | writer.println();
59 | for (Field field : classDef.getFields()) {
60 | String fieldName = field.getName();
61 | writer.print(prefix);
62 | writer.print(MEMBER_INDENTATION);
63 | writer.print(Label.fromFieldDescriptor(field.getType()));
64 | writer.print(" ");
65 | writer.print(fieldName);
66 | writer.print(" -> ");
67 | writer.print(fieldName);
68 | writer.println();
69 | }
70 | for (Method method : classDef.getMethods()) {
71 | if (DexUtils.isStaticConstructor(method) || DexUtils.isInstanceConstructor(method)) continue;
72 | String methodName = method.getName();
73 | writer.print(prefix);
74 | writer.print(MEMBER_INDENTATION);
75 | writer.print(Label.fromReturnDescriptor(method.getReturnType()));
76 | writer.print(" ");
77 | writer.print(methodName);
78 | writer.print("(");
79 | boolean first = true;
80 | for (CharSequence parameterType : method.getParameterTypes()) {
81 | if (!first) writer.print(", ");
82 | writer.print(Label.fromFieldDescriptor(parameterType.toString()));
83 | first = false;
84 | }
85 | writer.print(") -> ");
86 | writer.print(methodName);
87 | writer.println();
88 | }
89 | writer.println();
90 | }
91 | if (writer.checkError()) throw new IOException("Cannot write template map file");
92 | }
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/core/util/TypeName.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.core.util;
12 |
13 | import lanchon.dexpatcher.core.Marker;
14 |
15 | import com.google.common.collect.ImmutableBiMap;
16 |
17 | public class TypeName {
18 |
19 | private static final ImmutableBiMap fieldTypeToNameMap = ImmutableBiMap.builder()
20 | .put("Z", "boolean")
21 | .put("C", "char")
22 | .put("B", "byte")
23 | .put("S", "short")
24 | .put("I", "int")
25 | .put("J", "long")
26 | .put("F", "float")
27 | .put("D", "double")
28 | .build();
29 |
30 | private static final ImmutableBiMap returnTypeToNameMap = ImmutableBiMap.builder()
31 | .putAll(fieldTypeToNameMap)
32 | .put(Marker.TYPE_VOID, Marker.NAME_VOID)
33 | .build();
34 |
35 | private static final ImmutableBiMap nameToFieldTypeMap = fieldTypeToNameMap.inverse();
36 |
37 | public static String fromClassDescriptor(String descriptor) throws InvalidTypeDescriptorException {
38 | if (!DexUtils.isClassDescriptor(descriptor)) {
39 | throw new InvalidTypeDescriptorException("class", descriptor);
40 | }
41 | int length = descriptor.length();
42 | StringBuilder sb = new StringBuilder(length - 2);
43 | length--;
44 | for (int i = 1; i < length; i++) {
45 | char c = descriptor.charAt(i);
46 | sb.append(c == '/' ? '.' : c);
47 | }
48 | String name = sb.toString();
49 | if (returnTypeToNameMap.containsValue(name)) name = '.' + name;
50 | return name;
51 | }
52 |
53 | public static String toClassDescriptor(String name) {
54 | int length = name.length();
55 | int start = name.startsWith(".") ? 1 : 0;
56 | StringBuilder sb = new StringBuilder(length - start + 2);
57 | sb.append('L');
58 | for (int i = start; i < length; i++) {
59 | char c = name.charAt(i);
60 | sb.append(c == '.' ? '/' : c);
61 | }
62 | sb.append(';');
63 | return sb.toString();
64 | }
65 |
66 | public static String fromFieldDescriptor(String descriptor) throws InvalidTypeDescriptorException {
67 | try {
68 | if (descriptor.length() == 1) {
69 | String name = fieldTypeToNameMap.get(descriptor);
70 | if (name != null) return name;
71 | } else if (descriptor.startsWith("[")) {
72 | return fromFieldDescriptor(descriptor.substring(1)) + "[]";
73 | }
74 | return fromClassDescriptor(descriptor);
75 | } catch (InvalidTypeDescriptorException e) {
76 | throw new InvalidTypeDescriptorException("field", descriptor);
77 | }
78 | }
79 |
80 | public static String toFieldDescriptor(String name) {
81 | if (name.endsWith("[]")) {
82 | return '[' + toFieldDescriptor(name.substring(0, name.length() - 2));
83 | }
84 | String type = nameToFieldTypeMap.get(name);
85 | return type != null ? type : toClassDescriptor(name);
86 | }
87 |
88 | public static String fromReturnDescriptor(String descriptor) throws InvalidTypeDescriptorException {
89 | try {
90 | return Marker.TYPE_VOID.equals(descriptor) ? Marker.NAME_VOID : fromFieldDescriptor(descriptor);
91 | } catch (InvalidTypeDescriptorException e) {
92 | throw new InvalidTypeDescriptorException("return", descriptor);
93 | }
94 | }
95 |
96 | public static String toReturnDescriptor(String name) {
97 | return Marker.NAME_VOID.equals(name) ? Marker.TYPE_VOID : toFieldDescriptor(name);
98 | }
99 |
100 | private TypeName() {}
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/BaseLogger.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform;
12 |
13 | import lanchon.dexpatcher.core.util.Label;
14 |
15 | public abstract class BaseLogger {
16 |
17 | public final TransformLogger logger;
18 | private final String logPrefix;
19 |
20 | protected BaseLogger(TransformLogger logger, String logPrefix) {
21 | this.logger = logger;
22 | this.logPrefix = logPrefix;
23 | logger.markAsInUse();
24 | }
25 |
26 | public final StringBuilder getMessageHeader() {
27 | StringBuilder sb = new StringBuilder();
28 | if (logPrefix != null) sb.append(logPrefix).append(": ");
29 | return sb;
30 | }
31 |
32 | public final StringBuilder getMessageHeaderForClass(String descriptor) {
33 | StringBuilder sb = getMessageHeader();
34 | sb.append("type '").append(Label.fromClassDescriptor(descriptor)).append("': ");
35 | return sb;
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/MemberLogger.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform;
12 |
13 | import lanchon.dexpatcher.core.util.Label;
14 |
15 | import org.jf.dexlib2.iface.reference.FieldReference;
16 | import org.jf.dexlib2.iface.reference.MethodReference;
17 |
18 | public abstract class MemberLogger extends BaseLogger {
19 |
20 | private static final boolean LOG_TRANSFORMED_DEFINING_CLASS = false;
21 |
22 | public MemberLogger(TransformLogger logger, String logPrefix) {
23 | super(logger, logPrefix);
24 | }
25 |
26 | public final StringBuilder getMessageHeaderForMember(String definingClass) {
27 | StringBuilder sb = getMessageHeader();
28 | sb.append("type '").append(Label.fromClassDescriptor(definingClass));
29 | if (LOG_TRANSFORMED_DEFINING_CLASS) {
30 | String rewrittenDefiningClass = getTransformedDefiningClass(definingClass);
31 | if (rewrittenDefiningClass != null && !rewrittenDefiningClass.equals(definingClass)) {
32 | sb.append("' -> '").append(Label.fromClassDescriptor(rewrittenDefiningClass));
33 | }
34 | }
35 | sb.append("': ");
36 | return sb;
37 | }
38 |
39 | public final StringBuilder getMessageHeaderForField(FieldReference field) {
40 | StringBuilder sb = getMessageHeaderForMember(field.getDefiningClass());
41 | sb.append("field '").append(Label.ofField(field)).append("': ");
42 | return sb;
43 | }
44 |
45 | public final StringBuilder getMessageHeaderForMethod(MethodReference method) {
46 | StringBuilder sb = getMessageHeaderForMember(method.getDefiningClass());
47 | sb.append("method '").append(Label.ofMethod(method)).append("': ");
48 | return sb;
49 | }
50 |
51 | protected abstract String getTransformedDefiningClass(String definingClass);
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/TransformLogger.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform;
12 |
13 | import java.util.HashSet;
14 |
15 | import lanchon.dexpatcher.core.logger.Logger;
16 |
17 | public final class TransformLogger {
18 |
19 | private Logger logger;
20 | private boolean inUse;
21 | private boolean sync;
22 | private HashSet loggedMessages;
23 |
24 | public TransformLogger(Logger logger) {
25 | this.logger = logger;
26 | if (logger != null) loggedMessages = new HashSet<>();
27 | }
28 |
29 | public boolean isInUse() {
30 | return inUse;
31 | }
32 |
33 | public void markAsInUse() {
34 | this.inUse = true;
35 | }
36 |
37 | public boolean getSync() {
38 | return sync;
39 | }
40 |
41 | public void setSync(boolean sync) {
42 | this.sync = sync;
43 | }
44 |
45 | public boolean isLogging() {
46 | return logger != null;
47 | }
48 |
49 | public boolean isLogging(Logger.Level level) {
50 | // NOTE: Logger level is assumed to be constant during renaming.
51 | // This is why the call to logger.isLogging() is not synchronized.
52 | // NOTE: A null value for level disables logging.
53 | return logger != null && level != null && logger.isLogging(level);
54 | }
55 |
56 | public void log(Logger.Level level, String message) {
57 | if (isLogging(level)) {
58 | if (sync) {
59 | synchronized (logger) {
60 | if (loggedMessages.add(message)) logger.log(level, message);
61 | }
62 | } else {
63 | if (loggedMessages.add(message)) logger.log(level, message);
64 | }
65 | }
66 | }
67 |
68 | public void stopLogging() {
69 | logger = null;
70 | loggedMessages = null;
71 | }
72 |
73 | public TransformLogger cloneIf(boolean condition) {
74 | return condition ? new TransformLogger(logger) : this;
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/anonymizer/DexAnonymizer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.anonymizer;
12 |
13 | import lanchon.dexpatcher.core.logger.Logger;
14 | import lanchon.dexpatcher.core.util.Label;
15 | import lanchon.dexpatcher.transform.BaseLogger;
16 | import lanchon.dexpatcher.transform.TransformLogger;
17 |
18 | import org.jf.dexlib2.rewriter.Rewriter;
19 | import org.jf.dexlib2.rewriter.RewriterModule;
20 | import org.jf.dexlib2.rewriter.Rewriters;
21 |
22 | public final class DexAnonymizer extends BaseLogger implements Rewriter, TypeAnonymizer.ErrorHandler {
23 |
24 | private final TypeAnonymizer typeAnonymizer;
25 | private final Logger.Level infoLevel;
26 | private final Logger.Level errorLevel;
27 |
28 | public DexAnonymizer(TypeAnonymizer typeAnonymizer, TransformLogger logger, String logPrefix,
29 | Logger.Level infoLevel, Logger.Level errorLevel) {
30 | super(logger, logPrefix);
31 | this.typeAnonymizer = typeAnonymizer;
32 | this.infoLevel = infoLevel;
33 | this.errorLevel = errorLevel;
34 | }
35 |
36 | public RewriterModule getModule() {
37 | return new RewriterModule() {
38 | @Override
39 | public Rewriter getTypeRewriter(Rewriters rewriters) {
40 | return DexAnonymizer.this;
41 | }
42 | };
43 | }
44 |
45 | @Override
46 | public String rewrite(String type) {
47 | String anonymizedType = typeAnonymizer.anonymizeType(type, this);
48 | if (logger.isLogging(infoLevel) && !anonymizedType.equals(type)) {
49 | StringBuilder sb = getMessageHeaderForClass(type);
50 | sb.append(typeAnonymizer.isReanonymizer() ? "reanonymized to '" : "deanonymized to '")
51 | .append(Label.fromClassDescriptor(anonymizedType)).append("'");
52 | logger.log(infoLevel, sb.toString());
53 | }
54 | return anonymizedType;
55 | }
56 |
57 | @Override
58 | public void onError(String type, String message) {
59 | if (logger.isLogging(errorLevel)) {
60 | StringBuilder sb = getMessageHeaderForClass(type);
61 | sb.append(message);
62 | logger.log(errorLevel, sb.toString());
63 | }
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/codec/BinaryClassNameRewriter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.codec;
12 |
13 | import org.jf.dexlib2.rewriter.Rewriter;
14 |
15 | // Binary class name '' (eg: 'java/lang/String') corresponds to type descriptor 'L;'.
16 | public abstract class BinaryClassNameRewriter implements Rewriter {
17 |
18 | @Override
19 | public String rewrite(String value) {
20 | int end = value.length() - 1;
21 | if (end < 0 || value.charAt(end) != ';') return value;
22 | int start = 0;
23 | char c;
24 | while ((c = value.charAt(start)) == '[') start++;
25 | if (c != 'L') return value;
26 | start++;
27 | String name = value.substring(start, end);
28 | String rewrittenName = rewriteBinaryClassName(name);
29 | if (rewrittenName.equals(name)) return value;
30 | StringBuilder sb = new StringBuilder(start + rewrittenName.length() + 1);
31 | sb.append(value, 0, start).append(rewrittenName).append(';');
32 | return sb.toString();
33 | }
34 |
35 | public abstract String rewriteBinaryClassName(String binaryClassName);
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/codec/DexCodec.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.codec;
12 |
13 | import lanchon.dexpatcher.transform.MemberLogger;
14 | import lanchon.dexpatcher.transform.TransformLogger;
15 | import lanchon.dexpatcher.transform.codec.DexCodecModule.ItemType;
16 |
17 | import org.jf.dexlib2.rewriter.RewriterModule;
18 |
19 | public abstract class DexCodec extends MemberLogger implements DexCodecModule.ItemRewriter {
20 |
21 | public static String formatValue(ItemType itemType, String value) {
22 | return itemType == ItemType.BINARY_CLASS_NAME ? value.replace('/', '.') : value;
23 | }
24 |
25 | public DexCodec(TransformLogger logger, String logPrefix) {
26 | super(logger, logPrefix);
27 | }
28 |
29 | public final RewriterModule getModule() {
30 | return new DexCodecModule(this);
31 | }
32 |
33 | public final StringBuilder getMessageHeader(String definingClass, ItemType itemType, String value) {
34 | StringBuilder sb = (definingClass != null) ? getMessageHeaderForMember(definingClass) : getMessageHeader();
35 | sb.append(itemType.label).append(" '").append(formatValue(itemType, value)).append("': ");
36 | return sb;
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/codec/StringCodec.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.codec;
12 |
13 | public abstract class StringCodec {
14 |
15 | public static final String DEFAULT_CODE_MARKER = "_$$_";
16 |
17 | public static boolean isValidCodeMarker(String marker) {
18 | return marker.length() >= 2 && marker.startsWith("_") && !marker.startsWith("__") && !marker.endsWith("__");
19 | }
20 |
21 | protected final String codeMarker;
22 |
23 | public StringCodec(String codeMarker) {
24 | if (!isValidCodeMarker(codeMarker)) {
25 | throw new IllegalArgumentException("codeMarker");
26 | }
27 | this.codeMarker = codeMarker;
28 | }
29 |
30 | public String getCodeMarker() {
31 | return codeMarker;
32 | }
33 |
34 | public boolean isCodedString(String string) {
35 | return string.contains(codeMarker);
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/codec/decoder/DexDecoder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.codec.decoder;
12 |
13 | import lanchon.dexpatcher.core.logger.Logger;
14 | import lanchon.dexpatcher.transform.TransformLogger;
15 | import lanchon.dexpatcher.transform.codec.DexCodec;
16 | import lanchon.dexpatcher.transform.codec.DexCodecModule.ItemType;
17 |
18 | public final class DexDecoder extends DexCodec {
19 |
20 | private final StringDecoder stringDecoder;
21 | private final Logger.Level infoLevel;
22 | private final Logger.Level errorLevel;
23 |
24 | public DexDecoder(StringDecoder stringDecoder, TransformLogger logger, String logPrefix, Logger.Level infoLevel,
25 | Logger.Level errorLevel) {
26 | super(logger, logPrefix);
27 | this.stringDecoder = stringDecoder;
28 | this.infoLevel = infoLevel;
29 | this.errorLevel = errorLevel;
30 | }
31 |
32 | @Override
33 | protected String getTransformedDefiningClass(String definingClass) {
34 | return stringDecoder.decodeString(definingClass);
35 | }
36 |
37 | @Override
38 | public String rewriteItem(final String definingClass, final ItemType itemType, final String value) {
39 | if (value == null) return null;
40 | String decodedValue = stringDecoder.decodeString(value, new StringDecoder.ErrorHandler() {
41 | @Override
42 | public void onError(String message, String string, int codeStart, int codeEnd, int errorStart,
43 | int errorEnd) {
44 | if (logger.isLogging(errorLevel)) {
45 | StringBuilder sb = getMessageHeader(definingClass, itemType, value);
46 | sb.append(message);
47 | sb.append(" in '").append(string, codeStart, errorStart)
48 | .append("[->]").append(string, errorStart, errorEnd).append("[<-]")
49 | .append(string, errorEnd, codeEnd).append("'");
50 | logger.log(errorLevel, sb.toString());
51 | }
52 | }
53 | });
54 | if (logger.isLogging(infoLevel) && !decodedValue.equals(value)) {
55 | StringBuilder sb = getMessageHeader(definingClass, itemType, value);
56 | sb.append("decoded to '").append(formatValue(itemType, decodedValue)).append("'");
57 | logger.log(infoLevel, sb.toString());
58 | }
59 | return decodedValue;
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/codec/decoder/StringDecoder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.codec.decoder;
12 |
13 | import lanchon.dexpatcher.transform.codec.StringCodec;
14 |
15 | public final class StringDecoder extends StringCodec {
16 |
17 | public interface ErrorHandler {
18 | void onError(String message, String string, int codeStart, int codeEnd, int errorStart, int errorEnd);
19 | }
20 |
21 | public static final ErrorHandler NULL_ERROR_HANDLER = new ErrorHandler() {
22 | @Override
23 | public void onError(String message, String string, int codeStart, int codeEnd, int errorStart, int errorEnd) {}
24 | };
25 |
26 | public StringDecoder(String codeMarker) {
27 | super(codeMarker);
28 | }
29 |
30 | public String decodeString(String string) {
31 | return decodeString(string, NULL_ERROR_HANDLER);
32 | }
33 |
34 | public String decodeString(String string, ErrorHandler errorHandler) {
35 | return string != null ? decodeStringTail(string, 0, errorHandler) : null;
36 | }
37 |
38 | private String decodeStringTail(String string, int start, ErrorHandler errorHandler) {
39 |
40 | int markerStart = string.indexOf(codeMarker, start);
41 | if (markerStart < 0) return string.substring(start);
42 |
43 | int markerEnd = markerStart + codeMarker.length();
44 | int length = string.length();
45 |
46 | recoverFromError:
47 | do {
48 |
49 | int codeStart = markerStart;
50 | while (--codeStart >= start) {
51 | if (string.startsWith("__", codeStart)) break;
52 | }
53 | int codeEnd = markerEnd;
54 | while (++codeEnd <= length) {
55 | if (string.startsWith("__", codeEnd - 2)) break;
56 | }
57 |
58 | if (codeStart < start) {
59 | if (codeEnd > length) codeEnd = length;
60 | errorHandler.onError("missing start of code", string, start, codeEnd, start, markerEnd);
61 | break recoverFromError;
62 | }
63 | if (codeEnd > length) {
64 | errorHandler.onError("missing end of code", string, codeStart, length, markerStart, length);
65 | break recoverFromError;
66 | }
67 |
68 | int escapeEnd = codeEnd - 2;
69 | if (markerEnd >= escapeEnd) {
70 | //return string.substring(start, codeStart) + decodeStringTail(string, codeEnd, errorHandler);
71 | errorHandler.onError("empty code", string, codeStart, codeEnd, markerStart, codeEnd);
72 | break recoverFromError;
73 | }
74 |
75 | StringBuilder sb = new StringBuilder(codeStart + (length - markerEnd - 2));
76 | sb.append(string, start, codeStart);
77 |
78 | for (int i = markerEnd; i < escapeEnd; i++) {
79 | char c = string.charAt(i);
80 | switch (c) {
81 | case '_':
82 | errorHandler.onError("invalid character '_'", string, codeStart, codeEnd, i, i + 1);
83 | break recoverFromError;
84 | case '$':
85 | int escapeIndex = i;
86 | if (i + 1 < escapeEnd) {
87 | char e = string.charAt(++i);
88 | switch (e) {
89 | case 'S':
90 | sb.append('$');
91 | continue;
92 | case 'U':
93 | sb.append('_');
94 | continue;
95 | case 'a':
96 | case 'u':
97 | case 'p':
98 | int n = (e == 'a' ? 2 : e == 'u' ? 4 : 6);
99 | int value = 0;
100 | for (; n != 0; n--) {
101 | if (i + 1 >= escapeEnd) break;
102 | int digit = Character.digit(string.charAt(++i), 16);
103 | if (digit < 0) break;
104 | value = (value << 4 | digit);
105 | }
106 | if (n == 0) {
107 | if (Character.isValidCodePoint(value)) {
108 | sb.appendCodePoint(value);
109 | continue;
110 | }
111 | }
112 | }
113 | }
114 | i++;
115 | String message = "invalid escape sequence '" + string.substring(escapeIndex, i) + "'";
116 | errorHandler.onError(message, string, codeStart, codeEnd, escapeIndex, i);
117 | break recoverFromError;
118 | default:
119 | sb.append(c);
120 | continue;
121 | }
122 | }
123 |
124 | sb.append(decodeStringTail(string, codeEnd, errorHandler));
125 | return sb.toString();
126 |
127 | } while (false);
128 |
129 | int i = markerStart + 1;
130 | return string.substring(start, i) + decodeStringTail(string, i, errorHandler);
131 |
132 | }
133 |
134 | }
135 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/codec/encoder/BasicDexEncoder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.codec.encoder;
12 |
13 | import lanchon.dexpatcher.core.logger.Logger;
14 | import lanchon.dexpatcher.transform.TransformLogger;
15 | import lanchon.dexpatcher.transform.codec.DexCodec;
16 | import lanchon.dexpatcher.transform.codec.DexCodecModule.ItemType;
17 |
18 | public final class BasicDexEncoder extends DexCodec {
19 |
20 | private final BasicStringEncoder basicStringEncoder;
21 | private final Logger.Level infoLevel;
22 |
23 | public BasicDexEncoder(BasicStringEncoder basicStringEncoder, TransformLogger logger, String logPrefix,
24 | Logger.Level infoLevel) {
25 | super(logger, logPrefix);
26 | this.basicStringEncoder = basicStringEncoder;
27 | this.infoLevel = infoLevel;
28 | }
29 |
30 | @Override
31 | protected String getTransformedDefiningClass(String definingClass) {
32 | return basicStringEncoder.encodeString(definingClass);
33 | }
34 |
35 | @Override
36 | public String rewriteItem(String definingClass, ItemType itemType, String value) {
37 | if (value == null) return null;
38 | String encodedValue = basicStringEncoder.encodeString(value);
39 | if (logger.isLogging(infoLevel) && !encodedValue.equals(value)) {
40 | StringBuilder sb = getMessageHeader(definingClass, itemType, value);
41 | sb.append("escaped to '").append(formatValue(itemType, encodedValue)).append("'");
42 | logger.log(infoLevel, sb.toString());
43 | }
44 | return encodedValue;
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/codec/encoder/BasicStringEncoder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.codec.encoder;
12 |
13 | import lanchon.dexpatcher.transform.codec.StringCodec;
14 |
15 | public final class BasicStringEncoder extends StringCodec {
16 |
17 | protected final String encodedCodeMarker;
18 |
19 | public BasicStringEncoder(String codeMarker) {
20 | super(codeMarker);
21 | encodedCodeMarker = "_" + codeMarker + "$U__" + codeMarker.substring(1);
22 | }
23 |
24 | public BasicStringEncoder(String codeMarker, String encodedCodeMarker) {
25 | super(codeMarker);
26 | this.encodedCodeMarker = encodedCodeMarker;
27 | }
28 |
29 | public String encodeString(String string) {
30 | return string != null ? string.replace(codeMarker, encodedCodeMarker) : null;
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/codec/encoder/CopyStringBuilder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.codec.encoder;
12 |
13 | public final class CopyStringBuilder {
14 |
15 | private static final boolean CHECK_ARGS = false;
16 |
17 | private final int initialCapacity;
18 | private final String source;
19 |
20 | private StringBuilder sb;
21 | private int pos;
22 |
23 | public CopyStringBuilder(String source, int copyPos) {
24 | this(source.length() + 16, source, copyPos);
25 | }
26 |
27 | public CopyStringBuilder(int initialCapacity, String source, int copyPos) {
28 | if (CHECK_ARGS && (copyPos < 0 || copyPos > source.length())) throw new IllegalArgumentException("copyPos");
29 | this.initialCapacity = initialCapacity;
30 | this.source = source;
31 | pos = copyPos;
32 | }
33 |
34 | public void copyCount(int count) {
35 | copy(pos + count);
36 | }
37 |
38 | public void copyToEnd() {
39 | copy(source.length());
40 | }
41 |
42 | public void copy(int newPos) {
43 | if (CHECK_ARGS && (newPos < pos || newPos > source.length())) throw new IllegalArgumentException("newPos");
44 | if (sb != null) sb.append(source, pos, newPos);
45 | pos = newPos;
46 | }
47 |
48 | public StringBuilder skip(int newPos) {
49 | if (CHECK_ARGS && (newPos < pos || newPos > source.length())) throw new IllegalArgumentException("newPos");
50 | if (sb == null) sb = new StringBuilder(initialCapacity).append(source, 0, pos);
51 | pos = newPos;
52 | return sb;
53 | }
54 |
55 | public StringBuilder get() {
56 | if (sb == null) sb = new StringBuilder(initialCapacity).append(source, 0, pos);
57 | return sb;
58 | }
59 |
60 | public StringBuilder getOrNull() {
61 | return sb;
62 | }
63 |
64 | public String getSource() {
65 | return source;
66 | }
67 |
68 | public int getPos() {
69 | return pos;
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/codec/encoder/DefaultIgnoredHintTypes.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.codec.encoder;
12 |
13 | import java.io.Closeable;
14 | import java.io.Externalizable;
15 | import java.io.Flushable;
16 | import java.io.Serializable;
17 |
18 | import lanchon.dexpatcher.core.util.TypeName;
19 |
20 | import com.google.common.collect.ImmutableSet;
21 |
22 | public final class DefaultIgnoredHintTypes {
23 |
24 | public static final ImmutableSet SET;
25 |
26 | static {
27 |
28 | Class>[] types = new Class[] {
29 |
30 | // java.lang
31 | AutoCloseable.class,
32 | Cloneable.class,
33 | Comparable.class,
34 |
35 | // java.io
36 | Closeable.class,
37 | Externalizable.class,
38 | Flushable.class,
39 | Serializable.class
40 |
41 | };
42 |
43 | ImmutableSet.Builder builder = ImmutableSet.builder();
44 | for (Class> type : types) builder.add(TypeName.toClassDescriptor(type.getName()));
45 | SET = builder.build();
46 |
47 | }
48 |
49 | private DefaultIgnoredHintTypes() {}
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/codec/encoder/EncoderConfiguration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.codec.encoder;
12 |
13 | import java.util.Set;
14 | import java.util.regex.Pattern;
15 |
16 | public class EncoderConfiguration extends StringEscaperConfiguration {
17 |
18 | public Pattern obfuscatedBinaryTypeNamePattern;
19 |
20 | public Pattern obfuscatedPackageNamePattern;
21 | public Pattern obfuscatedClassNamePattern;
22 | public Pattern obfuscatedMemberNamePattern;
23 |
24 | //public boolean encodeAllPackages;
25 | public boolean encodeAllClasses;
26 | //public boolean encodeAllMembers;
27 |
28 | public boolean encodeObfuscatedPackages;
29 | public boolean encodeObfuscatedClasses;
30 | public boolean encodeObfuscatedMembers;
31 |
32 | public boolean encodeReservedCharacters;
33 | public boolean encodeReservedWords;
34 |
35 | public boolean encodeTypeHintsInClasses;
36 | public boolean encodeTypeHintsInMembers;
37 | public boolean encodeTypeInfoInMembers;
38 |
39 | public boolean includeIdentifierType = true;
40 | public boolean allowMultipleTypeHints = true;
41 | public boolean processNestedClasses = true;
42 |
43 | public Pattern ignoredHintTypePattern;
44 | public Set ignoredHintTypes = DefaultIgnoredHintTypes.SET;
45 |
46 | public void setEncodeCompilable() {
47 | encodeAllClasses = true;
48 | encodeReservedCharacters = true;
49 | encodeReservedWords = true;
50 | encodeTypeInfoInMembers = true;
51 | includeIdentifierType = true;
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/codec/encoder/ReservedWords.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.codec.encoder;
12 |
13 | import java.util.Arrays;
14 | import java.util.HashSet;
15 | import java.util.Set;
16 |
17 | public final class ReservedWords {
18 |
19 | // Based on the Java 13 JLS.
20 |
21 | private static final Set RESERVED_WORDS;
22 |
23 | static {
24 | String[] keywords = new String[] {
25 | "abstract", "continue", "for", "new", "switch",
26 | "assert", "default", "if", "package", "synchronized",
27 | "boolean", "do", "goto", "private", "this",
28 | "break", "double", "implements", "protected", "throw",
29 | "byte", "else", "import", "public", "throws",
30 | "case", "enum", "instanceof", "return", "transient",
31 | "catch", "extends", "int", "short", "try",
32 | "char", "final", "interface", "static", "void",
33 | "class", "finally", "long", "strictfp", "volatile",
34 | "const", "float", "native", "super", "while",
35 | "_"
36 | };
37 | String[] literals = new String[] {
38 | "false", "true", "null"
39 | };
40 | String[] reservedTypeNames = new String[] {
41 | "var"
42 | };
43 | String[] restrictedKeywords = new String[] {
44 | "exports", "open", "provides", "to", "uses",
45 | "module", "opens", "requires", "transitive", "with"
46 | };
47 | RESERVED_WORDS = new HashSet<>();
48 | RESERVED_WORDS.addAll(Arrays.asList(keywords));
49 | RESERVED_WORDS.addAll(Arrays.asList(literals));
50 | RESERVED_WORDS.addAll(Arrays.asList(reservedTypeNames));
51 | //RESERVED_WORDS.addAll(Arrays.asList(restrictedKeywords));
52 | }
53 |
54 | public static boolean isReserved(String word) {
55 | return RESERVED_WORDS.contains(word);
56 | }
57 |
58 | private ReservedWords() {}
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/codec/encoder/StringEscaper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.codec.encoder;
12 |
13 | import java.util.Locale;
14 |
15 | public final class StringEscaper {
16 |
17 | private final boolean escapeNonAscii;
18 | private final boolean escapeNonAsciiLatin1;
19 |
20 | private final boolean disableAsciiLatin1Escapes;
21 | private final boolean disableCodePointEscapes;
22 |
23 | public StringEscaper(StringEscaperConfiguration configuration) {
24 | this.escapeNonAscii = configuration.escapeNonAscii;
25 | this.escapeNonAsciiLatin1 = configuration.escapeNonAsciiLatin1;
26 | this.disableAsciiLatin1Escapes = configuration.disableAsciiLatin1Escapes;
27 | this.disableCodePointEscapes = configuration.disableCodePointEscapes;
28 | }
29 |
30 | public boolean shouldEscape(int codePoint) {
31 | if (codePoint < 0) throw new IllegalArgumentException("codePoint");
32 | return Character.isISOControl(codePoint) ||
33 | (escapeNonAscii && codePoint > 0x7F) ||
34 | (escapeNonAsciiLatin1 && codePoint > 0xFF) ||
35 | !Character.isJavaIdentifierPart(codePoint) ||
36 | Character.isIdentifierIgnorable(codePoint);
37 | }
38 |
39 | public boolean shouldEscape(String s) {
40 | int length = s.length();
41 | int i = 0;
42 | while (i < length) {
43 | int codePoint = s.codePointAt(i);
44 | if (shouldEscape(codePoint)) return true;
45 | i += Character.charCount(codePoint);
46 | }
47 | return false;
48 | }
49 |
50 | public StringBuilder escape(StringBuilder sb, int codePoint) {
51 | if (codePoint <= 0xFF && !disableAsciiLatin1Escapes) {
52 | sb.append("$a").append(String.format(Locale.ROOT, "%02X", codePoint));
53 | } else if (Character.isBmpCodePoint(codePoint)) {
54 | sb.append("$u").append(String.format(Locale.ROOT, "%04X", codePoint));
55 | } else if (Character.isSupplementaryCodePoint(codePoint)) {
56 | if (!disableCodePointEscapes) {
57 | sb.append("$p").append(String.format(Locale.ROOT, "%06X", codePoint));
58 | } else {
59 | sb.append("$u").append(String.format(Locale.ROOT, "%04X", (int) Character.highSurrogate(codePoint)));
60 | sb.append("$u").append(String.format(Locale.ROOT, "%04X", (int) Character.lowSurrogate(codePoint)));
61 | }
62 | } else {
63 | throw new IllegalArgumentException("codePoint");
64 | }
65 | return sb;
66 | }
67 |
68 | public StringBuilder escape(StringBuilder sb, String s) {
69 | int length = s.length();
70 | int i = 0;
71 | while (i < length) {
72 | int codePoint = s.codePointAt(i);
73 | if (codePoint == '$') {
74 | sb.append("$S");
75 | } else if (codePoint == '_') {
76 | sb.append("$U");
77 | } else if (shouldEscape(codePoint)) {
78 | escape(sb, codePoint);
79 | } else {
80 | sb.appendCodePoint(codePoint);
81 | }
82 | i += Character.charCount(codePoint);
83 | }
84 | return sb;
85 | }
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/codec/encoder/StringEscaperConfiguration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.codec.encoder;
12 |
13 | public class StringEscaperConfiguration {
14 |
15 | public boolean escapeNonAscii;
16 | public boolean escapeNonAsciiLatin1;
17 |
18 | public boolean disableAsciiLatin1Escapes;
19 | public boolean disableCodePointEscapes;
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/codec/encoder/TypeClassifier.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.codec.encoder;
12 |
13 | import java.util.regex.Pattern;
14 |
15 | public final class TypeClassifier {
16 |
17 | private final Pattern obfuscatedBinaryTypeNamePattern;
18 | private final Pattern obfuscatedClassNamePattern;
19 |
20 | public TypeClassifier(Pattern obfuscatedBinaryTypeNamePattern, Pattern obfuscatedClassNamePattern) {
21 | this.obfuscatedBinaryTypeNamePattern = obfuscatedBinaryTypeNamePattern;
22 | this.obfuscatedClassNamePattern = obfuscatedClassNamePattern;
23 | }
24 |
25 | public boolean isObfuscatedType(String type, boolean defaultValue) {
26 | //if (!DexUtils.isClassDescriptor(type)) throw new AssertionError("Invalid class descriptor");
27 | if (obfuscatedBinaryTypeNamePattern != null) {
28 | if (obfuscatedBinaryTypeNamePattern.matcher(type).region(1, type.length() - 1).matches()) return true;
29 | defaultValue = false;
30 | }
31 | if (obfuscatedClassNamePattern != null) {
32 | int packageEnd = type.lastIndexOf('/');
33 | int nameStart = (packageEnd < 0) ? 1 : packageEnd + 1;
34 | String name = type.substring(nameStart, type.length() - 1);
35 | return obfuscatedClassNamePattern.matcher(name).matches();
36 | }
37 | return defaultValue;
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/codec/encoder/TypeHintMapper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.codec.encoder;
12 |
13 | import java.util.HashMap;
14 | import java.util.Map;
15 | import java.util.Set;
16 | import java.util.regex.Pattern;
17 |
18 | import org.jf.dexlib2.iface.ClassDef;
19 | import org.jf.dexlib2.iface.DexFile;
20 |
21 | public class TypeHintMapper extends TypeInfoMapper{
22 |
23 | public static final String NON_OBFUSCATED_TYPE_HINT = new String();
24 |
25 | public static Map buildBasicTypeHintMap(DexFile dex, TypeClassifier typeClassifier,
26 | boolean defaultValue) {
27 | Set extends ClassDef> classes = dex.getClasses();
28 | Map typeHintMap = new HashMap<>(classes.size());
29 | for (ClassDef classDef : classes) {
30 | String type = classDef.getType();
31 | boolean obfuscated = typeClassifier.isObfuscatedType(type, defaultValue);
32 | typeHintMap.put(type, obfuscated ? "" : NON_OBFUSCATED_TYPE_HINT);
33 | }
34 | return typeHintMap;
35 | }
36 |
37 | public static StringBuilder encodeTypeHint(StringBuilder sb, String type, StringEscaper stringEscaper) {
38 | //if (!DexUtils.isClassDescriptor(type)) throw new AssertionError("Invalid class descriptor");
39 | int packageEnd = type.lastIndexOf('/');
40 | int nameStart = (packageEnd < 0) ? 1 : packageEnd + 1;
41 | stringEscaper.escape(sb.append('_'), type.substring(nameStart, type.length() - 1));
42 | return sb;
43 | }
44 |
45 | protected final boolean allowMultipleTypeHints;
46 | protected final Pattern ignoredHintTypePattern;
47 | protected final Set ignoredHintTypes;
48 | protected final StringEscaper stringEscaper;
49 |
50 | public TypeHintMapper(TypeClassifier typeClassifier, boolean allowMultipleTypeHints,
51 | Pattern ignoredHintTypePattern, Set ignoredHintTypes, StringEscaper stringEscaper) {
52 | super(typeClassifier, true);
53 | this.allowMultipleTypeHints = allowMultipleTypeHints;
54 | this.ignoredHintTypePattern = ignoredHintTypePattern;
55 | this.ignoredHintTypes = ignoredHintTypes;
56 | this.stringEscaper = stringEscaper;
57 | }
58 |
59 | public Map buildTypeHintMap(DexFile dex) {
60 | Map typeInfoMap = buildTypeInfoMap(dex);
61 | Map typeHintMap = new HashMap<>(typeInfoMap.size());
62 | for (Map.Entry entry : typeInfoMap.entrySet()) {
63 | String type = entry.getKey();
64 | TypeInfoMapper.TypeInfo info = entry.getValue();
65 | String hint;
66 | if (info == TypeInfoMapper.NON_OBFUSCATED_TYPE_INFO) {
67 | hint = NON_OBFUSCATED_TYPE_HINT;
68 | } else {
69 | StringBuilder sb = new StringBuilder();
70 | if (info.clearType != null) {
71 | encodeTypeHint(sb, info.clearType, stringEscaper);
72 | } else {
73 | Set clearInterfaces = info.clearInterfaces;
74 | if (allowMultipleTypeHints || clearInterfaces.size() == 1) {
75 | for (String interfaceType : clearInterfaces) {
76 | encodeTypeHint(sb, interfaceType, stringEscaper);
77 | }
78 | }
79 | }
80 | hint = sb.toString();
81 | }
82 | typeHintMap.put(type, hint);
83 | }
84 | return typeHintMap;
85 | }
86 |
87 | @Override
88 | public boolean isIgnoredType(String type) {
89 | return
90 | (ignoredHintTypes != null &&
91 | ignoredHintTypes.contains(type)) ||
92 | (ignoredHintTypePattern != null &&
93 | ignoredHintTypePattern.matcher(type).region(1, type.length() - 1).matches());
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/codec/encoder/TypeInfoMapper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.codec.encoder;
12 |
13 | import java.util.Collections;
14 | import java.util.HashMap;
15 | import java.util.Map;
16 | import java.util.Set;
17 | import java.util.TreeSet;
18 |
19 | import org.jf.dexlib2.iface.ClassDef;
20 | import org.jf.dexlib2.iface.DexFile;
21 |
22 | public class TypeInfoMapper {
23 |
24 | public static class TypeInfo {
25 | // Note: clearInterfaces can only contain elements if clearType is null.
26 | public String clearType;
27 | public Set clearInterfaces = Collections.emptySet();
28 | }
29 |
30 | public static final TypeInfo NON_OBFUSCATED_TYPE_INFO = new TypeInfo();
31 |
32 | private static final TypeInfo IGNORED_TYPE_INFO = new TypeInfo();
33 | private static final String JAVA_LANG_OBJECT = "Ljava/lang/Object;";
34 |
35 | protected final TypeClassifier typeClassifier;
36 | protected final boolean processInterfaces;
37 |
38 | public TypeInfoMapper(TypeClassifier typeClassifier, boolean processInterfaces) {
39 | this.typeClassifier = typeClassifier;
40 | this.processInterfaces = processInterfaces;
41 | }
42 |
43 | public Map buildTypeInfoMap(DexFile dex) {
44 | Set extends ClassDef> classes = dex.getClasses();
45 | Map classMap = new HashMap<>(classes.size());
46 | for (ClassDef classDef : classes) {
47 | classMap.put(classDef.getType(), classDef);
48 | }
49 | Map typeInfoMap = new HashMap<>(classes.size());
50 | for (ClassDef classDef : classes) {
51 | buildTypeInfo(typeInfoMap, classMap, classDef, classDef.getType());
52 | }
53 | return typeInfoMap;
54 | }
55 |
56 | private TypeInfo buildTypeInfo(Map typeInfoMap, Map classMap,
57 | String type) {
58 | ClassDef classDef = classMap.get(type);
59 | if (classDef == null) return null;
60 | return buildTypeInfo(typeInfoMap, classMap, classDef, type);
61 | }
62 |
63 | private TypeInfo buildTypeInfo(Map typeInfoMap, Map classMap,
64 | ClassDef classDef, String type) {
65 | TypeInfo info = typeInfoMap.get(type);
66 | if (info == NON_OBFUSCATED_TYPE_INFO) return null;
67 | if (info != null) return info;
68 | if (!typeClassifier.isObfuscatedType(type, true)) {
69 | typeInfoMap.put(type, NON_OBFUSCATED_TYPE_INFO);
70 | return null;
71 | }
72 | if (isIgnoredType(type)) {
73 | typeInfoMap.put(type, IGNORED_TYPE_INFO);
74 | return null;
75 | }
76 | info = new TypeInfo();
77 | // Early put to avoid infinite recursion while processing malformed dex files.
78 | typeInfoMap.put(type, info);
79 | String superclassType = classDef.getSuperclass();
80 | if (JAVA_LANG_OBJECT.equals(superclassType)) superclassType = null;
81 | Set superclassClearInterfaces = null;
82 | if (superclassType != null && !isIgnoredType(superclassType)) {
83 | TypeInfo superclassInfo = buildTypeInfo(typeInfoMap, classMap, superclassType);
84 | if (superclassInfo == null) {
85 | // Type is external to dex file or not obfuscated.
86 | info.clearType = superclassType;
87 | return info;
88 | }
89 | if (superclassInfo.clearType != null) {
90 | info.clearType = superclassInfo.clearType;
91 | return info;
92 | }
93 | superclassClearInterfaces = superclassInfo.clearInterfaces;
94 | }
95 | if (!processInterfaces) {
96 | return info;
97 | }
98 | Set clearInterfaces = new TreeSet<>();
99 | if (superclassClearInterfaces != null) {
100 | clearInterfaces.addAll(superclassClearInterfaces);
101 | }
102 | for (String interfaceType : classDef.getInterfaces()) {
103 | if (!isIgnoredType(interfaceType)) {
104 | TypeInfo interfaceInfo = buildTypeInfo(typeInfoMap, classMap, interfaceType);
105 | if (interfaceInfo == null) {
106 | // Type is external to dex file or not obfuscated.
107 | clearInterfaces.add(interfaceType);
108 | } else {
109 | if (interfaceInfo.clearType != null) {
110 | clearInterfaces.add(interfaceInfo.clearType);
111 | } else {
112 | clearInterfaces.addAll(interfaceInfo.clearInterfaces);
113 | }
114 | }
115 | }
116 | }
117 | if (!clearInterfaces.isEmpty()) info.clearInterfaces = clearInterfaces;
118 | return info;
119 | }
120 |
121 | protected boolean isIgnoredType(String type) {
122 | return false;
123 | }
124 |
125 | }
126 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/mapper/DexMapperModule.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.mapper;
12 |
13 | import lanchon.dexpatcher.core.util.DexUtils;
14 | import lanchon.dexpatcher.core.util.ElementalTypeRewriter;
15 | import lanchon.dexpatcher.transform.mapper.map.DexMap;
16 | import lanchon.dexpatcher.transform.util.wrapper.WrapperFieldReference;
17 | import lanchon.dexpatcher.transform.util.wrapper.WrapperMethodReference;
18 | import lanchon.dexpatcher.transform.util.wrapper.WrapperRewriterModule;
19 |
20 | import org.jf.dexlib2.iface.reference.FieldReference;
21 | import org.jf.dexlib2.iface.reference.MethodReference;
22 | import org.jf.dexlib2.rewriter.Rewriter;
23 | import org.jf.dexlib2.rewriter.RewriterModule;
24 | import org.jf.dexlib2.rewriter.Rewriters;
25 |
26 | public class DexMapperModule extends WrapperRewriterModule {
27 |
28 | protected final DexMap dexMap;
29 |
30 | public DexMapperModule(DexMap dexMap) {
31 | this(dexMap, new RewriterModule());
32 | }
33 |
34 | public DexMapperModule(DexMap dexMap, RewriterModule wrappedModule) {
35 | super(wrappedModule);
36 | this.dexMap = dexMap;
37 | }
38 |
39 | @Override
40 | public Rewriter getTypeRewriter(Rewriters rewriters) {
41 | final Rewriter wrappedTypeRewriter = wrappedModule.getTypeRewriter(rewriters);
42 | return new ElementalTypeRewriter() {
43 | @Override
44 | public String rewriteElementalType(String type) {
45 | if (DexUtils.isClassDescriptor(type)) {
46 | String mapping = dexMap.getClassMapping(type);
47 | if (mapping != null) return mapping;
48 | }
49 | // WARNING: This routes the elemental type to the wrapped rewriter.
50 | return wrappedTypeRewriter.rewrite(type);
51 | }
52 | };
53 | }
54 |
55 | @Override
56 | public Rewriter getFieldReferenceRewriter(Rewriters rewriters) {
57 | final Rewriter wrappedFieldReferenceRewriter =
58 | wrappedModule.getFieldReferenceRewriter(rewriters);
59 | return new Rewriter() {
60 | @Override
61 | public FieldReference rewrite(FieldReference field) {
62 | FieldReference rewrittenField = wrappedFieldReferenceRewriter.rewrite(field);
63 | final String mapping = dexMap.getFieldMapping(field);
64 | if (mapping != null) {
65 | return new WrapperFieldReference(rewrittenField) {
66 | @Override
67 | public String getName() {
68 | return mapping;
69 | }
70 | };
71 | }
72 | return rewrittenField;
73 | }
74 | };
75 | }
76 |
77 | @Override
78 | public Rewriter getMethodReferenceRewriter(Rewriters rewriters) {
79 | final Rewriter wrappedMethodReferenceRewriter =
80 | wrappedModule.getMethodReferenceRewriter(rewriters);
81 | return new Rewriter() {
82 | @Override
83 | public MethodReference rewrite(MethodReference method) {
84 | MethodReference rewrittenMethod = wrappedMethodReferenceRewriter.rewrite(method);
85 | final String mapping = dexMap.getMethodMapping(method);
86 | if (mapping != null) {
87 | return new WrapperMethodReference(rewrittenMethod) {
88 | @Override
89 | public String getName() {
90 | return mapping;
91 | }
92 | };
93 | }
94 | return rewrittenMethod;
95 | }
96 | };
97 | }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/mapper/map/DexMap.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.mapper.map;
12 |
13 | import org.jf.dexlib2.iface.reference.FieldReference;
14 | import org.jf.dexlib2.iface.reference.MethodReference;
15 |
16 | public interface DexMap {
17 |
18 | String getClassMapping(String descriptor);
19 | String getFieldMapping(FieldReference field);
20 | String getMethodMapping(MethodReference method);
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/mapper/map/DexMaps.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.mapper.map;
12 |
13 | import lanchon.dexpatcher.core.util.DexUtils;
14 |
15 | public class DexMaps {
16 |
17 | public static String mapType(String descriptor, DexMap dexMap) {
18 | int length = descriptor.length();
19 | if (length == 0 || descriptor.charAt(0) != '[') return mapElementalType(descriptor, dexMap);
20 | int start = 1;
21 | while (start < length && descriptor.charAt(start) == '[') start++;
22 | String elementalType = descriptor.substring(start);
23 | String mappedElementalType = mapElementalType(elementalType, dexMap);
24 | if (mappedElementalType.equals(elementalType)) return descriptor;
25 | StringBuilder sb = new StringBuilder(start + mappedElementalType.length());
26 | sb.append(descriptor, 0, start).append(mappedElementalType);
27 | return sb.toString();
28 | }
29 |
30 | public static String mapElementalType(String descriptor, DexMap dexMap) {
31 | if (DexUtils.isClassDescriptor(descriptor)) {
32 | String mapping = dexMap.getClassMapping(descriptor);
33 | if (mapping != null) return mapping;
34 | }
35 | return descriptor;
36 | }
37 |
38 | private DexMaps() {}
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/mapper/map/LoggingDexMap.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.mapper.map;
12 |
13 | import java.util.Locale;
14 |
15 | import lanchon.dexpatcher.core.logger.Logger;
16 | import lanchon.dexpatcher.core.util.Label;
17 | import lanchon.dexpatcher.transform.MemberLogger;
18 | import lanchon.dexpatcher.transform.TransformLogger;
19 |
20 | import org.jf.dexlib2.iface.reference.FieldReference;
21 | import org.jf.dexlib2.iface.reference.MethodReference;
22 |
23 | public class LoggingDexMap extends MemberLogger implements DexMap {
24 |
25 | protected final DexMap wrappedDexMap;
26 | protected final String message;
27 | protected final Logger.Level infoLevel;
28 |
29 | public LoggingDexMap(DexMap wrappedDexMap, TransformLogger logger, String logPrefix, Logger.Level infoLevel) {
30 | this(wrappedDexMap, "mapped to '%s'", logger, logPrefix, infoLevel);
31 | }
32 |
33 | public LoggingDexMap(DexMap wrappedDexMap, boolean isInverseMap, TransformLogger logger, String logPrefix,
34 | Logger.Level infoLevel) {
35 | this(wrappedDexMap, isInverseMap ? "unmapped to '%s'" : "mapped to '%s'", logger, logPrefix, infoLevel);
36 | }
37 |
38 | public LoggingDexMap(DexMap wrappedDexMap, String message, TransformLogger logger, String logPrefix,
39 | Logger.Level infoLevel) {
40 | super(logger, logPrefix);
41 | this.wrappedDexMap = wrappedDexMap;
42 | this.message = message;
43 | this.infoLevel = infoLevel;
44 | }
45 |
46 | @Override
47 | protected String getTransformedDefiningClass(String definingClass) {
48 | return wrappedDexMap.getClassMapping(definingClass);
49 | }
50 |
51 | @Override
52 | public String getClassMapping(String descriptor) {
53 | String mapping = wrappedDexMap.getClassMapping(descriptor);
54 | if (mapping != null && logger.isLogging(infoLevel)) {
55 | StringBuilder sb = getMessageHeaderForClass(descriptor);
56 | sb.append(String.format(Locale.ROOT, message, Label.fromClassDescriptor(mapping)));
57 | logger.log(infoLevel, sb.toString());
58 | }
59 | return mapping;
60 | }
61 |
62 | @Override
63 | public String getFieldMapping(FieldReference field) {
64 | String mapping = wrappedDexMap.getFieldMapping(field);
65 | if (mapping != null && logger.isLogging(infoLevel)) {
66 | StringBuilder sb = getMessageHeaderForField(field);
67 | sb.append(String.format(Locale.ROOT, message, Label.ofTargetMember(mapping)));
68 | logger.log(infoLevel, sb.toString());
69 | }
70 | return mapping;
71 | }
72 |
73 | @Override
74 | public String getMethodMapping(MethodReference method) {
75 | String mapping = wrappedDexMap.getMethodMapping(method);
76 | if (mapping != null && logger.isLogging(infoLevel)) {
77 | StringBuilder sb = getMessageHeaderForMethod(method);
78 | sb.append(String.format(Locale.ROOT, message, Label.ofTargetMember(mapping)));
79 | logger.log(infoLevel, sb.toString());
80 | }
81 | return mapping;
82 | }
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/mapper/map/builder/DexMapping.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.mapper.map.builder;
12 |
13 | import java.util.Arrays;
14 | import java.util.HashMap;
15 | import java.util.Map;
16 |
17 | import lanchon.dexpatcher.core.util.Id;
18 | import lanchon.dexpatcher.transform.mapper.map.DexMap;
19 |
20 | import org.jf.dexlib2.iface.reference.FieldReference;
21 | import org.jf.dexlib2.iface.reference.MethodReference;
22 |
23 | public class DexMapping implements MapBuilder, DexMap {
24 |
25 | protected static class ClassMapping implements MemberMapBuilder {
26 |
27 | protected final String mapping;
28 |
29 | protected final Map fieldMappings = new HashMap<>();
30 | protected final Map methodMappings = new HashMap<>();
31 |
32 | public ClassMapping(String mapping) {
33 | this.mapping = mapping;
34 | }
35 |
36 | public String getMapping() {
37 | return mapping;
38 | }
39 |
40 | @Override
41 | public void addFieldMapping(String type, String name, String newName) {
42 | if (newName == null) throw new NullPointerException("newName");
43 | String id = Id.ofField(type, name);
44 | String currentName = fieldMappings.put(id, newName);
45 | if (currentName != null) {
46 | fieldMappings.put(id, currentName);
47 | throw new BuilderException("duplicate field mapping");
48 | }
49 | }
50 |
51 | public String getFieldMapping(String fieldId) {
52 | return fieldMappings.get(fieldId);
53 | }
54 |
55 | @Override
56 | public void addMethodMapping(String[] parameterTypes, String returnType, String name, String newName) {
57 | if (newName == null) throw new NullPointerException("newName");
58 | String id = Id.ofMethod(Arrays.asList(parameterTypes), returnType, name);
59 | String currentName = methodMappings.put(id, newName);
60 | if (currentName != null) {
61 | methodMappings.put(id, currentName);
62 | throw new BuilderException("duplicate method mapping");
63 | }
64 | }
65 |
66 | public String getMethodMapping(String methodId) {
67 | return methodMappings.get(methodId);
68 | }
69 |
70 | }
71 |
72 | protected final Map classMappings = new HashMap<>();
73 |
74 | @Override
75 | public MemberMapBuilder addClassMapping(String name, String newName) {
76 | if (newName == null) throw new NullPointerException("newName");
77 | String id = Id.ofClass(name);
78 | ClassMapping newMapping = new ClassMapping(newName);
79 | ClassMapping currentMapping = classMappings.put(id, newMapping);
80 | if (currentMapping != null) {
81 | classMappings.put(id, currentMapping);
82 | throw new BuilderException("duplicate type mapping");
83 | }
84 | return newMapping;
85 | }
86 |
87 | @Override
88 | public String getClassMapping(String descriptor) {
89 | return getClassMappingById(Id.ofClass(descriptor));
90 | }
91 |
92 | @Override
93 | public String getFieldMapping(FieldReference field) {
94 | return getFieldMappingById(Id.ofClass(field.getDefiningClass()), Id.ofField(field));
95 | }
96 |
97 | @Override
98 | public String getMethodMapping(MethodReference method) {
99 | return getMethodMappingById(Id.ofClass(method.getDefiningClass()), Id.ofMethod(method));
100 |
101 | }
102 |
103 | protected final String getClassMappingById(String classId) {
104 | ClassMapping classMapping = classMappings.get(classId);
105 | return classMapping != null ? classMapping.getMapping() : null;
106 | }
107 |
108 | protected final String getFieldMappingById(String classId, String fieldId) {
109 | ClassMapping classMapping = classMappings.get(classId);
110 | return classMapping != null ? classMapping.getFieldMapping(fieldId) : null;
111 | }
112 |
113 | protected final String getMethodMappingById(String classId, String methodId) {
114 | ClassMapping classMapping = classMappings.get(classId);
115 | return classMapping != null ? classMapping.getMethodMapping(methodId) : null;
116 | }
117 |
118 | }
119 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/mapper/map/builder/InverseMapBuilder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.mapper.map.builder;
12 |
13 | import lanchon.dexpatcher.transform.mapper.map.DexMap;
14 | import lanchon.dexpatcher.transform.mapper.map.DexMaps;
15 |
16 | public class InverseMapBuilder implements MapBuilder {
17 |
18 | private static final String EXCEPTION_HEADER = "on inverse map: ";
19 |
20 | protected final MapBuilder wrappedMapBuilder;
21 | protected final DexMap directDexMap;
22 |
23 | public InverseMapBuilder(MapBuilder wrappedMapBuilder, DexMap directDexMap) {
24 | this.wrappedMapBuilder = wrappedMapBuilder;
25 | this.directDexMap = directDexMap;
26 | }
27 |
28 | @Override
29 | public MemberMapBuilder addClassMapping(String name, String newName) {
30 | try {
31 | final MemberMapBuilder wrappedMemberMapBuilder = wrappedMapBuilder.addClassMapping(newName, name);
32 | return new MemberMapBuilder() {
33 | @Override
34 | public void addFieldMapping(String type, String name, String newName) {
35 | try {
36 | String mappedType = DexMaps.mapType(type, directDexMap);
37 | wrappedMemberMapBuilder.addFieldMapping(mappedType, newName, name);
38 | } catch (BuilderException e) {
39 | throw new BuilderException(EXCEPTION_HEADER + e.getMessage());
40 | }
41 | }
42 | @Override
43 | public void addMethodMapping(String[] parameterTypes, String returnType, String name, String newName) {
44 | try {
45 | int length = parameterTypes.length;
46 | String[] mappedParameterTypes = new String[length];
47 | for (int i = 0; i < length; i++) {
48 | mappedParameterTypes[i] = DexMaps.mapType(parameterTypes[i], directDexMap);
49 | }
50 | String mappedReturnType = DexMaps.mapType(returnType, directDexMap);
51 | wrappedMemberMapBuilder.addMethodMapping(mappedParameterTypes, mappedReturnType, newName, name);
52 | } catch (BuilderException e) {
53 | throw new BuilderException(EXCEPTION_HEADER + e.getMessage());
54 | }
55 | }
56 | };
57 | } catch (BuilderException e) {
58 | throw new BuilderException(EXCEPTION_HEADER + e.getMessage());
59 | }
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/mapper/map/builder/MapBuilder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.mapper.map.builder;
12 |
13 | public interface MapBuilder {
14 |
15 | MemberMapBuilder addClassMapping(String name, String newName);
16 |
17 | interface MemberMapBuilder {
18 | void addFieldMapping(String type, String name, String newName);
19 | void addMethodMapping(String[] parameterTypes, String returnType, String name, String newName);
20 | }
21 |
22 | class BuilderException extends RuntimeException {
23 | public BuilderException(String s) {
24 | super(s);
25 | }
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/util/wrapper/WrapperAnnotation.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.util.wrapper;
12 |
13 | import java.util.Set;
14 |
15 | import org.jf.dexlib2.base.BaseAnnotation;
16 | import org.jf.dexlib2.iface.Annotation;
17 | import org.jf.dexlib2.iface.AnnotationElement;
18 |
19 | public class WrapperAnnotation extends BaseAnnotation {
20 |
21 | protected final Annotation wrappedAnnotation;
22 |
23 | public WrapperAnnotation(Annotation wrappedAnnotation) {
24 | this.wrappedAnnotation = wrappedAnnotation;
25 | }
26 |
27 | @Override
28 | public int getVisibility() {
29 | return wrappedAnnotation.getVisibility();
30 | }
31 |
32 | @Override
33 | public String getType() {
34 | return wrappedAnnotation.getType();
35 | }
36 |
37 | @Override
38 | public Set extends AnnotationElement> getElements() {
39 | return wrappedAnnotation.getElements();
40 | }
41 |
42 | }
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/util/wrapper/WrapperAnnotationElement.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.util.wrapper;
12 |
13 | import org.jf.dexlib2.base.BaseAnnotationElement;
14 | import org.jf.dexlib2.iface.AnnotationElement;
15 | import org.jf.dexlib2.iface.value.EncodedValue;
16 |
17 | public class WrapperAnnotationElement extends BaseAnnotationElement {
18 |
19 | protected final AnnotationElement wrappedAnnotationElement;
20 |
21 | public WrapperAnnotationElement(AnnotationElement wrappedAnnotationElement) {
22 | this.wrappedAnnotationElement = wrappedAnnotationElement;
23 | }
24 |
25 | @Override
26 | public String getName() {
27 | return wrappedAnnotationElement.getName();
28 | }
29 |
30 | @Override
31 | public EncodedValue getValue() {
32 | return wrappedAnnotationElement.getValue();
33 | }
34 |
35 | }
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/util/wrapper/WrapperClassDef.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.util.wrapper;
12 |
13 | import java.util.Iterator;
14 | import java.util.List;
15 | import java.util.Set;
16 |
17 | import com.google.common.collect.Iterators;
18 | import org.jf.dexlib2.base.reference.BaseTypeReference;
19 | import org.jf.dexlib2.iface.Annotation;
20 | import org.jf.dexlib2.iface.ClassDef;
21 | import org.jf.dexlib2.iface.Field;
22 | import org.jf.dexlib2.iface.Method;
23 |
24 | public class WrapperClassDef extends BaseTypeReference implements ClassDef {
25 |
26 | protected final ClassDef wrappedClassDef;
27 |
28 | public WrapperClassDef(ClassDef wrappedClassDef) {
29 | this.wrappedClassDef = wrappedClassDef;
30 | }
31 |
32 | @Override
33 | public String getType() {
34 | return wrappedClassDef.getType();
35 | }
36 |
37 | @Override
38 | public int getAccessFlags() {
39 | return wrappedClassDef.getAccessFlags();
40 | }
41 |
42 | @Override
43 | public String getSuperclass() {
44 | return wrappedClassDef.getSuperclass();
45 | }
46 |
47 | @Override
48 | public List getInterfaces() {
49 | return wrappedClassDef.getInterfaces();
50 | }
51 |
52 | @Override
53 | public String getSourceFile() {
54 | return wrappedClassDef.getSourceFile();
55 | }
56 |
57 | @Override
58 | public Set extends Annotation> getAnnotations() {
59 | return wrappedClassDef.getAnnotations();
60 | }
61 |
62 | @Override
63 | public Iterable extends Field> getStaticFields() {
64 | return wrappedClassDef.getStaticFields();
65 | }
66 |
67 | @Override
68 | public Iterable extends Field> getInstanceFields() {
69 | return wrappedClassDef.getInstanceFields();
70 | }
71 |
72 | @Override
73 | public Iterable extends Method> getDirectMethods() {
74 | return wrappedClassDef.getDirectMethods();
75 | }
76 |
77 | @Override
78 | public Iterable extends Method> getVirtualMethods() {
79 | return wrappedClassDef.getVirtualMethods();
80 | }
81 |
82 | @Override
83 | public final Iterable extends Field> getFields() {
84 | return new Iterable() {
85 | @Override
86 | public Iterator iterator() {
87 | return Iterators.concat(getStaticFields().iterator(), getInstanceFields().iterator());
88 | }
89 | };
90 | }
91 |
92 | @Override
93 | public final Iterable extends Method> getMethods() {
94 | return new Iterable() {
95 | @Override
96 | public Iterator iterator() {
97 | return Iterators.concat(getDirectMethods().iterator(), getVirtualMethods().iterator());
98 | }
99 | };
100 | }
101 |
102 | }
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/util/wrapper/WrapperField.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.util.wrapper;
12 |
13 | import java.util.Set;
14 |
15 | import org.jf.dexlib2.base.reference.BaseFieldReference;
16 | import org.jf.dexlib2.iface.Annotation;
17 | import org.jf.dexlib2.iface.Field;
18 | import org.jf.dexlib2.iface.value.EncodedValue;
19 |
20 | public class WrapperField extends BaseFieldReference implements Field {
21 |
22 | protected final Field wrappedField;
23 |
24 | public WrapperField(Field wrappedField) {
25 | this.wrappedField = wrappedField;
26 | }
27 |
28 | @Override
29 | public String getDefiningClass() {
30 | return wrappedField.getDefiningClass();
31 | }
32 |
33 | @Override
34 | public String getName() {
35 | return wrappedField.getName();
36 | }
37 |
38 | @Override
39 | public String getType() {
40 | return wrappedField.getType();
41 | }
42 |
43 | @Override
44 | public int getAccessFlags() {
45 | return wrappedField.getAccessFlags();
46 | }
47 |
48 | @Override
49 | public EncodedValue getInitialValue() {
50 | return wrappedField.getInitialValue();
51 | }
52 |
53 | @Override
54 | public Set extends Annotation> getAnnotations() {
55 | return wrappedField.getAnnotations();
56 | }
57 |
58 | }
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/util/wrapper/WrapperFieldReference.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.util.wrapper;
12 |
13 | import org.jf.dexlib2.base.reference.BaseFieldReference;
14 | import org.jf.dexlib2.iface.reference.FieldReference;
15 |
16 | public class WrapperFieldReference extends BaseFieldReference {
17 |
18 | protected final FieldReference wrappedFieldReference;
19 |
20 | public WrapperFieldReference(FieldReference wrappedFieldReference) {
21 | this.wrappedFieldReference = wrappedFieldReference;
22 | }
23 |
24 | @Override
25 | public String getDefiningClass() {
26 | return wrappedFieldReference.getDefiningClass();
27 | }
28 |
29 | @Override
30 | public String getName() {
31 | return wrappedFieldReference.getName();
32 | }
33 |
34 | @Override
35 | public String getType() {
36 | return wrappedFieldReference.getType();
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/util/wrapper/WrapperMethod.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.util.wrapper;
12 |
13 | import java.util.List;
14 | import java.util.Set;
15 |
16 | import org.jf.dexlib2.base.reference.BaseMethodReference;
17 | import org.jf.dexlib2.iface.Annotation;
18 | import org.jf.dexlib2.iface.Method;
19 | import org.jf.dexlib2.iface.MethodImplementation;
20 | import org.jf.dexlib2.iface.MethodParameter;
21 |
22 | public class WrapperMethod extends BaseMethodReference implements Method {
23 |
24 | protected final Method wrappedMethod;
25 |
26 | public WrapperMethod(Method wrappedMethod) {
27 | this.wrappedMethod = wrappedMethod;
28 | }
29 |
30 | @Override
31 | public String getDefiningClass() {
32 | return wrappedMethod.getDefiningClass();
33 | }
34 |
35 | @Override
36 | public String getName() {
37 | return wrappedMethod.getName();
38 | }
39 |
40 | @Override
41 | public List extends MethodParameter> getParameters() {
42 | return wrappedMethod.getParameters();
43 | }
44 |
45 | @Override
46 | public List extends CharSequence> getParameterTypes() {
47 | return wrappedMethod.getParameterTypes();
48 | }
49 |
50 | @Override
51 | public String getReturnType() {
52 | return wrappedMethod.getReturnType();
53 | }
54 |
55 | @Override
56 | public int getAccessFlags() {
57 | return wrappedMethod.getAccessFlags();
58 | }
59 |
60 | @Override
61 | public Set extends Annotation> getAnnotations() {
62 | return wrappedMethod.getAnnotations();
63 | }
64 |
65 | @Override
66 | public MethodImplementation getImplementation() {
67 | return wrappedMethod.getImplementation();
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/util/wrapper/WrapperMethodReference.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.util.wrapper;
12 |
13 | import java.util.List;
14 |
15 | import org.jf.dexlib2.base.reference.BaseMethodReference;
16 | import org.jf.dexlib2.iface.reference.MethodReference;
17 |
18 | public class WrapperMethodReference extends BaseMethodReference {
19 |
20 | protected final MethodReference wrappedMethodReference;
21 |
22 | public WrapperMethodReference(MethodReference wrappedMethodReference) {
23 | this.wrappedMethodReference = wrappedMethodReference;
24 | }
25 |
26 | @Override
27 | public String getDefiningClass() {
28 | return wrappedMethodReference.getDefiningClass();
29 | }
30 |
31 | @Override
32 | public String getName() {
33 | return wrappedMethodReference.getName();
34 | }
35 |
36 | @Override
37 | public List extends CharSequence> getParameterTypes() {
38 | return wrappedMethodReference.getParameterTypes();
39 | }
40 |
41 | @Override
42 | public String getReturnType() {
43 | return wrappedMethodReference.getReturnType();
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/tool/src/main/java/lanchon/dexpatcher/transform/util/wrapper/WrapperRewriterModule.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DexPatcher - Copyright 2015-2020 Rodrigo Balerdi
3 | * (GNU General Public License version 3 or later)
4 | *
5 | * DexPatcher is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License,
8 | * or (at your option) any later version.
9 | */
10 |
11 | package lanchon.dexpatcher.transform.util.wrapper;
12 |
13 | import org.jf.dexlib2.iface.Annotation;
14 | import org.jf.dexlib2.iface.AnnotationElement;
15 | import org.jf.dexlib2.iface.ClassDef;
16 | import org.jf.dexlib2.iface.ExceptionHandler;
17 | import org.jf.dexlib2.iface.Field;
18 | import org.jf.dexlib2.iface.Method;
19 | import org.jf.dexlib2.iface.MethodImplementation;
20 | import org.jf.dexlib2.iface.MethodParameter;
21 | import org.jf.dexlib2.iface.TryBlock;
22 | import org.jf.dexlib2.iface.debug.DebugItem;
23 | import org.jf.dexlib2.iface.instruction.Instruction;
24 | import org.jf.dexlib2.iface.reference.FieldReference;
25 | import org.jf.dexlib2.iface.reference.MethodReference;
26 | import org.jf.dexlib2.iface.value.EncodedValue;
27 | import org.jf.dexlib2.rewriter.Rewriter;
28 | import org.jf.dexlib2.rewriter.RewriterModule;
29 | import org.jf.dexlib2.rewriter.Rewriters;
30 |
31 | public class WrapperRewriterModule extends RewriterModule {
32 |
33 | protected final M wrappedModule;
34 |
35 | public WrapperRewriterModule(M wrappedModule) {
36 | this.wrappedModule = wrappedModule;
37 | }
38 |
39 | @Override
40 | public Rewriter getClassDefRewriter(Rewriters rewriters) {
41 | return wrappedModule.getClassDefRewriter(rewriters);
42 | }
43 |
44 | @Override
45 | public Rewriter getFieldRewriter(Rewriters rewriters) {
46 | return wrappedModule.getFieldRewriter(rewriters);
47 | }
48 |
49 | @Override
50 | public Rewriter getMethodRewriter(Rewriters rewriters) {
51 | return wrappedModule.getMethodRewriter(rewriters);
52 | }
53 |
54 | @Override
55 | public Rewriter getMethodParameterRewriter(Rewriters rewriters) {
56 | return wrappedModule.getMethodParameterRewriter(rewriters);
57 | }
58 |
59 | @Override
60 | public Rewriter getMethodImplementationRewriter(Rewriters rewriters) {
61 | return wrappedModule.getMethodImplementationRewriter(rewriters);
62 | }
63 |
64 | @Override
65 | public Rewriter getInstructionRewriter(Rewriters rewriters) {
66 | return wrappedModule.getInstructionRewriter(rewriters);
67 | }
68 |
69 | @Override
70 | public Rewriter> getTryBlockRewriter(Rewriters rewriters) {
71 | return wrappedModule.getTryBlockRewriter(rewriters);
72 | }
73 |
74 | @Override
75 | public Rewriter getExceptionHandlerRewriter(Rewriters rewriters) {
76 | return wrappedModule.getExceptionHandlerRewriter(rewriters);
77 | }
78 |
79 | @Override
80 | public Rewriter getDebugItemRewriter(Rewriters rewriters) {
81 | return wrappedModule.getDebugItemRewriter(rewriters);
82 | }
83 |
84 | @Override
85 | public Rewriter getTypeRewriter(Rewriters rewriters) {
86 | return wrappedModule.getTypeRewriter(rewriters);
87 | }
88 |
89 | @Override
90 | public Rewriter getFieldReferenceRewriter(Rewriters rewriters) {
91 | return wrappedModule.getFieldReferenceRewriter(rewriters);
92 | }
93 |
94 | @Override
95 | public Rewriter getMethodReferenceRewriter(Rewriters rewriters) {
96 | return wrappedModule.getMethodReferenceRewriter(rewriters);
97 | }
98 |
99 | @Override
100 | public Rewriter getAnnotationRewriter(Rewriters rewriters) {
101 | return wrappedModule.getAnnotationRewriter(rewriters);
102 | }
103 |
104 | @Override
105 | public Rewriter getAnnotationElementRewriter(Rewriters rewriters) {
106 | return wrappedModule.getAnnotationElementRewriter(rewriters);
107 | }
108 |
109 | @Override
110 | public Rewriter getEncodedValueRewriter(Rewriters rewriters) {
111 | return wrappedModule.getEncodedValueRewriter(rewriters);
112 | }
113 |
114 | }
115 |
--------------------------------------------------------------------------------