Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
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
6ddb71e2
Commit
6ddb71e2
authored
Aug 01, 2013
by
Skylot
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
core: add classpath for precise class types resolving
parent
d0f120c3
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
618 additions
and
82 deletions
+618
-82
.gitignore
.gitignore
+2
-1
build.gradle
build.gradle
+0
-1
build.gradle
jadx-core/build.gradle
+5
-0
android-4.3.jar
jadx-core/clsp-data/android-4.3.jar
+0
-0
Decompiler.java
jadx-core/src/main/java/jadx/api/Decompiler.java
+6
-6
ClsSet.java
jadx-core/src/main/java/jadx/core/clsp/ClsSet.java
+218
-0
ClspGraph.java
jadx-core/src/main/java/jadx/core/clsp/ClspGraph.java
+115
-0
ConvertToClsSet.java
jadx-core/src/main/java/jadx/core/clsp/ConvertToClsSet.java
+67
-0
NClass.java
jadx-core/src/main/java/jadx/core/clsp/NClass.java
+55
-0
CodeWriter.java
jadx-core/src/main/java/jadx/core/codegen/CodeWriter.java
+2
-11
MethodGen.java
jadx-core/src/main/java/jadx/core/codegen/MethodGen.java
+5
-1
ClassInfo.java
jadx-core/src/main/java/jadx/core/dex/info/ClassInfo.java
+4
-0
ArgType.java
...rc/main/java/jadx/core/dex/instructions/args/ArgType.java
+25
-19
ClassNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
+5
-1
RootNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java
+40
-33
Utils.java
jadx-core/src/main/java/jadx/core/utils/Utils.java
+13
-0
TypeMergeTest.java
jadx-core/src/test/java/jadx/tests/TypeMergeTest.java
+32
-7
build.gradle
jadx-gui/build.gradle
+1
-0
Utils.java
jadx-gui/src/main/java/jadx/gui/utils/Utils.java
+3
-0
TestTryCatch.java
jadx-samples/src/main/java/jadx/samples/TestTryCatch.java
+20
-2
No files found.
.gitignore
View file @
6ddb71e2
...
...
@@ -17,8 +17,9 @@ idea/
.gradle/
gradle.properties
*-tmp/
*.dex
*.jar
*.class
*.dump
*.log
...
...
build.gradle
View file @
6ddb71e2
...
...
@@ -20,7 +20,6 @@ subprojects {
dependencies
{
compile
'org.slf4j:slf4j-api:1.7.5'
compile
'ch.qos.logback:logback-classic:1.0.13'
testCompile
'junit:junit:4.11'
}
...
...
jadx-core/build.gradle
View file @
6ddb71e2
ext
.
jadxClasspath
=
'clsp-data/android-4.3.jar'
dependencies
{
compile
'com.google.android.tools:dx:1.7'
compile
'ch.qos.logback:logback-classic:1.0.13'
runtime
files
(
jadxClasspath
)
}
jadx-core/clsp-data/android-4.3.jar
0 → 100644
View file @
6ddb71e2
File added
jadx-core/src/main/java/jadx/api/Decompiler.java
View file @
6ddb71e2
...
...
@@ -64,8 +64,9 @@ public final class Decompiler {
}
public
List
<
JavaClass
>
getClasses
()
{
List
<
JavaClass
>
classes
=
new
ArrayList
<
JavaClass
>(
root
.
getClasses
().
size
());
for
(
ClassNode
classNode
:
root
.
getClasses
())
{
List
<
ClassNode
>
classNodeList
=
root
.
getClasses
(
false
);
List
<
JavaClass
>
classes
=
new
ArrayList
<
JavaClass
>(
classNodeList
.
size
());
for
(
ClassNode
classNode
:
classNodeList
)
{
classes
.
add
(
new
JavaClass
(
this
,
classNode
));
}
return
Collections
.
unmodifiableList
(
classes
);
...
...
@@ -101,7 +102,7 @@ public final class Decompiler {
LOG
.
info
(
"processing ..."
);
ThreadPoolExecutor
executor
=
(
ThreadPoolExecutor
)
Executors
.
newFixedThreadPool
(
threadsCount
);
for
(
ClassNode
cls
:
root
.
getClasses
())
{
for
(
ClassNode
cls
:
root
.
getClasses
(
false
))
{
if
(
cls
.
getCode
()
==
null
)
{
ProcessClass
job
=
new
ProcessClass
(
cls
,
passList
);
executor
.
execute
(
job
);
...
...
@@ -133,10 +134,9 @@ public final class Decompiler {
ClassInfo
.
clearCache
();
ErrorsCounter
.
reset
();
root
=
new
RootNode
(
args
,
inputFiles
);
root
=
new
RootNode
();
LOG
.
info
(
"loading ..."
);
root
.
load
();
root
.
init
();
root
.
load
(
inputFiles
);
}
void
processClass
(
ClassNode
cls
)
{
...
...
jadx-core/src/main/java/jadx/core/clsp/ClsSet.java
0 → 100644
View file @
6ddb71e2
package
jadx
.
core
.
clsp
;
import
jadx.core.dex.info.ClassInfo
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.core.dex.nodes.RootNode
;
import
jadx.core.utils.Utils
;
import
jadx.core.utils.exceptions.DecodeException
;
import
java.io.BufferedOutputStream
;
import
java.io.DataInputStream
;
import
java.io.DataOutputStream
;
import
java.io.File
;
import
java.io.FileInputStream
;
import
java.io.FileOutputStream
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.zip.ZipEntry
;
import
java.util.zip.ZipInputStream
;
import
java.util.zip.ZipOutputStream
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
/**
* Classes list for import into classpath graph
*/
public
class
ClsSet
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
ClsSet
.
class
);
private
static
final
String
CLST_EXTENSION
=
".jcst"
;
private
static
final
String
CLST_FILENAME
=
"core"
+
CLST_EXTENSION
;
private
static
final
String
CLST_PKG_PATH
=
ClsSet
.
class
.
getPackage
().
getName
().
replace
(
'.'
,
'/'
);
private
static
final
String
JADX_CLS_SET_HEADER
=
"jadx-cst"
;
private
static
final
int
VERSION
=
1
;
private
NClass
[]
classes
;
public
void
load
(
RootNode
root
)
{
List
<
ClassNode
>
list
=
root
.
getClasses
(
true
);
Map
<
String
,
NClass
>
names
=
new
HashMap
<
String
,
NClass
>(
list
.
size
());
int
k
=
0
;
for
(
ClassNode
cls
:
list
)
{
String
clsRawName
=
cls
.
getRawName
();
if
(
cls
.
getAccessFlags
().
isPublic
())
{
NClass
nClass
=
new
NClass
(
clsRawName
,
k
);
if
(
names
.
put
(
clsRawName
,
nClass
)
!=
null
)
{
throw
new
RuntimeException
(
"Duplicate class: "
+
clsRawName
);
}
k
++;
}
else
{
names
.
put
(
clsRawName
,
null
);
}
}
classes
=
new
NClass
[
k
];
k
=
0
;
for
(
ClassNode
cls
:
list
)
{
if
(
cls
.
getAccessFlags
().
isPublic
())
{
NClass
nClass
=
getCls
(
cls
.
getRawName
(),
names
);
nClass
.
setParents
(
makeParentsArray
(
cls
,
names
));
classes
[
k
]
=
nClass
;
k
++;
}
}
}
public
static
NClass
[]
makeParentsArray
(
ClassNode
cls
,
Map
<
String
,
NClass
>
names
)
{
List
<
NClass
>
parents
=
new
ArrayList
<
NClass
>(
1
+
cls
.
getInterfaces
().
size
());
ClassInfo
superClass
=
cls
.
getSuperClass
();
if
(
superClass
!=
null
)
{
NClass
c
=
getCls
(
superClass
.
getRawName
(),
names
);
if
(
c
!=
null
)
{
parents
.
add
(
c
);
}
}
for
(
ClassInfo
iface
:
cls
.
getInterfaces
())
{
NClass
c
=
getCls
(
iface
.
getRawName
(),
names
);
if
(
c
!=
null
)
{
parents
.
add
(
c
);
}
}
return
parents
.
toArray
(
new
NClass
[
parents
.
size
()]);
}
private
static
NClass
getCls
(
String
fullName
,
Map
<
String
,
NClass
>
names
)
{
NClass
id
=
names
.
get
(
fullName
);
if
(
id
==
null
&&
!
names
.
containsKey
(
fullName
))
{
LOG
.
warn
(
"Class not found: "
+
fullName
);
}
return
id
;
}
void
save
(
File
output
)
throws
IOException
{
Utils
.
makeDirsForFile
(
output
);
BufferedOutputStream
outputStream
=
new
BufferedOutputStream
(
new
FileOutputStream
(
output
));
String
outputName
=
output
.
getName
();
if
(
outputName
.
endsWith
(
CLST_EXTENSION
))
{
save
(
outputStream
);
}
else
if
(
outputName
.
endsWith
(
".jar"
))
{
ZipOutputStream
out
=
new
ZipOutputStream
(
outputStream
);
try
{
out
.
putNextEntry
(
new
ZipEntry
(
CLST_PKG_PATH
+
"/"
+
CLST_FILENAME
));
save
(
out
);
out
.
closeEntry
();
}
finally
{
out
.
close
();
outputStream
.
close
();
}
}
else
{
throw
new
RuntimeException
(
"Unknown file format: "
+
outputName
);
}
}
public
void
save
(
OutputStream
output
)
throws
IOException
{
DataOutputStream
out
=
new
DataOutputStream
(
output
);
out
.
writeBytes
(
JADX_CLS_SET_HEADER
);
out
.
writeByte
(
VERSION
);
LOG
.
info
(
"Classes count: "
+
classes
.
length
);
out
.
writeInt
(
classes
.
length
);
for
(
NClass
cls
:
classes
)
{
writeString
(
out
,
cls
.
getName
());
}
for
(
NClass
cls
:
classes
)
{
NClass
[]
parents
=
cls
.
getParents
();
out
.
writeByte
(
parents
.
length
);
for
(
NClass
parent
:
parents
)
{
out
.
writeInt
(
parent
.
getId
());
}
}
}
public
void
load
()
throws
IOException
,
DecodeException
{
InputStream
input
=
getClass
().
getResourceAsStream
(
CLST_FILENAME
);
if
(
input
==
null
)
{
throw
new
RuntimeException
(
"Can't load classpath file: "
+
CLST_FILENAME
);
}
load
(
input
);
}
public
void
load
(
File
input
)
throws
IOException
,
DecodeException
{
String
name
=
input
.
getName
();
InputStream
inputStream
=
new
FileInputStream
(
input
);
if
(
name
.
endsWith
(
CLST_EXTENSION
))
{
load
(
inputStream
);
}
else
if
(
name
.
endsWith
(
".jar"
))
{
ZipInputStream
in
=
new
ZipInputStream
(
inputStream
);
try
{
ZipEntry
entry
=
in
.
getNextEntry
();
while
(
entry
!=
null
)
{
if
(
entry
.
getName
().
endsWith
(
CLST_EXTENSION
))
{
load
(
in
);
}
entry
=
in
.
getNextEntry
();
}
}
finally
{
in
.
close
();
}
}
else
{
throw
new
RuntimeException
(
"Unknown file format: "
+
name
);
}
}
public
void
load
(
InputStream
input
)
throws
IOException
,
DecodeException
{
DataInputStream
in
=
new
DataInputStream
(
input
);
byte
[]
header
=
new
byte
[
JADX_CLS_SET_HEADER
.
length
()];
in
.
read
(
header
);
int
version
=
in
.
readByte
();
if
(!
JADX_CLS_SET_HEADER
.
equals
(
new
String
(
header
))
||
version
!=
VERSION
)
{
throw
new
DecodeException
(
"Wrong jadx class set header"
);
}
int
count
=
in
.
readInt
();
classes
=
new
NClass
[
count
];
for
(
int
i
=
0
;
i
<
count
;
i
++)
{
String
name
=
readString
(
in
);
classes
[
i
]
=
new
NClass
(
name
,
i
);
}
for
(
int
i
=
0
;
i
<
count
;
i
++)
{
int
pCount
=
in
.
readByte
();
NClass
[]
parents
=
new
NClass
[
pCount
];
for
(
int
j
=
0
;
j
<
pCount
;
j
++)
{
parents
[
j
]
=
classes
[
in
.
readInt
()];
}
classes
[
i
].
setParents
(
parents
);
}
}
private
void
writeString
(
DataOutputStream
out
,
String
name
)
throws
IOException
{
byte
[]
bytes
=
name
.
getBytes
();
out
.
writeByte
(
bytes
.
length
);
out
.
write
(
bytes
);
}
private
static
String
readString
(
DataInputStream
in
)
throws
IOException
{
int
len
=
in
.
readByte
();
byte
[]
bytes
=
new
byte
[
len
];
int
count
=
in
.
read
(
bytes
);
while
(
count
!=
len
)
{
int
res
=
in
.
read
(
bytes
,
count
,
len
-
count
);
if
(
res
==
-
1
)
{
throw
new
IOException
(
"String read error"
);
}
else
{
count
+=
res
;
}
}
return
new
String
(
bytes
);
}
public
NClass
[]
getClasses
()
{
return
classes
;
}
}
jadx-core/src/main/java/jadx/core/clsp/ClspGraph.java
0 → 100644
View file @
6ddb71e2
package
jadx
.
core
.
clsp
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.core.utils.exceptions.DecodeException
;
import
java.io.IOException
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.WeakHashMap
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
/**
* Classes hierarchy graph
*/
public
class
ClspGraph
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
ClspGraph
.
class
);
private
Map
<
String
,
NClass
>
nameMap
;
private
Map
<
String
,
Set
<
String
>>
ancestorCache
=
new
WeakHashMap
<
String
,
Set
<
String
>>();
public
void
load
()
throws
IOException
,
DecodeException
{
ClsSet
set
=
new
ClsSet
();
set
.
load
();
addClasspath
(
set
);
}
public
void
addClasspath
(
ClsSet
set
)
{
NClass
[]
arr
=
set
.
getClasses
();
if
(
nameMap
==
null
)
{
nameMap
=
new
HashMap
<
String
,
NClass
>(
arr
.
length
);
for
(
NClass
cls
:
arr
)
{
nameMap
.
put
(
cls
.
getName
(),
cls
);
}
}
else
{
throw
new
RuntimeException
(
"Classpath already loaded"
);
}
}
public
void
addApp
(
List
<
ClassNode
>
classes
)
{
if
(
nameMap
==
null
)
{
throw
new
RuntimeException
(
"Classpath must be loaded first"
);
}
int
size
=
classes
.
size
();
NClass
[]
nClasses
=
new
NClass
[
size
];
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
ClassNode
cls
=
classes
.
get
(
i
);
NClass
nClass
=
new
NClass
(
cls
.
getRawName
(),
-
1
);
nClasses
[
i
]
=
nClass
;
nameMap
.
put
(
cls
.
getRawName
(),
nClass
);
}
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
nClasses
[
i
].
setParents
(
ClsSet
.
makeParentsArray
(
classes
.
get
(
i
),
nameMap
));
}
}
public
boolean
isImplements
(
String
clsName
,
String
implClsName
)
{
Set
<
String
>
anc
=
getAncestors
(
clsName
);
return
anc
.
contains
(
implClsName
);
}
public
String
getCommonAncestor
(
String
clsName
,
String
implClsName
)
{
if
(
isImplements
(
clsName
,
implClsName
))
{
return
implClsName
;
}
Set
<
String
>
anc
=
getAncestors
(
clsName
);
NClass
cls
=
nameMap
.
get
(
implClsName
);
if
(
cls
!=
null
)
{
return
searchCommonParent
(
anc
,
cls
);
}
else
{
LOG
.
debug
(
"Missing class: {}"
,
implClsName
);
return
null
;
}
}
private
String
searchCommonParent
(
Set
<
String
>
anc
,
NClass
cls
)
{
for
(
NClass
p
:
cls
.
getParents
())
{
String
name
=
p
.
getName
();
if
(
anc
.
contains
(
name
))
{
return
name
;
}
else
{
String
r
=
searchCommonParent
(
anc
,
p
);
if
(
r
!=
null
)
return
r
;
}
}
return
null
;
}
private
Set
<
String
>
getAncestors
(
String
clsName
)
{
Set
<
String
>
result
=
ancestorCache
.
get
(
clsName
);
if
(
result
==
null
)
{
result
=
new
HashSet
<
String
>();
ancestorCache
.
put
(
clsName
,
result
);
NClass
cls
=
nameMap
.
get
(
clsName
);
if
(
cls
!=
null
)
{
addAncestorsNames
(
cls
,
result
);
}
else
{
LOG
.
debug
(
"Missing class: {}"
,
clsName
);
}
}
return
result
;
}
private
void
addAncestorsNames
(
NClass
cls
,
Set
<
String
>
result
)
{
result
.
add
(
cls
.
getName
());
for
(
NClass
p
:
cls
.
getParents
())
{
addAncestorsNames
(
p
,
result
);
}
}
}
jadx-core/src/main/java/jadx/core/clsp/ConvertToClsSet.java
0 → 100644
View file @
6ddb71e2
package
jadx
.
core
.
clsp
;
import
jadx.core.dex.nodes.RootNode
;
import
jadx.core.utils.exceptions.DecodeException
;
import
jadx.core.utils.files.InputFile
;
import
java.io.File
;
import
java.io.IOException
;
import
java.util.ArrayList
;
import
java.util.List
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
/**
* Utility class for convert dex or jar to jadx classes set (.jcst)
*/
public
class
ConvertToClsSet
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
ConvertToClsSet
.
class
);
public
static
void
usage
()
{
LOG
.
info
(
"<output .jcst or .jar file> <several input dex or jar files> "
);
}
public
static
void
main
(
String
[]
args
)
throws
IOException
,
DecodeException
{
if
(
args
.
length
<
2
)
{
usage
();
System
.
exit
(
1
);
}
File
output
=
new
File
(
args
[
0
]);
List
<
InputFile
>
inputFiles
=
new
ArrayList
<
InputFile
>(
args
.
length
-
1
);
for
(
int
i
=
1
;
i
<
args
.
length
;
i
++)
{
File
f
=
new
File
(
args
[
i
]);
if
(
f
.
isDirectory
())
{
addFilesFromDirectory
(
f
,
inputFiles
);
}
else
{
inputFiles
.
add
(
new
InputFile
(
f
));
}
}
for
(
InputFile
inputFile
:
inputFiles
)
{
LOG
.
info
(
"Loaded: "
+
inputFile
.
getFile
());
}
RootNode
root
=
new
RootNode
();
root
.
load
(
inputFiles
);
ClsSet
set
=
new
ClsSet
();
set
.
load
(
root
);
set
.
save
(
output
);
LOG
.
info
(
"Output: "
+
output
);
LOG
.
info
(
"done"
);
}
private
static
void
addFilesFromDirectory
(
File
dir
,
List
<
InputFile
>
inputFiles
)
throws
IOException
,
DecodeException
{
File
[]
files
=
dir
.
listFiles
();
for
(
File
file
:
files
)
{
if
(
file
.
isDirectory
())
{
addFilesFromDirectory
(
file
,
inputFiles
);
}
if
(
file
.
getName
().
endsWith
(
".dex"
))
{
inputFiles
.
add
(
new
InputFile
(
file
));
}
}
}
}
jadx-core/src/main/java/jadx/core/clsp/NClass.java
0 → 100644
View file @
6ddb71e2
package
jadx
.
core
.
clsp
;
/**
* Class node in classpath graph
*/
public
class
NClass
{
private
final
String
name
;
private
NClass
[]
parents
;
private
int
id
;
public
NClass
(
String
name
,
int
id
)
{
this
.
name
=
name
;
this
.
id
=
id
;
}
public
String
getName
()
{
return
name
;
}
public
int
getId
()
{
return
id
;
}
public
void
setId
(
int
id
)
{
this
.
id
=
id
;
}
public
NClass
[]
getParents
()
{
return
parents
;
}
public
void
setParents
(
NClass
[]
parents
)
{
this
.
parents
=
parents
;
}
@Override
public
int
hashCode
()
{
return
name
.
hashCode
();
}
@Override
public
boolean
equals
(
Object
o
)
{
if
(
this
==
o
)
return
true
;
if
(
o
==
null
||
getClass
()
!=
o
.
getClass
())
return
false
;
NClass
nClass
=
(
NClass
)
o
;
if
(!
name
.
equals
(
nClass
.
name
))
return
false
;
return
true
;
}
@Override
public
String
toString
()
{
return
name
;
}
}
jadx-core/src/main/java/jadx/core/codegen/CodeWriter.java
View file @
6ddb71e2
package
jadx
.
core
.
codegen
;
import
jadx.core.dex.attributes.LineAttrNode
;
import
jadx.core.utils.
exceptions.JadxRuntimeException
;
import
jadx.core.utils.
Utils
;
import
java.io.File
;
import
java.io.PrintWriter
;
...
...
@@ -214,7 +214,7 @@ public class CodeWriter {
PrintWriter
out
=
null
;
try
{
makeDirsForFile
(
file
);
Utils
.
makeDirsForFile
(
file
);
out
=
new
PrintWriter
(
file
,
"UTF-8"
);
String
code
=
buf
.
toString
();
code
=
removeFirstEmptyLine
(
code
);
...
...
@@ -227,13 +227,4 @@ public class CodeWriter {
}
}
private
void
makeDirsForFile
(
File
file
)
{
File
dir
=
file
.
getParentFile
();
if
(!
dir
.
exists
())
{
// if directory already created in other thread mkdirs will return false,
// so check dir existence again
if
(!
dir
.
mkdirs
()
&&
!
dir
.
exists
())
throw
new
JadxRuntimeException
(
"Can't create directory "
+
dir
);
}
}
}
jadx-core/src/main/java/jadx/core/codegen/MethodGen.java
View file @
6ddb71e2
...
...
@@ -172,7 +172,11 @@ public class MethodGen {
else
return
name
;
}
else
{
return
base
+
"_"
+
Utils
.
escape
(
TypeGen
.
translate
(
classGen
,
arg
.
getType
()));
ArgType
type
=
arg
.
getType
();
if
(
type
.
isPrimitive
())
return
base
+
type
.
getPrimitiveType
().
getShortName
().
toLowerCase
();
else
return
base
+
"_"
+
Utils
.
escape
(
TypeGen
.
translate
(
classGen
,
arg
.
getType
()));
}
}
}
...
...
jadx-core/src/main/java/jadx/core/dex/info/ClassInfo.java
View file @
6ddb71e2
...
...
@@ -105,6 +105,10 @@ public final class ClassInfo {
return
name
;
}
public
String
getRawName
()
{
return
type
.
getObject
();
}
public
String
getPackage
()
{
return
pkg
;
}
...
...
jadx-core/src/main/java/jadx/core/dex/instructions/args/ArgType.java
View file @
6ddb71e2
package
jadx
.
core
.
dex
.
instructions
.
args
;
import
jadx.core.Consts
;
import
jadx.core.clsp.ClspGraph
;
import
jadx.core.utils.Utils
;
import
java.util.ArrayList
;
...
...
@@ -43,6 +44,16 @@ public abstract class ArgType {
protected
int
hash
;
private
static
ClspGraph
clsp
;
public
static
ClspGraph
getClsp
()
{
return
clsp
;
}
public
static
void
setClsp
(
ClspGraph
clsp
)
{
ArgType
.
clsp
=
clsp
;
}
private
static
ArgType
primitive
(
PrimitiveType
stype
)
{
return
new
PrimitiveArg
(
stype
);
}
...
...
@@ -344,35 +355,30 @@ public abstract class ArgType {
}
}
}
else
{
if
(
a
.
isGenericType
())
return
a
;
if
(
b
.
isGenericType
())
return
b
;
if
(
a
.
isGenericType
())
return
a
;
if
(
b
.
isGenericType
())
return
b
;
if
(
a
.
isObject
()
&&
b
.
isObject
())
{
if
(
a
.
getObject
().
equals
(
b
.
getObject
()))
{
if
(
a
.
getGenericTypes
()
!=
null
)
return
a
;
else
return
b
;
}
else
if
(
a
.
getObject
().
equals
(
OBJECT
.
getObject
()))
String
aObj
=
a
.
getObject
();
String
bObj
=
b
.
getObject
();
if
(
aObj
.
equals
(
bObj
))
{
return
(
a
.
getGenericTypes
()
!=
null
?
a
:
b
);
}
else
if
(
aObj
.
equals
(
Consts
.
CLASS_OBJECT
))
{
return
b
;
else
if
(
b
.
getObject
().
equals
(
OBJECT
.
getObject
()))
}
else
if
(
bObj
.
equals
(
Consts
.
CLASS_OBJECT
))
{
return
a
;
else
}
else
{
// different objects
return
null
;
String
obj
=
clsp
.
getCommonAncestor
(
aObj
,
bObj
);
return
(
obj
==
null
?
null
:
object
(
obj
));
}
}
if
(
a
.
isArray
()
&&
b
.
isArray
())
{
ArgType
res
=
merge
(
a
.
getArrayElement
(),
b
.
getArrayElement
());
return
(
res
==
null
?
null
:
ArgType
.
array
(
res
));
}
if
(
a
.
isPrimitive
()
&&
b
.
isPrimitive
())
{
if
(
a
.
getRegCount
()
==
b
.
getRegCount
())
// return primitive(PrimitiveType.getWidest(a.getPrimitiveType(), b.getPrimitiveType()));
return
primitive
(
PrimitiveType
.
getSmaller
(
a
.
getPrimitiveType
(),
b
.
getPrimitiveType
()));
if
(
a
.
isPrimitive
()
&&
b
.
isPrimitive
()
&&
a
.
getRegCount
()
==
b
.
getRegCount
())
{
return
primitive
(
PrimitiveType
.
getSmaller
(
a
.
getPrimitiveType
(),
b
.
getPrimitiveType
()));
}
}
return
null
;
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
View file @
6ddb71e2
...
...
@@ -240,7 +240,7 @@ public class ClassNode extends LineAttrNode implements ILoadable {
public
FieldNode
getConstField
(
Object
o
)
{
FieldNode
field
=
constFields
.
get
(
o
);
if
(
field
==
null
)
if
(
field
==
null
)
field
=
dex
.
getConstFields
().
get
(
o
);
return
field
;
}
...
...
@@ -329,6 +329,10 @@ public class ClassNode extends LineAttrNode implements ILoadable {
return
clsInfo
.
getPackage
();
}
public
String
getRawName
()
{
return
clsInfo
.
getRawName
();
}
public
void
setCode
(
CodeWriter
code
)
{
this
.
code
=
code
;
}
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java
View file @
6ddb71e2
package
jadx
.
core
.
dex
.
nodes
;
import
jadx.
api.IJadxArgs
;
import
jadx.
core.clsp.ClspGraph
;
import
jadx.core.dex.info.ClassInfo
;
import
jadx.core.dex.instructions.args.ArgType
;
import
jadx.core.utils.exceptions.DecodeException
;
import
jadx.core.utils.files.InputFile
;
import
java.io.IOException
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
public
class
RootNode
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
RootNode
.
class
);
private
final
IJadxArgs
args
;
private
final
List
<
InputFile
>
dexFiles
;
private
List
<
DexNode
>
dexNodes
;
private
final
List
<
ClassNode
>
classes
=
new
ArrayList
<
ClassNode
>();
private
final
Map
<
String
,
ClassNode
>
names
=
new
HashMap
<
String
,
ClassNode
>();
private
List
<
DexNode
>
dexNodes
;
private
ClspGraph
clsp
;
public
RootNode
(
IJadxArgs
args
,
List
<
InputFile
>
dexFiles
)
{
this
.
args
=
args
;
this
.
dexFiles
=
dexFiles
;
}
public
void
load
()
throws
DecodeException
{
public
void
load
(
List
<
InputFile
>
dexFiles
)
throws
DecodeException
{
dexNodes
=
new
ArrayList
<
DexNode
>(
dexFiles
.
size
());
for
(
InputFile
dex
:
dexFiles
)
{
DexNode
dexNode
;
...
...
@@ -39,37 +28,63 @@ public class RootNode {
}
dexNodes
.
add
(
dexNode
);
}
for
(
DexNode
dexNode
:
dexNodes
)
for
(
DexNode
dexNode
:
dexNodes
)
{
dexNode
.
loadClasses
();
}
List
<
ClassNode
>
classes
=
new
ArrayList
<
ClassNode
>();
for
(
DexNode
dexNode
:
dexNodes
)
{
for
(
ClassNode
cls
:
dexNode
.
getClasses
())
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
);
}
private
void
initClassPath
(
List
<
ClassNode
>
classes
)
throws
IOException
,
DecodeException
{
clsp
=
new
ClspGraph
();
clsp
.
load
();
clsp
.
addApp
(
classes
);
ArgType
.
setClsp
(
clsp
);
}
p
ublic
void
init
(
)
{
p
rivate
void
initInnerClasses
(
List
<
ClassNode
>
classes
)
{
// move inner classes
List
<
ClassNode
>
inner
=
new
ArrayList
<
ClassNode
>();
for
(
ClassNode
cls
:
getClasses
()
)
{
for
(
ClassNode
cls
:
classes
)
{
if
(
cls
.
getClassInfo
().
isInner
())
inner
.
add
(
cls
);
}
for
(
ClassNode
cls
:
inner
)
{
ClassNode
parent
=
resolveClass
(
cls
.
getClassInfo
().
getParentClass
());
if
(
parent
==
null
)
{
cls
.
getClassInfo
().
notInner
();
}
else
{
parent
.
addInnerClass
(
cls
);
getClasses
().
remove
(
cls
);
}
}
}
public
List
<
ClassNode
>
getClasses
()
{
public
List
<
ClassNode
>
getClasses
(
boolean
includeInner
)
{
List
<
ClassNode
>
classes
=
new
ArrayList
<
ClassNode
>();
for
(
DexNode
dexNode
:
dexNodes
)
{
for
(
ClassNode
cls
:
dexNode
.
getClasses
())
{
if
(
includeInner
)
{
classes
.
add
(
cls
);
}
else
{
if
(!
cls
.
getClassInfo
().
isInner
())
classes
.
add
(
cls
);
}
}
}
return
classes
;
}
...
...
@@ -82,12 +97,4 @@ public class RootNode {
ClassNode
rCls
=
searchClassByName
(
fullName
);
return
rCls
;
}
public
List
<
DexNode
>
getDexNodes
()
{
return
dexNodes
;
}
public
IJadxArgs
getJadxArgs
()
{
return
args
;
}
}
jadx-core/src/main/java/jadx/core/utils/Utils.java
View file @
6ddb71e2
package
jadx
.
core
.
utils
;
import
jadx.core.utils.exceptions.JadxRuntimeException
;
import
java.io.File
;
import
java.io.IOException
;
import
java.io.PrintWriter
;
import
java.io.StringWriter
;
...
...
@@ -138,4 +141,14 @@ public class Utils {
}
return
"dev"
;
}
public
static
void
makeDirsForFile
(
File
file
)
{
File
dir
=
file
.
getParentFile
();
if
(!
dir
.
exists
())
{
// if directory already created in other thread mkdirs will return false,
// so check dir existence again
if
(!
dir
.
mkdirs
()
&&
!
dir
.
exists
())
throw
new
JadxRuntimeException
(
"Can't create directory "
+
dir
);
}
}
}
jadx-core/src/test/java/jadx/tests/TypeMergeTest.java
View file @
6ddb71e2
package
jadx
.
tests
;
import
jadx.core.clsp.ClspGraph
;
import
jadx.core.dex.instructions.args.ArgType
;
import
jadx.core.dex.instructions.args.PrimitiveType
;
import
jadx.core.utils.exceptions.DecodeException
;
import
junit.framework.TestCase
;
import
java.io.IOException
;
import
static
jadx
.
core
.
dex
.
instructions
.
args
.
ArgType
.
BOOLEAN
;
import
static
jadx
.
core
.
dex
.
instructions
.
args
.
ArgType
.
CHAR
;
import
static
jadx
.
core
.
dex
.
instructions
.
args
.
ArgType
.
INT
;
...
...
@@ -12,12 +16,21 @@ import static jadx.core.dex.instructions.args.ArgType.NARROW;
import
static
jadx
.
core
.
dex
.
instructions
.
args
.
ArgType
.
OBJECT
;
import
static
jadx
.
core
.
dex
.
instructions
.
args
.
ArgType
.
UNKNOWN
;
import
static
jadx
.
core
.
dex
.
instructions
.
args
.
ArgType
.
UNKNOWN_OBJECT
;
import
static
jadx
.
core
.
dex
.
instructions
.
args
.
ArgType
.
genericType
;
import
static
jadx
.
core
.
dex
.
instructions
.
args
.
ArgType
.
object
;
import
static
jadx
.
core
.
dex
.
instructions
.
args
.
ArgType
.
unknown
;
public
class
TypeMergeTest
extends
TestCase
{
public
void
testMerge
()
{
private
void
initClsp
()
throws
IOException
,
DecodeException
{
ClspGraph
clsp
=
new
ClspGraph
();
clsp
.
load
();
ArgType
.
setClsp
(
clsp
);
}
public
void
testMerge
()
throws
IOException
,
DecodeException
{
initClsp
();
first
(
INT
,
INT
);
first
(
BOOLEAN
,
INT
);
reject
(
INT
,
LONG
);
...
...
@@ -27,21 +40,33 @@ public class TypeMergeTest extends TestCase {
first
(
INT
,
NARROW
);
first
(
CHAR
,
INT
);
merge
(
unknown
(
PrimitiveType
.
INT
,
PrimitiveType
.
BOOLEAN
,
PrimitiveType
.
FLOAT
),
check
(
unknown
(
PrimitiveType
.
INT
,
PrimitiveType
.
BOOLEAN
,
PrimitiveType
.
FLOAT
),
unknown
(
PrimitiveType
.
INT
,
PrimitiveType
.
BOOLEAN
),
unknown
(
PrimitiveType
.
INT
,
PrimitiveType
.
BOOLEAN
));
merge
(
unknown
(
PrimitiveType
.
INT
,
PrimitiveType
.
FLOAT
),
check
(
unknown
(
PrimitiveType
.
INT
,
PrimitiveType
.
FLOAT
),
unknown
(
PrimitiveType
.
INT
,
PrimitiveType
.
BOOLEAN
),
INT
);
merge
(
unknown
(
PrimitiveType
.
INT
,
PrimitiveType
.
OBJECT
),
check
(
unknown
(
PrimitiveType
.
INT
,
PrimitiveType
.
OBJECT
),
unknown
(
PrimitiveType
.
OBJECT
,
PrimitiveType
.
ARRAY
),
unknown
(
PrimitiveType
.
OBJECT
));
first
(
object
(
"Lsomeobj;"
),
object
(
"Lsomeobj;"
));
merge
(
object
(
"Lsomeobj;"
),
object
(
"Lotherobj;"
),
null
);
first
(
object
(
"Lsomeobj;"
),
OBJECT
);
ArgType
objExc
=
object
(
"java.lang.Exception"
);
ArgType
objThr
=
object
(
"java.lang.Throwable"
);
ArgType
objIO
=
object
(
"java.io.IOException"
);
ArgType
objArr
=
object
(
"java.lang.ArrayIndexOutOfBoundsException"
);
ArgType
objList
=
object
(
"java.util.List"
);
first
(
objExc
,
objExc
);
check
(
objExc
,
objList
,
OBJECT
);
first
(
objExc
,
OBJECT
);
check
(
objExc
,
objThr
,
objThr
);
check
(
objIO
,
objArr
,
objExc
);
ArgType
generic
=
genericType
(
"T"
);
first
(
generic
,
objExc
);
}
private
void
first
(
ArgType
t1
,
ArgType
t2
)
{
...
...
jadx-gui/build.gradle
View file @
6ddb71e2
...
...
@@ -6,6 +6,7 @@ dependencies {
compile
(
project
(
":jadx-core"
))
compile
(
project
(
":jadx-cli"
))
compile
'com.fifesoft:rsyntaxtextarea:2.0.7'
compile
'ch.qos.logback:logback-classic:1.0.13'
}
startScripts
{
...
...
jadx-gui/src/main/java/jadx/gui/utils/Utils.java
View file @
6ddb71e2
...
...
@@ -37,6 +37,9 @@ public class Utils {
}
public
static
String
typeStr
(
ArgType
type
)
{
if
(
type
==
null
)
{
return
"null"
;
}
if
(
type
.
isObject
())
{
String
cls
=
type
.
getObject
();
int
dot
=
cls
.
lastIndexOf
(
'.'
);
...
...
jadx-samples/src/main/java/jadx/samples/TestTryCatch.java
View file @
6ddb71e2
...
...
@@ -168,6 +168,20 @@ public class TestTryCatch extends AbstractTest {
return
b
;
}
public
int
catchInLoop
(
int
i
,
int
j
)
{
while
(
true
)
{
try
{
while
(
i
<
j
)
i
=
j
++
/
i
;
}
catch
(
RuntimeException
e
)
{
i
=
10
;
continue
;
}
break
;
}
return
j
;
}
@Override
public
boolean
testRun
()
throws
Exception
{
Object
obj
=
new
Object
();
...
...
@@ -180,8 +194,8 @@ public class TestTryCatch extends AbstractTest {
assertTrue
(
test6
(
obj
));
assertTrue
(
test7
());
assertTrue
(
testSynchronize
(
obj
)
==
true
);
assert
True
(
testSynchronize
(
"str"
)
==
false
);
assertTrue
(
testSynchronize
(
obj
));
assert
False
(
testSynchronize
(
"str"
)
);
assertTrue
(
testSynchronize2
(
"str"
));
assertTrue
(
testSynchronize3
());
...
...
@@ -191,6 +205,10 @@ public class TestTryCatch extends AbstractTest {
assertTrue
(
test8a
(
"a"
));
assertTrue
(
test8a
(
null
));
assertEquals
(
catchInLoop
(
1
,
0
),
0
);
assertEquals
(
catchInLoop
(
0
,
1
),
2
);
assertEquals
(
catchInLoop
(
788
,
100
),
100
);
return
true
;
}
...
...
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