Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
J
jadx
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
open-source
jadx
Commits
5f302238
Commit
5f302238
authored
Mar 13, 2016
by
Skylot
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
core: allow to disable constant dereference (#106)
parent
7cba2c3f
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
366 additions
and
139 deletions
+366
-139
README.md
README.md
+6
-5
JadxCLIArgs.java
jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java
+29
-12
JadxCLIArgsTest.java
jadx-cli/src/test/java/jadx/cli/JadxCLIArgsTest.java
+22
-0
IJadxArgs.java
jadx-core/src/main/java/jadx/api/IJadxArgs.java
+5
-0
JadxArgs.java
jadx-core/src/main/java/jadx/api/JadxArgs.java
+10
-0
ClassInfo.java
jadx-core/src/main/java/jadx/core/dex/info/ClassInfo.java
+1
-1
ConstStorage.java
jadx-core/src/main/java/jadx/core/dex/info/ConstStorage.java
+187
-0
ClassNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
+29
-74
DexNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/DexNode.java
+0
-6
RootNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java
+8
-8
BlockProcessor.java
...va/jadx/core/dex/visitors/blocksmaker/BlockProcessor.java
+2
-1
BinaryXMLParser.java
...-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java
+9
-10
IntegrationTest.java
jadx-core/src/test/java/jadx/tests/api/IntegrationTest.java
+24
-20
DynamicCompiler.java
...rc/test/java/jadx/tests/api/compiler/DynamicCompiler.java
+1
-1
TestSwitchLabels.java
...ava/jadx/tests/integration/switches/TestSwitchLabels.java
+18
-1
JadxSettings.java
jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java
+4
-0
JadxSettingsWindow.java
...i/src/main/java/jadx/gui/settings/JadxSettingsWindow.java
+10
-0
Messages_en_US.properties
jadx-gui/src/main/resources/i18n/Messages_en_US.properties
+1
-0
No files found.
README.md
View file @
5f302238
...
...
@@ -44,19 +44,20 @@ jadx[-gui] [options] <input file> (.dex, .apk, .jar or .class)
options:
-d, --output-dir - output directory
-j, --threads-count - processing threads count
-f, --fallback - make simple dump (using goto instead of 'if', 'for', etc)
-r, --no-res - do not decode resources
-s, --no-src - do not decompile source code
--show-bad-code - show inconsistent code (incorrectly decompiled)
--cfg - save methods control flow graph to dot file
--raw-cfg - save methods control flow graph (use raw instructions)
-v, --verbose - verbose output
--no-replace-consts - don't replace constant value with matching constant field
--escape-unicode - escape non latin characters in strings (with \u)
--deobf - activate deobfuscation
--deobf-min - min length of name
--deobf-max - max length of name
--deobf-rewrite-cfg - force to save deobfuscation map
--deobf-use-sourcename - use source file name as class name alias
--escape-unicode - escape non latin characters in strings (with \u)
--cfg - save methods control flow graph to dot file
--raw-cfg - save methods control flow graph (use raw instructions)
-f, --fallback - make simple dump (using goto instead of 'if', 'for', etc)
-v, --verbose - verbose output
-h, --help - print this help
Example:
jadx -d out classes.dex
...
...
jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java
View file @
5f302238
...
...
@@ -17,6 +17,7 @@ import java.util.Map;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
com.beust.jcommander.IStringConverter
;
import
com.beust.jcommander.JCommander
;
import
com.beust.jcommander.Parameter
;
import
com.beust.jcommander.ParameterDescription
;
...
...
@@ -33,9 +34,6 @@ public class JadxCLIArgs implements IJadxArgs {
@Parameter
(
names
=
{
"-j"
,
"--threads-count"
},
description
=
"processing threads count"
)
protected
int
threadsCount
=
Math
.
max
(
1
,
Runtime
.
getRuntime
().
availableProcessors
()
/
2
);
@Parameter
(
names
=
{
"-f"
,
"--fallback"
},
description
=
"make simple dump (using goto instead of 'if', 'for', etc)"
)
protected
boolean
fallbackMode
=
false
;
@Parameter
(
names
=
{
"-r"
,
"--no-res"
},
description
=
"do not decode resources"
)
protected
boolean
skipResources
=
false
;
...
...
@@ -45,14 +43,12 @@ public class JadxCLIArgs implements IJadxArgs {
@Parameter
(
names
=
{
"--show-bad-code"
},
description
=
"show inconsistent code (incorrectly decompiled)"
)
protected
boolean
showInconsistentCode
=
false
;
@Parameter
(
names
=
{
"--cfg"
},
description
=
"save methods control flow graph to dot file"
)
protected
boolean
cfgOutput
=
false
;
@Parameter
(
names
=
{
"--raw-cfg"
},
description
=
"save methods control flow graph (use raw instructions)"
)
protected
boolean
rawCfgOutput
=
false
;
@Parameter
(
names
=
"--no-replace-consts"
,
converter
=
InvertedBooleanConverter
.
class
,
description
=
"don't replace constant value with matching constant field"
)
protected
boolean
replaceConsts
=
true
;
@Parameter
(
names
=
{
"-
v"
,
"--verbose"
},
description
=
"verbose output
"
)
protected
boolean
verbos
e
=
false
;
@Parameter
(
names
=
{
"-
-escape-unicode"
},
description
=
"escape non latin characters in strings (with \\u)
"
)
protected
boolean
escapeUnicod
e
=
false
;
@Parameter
(
names
=
{
"--deobf"
},
description
=
"activate deobfuscation"
)
protected
boolean
deobfuscationOn
=
false
;
...
...
@@ -69,8 +65,17 @@ public class JadxCLIArgs implements IJadxArgs {
@Parameter
(
names
=
{
"--deobf-use-sourcename"
},
description
=
"use source file name as class name alias"
)
protected
boolean
deobfuscationUseSourceNameAsAlias
=
false
;
@Parameter
(
names
=
{
"--escape-unicode"
},
description
=
"escape non latin characters in strings (with \\u)"
)
protected
boolean
escapeUnicode
=
false
;
@Parameter
(
names
=
{
"--cfg"
},
description
=
"save methods control flow graph to dot file"
)
protected
boolean
cfgOutput
=
false
;
@Parameter
(
names
=
{
"--raw-cfg"
},
description
=
"save methods control flow graph (use raw instructions)"
)
protected
boolean
rawCfgOutput
=
false
;
@Parameter
(
names
=
{
"-f"
,
"--fallback"
},
description
=
"make simple dump (using goto instead of 'if', 'for', etc)"
)
protected
boolean
fallbackMode
=
false
;
@Parameter
(
names
=
{
"-v"
,
"--verbose"
},
description
=
"verbose output"
)
protected
boolean
verbose
=
false
;
@Parameter
(
names
=
{
"-h"
,
"--help"
},
description
=
"print this help"
,
help
=
true
)
protected
boolean
printHelp
=
false
;
...
...
@@ -178,6 +183,13 @@ public class JadxCLIArgs implements IJadxArgs {
}
}
public
static
class
InvertedBooleanConverter
implements
IStringConverter
<
Boolean
>
{
@Override
public
Boolean
convert
(
String
value
)
{
return
"false"
.
equals
(
value
);
}
}
public
List
<
File
>
getInput
()
{
return
input
;
}
...
...
@@ -264,4 +276,9 @@ public class JadxCLIArgs implements IJadxArgs {
public
boolean
escapeUnicode
()
{
return
escapeUnicode
;
}
@Override
public
boolean
isReplaceConsts
()
{
return
replaceConsts
;
}
}
jadx-cli/src/test/java/jadx/cli/JadxCLIArgsTest.java
0 → 100644
View file @
5f302238
package
jadx
.
cli
;
import
org.junit.Test
;
import
static
org
.
hamcrest
.
Matchers
.
is
;
import
static
org
.
junit
.
Assert
.
assertThat
;
public
class
JadxCLIArgsTest
{
@Test
public
void
testInvertedBooleanOption
()
throws
Exception
{
assertThat
(
parse
(
"--no-replace-consts"
).
isReplaceConsts
(),
is
(
false
));
assertThat
(
parse
(
""
).
isReplaceConsts
(),
is
(
true
));
}
private
JadxCLIArgs
parse
(
String
...
args
)
{
JadxCLIArgs
jadxArgs
=
new
JadxCLIArgs
();
boolean
res
=
jadxArgs
.
processArgs
(
args
);
assertThat
(
res
,
is
(
true
));
return
jadxArgs
;
}
}
jadx-core/src/main/java/jadx/api/IJadxArgs.java
View file @
5f302238
...
...
@@ -32,4 +32,9 @@ public interface IJadxArgs {
boolean
useSourceNameAsClassAlias
();
boolean
escapeUnicode
();
/**
* Replace constant values with static final fields with same value
*/
boolean
isReplaceConsts
();
}
jadx-core/src/main/java/jadx/api/JadxArgs.java
View file @
5f302238
...
...
@@ -25,6 +25,7 @@ public class JadxArgs implements IJadxArgs {
private
int
deobfuscationMaxLength
=
Integer
.
MAX_VALUE
;
private
boolean
escapeUnicode
=
false
;
private
boolean
replaceConsts
=
true
;
@Override
public
File
getOutDir
()
{
...
...
@@ -160,4 +161,13 @@ public class JadxArgs implements IJadxArgs {
public
void
setEscapeUnicode
(
boolean
escapeUnicode
)
{
this
.
escapeUnicode
=
escapeUnicode
;
}
@Override
public
boolean
isReplaceConsts
()
{
return
replaceConsts
;
}
public
void
setReplaceConsts
(
boolean
replaceConsts
)
{
this
.
replaceConsts
=
replaceConsts
;
}
}
jadx-core/src/main/java/jadx/core/dex/info/ClassInfo.java
View file @
5f302238
...
...
@@ -167,7 +167,7 @@ public final class ClassInfo {
@Override
public
int
hashCode
()
{
return
fullNam
e
.
hashCode
();
return
typ
e
.
hashCode
();
}
@Override
...
...
jadx-core/src/main/java/jadx/core/dex/info/ConstStorage.java
0 → 100644
View file @
5f302238
package
jadx
.
core
.
dex
.
info
;
import
jadx.api.IJadxArgs
;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.instructions.args.LiteralArg
;
import
jadx.core.dex.instructions.args.PrimitiveType
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.core.dex.nodes.DexNode
;
import
jadx.core.dex.nodes.FieldNode
;
import
jadx.core.dex.nodes.ResRefField
;
import
jadx.core.dex.nodes.parser.FieldInitAttr
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
import
org.jetbrains.annotations.Nullable
;
public
class
ConstStorage
{
private
static
final
class
Values
{
private
final
Map
<
Object
,
FieldNode
>
values
=
new
HashMap
<
Object
,
FieldNode
>();
private
final
Set
<
Object
>
duplicates
=
new
HashSet
<
Object
>();
public
Map
<
Object
,
FieldNode
>
getValues
()
{
return
values
;
}
public
FieldNode
get
(
Object
key
)
{
return
values
.
get
(
key
);
}
/**
* @return true if this value is duplicated
*/
public
boolean
put
(
Object
value
,
FieldNode
fld
)
{
FieldNode
prev
=
values
.
put
(
value
,
fld
);
if
(
prev
!=
null
)
{
values
.
remove
(
value
);
duplicates
.
add
(
value
);
return
true
;
}
if
(
duplicates
.
contains
(
value
))
{
values
.
remove
(
value
);
return
true
;
}
return
false
;
}
public
boolean
contains
(
Object
value
)
{
return
duplicates
.
contains
(
value
)
||
values
.
containsKey
(
value
);
}
}
private
final
boolean
replaceEnabled
;
private
final
Values
globalValues
=
new
Values
();
private
final
Map
<
ClassNode
,
Values
>
classes
=
new
HashMap
<
ClassNode
,
Values
>();
private
Map
<
Integer
,
String
>
resourcesNames
=
new
HashMap
<
Integer
,
String
>();
public
ConstStorage
(
IJadxArgs
args
)
{
this
.
replaceEnabled
=
args
.
isReplaceConsts
();
}
public
void
processConstFields
(
ClassNode
cls
,
List
<
FieldNode
>
staticFields
)
{
if
(!
replaceEnabled
||
staticFields
.
isEmpty
())
{
return
;
}
for
(
FieldNode
f
:
staticFields
)
{
AccessInfo
accFlags
=
f
.
getAccessFlags
();
if
(
accFlags
.
isStatic
()
&&
accFlags
.
isFinal
())
{
FieldInitAttr
fv
=
f
.
get
(
AType
.
FIELD_INIT
);
if
(
fv
!=
null
&&
fv
.
getValue
()
!=
null
&&
fv
.
getValueType
()
==
FieldInitAttr
.
InitType
.
CONST
&&
fv
!=
FieldInitAttr
.
NULL_VALUE
)
{
addConstField
(
cls
,
f
,
fv
.
getValue
(),
accFlags
.
isPublic
());
}
}
}
}
private
void
addConstField
(
ClassNode
cls
,
FieldNode
fld
,
Object
value
,
boolean
isPublic
)
{
if
(
isPublic
)
{
globalValues
.
put
(
value
,
fld
);
}
else
{
getClsValues
(
cls
).
put
(
value
,
fld
);
}
}
private
Values
getClsValues
(
ClassNode
cls
)
{
Values
classValues
=
classes
.
get
(
cls
);
if
(
classValues
==
null
)
{
classValues
=
new
Values
();
classes
.
put
(
cls
,
classValues
);
}
return
classValues
;
}
@Nullable
public
FieldNode
getConstField
(
ClassNode
cls
,
Object
value
,
boolean
searchGlobal
)
{
DexNode
dex
=
cls
.
dex
();
if
(
value
instanceof
Integer
)
{
String
str
=
resourcesNames
.
get
(
value
);
if
(
str
!=
null
)
{
return
new
ResRefField
(
dex
,
str
.
replace
(
'/'
,
'.'
));
}
}
if
(!
replaceEnabled
)
{
return
null
;
}
boolean
foundInGlobal
=
globalValues
.
contains
(
value
);
if
(
foundInGlobal
&&
!
searchGlobal
)
{
return
null
;
}
ClassNode
current
=
cls
;
while
(
current
!=
null
)
{
Values
classValues
=
classes
.
get
(
current
);
if
(
classValues
!=
null
)
{
FieldNode
field
=
classValues
.
get
(
value
);
if
(
field
!=
null
)
{
if
(
foundInGlobal
)
{
return
null
;
}
return
field
;
}
}
ClassInfo
parentClass
=
current
.
getClassInfo
().
getParentClass
();
if
(
parentClass
==
null
)
{
break
;
}
current
=
dex
.
resolveClass
(
parentClass
);
}
if
(
searchGlobal
)
{
return
globalValues
.
get
(
value
);
}
return
null
;
}
@Nullable
public
FieldNode
getConstFieldByLiteralArg
(
ClassNode
cls
,
LiteralArg
arg
)
{
PrimitiveType
type
=
arg
.
getType
().
getPrimitiveType
();
if
(
type
==
null
)
{
return
null
;
}
long
literal
=
arg
.
getLiteral
();
switch
(
type
)
{
case
BOOLEAN:
return
getConstField
(
cls
,
literal
==
1
,
false
);
case
CHAR:
return
getConstField
(
cls
,
(
char
)
literal
,
Math
.
abs
(
literal
)
>
10
);
case
BYTE:
return
getConstField
(
cls
,
(
byte
)
literal
,
Math
.
abs
(
literal
)
>
10
);
case
SHORT:
return
getConstField
(
cls
,
(
short
)
literal
,
Math
.
abs
(
literal
)
>
100
);
case
INT:
return
getConstField
(
cls
,
(
int
)
literal
,
Math
.
abs
(
literal
)
>
100
);
case
LONG:
return
getConstField
(
cls
,
literal
,
Math
.
abs
(
literal
)
>
1000
);
case
FLOAT:
float
f
=
Float
.
intBitsToFloat
((
int
)
literal
);
return
getConstField
(
cls
,
f
,
f
!=
0.0
);
case
DOUBLE:
double
d
=
Double
.
longBitsToDouble
(
literal
);
return
getConstField
(
cls
,
d
,
d
!=
0
);
}
return
null
;
}
public
void
setResourcesNames
(
Map
<
Integer
,
String
>
resourcesNames
)
{
this
.
resourcesNames
=
resourcesNames
;
}
public
Map
<
Integer
,
String
>
getResourcesNames
()
{
return
resourcesNames
;
}
public
Map
<
Object
,
FieldNode
>
getGlobalConstFields
()
{
return
globalValues
.
getValues
();
}
public
boolean
isReplaceEnabled
()
{
return
replaceEnabled
;
}
}
jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
View file @
5f302238
...
...
@@ -2,7 +2,6 @@ package jadx.core.dex.nodes;
import
jadx.core.Consts
;
import
jadx.core.codegen.CodeWriter
;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.attributes.annotations.Annotation
;
import
jadx.core.dex.attributes.nodes.JadxErrorAttr
;
import
jadx.core.dex.attributes.nodes.LineAttrNode
;
...
...
@@ -14,10 +13,8 @@ import jadx.core.dex.info.FieldInfo;
import
jadx.core.dex.info.MethodInfo
;
import
jadx.core.dex.instructions.args.ArgType
;
import
jadx.core.dex.instructions.args.LiteralArg
;
import
jadx.core.dex.instructions.args.PrimitiveType
;
import
jadx.core.dex.nodes.parser.AnnotationsParser
;
import
jadx.core.dex.nodes.parser.FieldInitAttr
;
import
jadx.core.dex.nodes.parser.FieldInitAttr.InitType
;
import
jadx.core.dex.nodes.parser.SignatureParser
;
import
jadx.core.dex.nodes.parser.StaticValuesParser
;
import
jadx.core.utils.exceptions.DecodeException
;
...
...
@@ -27,7 +24,6 @@ import java.util.ArrayList;
import
java.util.Collections
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.LinkedHashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
...
...
@@ -41,6 +37,7 @@ import com.android.dex.ClassData;
import
com.android.dex.ClassData.Field
;
import
com.android.dex.ClassData.Method
;
import
com.android.dex.ClassDef
;
import
com.android.dex.Dex
;
import
com.android.dx.rop.code.AccessFlags
;
public
class
ClassNode
extends
LineAttrNode
implements
ILoadable
,
IDexNode
{
...
...
@@ -55,7 +52,6 @@ public class ClassNode extends LineAttrNode implements ILoadable, IDexNode {
private
final
List
<
MethodNode
>
methods
;
private
final
List
<
FieldNode
>
fields
;
private
Map
<
Object
,
FieldNode
>
constFields
=
Collections
.
emptyMap
();
private
List
<
ClassNode
>
innerClasses
=
Collections
.
emptyList
();
// store decompiled code
...
...
@@ -168,24 +164,12 @@ public class ClassNode extends LineAttrNode implements ILoadable, IDexNode {
if
(
offset
==
0
)
{
return
;
}
StaticValuesParser
parser
=
new
StaticValuesParser
(
dex
,
dex
.
openSection
(
offset
));
int
count
=
parser
.
processFields
(
staticFields
);
if
(
count
==
0
)
{
return
;
}
constFields
=
new
LinkedHashMap
<
Object
,
FieldNode
>(
count
);
for
(
FieldNode
f
:
staticFields
)
{
AccessInfo
accFlags
=
f
.
getAccessFlags
();
if
(
accFlags
.
isStatic
()
&&
accFlags
.
isFinal
())
{
FieldInitAttr
fv
=
f
.
get
(
AType
.
FIELD_INIT
);
if
(
fv
!=
null
&&
fv
.
getValue
()
!=
null
&&
fv
.
getValueType
()
==
InitType
.
CONST
)
{
if
(
accFlags
.
isPublic
())
{
dex
.
getConstFields
().
put
(
fv
.
getValue
(),
f
);
}
constFields
.
put
(
fv
.
getValue
(),
f
);
}
}
}
Dex
.
Section
section
=
dex
.
openSection
(
offset
);
StaticValuesParser
parser
=
new
StaticValuesParser
(
dex
,
section
);
parser
.
processFields
(
staticFields
);
// process const fields
root
().
getConstValues
().
processConstFields
(
this
,
staticFields
);
}
private
void
parseClassSignature
()
{
...
...
@@ -315,61 +299,14 @@ public class ClassNode extends LineAttrNode implements ILoadable, IDexNode {
return
getConstField
(
obj
,
true
);
}
@Nullable
public
FieldNode
getConstField
(
Object
obj
,
boolean
searchGlobal
)
{
ClassNode
cn
=
this
;
FieldNode
field
;
do
{
field
=
cn
.
constFields
.
get
(
obj
);
}
while
(
field
==
null
&&
cn
.
clsInfo
.
getParentClass
()
!=
null
&&
(
cn
=
dex
.
resolveClass
(
cn
.
clsInfo
.
getParentClass
()))
!=
null
);
if
(
field
==
null
&&
searchGlobal
)
{
field
=
dex
.
getConstFields
().
get
(
obj
);
}
if
(
obj
instanceof
Integer
)
{
String
str
=
dex
.
root
().
getResourcesNames
().
get
(
obj
);
if
(
str
!=
null
)
{
ResRefField
resField
=
new
ResRefField
(
dex
,
str
.
replace
(
'/'
,
'.'
));
if
(
field
==
null
)
{
return
resField
;
}
if
(!
field
.
getName
().
equals
(
resField
.
getName
()))
{
field
=
resField
;
}
}
}
return
field
;
return
root
().
getConstValues
().
getConstField
(
this
,
obj
,
searchGlobal
);
}
@Nullable
public
FieldNode
getConstFieldByLiteralArg
(
LiteralArg
arg
)
{
PrimitiveType
type
=
arg
.
getType
().
getPrimitiveType
();
if
(
type
==
null
)
{
return
null
;
}
long
literal
=
arg
.
getLiteral
();
switch
(
type
)
{
case
BOOLEAN:
return
getConstField
(
literal
==
1
,
false
);
case
CHAR:
return
getConstField
((
char
)
literal
,
Math
.
abs
(
literal
)
>
10
);
case
BYTE:
return
getConstField
((
byte
)
literal
,
Math
.
abs
(
literal
)
>
10
);
case
SHORT:
return
getConstField
((
short
)
literal
,
Math
.
abs
(
literal
)
>
100
);
case
INT:
return
getConstField
((
int
)
literal
,
Math
.
abs
(
literal
)
>
100
);
case
LONG:
return
getConstField
(
literal
,
Math
.
abs
(
literal
)
>
1000
);
case
FLOAT:
float
f
=
Float
.
intBitsToFloat
((
int
)
literal
);
return
getConstField
(
f
,
f
!=
0.0
);
case
DOUBLE:
double
d
=
Double
.
longBitsToDouble
(
literal
);
return
getConstField
(
d
,
d
!=
0
);
}
return
null
;
return
root
().
getConstValues
().
getConstFieldByLiteralArg
(
this
,
arg
);
}
public
FieldNode
searchFieldById
(
int
id
)
{
...
...
@@ -533,6 +470,24 @@ public class ClassNode extends LineAttrNode implements ILoadable, IDexNode {
}
@Override
public
int
hashCode
()
{
return
clsInfo
.
hashCode
();
}
@Override
public
boolean
equals
(
Object
o
)
{
if
(
this
==
o
)
{
return
true
;
}
if
(
o
instanceof
ClassNode
)
{
ClassNode
other
=
(
ClassNode
)
o
;
return
clsInfo
.
equals
(
other
.
clsInfo
);
}
return
false
;
}
@Override
public
String
toString
()
{
return
clsInfo
.
getFullName
();
}
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/DexNode.java
View file @
5f302238
...
...
@@ -39,8 +39,6 @@ public class DexNode implements IDexNode {
private
final
List
<
ClassNode
>
classes
=
new
ArrayList
<
ClassNode
>();
private
final
Map
<
ClassInfo
,
ClassNode
>
clsMap
=
new
HashMap
<
ClassInfo
,
ClassNode
>();
private
final
Map
<
Object
,
FieldNode
>
constFields
=
new
HashMap
<
Object
,
FieldNode
>();
private
final
InfoStorage
infoStorage
=
new
InfoStorage
();
public
DexNode
(
RootNode
root
,
DexFile
input
)
{
...
...
@@ -155,10 +153,6 @@ public class DexNode implements IDexNode {
return
null
;
}
public
Map
<
Object
,
FieldNode
>
getConstFields
()
{
return
constFields
;
}
public
InfoStorage
getInfoStorage
()
{
return
infoStorage
;
}
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java
View file @
5f302238
...
...
@@ -6,6 +6,7 @@ import jadx.api.ResourceType;
import
jadx.api.ResourcesLoader
;
import
jadx.core.clsp.ClspGraph
;
import
jadx.core.dex.info.ClassInfo
;
import
jadx.core.dex.info.ConstStorage
;
import
jadx.core.utils.ErrorsCounter
;
import
jadx.core.utils.StringUtils
;
import
jadx.core.utils.exceptions.DecodeException
;
...
...
@@ -19,9 +20,7 @@ import jadx.core.xmlgen.ResourceStorage;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
org.jetbrains.annotations.Nullable
;
import
org.slf4j.Logger
;
...
...
@@ -33,9 +32,9 @@ public class RootNode {
private
final
ErrorsCounter
errorsCounter
=
new
ErrorsCounter
();
private
final
IJadxArgs
args
;
private
final
StringUtils
stringUtils
;
private
final
ConstStorage
constValues
;
private
List
<
DexNode
>
dexNodes
;
private
Map
<
Integer
,
String
>
resourcesNames
=
new
HashMap
<
Integer
,
String
>();
@Nullable
private
String
appPackage
;
private
ClassNode
appResClass
;
...
...
@@ -44,6 +43,7 @@ public class RootNode {
public
RootNode
(
IJadxArgs
args
)
{
this
.
args
=
args
;
this
.
stringUtils
=
new
StringUtils
(
args
);
this
.
constValues
=
new
ConstStorage
(
args
);
}
public
void
load
(
List
<
InputFile
>
inputFiles
)
throws
DecodeException
{
...
...
@@ -92,7 +92,7 @@ public class RootNode {
}
ResourceStorage
resStorage
=
parser
.
getResStorage
();
resourcesNames
=
resStorage
.
getResourcesNames
(
);
constValues
.
setResourcesNames
(
resStorage
.
getResourcesNames
()
);
appPackage
=
resStorage
.
getAppPackage
();
}
...
...
@@ -181,10 +181,6 @@ public class RootNode {
return
errorsCounter
;
}
public
Map
<
Integer
,
String
>
getResourcesNames
()
{
return
resourcesNames
;
}
@Nullable
public
String
getAppPackage
()
{
return
appPackage
;
...
...
@@ -201,4 +197,8 @@ public class RootNode {
public
StringUtils
getStringUtils
()
{
return
stringUtils
;
}
public
ConstStorage
getConstValues
()
{
return
constValues
;
}
}
jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockProcessor.java
View file @
5f302238
...
...
@@ -367,7 +367,8 @@ public class BlockProcessor extends AbstractVisitor {
}
private
static
void
cleanExitNodes
(
MethodNode
mth
)
{
for
(
Iterator
<
BlockNode
>
iterator
=
mth
.
getExitBlocks
().
iterator
();
iterator
.
hasNext
();
)
{
Iterator
<
BlockNode
>
iterator
=
mth
.
getExitBlocks
().
iterator
();
while
(
iterator
.
hasNext
())
{
BlockNode
exitBlock
=
iterator
.
next
();
if
(
exitBlock
.
getPredecessors
().
isEmpty
())
{
mth
.
getBasicBlocks
().
remove
(
exitBlock
);
...
...
jadx-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java
View file @
5f302238
...
...
@@ -2,8 +2,8 @@ package jadx.core.xmlgen;
import
jadx.api.ResourcesLoader
;
import
jadx.core.codegen.CodeWriter
;
import
jadx.core.dex.info.ConstStorage
;
import
jadx.core.dex.instructions.args.ArgType
;
import
jadx.core.dex.nodes.DexNode
;
import
jadx.core.dex.nodes.FieldNode
;
import
jadx.core.dex.nodes.RootNode
;
import
jadx.core.utils.StringUtils
;
...
...
@@ -64,17 +64,16 @@ public class BinaryXMLParser extends CommonBinaryParser {
LOG
.
error
(
"R class loading failed"
,
th
);
}
// add application constants
for
(
DexNode
dexNode
:
root
.
getDexNodes
())
{
for
(
Map
.
Entry
<
Object
,
FieldNode
>
entry
:
dexNode
.
getConstFields
().
entrySet
())
{
Object
key
=
entry
.
getKey
();
FieldNode
field
=
entry
.
getValue
();
if
(
field
.
getType
().
equals
(
ArgType
.
INT
)
&&
key
instanceof
Integer
)
{
localStyleMap
.
put
((
Integer
)
key
,
field
);
}
ConstStorage
constStorage
=
root
.
getConstValues
();
Map
<
Object
,
FieldNode
>
constFields
=
constStorage
.
getGlobalConstFields
();
for
(
Map
.
Entry
<
Object
,
FieldNode
>
entry
:
constFields
.
entrySet
())
{
Object
key
=
entry
.
getKey
();
FieldNode
field
=
entry
.
getValue
();
if
(
field
.
getType
().
equals
(
ArgType
.
INT
)
&&
key
instanceof
Integer
)
{
localStyleMap
.
put
((
Integer
)
key
,
field
);
}
}
resNames
=
root
.
getResourcesNames
();
resNames
=
constStorage
.
getResourcesNames
();
attributes
=
new
ManifestAttributes
();
attributes
.
parseAll
();
...
...
jadx-core/src/test/java/jadx/tests/api/IntegrationTest.java
View file @
5f302238
package
jadx
.
tests
.
api
;
import
jadx.api.IJadxArgs
;
import
jadx.api.JadxArgs
;
import
jadx.api.JadxDecompiler
;
import
jadx.api.JadxInternalAccess
;
...
...
@@ -51,8 +50,8 @@ public abstract class IntegrationTest extends TestUtils {
private
static
final
String
TEST_DIRECTORY
=
"src/test/java"
;
private
static
final
String
TEST_DIRECTORY2
=
"jadx-core/"
+
TEST_DIRECTORY
;
pr
otected
boolean
outputCFG
=
false
;
protected
boolean
isFallback
=
false
;
pr
ivate
JadxArgs
args
;
protected
boolean
deleteTmpFiles
=
true
;
protected
boolean
withDebugInfo
=
true
;
protected
boolean
unloadCls
=
true
;
...
...
@@ -64,6 +63,13 @@ public abstract class IntegrationTest extends TestUtils {
protected
boolean
compile
=
true
;
private
DynamicCompiler
dynamicCompiler
;
public
IntegrationTest
()
{
args
=
new
JadxArgs
();
args
.
setShowInconsistentCode
(
true
);
args
.
setThreadsCount
(
1
);
args
.
setSkipResources
(
true
);
}
public
ClassNode
getClassNode
(
Class
<?>
clazz
)
{
try
{
File
jar
=
getJarForClass
(
clazz
);
...
...
@@ -76,7 +82,7 @@ public abstract class IntegrationTest extends TestUtils {
}
public
ClassNode
getClassNodeFromFile
(
File
file
,
String
clsName
)
{
JadxDecompiler
d
=
new
JadxDecompiler
(
getArgs
()
);
JadxDecompiler
d
=
new
JadxDecompiler
(
args
);
try
{
d
.
loadFile
(
file
);
}
catch
(
JadxException
e
)
{
...
...
@@ -84,7 +90,7 @@ public abstract class IntegrationTest extends TestUtils {
fail
(
e
.
getMessage
());
}
RootNode
root
=
JadxInternalAccess
.
getRoot
(
d
);
root
.
getResourcesNames
().
putAll
(
resMap
);
root
.
get
ConstValues
().
get
ResourcesNames
().
putAll
(
resMap
);
ClassNode
cls
=
root
.
searchClassByName
(
clsName
);
assertThat
(
"Class not found: "
+
clsName
,
cls
,
notNullValue
());
...
...
@@ -136,17 +142,6 @@ public abstract class IntegrationTest extends TestUtils {
assertThat
(
cls
.
getCode
().
toString
(),
not
(
containsString
(
"inconsistent"
)));
}
private
IJadxArgs
getArgs
()
{
JadxArgs
args
=
new
JadxArgs
();
args
.
setCfgOutput
(
outputCFG
);
args
.
setRawCFGOutput
(
outputCFG
);
args
.
setFallbackMode
(
isFallback
);
args
.
setShowInconsistentCode
(
true
);
args
.
setThreadsCount
(
1
);
args
.
setSkipResources
(
true
);
return
args
;
}
private
void
runAutoCheck
(
String
clsName
)
{
try
{
// run 'check' method from original class
...
...
@@ -228,12 +223,12 @@ public abstract class IntegrationTest extends TestUtils {
return
invoke
(
method
,
new
Class
<?>[
0
]);
}
public
Object
invoke
(
String
method
,
Class
[]
types
,
Object
...
args
)
throws
Exception
{
public
Object
invoke
(
String
method
,
Class
<?>
[]
types
,
Object
...
args
)
throws
Exception
{
Method
mth
=
getReflectMethod
(
method
,
types
);
return
invoke
(
mth
,
args
);
}
public
Method
getReflectMethod
(
String
method
,
Class
...
types
)
{
public
Method
getReflectMethod
(
String
method
,
Class
<?>
...
types
)
{
assertNotNull
(
"dynamicCompiler not ready"
,
dynamicCompiler
);
try
{
return
dynamicCompiler
.
getMethod
(
method
,
types
);
...
...
@@ -352,6 +347,14 @@ public abstract class IntegrationTest extends TestUtils {
return
files
;
}
public
JadxArgs
getArgs
()
{
return
args
;
}
public
void
setArgs
(
JadxArgs
args
)
{
this
.
args
=
args
;
}
public
void
setResMap
(
Map
<
Integer
,
String
>
resMap
)
{
this
.
resMap
=
resMap
;
}
...
...
@@ -361,7 +364,7 @@ public abstract class IntegrationTest extends TestUtils {
}
protected
void
setFallback
()
{
this
.
isFallback
=
true
;
this
.
args
.
setFallbackMode
(
true
)
;
}
protected
void
disableCompilation
()
{
...
...
@@ -375,7 +378,8 @@ public abstract class IntegrationTest extends TestUtils {
// Use only for debug purpose
@Deprecated
protected
void
setOutputCFG
()
{
this
.
outputCFG
=
true
;
this
.
args
.
setCfgOutput
(
true
);
this
.
args
.
setRawCFGOutput
(
true
);
}
// Use only for debug purpose
...
...
jadx-core/src/test/java/jadx/tests/api/compiler/DynamicCompiler.java
View file @
5f302238
...
...
@@ -57,7 +57,7 @@ public class DynamicCompiler {
return
instance
;
}
public
Method
getMethod
(
String
method
,
Class
[]
types
)
throws
Exception
{
public
Method
getMethod
(
String
method
,
Class
<?>
[]
types
)
throws
Exception
{
for
(
Class
<?>
type
:
types
)
{
checkType
(
type
);
}
...
...
jadx-core/src/test/java/jadx/tests/integration/switches/TestSwitchLabels.java
View file @
5f302238
...
...
@@ -6,6 +6,7 @@ import jadx.tests.api.IntegrationTest;
import
org.junit.Test
;
import
static
org
.
hamcrest
.
CoreMatchers
.
containsString
;
import
static
org
.
hamcrest
.
Matchers
.
not
;
import
static
org
.
junit
.
Assert
.
assertThat
;
public
class
TestSwitchLabels
extends
IntegrationTest
{
...
...
@@ -42,7 +43,23 @@ public class TestSwitchLabels extends IntegrationTest {
assertThat
(
code
,
containsString
(
"return CONST_CDE;"
));
cls
.
addInnerClass
(
getClassNode
(
TestCls
.
Inner
.
class
));
assertThat
(
code
,
containsString
(
"case CONST_CDE_PRIVATE"
));
assertThat
(
code
,
not
(
containsString
(
"case CONST_CDE_PRIVATE"
)
));
assertThat
(
code
,
containsString
(
".CONST_ABC;"
));
}
@Test
public
void
testWithDisabledConstReplace
()
{
getArgs
().
setReplaceConsts
(
false
);
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
String
code
=
cls
.
getCode
().
toString
();
assertThat
(
code
,
not
(
containsString
(
"case CONST_ABC"
)));
assertThat
(
code
,
containsString
(
"case 2748"
));
assertThat
(
code
,
not
(
containsString
(
"return CONST_CDE;"
)));
assertThat
(
code
,
containsString
(
"return 3294;"
));
cls
.
addInnerClass
(
getClassNode
(
TestCls
.
Inner
.
class
));
assertThat
(
code
,
not
(
containsString
(
"case CONST_CDE_PRIVATE"
)));
assertThat
(
code
,
not
(
containsString
(
".CONST_ABC;"
)));
}
}
jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java
View file @
5f302238
...
...
@@ -168,6 +168,10 @@ public class JadxSettings extends JadxCLIArgs {
this
.
escapeUnicode
=
escapeUnicode
;
}
public
void
setReplaceConsts
(
boolean
replaceConsts
)
{
this
.
replaceConsts
=
replaceConsts
;
}
public
boolean
isAutoStartJobs
()
{
return
autoStartJobs
;
}
...
...
jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java
View file @
5f302238
...
...
@@ -257,11 +257,21 @@ public class JadxSettingsWindow extends JDialog {
}
});
JCheckBox
replaceConsts
=
new
JCheckBox
();
replaceConsts
.
setSelected
(
settings
.
isReplaceConsts
());
replaceConsts
.
addItemListener
(
new
ItemListener
()
{
public
void
itemStateChanged
(
ItemEvent
e
)
{
settings
.
setReplaceConsts
(
e
.
getStateChange
()
==
ItemEvent
.
SELECTED
);
needReload
();
}
});
SettingsGroup
other
=
new
SettingsGroup
(
NLS
.
str
(
"preferences.decompile"
));
other
.
addRow
(
NLS
.
str
(
"preferences.threads"
),
threadsCount
);
other
.
addRow
(
NLS
.
str
(
"preferences.start_jobs"
),
autoStartJobs
);
other
.
addRow
(
NLS
.
str
(
"preferences.showInconsistentCode"
),
showInconsistentCode
);
other
.
addRow
(
NLS
.
str
(
"preferences.escapeUnicode"
),
escapeUnicode
);
other
.
addRow
(
NLS
.
str
(
"preferences.replaceConsts"
),
replaceConsts
);
other
.
addRow
(
NLS
.
str
(
"preferences.fallback"
),
fallback
);
other
.
addRow
(
NLS
.
str
(
"preferences.skipResourcesDecode"
),
resourceDecode
);
return
other
;
...
...
jadx-gui/src/main/resources/i18n/Messages_en_US.properties
View file @
5f302238
...
...
@@ -59,6 +59,7 @@ preferences.check_for_updates=Check for updates on startup
preferences.fallback
=
Fallback mode (simple dump)
preferences.showInconsistentCode
=
Show inconsistent code
preferences.escapeUnicode
=
Escape unicode
preferences.replaceConsts
=
Replace constants
preferences.skipResourcesDecode
=
Don't decode resources
preferences.threads
=
Processing threads count
preferences.cfg
=
Generate methods CFG graphs (in 'dot' format)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment