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
a532287d
Commit
a532287d
authored
Feb 21, 2015
by
Skylot
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
core: refactor deobfuscator
parent
7844e554
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
37 changed files
with
779 additions
and
858 deletions
+779
-858
DefaultJadxArgs.java
jadx-core/src/main/java/jadx/api/DefaultJadxArgs.java
+2
-2
JadxDecompiler.java
jadx-core/src/main/java/jadx/api/JadxDecompiler.java
+15
-44
JavaClass.java
jadx-core/src/main/java/jadx/api/JavaClass.java
+6
-4
JavaPackage.java
jadx-core/src/main/java/jadx/api/JavaPackage.java
+1
-3
Jadx.java
jadx-core/src/main/java/jadx/core/Jadx.java
+5
-0
ProcessClass.java
jadx-core/src/main/java/jadx/core/ProcessClass.java
+11
-3
ClsSet.java
jadx-core/src/main/java/jadx/core/clsp/ClsSet.java
+5
-5
ClspGraph.java
jadx-core/src/main/java/jadx/core/clsp/ClspGraph.java
+3
-8
ConvertToClsSet.java
jadx-core/src/main/java/jadx/core/clsp/ConvertToClsSet.java
+2
-1
ClassGen.java
jadx-core/src/main/java/jadx/core/codegen/ClassGen.java
+41
-39
InsnGen.java
jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
+8
-7
MethodGen.java
jadx-core/src/main/java/jadx/core/codegen/MethodGen.java
+3
-3
NameGen.java
jadx-core/src/main/java/jadx/core/codegen/NameGen.java
+4
-4
DefaultDeobfuscator.java
...re/src/main/java/jadx/core/deobf/DefaultDeobfuscator.java
+0
-415
Deobfuscator.java
jadx-core/src/main/java/jadx/core/deobf/Deobfuscator.java
+349
-21
IDeobfuscator.java
jadx-core/src/main/java/jadx/core/deobf/IDeobfuscator.java
+0
-18
PackageNode.java
jadx-core/src/main/java/jadx/core/deobf/PackageNode.java
+5
-6
StubDeobfuscator.java
...-core/src/main/java/jadx/core/deobf/StubDeobfuscator.java
+0
-48
ClassInfo.java
jadx-core/src/main/java/jadx/core/dex/info/ClassInfo.java
+39
-24
FieldInfo.java
jadx-core/src/main/java/jadx/core/dex/info/FieldInfo.java
+1
-1
InsnDecoder.java
...src/main/java/jadx/core/dex/instructions/InsnDecoder.java
+3
-5
ArgType.java
...rc/main/java/jadx/core/dex/instructions/args/ArgType.java
+1
-0
ClassNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
+35
-21
DexNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/DexNode.java
+33
-2
MethodNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java
+1
-1
RootNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java
+51
-61
AbstractVisitor.java
...src/main/java/jadx/core/dex/visitors/AbstractVisitor.java
+5
-0
ClassModifier.java
...e/src/main/java/jadx/core/dex/visitors/ClassModifier.java
+1
-1
DependencyCollector.java
...main/java/jadx/core/dex/visitors/DependencyCollector.java
+3
-3
DotGraphVisitor.java
...src/main/java/jadx/core/dex/visitors/DotGraphVisitor.java
+3
-4
IDexTreeVisitor.java
...src/main/java/jadx/core/dex/visitors/IDexTreeVisitor.java
+6
-0
RenameVisitor.java
...e/src/main/java/jadx/core/dex/visitors/RenameVisitor.java
+34
-0
SaveCode.java
jadx-core/src/main/java/jadx/core/dex/visitors/SaveCode.java
+1
-2
SimplifyVisitor.java
...src/main/java/jadx/core/dex/visitors/SimplifyVisitor.java
+60
-60
ParserStream.java
jadx-core/src/main/java/jadx/core/xmlgen/ParserStream.java
+3
-1
SmaliTest.java
jadx-core/src/test/java/jadx/tests/api/SmaliTest.java
+1
-3
TestSwitchReturnFromCase.java
.../tests/integration/switches/TestSwitchReturnFromCase.java
+38
-38
No files found.
jadx-core/src/main/java/jadx/api/DefaultJadxArgs.java
View file @
a532287d
...
...
@@ -56,12 +56,12 @@ public class DefaultJadxArgs implements IJadxArgs {
@Override
public
int
getDeobfuscationMinLength
()
{
return
Integer
.
MIN_VALUE
+
1
;
return
Integer
.
MIN_VALUE
+
1
;
}
@Override
public
int
getDeobfuscationMaxLength
()
{
return
Integer
.
MAX_VALUE
-
1
;
return
Integer
.
MAX_VALUE
-
1
;
}
@Override
...
...
jadx-core/src/main/java/jadx/api/JadxDecompiler.java
View file @
a532287d
...
...
@@ -4,8 +4,6 @@ import jadx.core.Jadx;
import
jadx.core.ProcessClass
;
import
jadx.core.codegen.CodeGen
;
import
jadx.core.codegen.CodeWriter
;
import
jadx.core.deobf.DefaultDeobfuscator
;
import
jadx.core.deobf.Deobfuscator
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.core.dex.nodes.RootNode
;
import
jadx.core.dex.visitors.IDexTreeVisitor
;
...
...
@@ -93,6 +91,8 @@ public final class JadxDecompiler {
resources
=
null
;
xmlParser
=
null
;
root
=
null
;
passes
=
null
;
codeGen
=
null
;
}
public
static
String
getVersion
()
{
...
...
@@ -254,56 +254,27 @@ public final class JadxDecompiler {
void
parse
()
throws
DecodeException
{
reset
();
root
=
new
RootNode
();
init
();
root
=
new
RootNode
(
args
);
LOG
.
info
(
"loading ..."
);
root
.
load
(
inputFiles
);
if
(
args
.
isDeobfuscationOn
())
{
final
String
firstInputFileName
=
inputFiles
.
get
(
0
).
getFile
().
getAbsolutePath
();
final
String
inputPath
=
org
.
apache
.
commons
.
io
.
FilenameUtils
.
getFullPathNoEndSeparator
(
firstInputFileName
);
final
String
inputName
=
org
.
apache
.
commons
.
io
.
FilenameUtils
.
getBaseName
(
firstInputFileName
);
final
File
deobfuscationMapFile
=
new
File
(
inputPath
,
inputName
+
".jobf"
);
DefaultDeobfuscator
deobfuscator
=
new
DefaultDeobfuscator
();
if
(
deobfuscationMapFile
.
exists
())
{
try
{
deobfuscator
.
load
(
deobfuscationMapFile
);
}
catch
(
IOException
e
)
{
LOG
.
error
(
"Failed to load deobfuscation map file '{}'"
,
deobfuscationMapFile
.
getAbsolutePath
());
}
}
deobfuscator
.
setInputData
(
root
.
getDexNodes
());
deobfuscator
.
setMinNameLength
(
args
.
getDeobfuscationMinLength
());
deobfuscator
.
setMaxNameLength
(
args
.
getDeobfuscationMaxLength
());
root
.
initClassPath
();
root
.
loadResources
(
getResources
());
root
.
initAppResClass
();
deobfuscator
.
process
();
initVisitors
();
}
private
void
initVisitors
()
{
for
(
IDexTreeVisitor
pass
:
passes
)
{
try
{
if
(
deobfuscationMapFile
.
exists
())
{
if
(
args
.
isDeobfuscationForceSave
())
{
deobfuscator
.
save
(
deobfuscationMapFile
);
}
else
{
LOG
.
warn
(
"Deobfuscation map file '{}' exists. Use command line option '--deobf=rewrite-cfg'"
+
" to rewrite it"
,
deobfuscationMapFile
.
getAbsolutePath
());
}
}
else
{
deobfuscator
.
save
(
deobfuscationMapFile
);
}
}
catch
(
IOException
e
)
{
LOG
.
error
(
"Failed to load deobfuscation map file '{}'"
,
deobfuscationMapFile
.
getAbsolutePath
());
pass
.
init
(
root
);
}
catch
(
Exception
e
)
{
LOG
.
error
(
"Visitor init failed: {}"
,
pass
.
getClass
().
getSimpleName
(),
e
);
}
Deobfuscator
.
setDeobfuscator
(
deobfuscator
);
}
root
.
loadResources
(
getResources
());
root
.
initAppResClass
();
}
void
processClass
(
ClassNode
cls
)
{
...
...
jadx-core/src/main/java/jadx/api/JavaClass.java
View file @
a532287d
package
jadx
.
api
;
import
jadx.core.codegen.CodeWriter
;
import
jadx.core.deobf.Deobfuscator
;
import
jadx.core.dex.attributes.AFlag
;
import
jadx.core.dex.attributes.nodes.LineAttrNode
;
import
jadx.core.dex.info.AccessInfo
;
...
...
@@ -116,6 +115,9 @@ public final class JavaClass implements JavaNode {
public
CodePosition
getDefinitionPosition
(
int
line
,
int
offset
)
{
Map
<
CodePosition
,
Object
>
map
=
getCodeAnnotations
();
if
(
map
.
isEmpty
())
{
return
null
;
}
Object
obj
=
map
.
get
(
new
CodePosition
(
line
,
offset
));
if
(!(
obj
instanceof
LineAttrNode
))
{
return
null
;
...
...
@@ -151,16 +153,16 @@ public final class JavaClass implements JavaNode {
@Override
public
String
getName
()
{
return
Deobfuscator
.
instance
().
getClassShortName
(
cls
);
return
cls
.
getShortName
(
);
}
@Override
public
String
getFullName
()
{
return
Deobfuscator
.
instance
().
getClassFullName
(
cls
);
return
cls
.
getFullName
(
);
}
public
String
getPackage
()
{
return
Deobfuscator
.
instance
().
getPackageName
(
cls
.
getPackage
()
);
return
cls
.
getPackage
(
);
}
@Override
...
...
jadx-core/src/main/java/jadx/api/JavaPackage.java
View file @
a532287d
package
jadx
.
api
;
import
jadx.core.deobf.Deobfuscator
;
import
java.util.List
;
import
org.jetbrains.annotations.NotNull
;
...
...
@@ -11,7 +9,7 @@ public final class JavaPackage implements JavaNode, Comparable<JavaPackage> {
private
final
List
<
JavaClass
>
classes
;
JavaPackage
(
String
name
,
List
<
JavaClass
>
classes
)
{
this
.
name
=
Deobfuscator
.
instance
().
getPackageName
(
name
)
;
this
.
name
=
name
;
this
.
classes
=
classes
;
}
...
...
jadx-core/src/main/java/jadx/core/Jadx.java
View file @
a532287d
...
...
@@ -14,6 +14,7 @@ import jadx.core.dex.visitors.MethodInlineVisitor;
import
jadx.core.dex.visitors.ModVisitor
;
import
jadx.core.dex.visitors.PrepareForCodeGen
;
import
jadx.core.dex.visitors.ReSugarCode
;
import
jadx.core.dex.visitors.RenameVisitor
;
import
jadx.core.dex.visitors.SimplifyVisitor
;
import
jadx.core.dex.visitors.blocksmaker.BlockExceptionHandler
;
import
jadx.core.dex.visitors.blocksmaker.BlockFinallyExtract
;
...
...
@@ -106,6 +107,10 @@ public class Jadx {
passes
.
add
(
new
ProcessVariables
());
passes
.
add
(
new
DependencyCollector
());
if
(
args
.
isDeobfuscationOn
())
{
passes
.
add
(
new
RenameVisitor
());
}
}
return
passes
;
}
...
...
jadx-core/src/main/java/jadx/core/ProcessClass.java
View file @
a532287d
...
...
@@ -33,9 +33,7 @@ public final class ProcessClass {
for
(
IDexTreeVisitor
visitor
:
passes
)
{
DepthTraversal
.
visit
(
visitor
,
cls
);
}
for
(
ClassNode
clsNode
:
cls
.
getDependencies
())
{
process
(
clsNode
,
passes
,
null
);
}
processDependencies
(
cls
,
passes
);
cls
.
setState
(
PROCESSED
);
}
if
(
cls
.
getState
()
==
PROCESSED
&&
codeGen
!=
null
)
{
...
...
@@ -52,4 +50,14 @@ public final class ProcessClass {
}
}
}
static
void
processDependencies
(
ClassNode
cls
,
List
<
IDexTreeVisitor
>
passes
)
{
for
(
ClassNode
depCls
:
cls
.
getDependencies
())
{
if
(
cls
.
getTopParentClass
()
==
cls
)
{
// ignore inner classes of this class
continue
;
}
process
(
depCls
,
passes
,
null
);
}
}
}
jadx-core/src/main/java/jadx/core/clsp/ClsSet.java
View file @
a532287d
package
jadx
.
core
.
clsp
;
import
jadx.core.dex.in
fo.ClassInfo
;
import
jadx.core.dex.in
structions.args.ArgType
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.core.dex.nodes.RootNode
;
import
jadx.core.utils.exceptions.DecodeException
;
...
...
@@ -77,15 +77,15 @@ public class ClsSet {
public
static
NClass
[]
makeParentsArray
(
ClassNode
cls
,
Map
<
String
,
NClass
>
names
)
{
List
<
NClass
>
parents
=
new
ArrayList
<
NClass
>(
1
+
cls
.
getInterfaces
().
size
());
ClassInfo
superClass
=
cls
.
getSuperClass
();
ArgType
superClass
=
cls
.
getSuperClass
();
if
(
superClass
!=
null
)
{
NClass
c
=
getCls
(
superClass
.
get
RawName
(),
names
);
NClass
c
=
getCls
(
superClass
.
get
Object
(),
names
);
if
(
c
!=
null
)
{
parents
.
add
(
c
);
}
}
for
(
ClassInfo
iface
:
cls
.
getInterfaces
())
{
NClass
c
=
getCls
(
iface
.
get
RawName
(),
names
);
for
(
ArgType
iface
:
cls
.
getInterfaces
())
{
NClass
c
=
getCls
(
iface
.
get
Object
(),
names
);
if
(
c
!=
null
)
{
parents
.
add
(
c
);
}
...
...
jadx-core/src/main/java/jadx/core/clsp/ClspGraph.java
View file @
a532287d
...
...
@@ -45,16 +45,10 @@ public class ClspGraph {
throw
new
JadxRuntimeException
(
"Classpath must be loaded first"
);
}
int
size
=
classes
.
size
();
for
(
ClassNode
cls
:
classes
)
{
size
+=
cls
.
getInnerClasses
().
size
();
}
NClass
[]
nClasses
=
new
NClass
[
size
];
int
k
=
0
;
for
(
ClassNode
cls
:
classes
)
{
nClasses
[
k
++]
=
addClass
(
cls
);
for
(
ClassNode
inner
:
cls
.
getInnerClasses
())
{
nClasses
[
k
++]
=
addClass
(
inner
);
}
}
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
nClasses
[
i
].
setParents
(
ClsSet
.
makeParentsArray
(
classes
.
get
(
i
),
nameMap
));
...
...
@@ -62,8 +56,9 @@ public class ClspGraph {
}
private
NClass
addClass
(
ClassNode
cls
)
{
NClass
nClass
=
new
NClass
(
cls
.
getRawName
(),
-
1
);
nameMap
.
put
(
cls
.
getRawName
(),
nClass
);
String
rawName
=
cls
.
getRawName
();
NClass
nClass
=
new
NClass
(
rawName
,
-
1
);
nameMap
.
put
(
rawName
,
nClass
);
return
nClass
;
}
...
...
jadx-core/src/main/java/jadx/core/clsp/ConvertToClsSet.java
View file @
a532287d
package
jadx
.
core
.
clsp
;
import
jadx.api.DefaultJadxArgs
;
import
jadx.core.dex.nodes.RootNode
;
import
jadx.core.utils.exceptions.DecodeException
;
import
jadx.core.utils.files.InputFile
;
...
...
@@ -42,7 +43,7 @@ public class ConvertToClsSet {
LOG
.
info
(
"Loaded: {}"
,
inputFile
.
getFile
());
}
RootNode
root
=
new
RootNode
();
RootNode
root
=
new
RootNode
(
new
DefaultJadxArgs
()
);
root
.
load
(
inputFiles
);
ClsSet
set
=
new
ClsSet
();
...
...
jadx-core/src/main/java/jadx/core/codegen/ClassGen.java
View file @
a532287d
package
jadx
.
core
.
codegen
;
import
jadx.api.IJadxArgs
;
import
jadx.core.Consts
;
import
jadx.core.deobf.Deobfuscator
;
import
jadx.core.dex.attributes.AFlag
;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.attributes.AttrNode
;
...
...
@@ -81,14 +79,14 @@ public class ClassGen {
CodeWriter
clsCode
=
new
CodeWriter
();
if
(!
""
.
equals
(
cls
.
getPackage
()))
{
clsCode
.
add
(
"package "
).
add
(
Deobfuscator
.
instance
().
getPackageName
(
cls
.
getPackage
()
)).
add
(
';'
);
clsCode
.
add
(
"package "
).
add
(
cls
.
getPackage
(
)).
add
(
';'
);
clsCode
.
newLine
();
}
int
importsCount
=
imports
.
size
();
if
(
importsCount
!=
0
)
{
List
<
String
>
sortImports
=
new
ArrayList
<
String
>(
importsCount
);
for
(
ClassInfo
ic
:
imports
)
{
sortImports
.
add
(
Deobfuscator
.
instance
().
getClassFullName
(
ic
));
sortImports
.
add
(
ic
.
getAlias
().
getFullName
(
));
}
Collections
.
sort
(
sortImports
);
...
...
@@ -126,7 +124,7 @@ public class ClassGen {
}
// 'static' modifier not allowed for top classes (not inner)
if
(!
cls
.
get
ClassInfo
().
isInner
())
{
if
(!
cls
.
get
Alias
().
isInner
())
{
af
=
af
.
remove
(
AccessFlags
.
ACC_STATIC
);
}
...
...
@@ -143,15 +141,15 @@ public class ClassGen {
}
else
{
clsCode
.
add
(
"class "
);
}
clsCode
.
add
(
Deobfuscator
.
instance
().
getClassShortName
(
cls
));
clsCode
.
add
(
cls
.
getShortName
(
));
addGenericMap
(
clsCode
,
cls
.
getGenericMap
());
clsCode
.
add
(
' '
);
ClassInfo
sup
=
cls
.
getSuperClass
();
ArgType
sup
=
cls
.
getSuperClass
();
if
(
sup
!=
null
&&
!
sup
.
getFullName
().
equals
(
Consts
.
CLASS_
OBJECT
)
&&
!
sup
.
get
FullName
().
equals
(
Consts
.
CLASS_ENUM
))
{
&&
!
sup
.
equals
(
ArgType
.
OBJECT
)
&&
!
sup
.
get
Object
().
equals
(
ArgType
.
ENUM
.
getObject
()
))
{
clsCode
.
add
(
"extends "
);
useClass
(
clsCode
,
sup
);
clsCode
.
add
(
' '
);
...
...
@@ -163,8 +161,8 @@ public class ClassGen {
}
else
{
clsCode
.
add
(
"implements "
);
}
for
(
Iterator
<
ClassInfo
>
it
=
cls
.
getInterfaces
().
iterator
();
it
.
hasNext
();
)
{
ClassInfo
interf
=
it
.
next
();
for
(
Iterator
<
ArgType
>
it
=
cls
.
getInterfaces
().
iterator
();
it
.
hasNext
();
)
{
ArgType
interf
=
it
.
next
();
useClass
(
clsCode
,
interf
);
if
(
it
.
hasNext
())
{
clsCode
.
add
(
", "
);
...
...
@@ -192,7 +190,7 @@ public class ClassGen {
if
(
type
.
isGenericType
())
{
code
.
add
(
type
.
getObject
());
}
else
{
useClass
(
code
,
ClassInfo
.
fromType
(
cls
.
dex
(),
type
)
);
useClass
(
code
,
type
);
}
if
(
list
!=
null
&&
!
list
.
isEmpty
())
{
code
.
add
(
" extends "
);
...
...
@@ -201,7 +199,7 @@ public class ClassGen {
if
(
g
.
isGenericType
())
{
code
.
add
(
g
.
getObject
());
}
else
{
useClass
(
code
,
ClassInfo
.
fromType
(
cls
.
dex
(),
g
)
);
useClass
(
code
,
g
);
}
if
(
it
.
hasNext
())
{
code
.
add
(
" & "
);
...
...
@@ -407,7 +405,7 @@ public class ClassGen {
if
(
type
.
isGenericType
())
{
code
.
add
(
type
.
getObject
());
}
else
{
useClass
(
code
,
ClassInfo
.
fromType
(
cls
.
dex
(),
type
)
);
useClass
(
code
,
type
);
}
}
else
if
(
stype
==
PrimitiveType
.
ARRAY
)
{
useType
(
code
,
type
.
getArrayElement
());
...
...
@@ -417,14 +415,9 @@ public class ClassGen {
}
}
public
void
useClass
(
CodeWriter
code
,
ClassInfo
classInfo
)
{
ClassNode
classNode
=
cls
.
dex
().
resolveClass
(
classInfo
);
if
(
classNode
!=
null
)
{
code
.
attachAnnotation
(
classNode
);
}
String
baseClass
=
useClassInternal
(
cls
.
getClassInfo
(),
classInfo
);
code
.
add
(
baseClass
);
ArgType
[]
generics
=
classInfo
.
getType
().
getGenericTypes
();
public
void
useClass
(
CodeWriter
code
,
ArgType
type
)
{
useClass
(
code
,
ClassInfo
.
extCls
(
cls
.
dex
(),
type
));
ArgType
[]
generics
=
type
.
getGenericTypes
();
if
(
generics
!=
null
)
{
code
.
add
(
'<'
);
int
len
=
generics
.
length
;
...
...
@@ -449,54 +442,63 @@ public class ClassGen {
}
}
private
String
useClassInternal
(
ClassInfo
useCls
,
ClassInfo
classInfo
)
{
String
fullName
=
classInfo
.
getFullName
();
public
void
useClass
(
CodeWriter
code
,
ClassInfo
classInfo
)
{
ClassNode
classNode
=
cls
.
dex
().
resolveClass
(
classInfo
);
if
(
classNode
!=
null
)
{
code
.
attachAnnotation
(
classNode
);
}
String
baseClass
=
useClassInternal
(
cls
.
getAlias
(),
classInfo
.
getAlias
());
code
.
add
(
baseClass
);
}
private
String
useClassInternal
(
ClassInfo
useCls
,
ClassInfo
extClsInfo
)
{
String
fullName
=
extClsInfo
.
getFullName
();
if
(
fallback
)
{
return
fullName
;
}
fullName
=
Deobfuscator
.
instance
().
getClassFullName
(
classInfo
);
String
shortName
=
Deobfuscator
.
instance
().
getClassShortName
(
classInfo
);
if
(
classInfo
.
getPackage
().
equals
(
"java.lang"
)
&&
clas
sInfo
.
getParentClass
()
==
null
)
{
fullName
=
extClsInfo
.
getFullName
(
);
String
shortName
=
extClsInfo
.
getShortName
(
);
if
(
extClsInfo
.
getPackage
().
equals
(
"java.lang"
)
&&
extCl
sInfo
.
getParentClass
()
==
null
)
{
return
shortName
;
}
else
{
// don't add import if this class inner for current class
if
(
isClassInnerFor
(
clas
sInfo
,
useCls
))
{
if
(
isClassInnerFor
(
extCl
sInfo
,
useCls
))
{
return
shortName
;
}
// don't add import if this class from same package
if
(
classInfo
.
getPackage
().
equals
(
useCls
.
getPackage
())
&&
!
clas
sInfo
.
isInner
())
{
if
(
extClsInfo
.
getPackage
().
equals
(
useCls
.
getPackage
())
&&
!
extCl
sInfo
.
isInner
())
{
return
shortName
;
}
// don't add import if class not public (must be accessed using inheritance)
ClassNode
classNode
=
cls
.
dex
().
resolveClass
(
clas
sInfo
);
ClassNode
classNode
=
cls
.
dex
().
resolveClass
(
extCl
sInfo
);
if
(
classNode
!=
null
&&
!
classNode
.
getAccessFlags
().
isPublic
())
{
return
shortName
;
}
if
(
searchCollision
(
cls
.
dex
(),
useCls
,
clas
sInfo
))
{
if
(
searchCollision
(
cls
.
dex
(),
useCls
,
extCl
sInfo
))
{
return
fullName
;
}
if
(
clas
sInfo
.
getPackage
().
equals
(
useCls
.
getPackage
()))
{
fullName
=
Deobfuscator
.
instance
().
getClassName
(
classInfo
);
if
(
extCl
sInfo
.
getPackage
().
equals
(
useCls
.
getPackage
()))
{
fullName
=
extClsInfo
.
getNameWithoutPackage
(
);
}
for
(
ClassInfo
importCls
:
getImports
())
{
if
(!
importCls
.
equals
(
clas
sInfo
)
if
(!
importCls
.
equals
(
extCl
sInfo
)
&&
importCls
.
getShortName
().
equals
(
shortName
))
{
if
(
clas
sInfo
.
isInner
())
{
String
parent
=
useClassInternal
(
useCls
,
classInfo
.
getParentClas
s
());
if
(
extCl
sInfo
.
isInner
())
{
String
parent
=
useClassInternal
(
useCls
,
extClsInfo
.
getParentClass
().
getAlia
s
());
return
parent
+
"."
+
shortName
;
}
else
{
return
fullName
;
}
}
}
addImport
(
clas
sInfo
);
addImport
(
extCl
sInfo
);
return
shortName
;
}
}
private
void
addImport
(
ClassInfo
classInfo
)
{
if
(
parentGen
!=
null
)
{
parentGen
.
addImport
(
classInfo
);
parentGen
.
addImport
(
classInfo
.
getAlias
()
);
}
else
{
imports
.
add
(
classInfo
);
}
...
...
@@ -530,7 +532,7 @@ public class ClassGen {
if
(
classNode
!=
null
)
{
for
(
ClassNode
inner
:
classNode
.
getInnerClasses
())
{
if
(
inner
.
getShortName
().
equals
(
shortName
)
&&
!
inner
.
get
ClassInfo
().
equals
(
searchCls
))
{
&&
!
inner
.
get
Alias
().
equals
(
searchCls
))
{
return
true
;
}
}
...
...
jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
View file @
a532287d
...
...
@@ -162,14 +162,14 @@ public class InsnGen {
public
static
void
makeStaticFieldAccess
(
CodeWriter
code
,
FieldInfo
field
,
ClassGen
clsGen
)
{
ClassInfo
declClass
=
field
.
getDeclClass
();
boolean
fieldFromThisClass
=
clsGen
.
getClassNode
().
get
FullName
().
startsWith
(
declClass
.
getFullName
()
);
boolean
fieldFromThisClass
=
clsGen
.
getClassNode
().
get
ClassInfo
().
equals
(
declClass
);
if
(!
fieldFromThisClass
)
{
// Android specific resources class handler
ClassInfo
parentClass
=
declClass
.
getParentClass
();
if
(
parentClass
!=
null
&&
parentClass
.
getShortName
().
equals
(
"R"
))
{
clsGen
.
useClass
(
code
,
parentClass
);
code
.
add
(
'.'
);
code
.
add
(
declClass
.
getShortName
());
code
.
add
(
declClass
.
get
Alias
().
get
ShortName
());
}
else
{
clsGen
.
useClass
(
code
,
declClass
);
}
...
...
@@ -186,6 +186,10 @@ public class InsnGen {
makeStaticFieldAccess
(
code
,
field
,
mgen
.
getClassGen
());
}
public
void
useClass
(
CodeWriter
code
,
ArgType
type
)
{
mgen
.
getClassGen
().
useClass
(
code
,
type
);
}
public
void
useClass
(
CodeWriter
code
,
ClassInfo
cls
)
{
mgen
.
getClassGen
().
useClass
(
code
,
cls
);
}
...
...
@@ -200,9 +204,6 @@ public class InsnGen {
protected
boolean
makeInsn
(
InsnNode
insn
,
CodeWriter
code
,
Flags
flag
)
throws
CodegenException
{
try
{
if
(
insn
.
getType
()
==
InsnType
.
NOP
)
{
return
false
;
}
Set
<
Flags
>
state
=
EnumSet
.
noneOf
(
Flags
.
class
);
if
(
flag
==
Flags
.
BODY_ONLY
||
flag
==
Flags
.
BODY_ONLY_NOWRAP
)
{
state
.
add
(
flag
);
...
...
@@ -531,7 +532,7 @@ public class InsnGen {
ClassNode
cls
=
mth
.
dex
().
resolveClass
(
insn
.
getClassType
());
if
(
cls
!=
null
&&
cls
.
isAnonymous
()
&&
!
fallback
)
{
// anonymous class construction
ClassInfo
parent
;
ArgType
parent
;
if
(
cls
.
getInterfaces
().
size
()
==
1
)
{
parent
=
cls
.
getInterfaces
().
get
(
0
);
}
else
{
...
...
@@ -600,7 +601,7 @@ public class InsnGen {
break
;
case
STATIC:
ClassInfo
insnCls
=
mth
.
getParentClass
().
get
ClassInfo
();
ClassInfo
insnCls
=
mth
.
getParentClass
().
get
Alias
();
ClassInfo
declClass
=
callMth
.
getDeclClass
();
if
(!
insnCls
.
equals
(
declClass
))
{
useClass
(
code
,
declClass
);
...
...
jadx-core/src/main/java/jadx/core/codegen/MethodGen.java
View file @
a532287d
package
jadx
.
core
.
codegen
;
import
jadx.core.deobf.Deobfuscator
;
import
jadx.core.dex.attributes.AFlag
;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.attributes.annotations.MethodParameters
;
import
jadx.core.dex.attributes.nodes.JadxErrorAttr
;
import
jadx.core.dex.info.AccessInfo
;
import
jadx.core.dex.instructions.InsnType
;
import
jadx.core.dex.instructions.args.ArgType
;
import
jadx.core.dex.instructions.args.RegisterArg
;
import
jadx.core.dex.nodes.InsnNode
;
...
...
@@ -86,7 +86,7 @@ public class MethodGen {
code
.
add
(
' '
);
}
if
(
mth
.
getAccessFlags
().
isConstructor
())
{
code
.
add
(
Deobfuscator
.
instance
().
getClassShortName
(
classGen
.
getClassNode
()
));
// constructor
code
.
add
(
classGen
.
getClassNode
().
getShortName
(
));
// constructor
}
else
{
classGen
.
useType
(
code
,
mth
.
getReturnType
());
code
.
add
(
' '
);
...
...
@@ -209,7 +209,7 @@ public class MethodGen {
public
static
void
addFallbackInsns
(
CodeWriter
code
,
MethodNode
mth
,
InsnNode
[]
insnArr
,
boolean
addLabels
)
{
InsnGen
insnGen
=
new
InsnGen
(
getFallbackMethodGen
(
mth
),
true
);
for
(
InsnNode
insn
:
insnArr
)
{
if
(
insn
==
null
)
{
if
(
insn
==
null
||
insn
.
getType
()
==
InsnType
.
NOP
)
{
continue
;
}
if
(
addLabels
&&
(
insn
.
contains
(
AType
.
JUMP
)
||
insn
.
contains
(
AType
.
EXC_HANDLER
)))
{
...
...
jadx-core/src/main/java/jadx/core/codegen/NameGen.java
View file @
a532287d
...
...
@@ -158,8 +158,8 @@ public class NameGen {
if
(
alias
!=
null
)
{
return
alias
;
}
ClassInfo
clsInfo
=
ClassInfo
.
fromType
(
mth
.
dex
(),
type
);
String
shortName
=
c
lsInfo
.
getShortName
();
ClassInfo
extClsInfo
=
ClassInfo
.
extCls
(
mth
.
dex
(),
type
);
String
shortName
=
extC
lsInfo
.
getShortName
();
String
vName
=
fromName
(
shortName
);
if
(
vName
!=
null
)
{
return
vName
;
...
...
@@ -223,12 +223,12 @@ public class NameGen {
return
null
;
}
private
static
String
makeNameFromInvoke
(
MethodInfo
callMth
)
{
private
String
makeNameFromInvoke
(
MethodInfo
callMth
)
{
String
name
=
callMth
.
getName
();
if
(
name
.
startsWith
(
"get"
)
||
name
.
startsWith
(
"set"
))
{
return
fromName
(
name
.
substring
(
3
));
}
ArgType
declType
=
callMth
.
getDeclClass
().
getType
();
ArgType
declType
=
callMth
.
getDeclClass
().
get
Alias
().
get
Type
();
if
(
"iterator"
.
equals
(
name
))
{
return
"it"
;
}
...
...
jadx-core/src/main/java/jadx/core/deobf/DefaultDeobfuscator.java
deleted
100644 → 0
View file @
7844e554
This diff is collapsed.
Click to expand it.
jadx-core/src/main/java/jadx/core/deobf/Deobfuscator.java
View file @
a532287d
This diff is collapsed.
Click to expand it.
jadx-core/src/main/java/jadx/core/deobf/IDeobfuscator.java
deleted
100644 → 0
View file @
7844e554
package
jadx
.
core
.
deobf
;
import
jadx.core.dex.info.ClassInfo
;
import
jadx.core.dex.nodes.ClassNode
;
public
interface
IDeobfuscator
{
public
String
getPackageName
(
String
packageName
);
public
String
getClassShortName
(
ClassNode
cls
);
public
String
getClassShortName
(
ClassInfo
clsInfo
);
public
String
getClassName
(
ClassNode
cls
);
public
String
getClassName
(
ClassInfo
clsInfo
);
public
String
getClassFullName
(
ClassNode
cls
);
public
String
getClassFullName
(
ClassInfo
clsInfo
);
public
String
getClassFullPath
(
ClassInfo
clsInfo
);
}
jadx-core/src/main/java/jadx/core/deobf/PackageNode.java
View file @
a532287d
...
...
@@ -14,7 +14,7 @@ public class PackageNode {
private
List
<
PackageNode
>
innerPackages
=
Collections
.
emptyList
();
public
static
final
char
separatorChar
=
'.'
;
private
String
packageName
;
private
String
packageAlias
;
...
...
@@ -51,14 +51,14 @@ public class PackageNode {
if
(
packageAlias
!=
null
)
{
return
packageAlias
;
}
return
packageName
;
}
public
void
setAlias
(
String
alias
)
{
packageAlias
=
alias
;
}
public
boolean
hasAlias
()
{
return
(
packageAlias
!=
null
);
}
...
...
@@ -108,9 +108,8 @@ public class PackageNode {
/**
* Gets inner package node by name
*
*
* @param name inner package name
*
* @return package node or {@code null}
*/
public
PackageNode
getInnerPackageByName
(
String
name
)
{
...
...
@@ -127,7 +126,7 @@ public class PackageNode {
/**
* Fills stack with parent packages exclude root node
*
*
* @return stack with parent packages
*/
private
Stack
<
PackageNode
>
getParentPackages
()
{
...
...
jadx-core/src/main/java/jadx/core/deobf/StubDeobfuscator.java
deleted
100644 → 0
View file @
7844e554
package
jadx
.
core
.
deobf
;
import
jadx.core.dex.info.ClassInfo
;
import
jadx.core.dex.nodes.ClassNode
;
public
class
StubDeobfuscator
implements
IDeobfuscator
{
@Override
public
String
getPackageName
(
String
packageName
)
{
return
packageName
;
}
@Override
public
String
getClassShortName
(
ClassNode
cls
)
{
return
cls
.
getShortName
();
}
@Override
public
String
getClassShortName
(
ClassInfo
clsInfo
)
{
return
clsInfo
.
getShortName
();
}
@Override
public
String
getClassName
(
ClassNode
cls
)
{
return
cls
.
getClassInfo
().
getNameWithoutPackage
();
}
@Override
public
String
getClassName
(
ClassInfo
clsInfo
)
{
return
clsInfo
.
getNameWithoutPackage
();
}
@Override
public
String
getClassFullName
(
ClassNode
cls
)
{
return
cls
.
getFullName
();
}
@Override
public
String
getClassFullName
(
ClassInfo
clsInfo
)
{
return
clsInfo
.
getFullName
();
}
@Override
public
String
getClassFullPath
(
ClassInfo
clsInfo
)
{
return
clsInfo
.
getFullPath
();
}
}
jadx-core/src/main/java/jadx/core/dex/info/ClassInfo.java
View file @
a532287d
...
...
@@ -16,17 +16,27 @@ public final class ClassInfo {
private
String
fullName
;
// for inner class not equals null
private
ClassInfo
parentClass
;
// class info after rename (deobfuscation)
private
ClassInfo
alias
;
private
ClassInfo
(
DexNode
dex
,
ArgType
type
)
{
if
(!
type
.
isObject
())
{
this
(
dex
,
type
,
true
);
}
private
ClassInfo
(
DexNode
dex
,
ArgType
type
,
boolean
inner
)
{
if
(!
type
.
isObject
()
||
type
.
isGeneric
())
{
throw
new
JadxRuntimeException
(
"Not class type: "
+
type
);
}
this
.
type
=
type
;
this
.
alias
=
this
;
splitNames
(
dex
,
true
);
splitNames
(
dex
,
inner
);
}
public
static
ClassInfo
fromType
(
DexNode
dex
,
ArgType
type
)
{
if
(
type
.
isArray
())
{
type
=
ArgType
.
OBJECT
;
}
ClassInfo
cls
=
dex
.
getInfoStorage
().
getCls
(
type
);
if
(
cls
!=
null
)
{
return
cls
;
...
...
@@ -39,26 +49,32 @@ public final class ClassInfo {
if
(
clsIndex
==
DexNode
.
NO_INDEX
)
{
return
null
;
}
ArgType
type
=
dex
.
getType
(
clsIndex
);
if
(
type
.
isArray
())
{
type
=
ArgType
.
OBJECT
;
}
return
fromType
(
dex
,
type
);
return
fromType
(
dex
,
dex
.
getType
(
clsIndex
));
}
public
static
ClassInfo
fromName
(
DexNode
dex
,
String
clsName
)
{
return
fromType
(
dex
,
ArgType
.
object
(
clsName
));
}
public
static
ClassInfo
extCls
(
DexNode
dex
,
ArgType
type
)
{
ClassInfo
classInfo
=
fromName
(
dex
,
type
.
getObject
());
return
classInfo
.
alias
;
}
public
void
rename
(
DexNode
dex
,
String
fullName
)
{
this
.
alias
=
new
ClassInfo
(
dex
,
ArgType
.
object
(
fullName
),
isInner
());
}
public
ClassInfo
getAlias
()
{
return
alias
;
}
private
void
splitNames
(
DexNode
dex
,
boolean
canBeInner
)
{
String
fullObjectName
=
type
.
getObject
();
assert
fullObjectName
.
indexOf
(
'/'
)
==
-
1
:
"Raw type: "
+
type
;
String
clsName
;
int
dot
=
fullObjectName
.
lastIndexOf
(
'.'
);
if
(
dot
==
-
1
)
{
// rename default package if it used from class with package (often for obfuscated apps),
pkg
=
Consts
.
DEFAULT_PACKAGE_NAME
;
pkg
=
""
;
clsName
=
fullObjectName
;
}
else
{
pkg
=
fullObjectName
.
substring
(
0
,
dot
);
...
...
@@ -83,8 +99,12 @@ public final class ClassInfo {
if
(
NameMapper
.
isReserved
(
clsName
))
{
clsName
+=
"_"
;
}
this
.
fullName
=
(
parentClass
!=
null
?
parentClass
.
getFullName
()
:
pkg
)
+
"."
+
clsName
;
this
.
name
=
clsName
;
if
(
parentClass
!=
null
)
{
this
.
fullName
=
parentClass
.
fullName
+
"."
+
clsName
;
}
else
{
this
.
fullName
=
pkg
.
isEmpty
()
?
clsName
:
pkg
+
"."
+
clsName
;
}
}
public
String
getFullPath
()
{
...
...
@@ -97,28 +117,23 @@ public final class ClassInfo {
return
fullName
;
}
public
boolean
isObject
()
{
return
fullName
.
equals
(
Consts
.
CLASS_OBJECT
);
}
public
String
getShortName
()
{
return
name
;
}
public
String
getRawName
()
{
return
type
.
getObject
();
}
public
String
getPackage
()
{
return
pkg
;
}
public
boolean
isPackageDefault
()
{
return
pkg
.
isEmpty
()
||
pkg
.
equals
(
Consts
.
DEFAULT_PACKAGE_NAME
);
public
String
getRawName
()
{
return
type
.
getObject
(
);
}
public
String
getNameWithoutPackage
()
{
return
(
parentClass
!=
null
?
parentClass
.
getNameWithoutPackage
()
+
"."
:
""
)
+
name
;
if
(
parentClass
==
null
)
{
return
name
;
}
return
parentClass
.
getNameWithoutPackage
()
+
"."
+
name
;
}
public
ClassInfo
getParentClass
()
{
...
...
@@ -154,7 +169,7 @@ public final class ClassInfo {
}
if
(
obj
instanceof
ClassInfo
)
{
ClassInfo
other
=
(
ClassInfo
)
obj
;
return
this
.
getFullName
().
equals
(
other
.
getFullName
()
);
return
this
.
type
.
equals
(
other
.
type
);
}
return
false
;
}
...
...
jadx-core/src/main/java/jadx/core/dex/info/FieldInfo.java
View file @
a532287d
...
...
@@ -5,7 +5,7 @@ import jadx.core.dex.nodes.DexNode;
import
com.android.dex.FieldId
;
public
class
FieldInfo
{
public
final
class
FieldInfo
{
private
final
ClassInfo
declClass
;
private
final
String
name
;
...
...
jadx-core/src/main/java/jadx/core/dex/instructions/InsnDecoder.java
View file @
a532287d
...
...
@@ -621,12 +621,10 @@ public class InsnDecoder {
regs
[
i
]
=
InsnArg
.
reg
(
regNum
,
elType
,
typeImmutable
);
}
}
InsnNode
node
=
new
FilledNewArrayNode
(
elType
,
regs
==
null
?
0
:
regs
.
length
);
InsnNode
node
=
new
FilledNewArrayNode
(
elType
,
regs
.
length
);
node
.
setResult
(
resReg
==
-
1
?
null
:
InsnArg
.
reg
(
resReg
,
arrType
));
if
(
regs
!=
null
)
{
for
(
InsnArg
arg
:
regs
)
{
node
.
addArg
(
arg
);
}
for
(
InsnArg
arg
:
regs
)
{
node
.
addArg
(
arg
);
}
return
node
;
}
...
...
jadx-core/src/main/java/jadx/core/dex/instructions/args/ArgType.java
View file @
a532287d
...
...
@@ -26,6 +26,7 @@ public abstract class ArgType {
public
static
final
ArgType
OBJECT
=
object
(
Consts
.
CLASS_OBJECT
);
public
static
final
ArgType
CLASS
=
object
(
Consts
.
CLASS_CLASS
);
public
static
final
ArgType
STRING
=
object
(
Consts
.
CLASS_STRING
);
public
static
final
ArgType
ENUM
=
object
(
Consts
.
CLASS_ENUM
);
public
static
final
ArgType
THROWABLE
=
object
(
Consts
.
CLASS_THROWABLE
);
public
static
final
ArgType
UNKNOWN
=
unknown
(
PrimitiveType
.
values
());
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
View file @
a532287d
...
...
@@ -30,6 +30,7 @@ import java.util.List;
import
java.util.Map
;
import
java.util.Set
;
import
org.jetbrains.annotations.Nullable
;
import
org.jetbrains.annotations.TestOnly
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
...
...
@@ -46,8 +47,8 @@ public class ClassNode extends LineAttrNode implements ILoadable {
private
final
DexNode
dex
;
private
final
ClassInfo
clsInfo
;
private
final
AccessInfo
accessFlags
;
private
ClassInfo
superClass
;
private
List
<
ClassInfo
>
interfaces
;
private
ArgType
superClass
;
private
List
<
ArgType
>
interfaces
;
private
Map
<
ArgType
,
List
<
ArgType
>>
genericMap
;
private
final
List
<
MethodNode
>
methods
;
...
...
@@ -70,11 +71,11 @@ public class ClassNode extends LineAttrNode implements ILoadable {
if
(
cls
.
getSupertypeIndex
()
==
DexNode
.
NO_INDEX
)
{
this
.
superClass
=
null
;
}
else
{
this
.
superClass
=
ClassInfo
.
fromDex
(
dex
,
cls
.
getSupertypeIndex
());
this
.
superClass
=
dex
.
getType
(
cls
.
getSupertypeIndex
());
}
this
.
interfaces
=
new
ArrayList
<
ClassInfo
>(
cls
.
getInterfaces
().
length
);
this
.
interfaces
=
new
ArrayList
<
ArgType
>(
cls
.
getInterfaces
().
length
);
for
(
short
interfaceIdx
:
cls
.
getInterfaces
())
{
this
.
interfaces
.
add
(
ClassInfo
.
fromDex
(
dex
,
interfaceIdx
));
this
.
interfaces
.
add
(
dex
.
getType
(
interfaceIdx
));
}
if
(
cls
.
getClassDataOffset
()
!=
0
)
{
ClassData
clsData
=
dex
.
readClassData
(
cls
);
...
...
@@ -111,7 +112,7 @@ public class ClassNode extends LineAttrNode implements ILoadable {
int
sfIdx
=
cls
.
getSourceFileIndex
();
if
(
sfIdx
!=
DexNode
.
NO_INDEX
)
{
String
fileName
=
dex
.
getString
(
sfIdx
);
if
(!
this
.
getFullName
().
contains
(
fileName
.
replace
(
".java"
,
""
))
if
(!
clsInfo
.
getFullName
().
contains
(
fileName
.
replace
(
".java"
,
""
))
&&
!
fileName
.
equals
(
"SourceFile"
))
{
this
.
addAttr
(
new
SourceFileAttr
(
fileName
));
LOG
.
debug
(
"Class '{}' compiled from '{}'"
,
this
,
fileName
);
...
...
@@ -129,7 +130,7 @@ public class ClassNode extends LineAttrNode implements ILoadable {
this
.
accessFlags
=
new
AccessInfo
(
accFlagsValue
,
AFType
.
CLASS
);
}
catch
(
Exception
e
)
{
throw
new
DecodeException
(
"Error decode class: "
+
getFullName
()
,
e
);
throw
new
DecodeException
(
"Error decode class: "
+
clsInfo
,
e
);
}
}
...
...
@@ -191,12 +192,12 @@ public class ClassNode extends LineAttrNode implements ILoadable {
// parse class generic map
genericMap
=
sp
.
consumeGenericMap
();
// parse super class signature
superClass
=
ClassInfo
.
fromType
(
dex
,
sp
.
consumeType
()
);
superClass
=
sp
.
consumeType
(
);
// parse interfaces signatures
for
(
int
i
=
0
;
i
<
interfaces
.
size
();
i
++)
{
ArgType
type
=
sp
.
consumeType
();
if
(
type
!=
null
)
{
interfaces
.
set
(
i
,
ClassInfo
.
fromType
(
dex
,
type
)
);
interfaces
.
set
(
i
,
type
);
}
else
{
break
;
}
...
...
@@ -247,11 +248,12 @@ public class ClassNode extends LineAttrNode implements ILoadable {
}
}
public
ClassInfo
getSuperClass
()
{
@Nullable
public
ArgType
getSuperClass
()
{
return
superClass
;
}
public
List
<
ClassInfo
>
getInterfaces
()
{
public
List
<
ArgType
>
getInterfaces
()
{
return
interfaces
;
}
...
...
@@ -403,12 +405,14 @@ public class ClassNode extends LineAttrNode implements ILoadable {
}
public
boolean
isEnum
()
{
return
getAccessFlags
().
isEnum
()
&&
getSuperClass
().
getFullName
().
equals
(
Consts
.
CLASS_ENUM
);
return
getAccessFlags
().
isEnum
()
&&
getSuperClass
()
!=
null
&&
getSuperClass
().
getObject
().
equals
(
ArgType
.
ENUM
.
getObject
());
}
public
boolean
isAnonymous
()
{
return
clsInfo
.
isInner
()
&&
getShortName
().
startsWith
(
Consts
.
ANONYMOUS_CLASS_PREFIX
)
&&
clsInfo
.
getShortName
().
startsWith
(
Consts
.
ANONYMOUS_CLASS_PREFIX
)
&&
getDefaultConstructor
()
!=
null
;
}
...
...
@@ -429,24 +433,34 @@ public class ClassNode extends LineAttrNode implements ILoadable {
return
dex
;
}
public
String
getRawName
()
{
return
clsInfo
.
getRawName
();
}
/**
* Internal class info (don't use in code generation and external api).
*/
public
ClassInfo
getClassInfo
()
{
return
clsInfo
;
}
/**
* Class info for external usage (code generation and external api).
*/
public
ClassInfo
getAlias
()
{
return
clsInfo
.
getAlias
();
}
public
String
getShortName
()
{
return
clsInfo
.
getShortName
();
return
clsInfo
.
get
Alias
().
get
ShortName
();
}
public
String
getFullName
()
{
return
clsInfo
.
getFullName
();
return
clsInfo
.
get
Alias
().
get
FullName
();
}
public
String
getPackage
()
{
return
clsInfo
.
getPackage
();
}
public
String
getRawName
()
{
return
clsInfo
.
getRawName
();
return
clsInfo
.
getAlias
().
getPackage
();
}
public
void
setCode
(
CodeWriter
code
)
{
...
...
@@ -471,6 +485,6 @@ public class ClassNode extends LineAttrNode implements ILoadable {
@Override
public
String
toString
()
{
return
getFullName
();
return
clsInfo
.
getFullName
();
}
}
jadx-core/src/main/java/jadx/core/dex/nodes/DexNode.java
View file @
a532287d
...
...
@@ -33,7 +33,10 @@ public class DexNode {
private
final
RootNode
root
;
private
final
Dex
dexBuf
;
private
final
InputFile
file
;
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
>();
...
...
@@ -41,12 +44,36 @@ public class DexNode {
public
DexNode
(
RootNode
root
,
InputFile
input
)
{
this
.
root
=
root
;
this
.
file
=
input
;
this
.
dexBuf
=
input
.
getDexBuffer
();
}
public
void
loadClasses
()
throws
DecodeException
{
for
(
ClassDef
cls
:
dexBuf
.
classDefs
())
{
classes
.
add
(
new
ClassNode
(
this
,
cls
));
ClassNode
clsNode
=
new
ClassNode
(
this
,
cls
);
classes
.
add
(
clsNode
);
clsMap
.
put
(
clsNode
.
getClassInfo
(),
clsNode
);
}
}
void
initInnerClasses
()
{
// move inner classes
List
<
ClassNode
>
inner
=
new
ArrayList
<
ClassNode
>();
for
(
ClassNode
cls
:
classes
)
{
if
(
cls
.
getClassInfo
().
isInner
())
{
inner
.
add
(
cls
);
}
}
for
(
ClassNode
cls
:
inner
)
{
ClassInfo
clsInfo
=
cls
.
getClassInfo
();
ClassNode
parent
=
resolveClass
(
clsInfo
.
getParentClass
());
if
(
parent
==
null
)
{
clsMap
.
remove
(
clsInfo
);
clsInfo
.
notInner
(
cls
.
dex
());
clsMap
.
put
(
clsInfo
,
cls
);
}
else
{
parent
.
addInnerClass
(
cls
);
}
}
}
...
...
@@ -56,7 +83,7 @@ public class DexNode {
@Nullable
public
ClassNode
resolveClass
(
ClassInfo
clsInfo
)
{
return
root
.
resolveClass
(
clsInfo
);
return
clsMap
.
get
(
clsInfo
);
}
@Nullable
...
...
@@ -85,6 +112,10 @@ public class DexNode {
return
infoStorage
;
}
public
InputFile
getInputFile
()
{
return
file
;
}
// DexBuffer wrappers
public
String
getString
(
int
index
)
{
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java
View file @
a532287d
...
...
@@ -597,7 +597,7 @@ public class MethodNode extends LineAttrNode implements ILoadable {
@Override
public
String
toString
()
{
return
parentClass
.
getFullName
()
+
"."
+
mthInfo
.
getName
()
return
parentClass
+
"."
+
mthInfo
.
getName
()
+
"("
+
Utils
.
listToString
(
mthInfo
.
getArgumentsTypes
())
+
"):"
+
retType
;
}
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java
View file @
a532287d
package
jadx
.
core
.
dex
.
nodes
;
import
jadx.api.IJadxArgs
;
import
jadx.api.ResourceFile
;
import
jadx.api.ResourceType
;
import
jadx.api.ResourcesLoader
;
...
...
@@ -27,19 +28,19 @@ import org.slf4j.LoggerFactory;
public
class
RootNode
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
RootNode
.
class
);
private
final
Map
<
String
,
ClassNode
>
names
=
new
HashMap
<
String
,
ClassNode
>();
private
final
ErrorsCounter
errorsCounter
=
new
ErrorsCounter
();
private
final
IJadxArgs
args
;
private
List
<
DexNode
>
dexNodes
;
/**
* Resources *
*/
private
Map
<
Integer
,
String
>
resourcesNames
=
new
HashMap
<
Integer
,
String
>();
@Nullable
private
String
appPackage
;
private
ClassNode
appResClass
;
public
RootNode
(
IJadxArgs
args
)
{
this
.
args
=
args
;
}
public
void
load
(
List
<
InputFile
>
dexFiles
)
throws
DecodeException
{
dexNodes
=
new
ArrayList
<
DexNode
>(
dexFiles
.
size
());
for
(
InputFile
dex
:
dexFiles
)
{
...
...
@@ -54,21 +55,7 @@ public class RootNode {
for
(
DexNode
dexNode
:
dexNodes
)
{
dexNode
.
loadClasses
();
}
List
<
ClassNode
>
classes
=
new
ArrayList
<
ClassNode
>();
for
(
DexNode
dexNode
:
dexNodes
)
{
for
(
ClassNode
cls
:
dexNode
.
getClasses
())
{
names
.
put
(
cls
.
getFullName
(),
cls
);
}
classes
.
addAll
(
dexNode
.
getClasses
());
}
try
{
initClassPath
(
classes
);
}
catch
(
IOException
e
)
{
throw
new
DecodeException
(
"Error loading classpath"
,
e
);
}
initInnerClasses
(
classes
);
initInnerClasses
();
}
public
void
loadResources
(
List
<
ResourceFile
>
resources
)
{
...
...
@@ -99,55 +86,52 @@ public class RootNode {
ResourceStorage
resStorage
=
parser
.
getResStorage
();
resourcesNames
=
resStorage
.
getResourcesNames
();
appPackage
=
resStorage
.
getAppPackage
();
}
public
void
initAppResClass
()
{
ClassNode
resCls
=
null
;
if
(
appPackage
!=
null
)
{
resCls
=
searchClassByName
(
appPackage
+
".R"
);
}
else
{
for
(
ClassNode
cls
:
names
.
values
())
{
if
(
cls
.
getShortName
().
equals
(
"R"
))
{
resCls
=
cls
;
break
;
}
}
ClassNode
resCls
;
if
(
appPackage
==
null
)
{
appResClass
=
makeClass
(
"R"
);
return
;
}
String
fullName
=
appPackage
+
".R"
;
resCls
=
searchClassByName
(
fullName
);
if
(
resCls
!=
null
)
{
appResClass
=
resCls
;
return
;
}
else
{
appResClass
=
makeClass
(
fullName
);
}
}
private
ClassNode
makeClass
(
String
clsName
)
{
DexNode
firstDex
=
dexNodes
.
get
(
0
);
appResClass
=
new
ClassNode
(
firstDex
,
ClassInfo
.
fromName
(
firstDex
,
"R"
));
ClassInfo
r
=
ClassInfo
.
fromName
(
firstDex
,
clsName
);
return
new
ClassNode
(
firstDex
,
r
);
}
p
rivate
static
void
initClassPath
(
List
<
ClassNode
>
classes
)
throws
IOException
,
DecodeException
{
if
(!
ArgType
.
isClspSet
())
{
ClspGraph
clsp
=
new
ClspGraph
();
clsp
.
load
();
clsp
.
addApp
(
classes
);
p
ublic
void
initClassPath
()
throws
DecodeException
{
try
{
if
(!
ArgType
.
isClspSet
())
{
ClspGraph
clsp
=
new
ClspGraph
();
clsp
.
load
(
);
ArgType
.
setClsp
(
clsp
);
}
}
List
<
ClassNode
>
classes
=
new
ArrayList
<
ClassNode
>();
for
(
DexNode
dexNode
:
dexNodes
)
{
classes
.
addAll
(
dexNode
.
getClasses
());
}
clsp
.
addApp
(
classes
);
private
void
initInnerClasses
(
List
<
ClassNode
>
classes
)
{
// move inner classes
List
<
ClassNode
>
inner
=
new
ArrayList
<
ClassNode
>();
for
(
ClassNode
cls
:
classes
)
{
if
(
cls
.
getClassInfo
().
isInner
())
{
inner
.
add
(
cls
);
ArgType
.
setClsp
(
clsp
);
}
}
catch
(
IOException
e
)
{
throw
new
DecodeException
(
"Error loading classpath"
,
e
);
}
for
(
ClassNode
cls
:
inner
)
{
ClassNode
parent
=
resolveClass
(
cls
.
getClassInfo
().
getParentClass
());
if
(
parent
==
null
)
{
names
.
remove
(
cls
.
getFullName
());
cls
.
getClassInfo
().
notInner
(
cls
.
dex
());
names
.
put
(
cls
.
getFullName
(),
cls
);
}
else
{
parent
.
addInnerClass
(
cls
);
}
}
private
void
initInnerClasses
()
{
for
(
DexNode
dexNode
:
dexNodes
)
{
dexNode
.
initInnerClasses
();
}
}
...
...
@@ -168,12 +152,14 @@ public class RootNode {
}
public
ClassNode
searchClassByName
(
String
fullName
)
{
return
names
.
get
(
fullName
);
}
public
ClassNode
resolveClass
(
ClassInfo
cls
)
{
String
fullName
=
cls
.
getFullName
();
return
searchClassByName
(
fullName
);
for
(
DexNode
dexNode
:
dexNodes
)
{
ClassInfo
clsInfo
=
ClassInfo
.
fromName
(
dexNode
,
fullName
);
ClassNode
cls
=
dexNode
.
resolveClass
(
clsInfo
);
if
(
cls
!=
null
)
{
return
cls
;
}
}
return
null
;
}
public
List
<
DexNode
>
getDexNodes
()
{
...
...
@@ -196,4 +182,8 @@ public class RootNode {
public
ClassNode
getAppResClass
()
{
return
appResClass
;
}
public
IJadxArgs
getArgs
()
{
return
args
;
}
}
jadx-core/src/main/java/jadx/core/dex/visitors/AbstractVisitor.java
View file @
a532287d
...
...
@@ -2,11 +2,16 @@ package jadx.core.dex.visitors;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.core.dex.nodes.MethodNode
;
import
jadx.core.dex.nodes.RootNode
;
import
jadx.core.utils.exceptions.JadxException
;
public
class
AbstractVisitor
implements
IDexTreeVisitor
{
@Override
public
void
init
(
RootNode
root
)
throws
JadxException
{
}
@Override
public
boolean
visit
(
ClassNode
cls
)
throws
JadxException
{
return
true
;
}
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/ClassModifier.java
View file @
a532287d
...
...
@@ -199,7 +199,7 @@ public class ClassModifier extends AbstractVisitor {
*/
private
static
void
processStaticFieldAssign
(
ClassNode
cls
,
IndexInsnNode
insn
)
{
FieldInfo
field
=
(
FieldInfo
)
insn
.
getIndex
();
String
thisClass
=
cls
.
getFullName
();
String
thisClass
=
cls
.
get
ClassInfo
().
get
FullName
();
if
(
field
.
getDeclClass
().
getFullName
().
equals
(
thisClass
))
{
FieldNode
fn
=
cls
.
searchField
(
field
);
if
(
fn
!=
null
&&
fn
.
getAccessFlags
().
isFinal
())
{
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/DependencyCollector.java
View file @
a532287d
...
...
@@ -31,8 +31,8 @@ public class DependencyCollector extends AbstractVisitor {
private
static
void
processClass
(
ClassNode
cls
,
DexNode
dex
,
Set
<
ClassNode
>
depList
)
{
addDep
(
dex
,
depList
,
cls
.
getSuperClass
());
for
(
ClassInfo
clsInfo
:
cls
.
getInterfaces
())
{
addDep
(
dex
,
depList
,
clsInfo
);
for
(
ArgType
iType
:
cls
.
getInterfaces
())
{
addDep
(
dex
,
depList
,
iType
);
}
for
(
FieldNode
fieldNode
:
cls
.
getFields
())
{
addDep
(
dex
,
depList
,
fieldNode
.
getType
());
...
...
@@ -77,7 +77,7 @@ public class DependencyCollector extends AbstractVisitor {
private
static
void
addDep
(
DexNode
dex
,
Set
<
ClassNode
>
depList
,
ArgType
type
)
{
if
(
type
!=
null
)
{
if
(
type
.
isObject
())
{
addDep
(
dex
,
depList
,
ClassInfo
.
fromName
(
type
.
getObject
()));
addDep
(
dex
,
depList
,
ClassInfo
.
fromName
(
dex
,
type
.
getObject
()));
ArgType
[]
genericTypes
=
type
.
getGenericTypes
();
if
(
type
.
isGeneric
()
&&
genericTypes
!=
null
)
{
for
(
ArgType
argType
:
genericTypes
)
{
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/DotGraphVisitor.java
View file @
a532287d
...
...
@@ -2,7 +2,6 @@ package jadx.core.dex.visitors;
import
jadx.core.codegen.CodeWriter
;
import
jadx.core.codegen.MethodGen
;
import
jadx.core.deobf.Deobfuscator
;
import
jadx.core.dex.attributes.IAttributeNode
;
import
jadx.core.dex.instructions.IfNode
;
import
jadx.core.dex.instructions.InsnType
;
...
...
@@ -68,7 +67,7 @@ public class DotGraphVisitor extends AbstractVisitor {
public
void
process
(
MethodNode
mth
)
{
dot
.
startLine
(
"digraph \"CFG for"
);
dot
.
add
(
escape
(
mth
.
getParentClass
()
.
getFullName
()
+
"."
+
mth
.
getMethodInfo
().
getShortId
()));
dot
.
add
(
escape
(
mth
.
getParentClass
()
+
"."
+
mth
.
getMethodInfo
().
getShortId
()));
dot
.
add
(
"\" {"
);
if
(
useRegions
)
{
...
...
@@ -85,7 +84,7 @@ public class DotGraphVisitor extends AbstractVisitor {
dot
.
startLine
(
"MethodNode[shape=record,label=\"{"
);
dot
.
add
(
escape
(
mth
.
getAccessFlags
().
makeString
()));
dot
.
add
(
escape
(
mth
.
getReturnType
()
+
" "
+
mth
.
getParentClass
()
.
getFullName
()
+
"."
+
mth
.
getName
()
+
mth
.
getParentClass
()
+
"."
+
mth
.
getName
()
+
"("
+
Utils
.
listToString
(
mth
.
getArguments
(
true
))
+
") "
));
String
attrs
=
attributesString
(
mth
);
...
...
@@ -105,7 +104,7 @@ public class DotGraphVisitor extends AbstractVisitor {
+
(
useRegions
?
".regions"
:
""
)
+
(
rawInsn
?
".raw"
:
""
)
+
".dot"
;
dot
.
save
(
dir
,
Deobfuscator
.
instance
().
getClassFullPath
(
mth
.
getParentClass
().
getClassInfo
()
)
+
"_graphs"
,
fileName
);
dot
.
save
(
dir
,
mth
.
getParentClass
().
getClassInfo
().
getFullPath
(
)
+
"_graphs"
,
fileName
);
}
private
void
processMethodRegion
(
MethodNode
mth
)
{
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/IDexTreeVisitor.java
View file @
a532287d
...
...
@@ -2,6 +2,7 @@ package jadx.core.dex.visitors;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.core.dex.nodes.MethodNode
;
import
jadx.core.dex.nodes.RootNode
;
import
jadx.core.utils.exceptions.JadxException
;
/**
...
...
@@ -10,6 +11,11 @@ import jadx.core.utils.exceptions.JadxException;
public
interface
IDexTreeVisitor
{
/**
* Called after loading dex tree, but before visitor traversal.
*/
void
init
(
RootNode
root
)
throws
JadxException
;
/**
* Visit class
*
* @return false for disable child methods and inner classes traversal
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/RenameVisitor.java
0 → 100644
View file @
a532287d
package
jadx
.
core
.
dex
.
visitors
;
import
jadx.core.deobf.Deobfuscator
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.core.dex.nodes.RootNode
;
import
jadx.core.utils.exceptions.JadxException
;
import
java.io.File
;
import
org.apache.commons.io.FilenameUtils
;
public
class
RenameVisitor
extends
AbstractVisitor
{
private
Deobfuscator
deobfuscator
;
@Override
public
void
init
(
RootNode
root
)
{
String
firstInputFileName
=
root
.
getDexNodes
().
get
(
0
).
getInputFile
().
getFile
().
getAbsolutePath
();
String
inputPath
=
FilenameUtils
.
getFullPathNoEndSeparator
(
firstInputFileName
);
String
inputName
=
FilenameUtils
.
getBaseName
(
firstInputFileName
);
File
deobfMapFile
=
new
File
(
inputPath
,
inputName
+
".jobf"
);
deobfuscator
=
new
Deobfuscator
(
root
.
getArgs
(),
root
.
getDexNodes
(),
deobfMapFile
);
// TODO: check classes for case sensitive names (issue #24)
// TODO: sometimes can be used source file name from 'SourceFileAttr'
deobfuscator
.
execute
();
}
@Override
public
boolean
visit
(
ClassNode
cls
)
throws
JadxException
{
// TODO: rename fields and methods
return
false
;
}
}
jadx-core/src/main/java/jadx/core/dex/visitors/SaveCode.java
View file @
a532287d
...
...
@@ -2,7 +2,6 @@ package jadx.core.dex.visitors;
import
jadx.api.IJadxArgs
;
import
jadx.core.codegen.CodeWriter
;
import
jadx.core.deobf.Deobfuscator
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.core.utils.exceptions.CodegenException
;
...
...
@@ -25,7 +24,7 @@ public class SaveCode extends AbstractVisitor {
public
static
void
save
(
File
dir
,
IJadxArgs
args
,
ClassNode
cls
)
{
CodeWriter
clsCode
=
cls
.
getCode
();
String
fileName
=
Deobfuscator
.
instance
().
getClassFullPath
(
cls
.
getClassInfo
()
)
+
".java"
;
String
fileName
=
cls
.
getClassInfo
().
getFullPath
(
)
+
".java"
;
if
(
args
.
isFallbackMode
())
{
fileName
+=
".jadx"
;
}
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/SimplifyVisitor.java
View file @
a532287d
...
...
@@ -145,70 +145,70 @@ public class SimplifyVisitor extends AbstractVisitor {
}
private
static
InsnNode
convertInvoke
(
MethodNode
mth
,
InsnNode
insn
)
{
MethodInfo
callMth
=
((
InvokeNode
)
insn
).
getCallMth
();
MethodInfo
callMth
=
((
InvokeNode
)
insn
).
getCallMth
();
// If this is a 'new StringBuilder(xxx).append(yyy).append(zzz).toString(),
// convert it to STRING_CONCAT pseudo instruction.
if
(
callMth
.
getDeclClass
().
getFullName
().
equals
(
Consts
.
CLASS_STRING_BUILDER
)
&&
callMth
.
getShortId
().
equals
(
Consts
.
MTH_TOSTRING_SIGNATURE
)
&&
insn
.
getArg
(
0
).
isInsnWrap
())
{
try
{
List
<
InsnNode
>
chain
=
flattenInsnChain
(
insn
);
int
constrIndex
=
-
1
;
//RAF
// Case where new StringBuilder() is called with NO args (the entire
// string is created using .append() calls:
if
(
chain
.
size
()>
1
&&
chain
.
get
(
0
).
getType
()==
InsnType
.
CONSTRUCTOR
)
{
constrIndex
=
0
;
}
else
if
(
chain
.
size
()>
2
&&
chain
.
get
(
1
).
getType
()==
InsnType
.
CONSTRUCTOR
)
{
//RAF Case where the first string element is String arg to the
// new StringBuilder("xxx") constructor
constrIndex
=
1
;
}
else
if
(
chain
.
size
()>
3
&&
chain
.
get
(
2
).
getType
()==
InsnType
.
CONSTRUCTOR
)
{
//RAF Case where the first string element is String.valueOf() arg
// to the new StringBuilder(String.valueOf(zzz)) constructor
constrIndex
=
2
;
}
// If this is a 'new StringBuilder(xxx).append(yyy).append(zzz).toString(),
// convert it to STRING_CONCAT pseudo instruction.
if
(
callMth
.
getDeclClass
().
getFullName
().
equals
(
Consts
.
CLASS_STRING_BUILDER
)
&&
callMth
.
getShortId
().
equals
(
Consts
.
MTH_TOSTRING_SIGNATURE
)
&&
insn
.
getArg
(
0
).
isInsnWrap
())
{
try
{
List
<
InsnNode
>
chain
=
flattenInsnChain
(
insn
);
int
constrIndex
=
-
1
;
//RAF
// Case where new StringBuilder() is called with NO args (the entire
// string is created using .append() calls:
if
(
chain
.
size
()
>
1
&&
chain
.
get
(
0
).
getType
()
==
InsnType
.
CONSTRUCTOR
)
{
constrIndex
=
0
;
}
else
if
(
chain
.
size
()
>
2
&&
chain
.
get
(
1
).
getType
()
==
InsnType
.
CONSTRUCTOR
)
{
//RAF Case where the first string element is String arg to the
// new StringBuilder("xxx") constructor
constrIndex
=
1
;
}
else
if
(
chain
.
size
()
>
3
&&
chain
.
get
(
2
).
getType
()
==
InsnType
.
CONSTRUCTOR
)
{
//RAF Case where the first string element is String.valueOf() arg
// to the new StringBuilder(String.valueOf(zzz)) constructor
constrIndex
=
2
;
}
if
(
constrIndex
!=
-
1
)
{
// If we found a CONSTRUCTOR, is it a StringBuilder?
ConstructorInsn
constr
=
(
ConstructorInsn
)
chain
.
get
(
constrIndex
);
if
(
constr
.
getClassType
().
getFullName
().
equals
(
Consts
.
CLASS_STRING_BUILDER
))
{
int
len
=
chain
.
size
(),
argInd
=
1
;
InsnNode
concatInsn
=
new
InsnNode
(
InsnType
.
STR_CONCAT
,
len
-
1
);
InsnNode
argInsn
;
if
(
constrIndex
>
0
)
{
// There was an arg to the StringBuilder constr
InsnWrapArg
iwa
;
if
(
constrIndex
==
2
&&
(
argInsn
=
chain
.
get
(
1
)).
getType
()==
InsnType
.
INVOKE
&&
((
InvokeNode
)
argInsn
).
getCallMth
().
getName
().
compareTo
(
"valueOf"
)==
0
)
{
// The argument of new StringBuilder() is a String.valueOf(chainElement0)
iwa
=
(
InsnWrapArg
)
argInsn
.
getArg
(
0
);
argInd
=
3
;
// Cause for loop below to skip to after the constructor
}
else
{
InsnNode
firstNode
=
chain
.
get
(
0
);
if
(
firstNode
instanceof
ConstStringNode
)
{
ConstStringNode
csn
=
(
ConstStringNode
)
firstNode
;
iwa
=
new
InsnWrapArg
(
csn
);
argInd
=
2
;
// Cause for loop below to skip to after the constructor
}
else
{
return
null
;
}
}
concatInsn
.
addArg
(
iwa
);
}
if
(
constrIndex
!=
-
1
)
{
// If we found a CONSTRUCTOR, is it a StringBuilder?
ConstructorInsn
constr
=
(
ConstructorInsn
)
chain
.
get
(
constrIndex
);
if
(
constr
.
getClassType
().
getFullName
().
equals
(
Consts
.
CLASS_STRING_BUILDER
))
{
int
len
=
chain
.
size
(),
argInd
=
1
;
InsnNode
concatInsn
=
new
InsnNode
(
InsnType
.
STR_CONCAT
,
len
-
1
);
InsnNode
argInsn
;
if
(
constrIndex
>
0
)
{
// There was an arg to the StringBuilder constr
InsnWrapArg
iwa
;
if
(
constrIndex
==
2
&&
(
argInsn
=
chain
.
get
(
1
)).
getType
()
==
InsnType
.
INVOKE
&&
((
InvokeNode
)
argInsn
).
getCallMth
().
getName
().
compareTo
(
"valueOf"
)
==
0
)
{
// The argument of new StringBuilder() is a String.valueOf(chainElement0)
iwa
=
(
InsnWrapArg
)
argInsn
.
getArg
(
0
);
argInd
=
3
;
// Cause for loop below to skip to after the constructor
}
else
{
InsnNode
firstNode
=
chain
.
get
(
0
);
if
(
firstNode
instanceof
ConstStringNode
)
{
ConstStringNode
csn
=
(
ConstStringNode
)
firstNode
;
iwa
=
new
InsnWrapArg
(
csn
);
argInd
=
2
;
// Cause for loop below to skip to after the constructor
}
else
{
return
null
;
}
}
concatInsn
.
addArg
(
iwa
);
}
for
(;
argInd
<
len
;
argInd
++)
{
// Add the .append(xxx) arg string to concat
concatInsn
.
addArg
(
chain
.
get
(
argInd
).
getArg
(
1
));
}
concatInsn
.
setResult
(
insn
.
getResult
());
return
concatInsn
;
}
// end of if constructor is for StringBuilder
}
// end of if we found a constructor early in the chain
for
(;
argInd
<
len
;
argInd
++)
{
// Add the .append(xxx) arg string to concat
concatInsn
.
addArg
(
chain
.
get
(
argInd
).
getArg
(
1
));
}
concatInsn
.
setResult
(
insn
.
getResult
());
return
concatInsn
;
}
// end of if constructor is for StringBuilder
}
// end of if we found a constructor early in the chain
}
catch
(
Throwable
e
)
{
LOG
.
debug
(
"Can't convert string concatenation: {} insn: {}"
,
mth
,
insn
,
e
);
}
}
return
null
;
}
catch
(
Throwable
e
)
{
LOG
.
debug
(
"Can't convert string concatenation: {} insn: {}"
,
mth
,
insn
,
e
);
}
}
return
null
;
}
private
static
InsnNode
simplifyArith
(
InsnNode
insn
)
{
...
...
jadx-core/src/main/java/jadx/core/xmlgen/ParserStream.java
View file @
a532287d
...
...
@@ -4,6 +4,8 @@ import java.io.IOException;
import
java.io.InputStream
;
import
java.nio.charset.Charset
;
import
org.jetbrains.annotations.NotNull
;
public
class
ParserStream
{
protected
static
final
Charset
STRING_CHARSET_UTF16
=
Charset
.
forName
(
"UTF-16LE"
);
...
...
@@ -15,7 +17,7 @@ public class ParserStream {
private
final
InputStream
input
;
private
long
readPos
=
0
;
public
ParserStream
(
InputStream
inputStream
)
{
public
ParserStream
(
@NotNull
InputStream
inputStream
)
{
this
.
input
=
inputStream
;
}
...
...
jadx-core/src/test/java/jadx/tests/api/SmaliTest.java
View file @
a532287d
package
jadx
.
tests
.
api
;
import
jadx.core.Consts
;
import
jadx.core.dex.nodes.ClassNode
;
import
java.io.File
;
...
...
@@ -21,8 +20,7 @@ public class SmaliTest extends IntegrationTest {
File
smaliFile
=
getSmaliFile
(
clsName
);
File
outDex
=
createTempFile
(
".dex"
);
compileSmali
(
smaliFile
,
outDex
);
String
fullClsName
=
Consts
.
DEFAULT_PACKAGE_NAME
+
"."
+
clsName
;
return
getClassNodeFromFile
(
outDex
,
fullClsName
);
return
getClassNodeFromFile
(
outDex
,
clsName
);
}
private
static
File
getSmaliFile
(
String
clsName
)
{
...
...
jadx-core/src/test/java/jadx/tests/integration/switches/TestSwitchReturnFromCase.java
View file @
a532287d
...
...
@@ -12,42 +12,42 @@ import static org.junit.Assert.assertThat;
public
class
TestSwitchReturnFromCase
extends
IntegrationTest
{
public
static
class
TestCls
{
public
void
test
(
int
a
)
{
String
s
=
null
;
if
(
a
>
1000
)
{
return
;
}
switch
(
a
%
4
)
{
case
1
:
s
=
"1"
;
break
;
case
2
:
s
=
"2"
;
break
;
case
3
:
case
4
:
s
=
"4"
;
break
;
case
5
:
return
;
}
s
=
"5"
;
}
}
@Test
public
void
test
()
{
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
String
code
=
cls
.
getCode
().
toString
();
assertThat
(
code
,
containsString
(
"switch (a % 4) {"
));
assertEquals
(
5
,
count
(
code
,
"case "
));
assertEquals
(
3
,
count
(
code
,
"break;"
));
assertThat
(
code
,
containsOne
(
"s = \"1\";"
));
assertThat
(
code
,
containsOne
(
"s = \"2\";"
));
assertThat
(
code
,
containsOne
(
"s = \"4\";"
));
assertThat
(
code
,
containsOne
(
"s = \"5\";"
));
}
public
static
class
TestCls
{
public
void
test
(
int
a
)
{
String
s
=
null
;
if
(
a
>
1000
)
{
return
;
}
switch
(
a
%
4
)
{
case
1
:
s
=
"1"
;
break
;
case
2
:
s
=
"2"
;
break
;
case
3
:
case
4
:
s
=
"4"
;
break
;
case
5
:
return
;
}
s
=
"5"
;
}
}
@Test
public
void
test
()
{
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
String
code
=
cls
.
getCode
().
toString
();
assertThat
(
code
,
containsString
(
"switch (a % 4) {"
));
assertEquals
(
5
,
count
(
code
,
"case "
));
assertEquals
(
3
,
count
(
code
,
"break;"
));
assertThat
(
code
,
containsOne
(
"s = \"1\";"
));
assertThat
(
code
,
containsOne
(
"s = \"2\";"
));
assertThat
(
code
,
containsOne
(
"s = \"4\";"
));
assertThat
(
code
,
containsOne
(
"s = \"5\";"
));
}
}
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