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
031582dd
Commit
031582dd
authored
Apr 29, 2019
by
Ahmed Ashour
Committed by
skylot
Apr 29, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(gui): show smali (#197) (PR #635)
parent
745c52e8
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
177 additions
and
47 deletions
+177
-47
build.gradle
jadx-core/build.gradle
+1
-1
JadxDecompiler.java
jadx-core/src/main/java/jadx/api/JadxDecompiler.java
+45
-0
JavaClass.java
jadx-core/src/main/java/jadx/api/JavaClass.java
+10
-0
ClassNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
+16
-5
DexFile.java
jadx-core/src/main/java/jadx/core/utils/files/DexFile.java
+9
-1
InputFile.java
jadx-core/src/main/java/jadx/core/utils/files/InputFile.java
+28
-26
JavaToDex.java
jadx-core/src/main/java/jadx/core/utils/files/JavaToDex.java
+5
-5
JClass.java
jadx-gui/src/main/java/jadx/gui/treemodel/JClass.java
+5
-0
JNode.java
jadx-gui/src/main/java/jadx/gui/treemodel/JNode.java
+4
-0
CodePanel.java
jadx-gui/src/main/java/jadx/gui/ui/codearea/CodePanel.java
+25
-9
SmaliArea.java
jadx-gui/src/main/java/jadx/gui/ui/codearea/SmaliArea.java
+23
-0
Messages_en_US.properties
jadx-gui/src/main/resources/i18n/Messages_en_US.properties
+2
-0
Messages_es_ES.properties
jadx-gui/src/main/resources/i18n/Messages_es_ES.properties
+2
-0
Messages_zh_CN.properties
jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties
+2
-0
No files found.
jadx-core/build.gradle
View file @
031582dd
...
...
@@ -13,7 +13,7 @@ dependencies {
}
compile
'com.google.guava:guava:27.1-jre'
testC
ompile
'org.smali:baksmali:2.2.7'
c
ompile
'org.smali:baksmali:2.2.7'
testCompile
'org.apache.commons:commons-lang3:3.8.1'
...
...
jadx-core/src/main/java/jadx/api/JadxDecompiler.java
View file @
031582dd
package
jadx
.
api
;
import
java.io.BufferedWriter
;
import
java.io.File
;
import
java.io.FileOutputStream
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.OutputStreamWriter
;
import
java.io.StringWriter
;
import
java.nio.file.Files
;
import
java.nio.file.Path
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.Comparator
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.concurrent.ConcurrentHashMap
;
import
java.util.concurrent.ExecutorService
;
import
java.util.concurrent.Executors
;
import
java.util.concurrent.TimeUnit
;
import
org.jf.baksmali.Adaptors.ClassDefinition
;
import
org.jf.baksmali.Baksmali
;
import
org.jf.baksmali.BaksmaliOptions
;
import
org.jf.dexlib2.DexFileFactory
;
import
org.jf.dexlib2.Opcodes
;
import
org.jf.dexlib2.dexbacked.DexBackedClassDef
;
import
org.jf.dexlib2.dexbacked.DexBackedDexFile
;
import
org.jf.dexlib2.iface.ClassDef
;
import
org.jf.util.IndentingWriter
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
...
...
@@ -26,6 +44,8 @@ import jadx.core.dex.visitors.IDexTreeVisitor;
import
jadx.core.dex.visitors.SaveCode
;
import
jadx.core.export.ExportGradleProject
;
import
jadx.core.utils.exceptions.JadxRuntimeException
;
import
jadx.core.utils.files.DexFile
;
import
jadx.core.utils.files.FileUtils
;
import
jadx.core.utils.files.InputFile
;
import
jadx.core.xmlgen.BinaryXMLParser
;
import
jadx.core.xmlgen.ResourcesSaver
;
...
...
@@ -290,6 +310,31 @@ public final class JadxDecompiler {
ProcessClass
.
process
(
cls
,
passes
,
true
);
}
void
generateSmali
(
ClassNode
cls
)
{
Path
path
=
cls
.
dex
().
getDexFile
().
getPath
();
String
className
=
cls
.
getAlias
().
makeRawFullName
();
className
=
'L'
+
className
.
replace
(
'.'
,
'/'
)
+
';'
;
try
(
InputStream
in
=
Files
.
newInputStream
(
path
))
{
DexBackedDexFile
dexFile
=
DexFileFactory
.
loadDexFile
(
path
.
toFile
(),
Opcodes
.
getDefault
());
boolean
decompiled
=
false
;
for
(
DexBackedClassDef
classDef
:
dexFile
.
getClasses
())
{
if
(
classDef
.
getType
().
equals
(
className
))
{
ClassDefinition
classDefinition
=
new
ClassDefinition
(
new
BaksmaliOptions
(),
classDef
);
StringWriter
sw
=
new
StringWriter
();
classDefinition
.
writeTo
(
new
IndentingWriter
(
sw
));
cls
.
setSmali
(
sw
.
toString
());
decompiled
=
true
;
break
;
}
}
if
(!
decompiled
)
{
LOG
.
error
(
"Failed to find smali class {}"
,
className
);
}
}
catch
(
IOException
e
)
{
LOG
.
error
(
"Error generating smali"
,
e
);
}
}
RootNode
getRoot
()
{
return
root
;
}
...
...
jadx-core/src/main/java/jadx/api/JavaClass.java
View file @
031582dd
...
...
@@ -64,6 +64,16 @@ public final class JavaClass implements JavaNode {
}
}
public
synchronized
String
getSmali
()
{
if
(
decompiler
==
null
)
{
return
null
;
}
if
(
cls
.
getSmali
()
==
null
)
{
decompiler
.
generateSmali
(
cls
);
}
return
cls
.
getSmali
();
}
public
synchronized
void
unload
()
{
cls
.
unload
();
}
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
View file @
031582dd
package
jadx
.
core
.
dex
.
nodes
;
import
static
jadx
.
core
.
dex
.
nodes
.
ProcessState
.
UNLOADED
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
org.jetbrains.annotations.Nullable
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
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
org.jetbrains.annotations.Nullable
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
jadx.core.Consts
;
import
jadx.core.codegen.CodeWriter
;
...
...
@@ -35,8 +38,6 @@ import jadx.core.dex.nodes.parser.StaticValuesParser;
import
jadx.core.utils.exceptions.DecodeException
;
import
jadx.core.utils.exceptions.JadxRuntimeException
;
import
static
jadx
.
core
.
dex
.
nodes
.
ProcessState
.
UNLOADED
;
public
class
ClassNode
extends
LineAttrNode
implements
ILoadable
,
ICodeNode
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
ClassNode
.
class
);
...
...
@@ -53,6 +54,8 @@ public class ClassNode extends LineAttrNode implements ILoadable, ICodeNode {
// store decompiled code
private
CodeWriter
code
;
// store smali
private
String
smali
;
// store parent for inner classes or 'this' otherwise
private
ClassNode
parentClass
;
...
...
@@ -482,6 +485,14 @@ public class ClassNode extends LineAttrNode implements ILoadable, ICodeNode {
return
code
;
}
public
void
setSmali
(
String
smali
)
{
this
.
smali
=
smali
;
}
public
String
getSmali
()
{
return
smali
;
}
public
ProcessState
getState
()
{
return
state
;
}
...
...
jadx-core/src/main/java/jadx/core/utils/files/DexFile.java
View file @
031582dd
package
jadx
.
core
.
utils
.
files
;
import
java.nio.file.Path
;
import
com.android.dex.Dex
;
public
class
DexFile
{
private
final
InputFile
inputFile
;
private
final
String
name
;
private
final
Dex
dexBuf
;
private
final
Path
path
;
public
DexFile
(
InputFile
inputFile
,
String
name
,
Dex
dexBuf
)
{
public
DexFile
(
InputFile
inputFile
,
String
name
,
Dex
dexBuf
,
Path
path
)
{
this
.
inputFile
=
inputFile
;
this
.
name
=
name
;
this
.
dexBuf
=
dexBuf
;
this
.
path
=
path
;
}
public
String
getName
()
{
...
...
@@ -21,6 +25,10 @@ public class DexFile {
return
dexBuf
;
}
public
Path
getPath
()
{
return
path
;
}
public
InputFile
getInputFile
()
{
return
inputFile
;
}
...
...
jadx-core/src/main/java/jadx/core/utils/files/InputFile.java
View file @
031582dd
...
...
@@ -54,7 +54,7 @@ public class InputFile {
String
fileName
=
file
.
getName
();
if
(
fileName
.
endsWith
(
".dex"
))
{
addDexFile
(
new
Dex
(
file
));
addDexFile
(
fileName
,
new
Dex
(
file
),
file
.
toPath
(
));
return
;
}
if
(
fileName
.
endsWith
(
".smali"
))
{
...
...
@@ -62,12 +62,12 @@ public class InputFile {
SmaliOptions
options
=
new
SmaliOptions
();
options
.
outputDexFile
=
output
.
toAbsolutePath
().
toString
();
Smali
.
assemble
(
options
,
file
.
getAbsolutePath
());
addDexFile
(
new
Dex
(
output
.
toFile
())
);
addDexFile
(
""
,
new
Dex
(
output
.
toFile
()),
output
);
return
;
}
if
(
fileName
.
endsWith
(
".class"
))
{
for
(
Dex
dex
:
loadFromClassFile
(
file
))
{
addDexFile
(
dex
);
for
(
Path
path
:
loadFromClassFile
(
file
))
{
addDexFile
(
path
);
}
return
;
}
...
...
@@ -81,8 +81,8 @@ public class InputFile {
return
;
}
if
(
fileName
.
endsWith
(
".jar"
))
{
for
(
Dex
dex
:
loadFromJar
(
file
.
toPath
()))
{
addDexFile
(
dex
);
for
(
Path
path
:
loadFromJar
(
file
.
toPath
()))
{
addDexFile
(
path
);
}
return
;
}
...
...
@@ -98,12 +98,16 @@ public class InputFile {
LOG
.
warn
(
"No dex files found in {}"
,
file
);
}
private
void
addDexFile
(
Dex
dexBuf
)
{
addDexFile
(
""
,
dexBuf
);
private
void
addDexFile
(
Path
path
)
throws
IOException
{
addDexFile
(
""
,
path
);
}
private
void
addDexFile
(
String
fileName
,
Dex
dexBuf
)
{
dexFiles
.
add
(
new
DexFile
(
this
,
fileName
,
dexBuf
));
private
void
addDexFile
(
String
fileName
,
Path
path
)
throws
IOException
{
addDexFile
(
fileName
,
new
Dex
(
Files
.
readAllBytes
(
path
)),
path
);
}
private
void
addDexFile
(
String
fileName
,
Dex
dexBuf
,
Path
path
)
{
dexFiles
.
add
(
new
DexFile
(
this
,
fileName
,
dexBuf
,
path
));
}
private
boolean
loadFromZip
(
String
ext
)
throws
IOException
,
DecodeException
{
...
...
@@ -125,9 +129,9 @@ public class InputFile {
||
entryName
.
endsWith
(
instantRunDexSuffix
))
{
switch
(
ext
)
{
case
".dex"
:
Dex
dexBuf
=
makeDexBuf
(
entryName
,
inputStream
);
if
(
dexBuf
!=
null
)
{
addDexFile
(
entryName
,
dexBuf
);
Path
path
=
makeDexBuf
(
entryName
,
inputStream
);
if
(
path
!=
null
)
{
addDexFile
(
entryName
,
path
);
index
++;
}
break
;
...
...
@@ -136,8 +140,8 @@ public class InputFile {
index
++;
Path
jarFile
=
FileUtils
.
createTempFile
(
entryName
);
Files
.
copy
(
inputStream
,
jarFile
,
StandardCopyOption
.
REPLACE_EXISTING
);
for
(
Dex
dex
:
loadFromJar
(
jarFile
))
{
addDexFile
(
entryName
,
dex
);
for
(
Path
p
:
loadFromJar
(
jarFile
))
{
addDexFile
(
entryName
,
p
);
}
break
;
...
...
@@ -164,28 +168,26 @@ public class InputFile {
}
@Nullable
private
Dex
makeDexBuf
(
String
entryName
,
InputStream
inputStream
)
{
private
Path
makeDexBuf
(
String
entryName
,
InputStream
inputStream
)
{
try
{
return
new
Dex
(
inputStream
);
Path
path
=
FileUtils
.
createTempFile
(
".dex"
);
Files
.
copy
(
inputStream
,
path
,
StandardCopyOption
.
REPLACE_EXISTING
);
return
path
;
}
catch
(
Exception
e
)
{
LOG
.
error
(
"Failed to load file: {}, error: {}"
,
entryName
,
e
.
getMessage
(),
e
);
return
null
;
}
}
private
static
List
<
Dex
>
loadFromJar
(
Path
jar
)
throws
DecodeException
{
private
static
List
<
Path
>
loadFromJar
(
Path
jar
)
throws
DecodeException
{
JavaToDex
j2d
=
new
JavaToDex
();
try
{
LOG
.
info
(
"converting to dex: {} ..."
,
jar
.
getFileName
());
List
<
byte
[]>
byte
List
=
j2d
.
convert
(
jar
);
if
(
byte
List
.
isEmpty
())
{
List
<
Path
>
path
List
=
j2d
.
convert
(
jar
);
if
(
path
List
.
isEmpty
())
{
throw
new
JadxException
(
"Empty dx output"
);
}
List
<
Dex
>
dexList
=
new
ArrayList
<>(
byteList
.
size
());
for
(
byte
[]
b
:
byteList
)
{
dexList
.
add
(
new
Dex
(
b
));
}
return
dexList
;
return
pathList
;
}
catch
(
Exception
e
)
{
throw
new
DecodeException
(
"java class to dex conversion error:\n "
+
e
.
getMessage
(),
e
);
}
finally
{
...
...
@@ -195,7 +197,7 @@ public class InputFile {
}
}
private
static
List
<
Dex
>
loadFromClassFile
(
File
file
)
throws
IOException
,
DecodeException
{
private
static
List
<
Path
>
loadFromClassFile
(
File
file
)
throws
IOException
,
DecodeException
{
Path
outFile
=
FileUtils
.
createTempFile
(
".jar"
);
try
(
JarOutputStream
jo
=
new
JarOutputStream
(
Files
.
newOutputStream
(
outFile
)))
{
String
clsName
=
AsmUtils
.
getNameFromClassFile
(
file
);
...
...
jadx-core/src/main/java/jadx/core/utils/files/JavaToDex.java
View file @
031582dd
...
...
@@ -37,7 +37,7 @@ public class JavaToDex {
private
String
dxErrors
;
public
List
<
byte
[]
>
convert
(
Path
jar
)
throws
JadxException
{
public
List
<
Path
>
convert
(
Path
jar
)
throws
JadxException
{
try
(
ByteArrayOutputStream
out
=
new
ByteArrayOutputStream
();
ByteArrayOutputStream
errOut
=
new
ByteArrayOutputStream
())
{
DxContext
context
=
new
DxContext
(
out
,
errOut
);
...
...
@@ -51,14 +51,14 @@ public class JavaToDex {
if
(
result
!=
0
)
{
throw
new
JadxException
(
"Java to dex conversion error, code: "
+
result
);
}
List
<
byte
[]
>
list
=
new
ArrayList
<>();
List
<
Path
>
list
=
new
ArrayList
<>();
try
(
DirectoryStream
<
Path
>
ds
=
Files
.
newDirectoryStream
(
dir
))
{
for
(
Path
child
:
ds
)
{
list
.
add
(
Files
.
readAllBytes
(
child
)
);
Files
.
delete
(
child
);
list
.
add
(
child
);
child
.
toFile
().
deleteOnExit
(
);
}
}
Files
.
delete
(
dir
);
dir
.
toFile
().
deleteOnExit
(
);
return
list
;
}
catch
(
Exception
e
)
{
throw
new
JadxException
(
"dx exception: "
+
e
.
getMessage
(),
e
);
...
...
jadx-gui/src/main/java/jadx/gui/treemodel/JClass.java
View file @
031582dd
...
...
@@ -82,6 +82,11 @@ public class JClass extends JLoadableNode {
}
@Override
public
String
getSmali
()
{
return
cls
.
getSmali
();
}
@Override
public
String
getSyntaxName
()
{
return
SyntaxConstants
.
SYNTAX_STYLE_JAVA
;
}
...
...
jadx-gui/src/main/java/jadx/gui/treemodel/JNode.java
View file @
031582dd
...
...
@@ -28,6 +28,10 @@ public abstract class JNode extends DefaultMutableTreeNode {
return
null
;
}
public
String
getSmali
()
{
return
null
;
}
public
String
getSyntaxName
()
{
return
SyntaxConstants
.
SYNTAX_STYLE_NONE
;
}
...
...
jadx-gui/src/main/java/jadx/gui/ui/codearea/CodePanel.java
View file @
031582dd
package
jadx
.
gui
.
ui
.
codearea
;
import
javax.swing.*
;
import
java.awt.*
;
import
java.awt.BorderLayout
;
import
java.awt.event.ActionEvent
;
import
java.awt.event.KeyEvent
;
import
javax.swing.AbstractAction
;
import
javax.swing.JScrollPane
;
import
javax.swing.JTabbedPane
;
import
javax.swing.KeyStroke
;
import
jadx.gui.treemodel.JClass
;
import
jadx.gui.treemodel.JNode
;
import
jadx.gui.treemodel.JResource
;
import
jadx.gui.ui.ContentPanel
;
import
jadx.gui.ui.TabbedPane
;
import
jadx.gui.utils.NLS
;
import
jadx.gui.utils.Utils
;
public
final
class
CodePanel
extends
ContentPanel
{
...
...
@@ -17,22 +22,36 @@ public final class CodePanel extends ContentPanel {
private
final
SearchBar
searchBar
;
private
final
CodeArea
codeArea
;
private
final
JScrollPane
scrollPane
;
private
final
SmaliArea
smaliArea
;
private
final
JScrollPane
codeScrollPane
;
private
final
JScrollPane
smaliScrollPane
;
private
JTabbedPane
areaTabbedPane
=
new
JTabbedPane
(
JTabbedPane
.
BOTTOM
);
public
CodePanel
(
TabbedPane
panel
,
JNode
jnode
)
{
super
(
panel
,
jnode
);
codeArea
=
new
CodeArea
(
this
);
smaliArea
=
new
SmaliArea
(
this
);
searchBar
=
new
SearchBar
(
codeArea
);
scrollPane
=
new
JScrollPane
(
codeArea
);
codeScrollPane
=
new
JScrollPane
(
codeArea
);
smaliScrollPane
=
new
JScrollPane
(
smaliArea
);
initLineNumbers
();
setLayout
(
new
BorderLayout
());
add
(
searchBar
,
BorderLayout
.
NORTH
);
add
(
scrollPane
);
areaTabbedPane
.
add
(
codeScrollPane
,
NLS
.
str
(
"tabs.code"
));
areaTabbedPane
.
add
(
smaliScrollPane
,
NLS
.
str
(
"tabs.smali"
));
add
(
areaTabbedPane
);
KeyStroke
key
=
KeyStroke
.
getKeyStroke
(
KeyEvent
.
VK_F
,
Utils
.
ctrlButton
());
Utils
.
addKeyBinding
(
codeArea
,
key
,
"SearchAction"
,
new
SearchAction
());
areaTabbedPane
.
addChangeListener
(
e
->
{
if
(
areaTabbedPane
.
getSelectedComponent
()
==
smaliScrollPane
)
{
smaliArea
.
load
();
}
});
}
private
void
initLineNumbers
()
{
...
...
@@ -40,7 +59,7 @@ public final class CodePanel extends ContentPanel {
if
(
codeArea
.
getDocument
().
getLength
()
<=
100_000
)
{
LineNumbers
numbers
=
new
LineNumbers
(
codeArea
);
numbers
.
setUseSourceLines
(
isUseSourceLines
());
s
crollPane
.
setRowHeaderView
(
numbers
);
codeS
crollPane
.
setRowHeaderView
(
numbers
);
}
}
...
...
@@ -89,7 +108,4 @@ public final class CodePanel extends ContentPanel {
return
codeArea
;
}
JScrollPane
getScrollPane
()
{
return
scrollPane
;
}
}
jadx-gui/src/main/java/jadx/gui/ui/codearea/SmaliArea.java
0 → 100644
View file @
031582dd
package
jadx
.
gui
.
ui
.
codearea
;
import
org.fife.ui.rsyntaxtextarea.RSyntaxTextArea
;
import
jadx.gui.treemodel.JNode
;
public
final
class
SmaliArea
extends
RSyntaxTextArea
{
private
static
final
long
serialVersionUID
=
1334485631870306494L
;
private
final
JNode
node
;
SmaliArea
(
CodePanel
panel
)
{
node
=
panel
.
getNode
();
setEditable
(
false
);
}
void
load
()
{
if
(
getText
().
isEmpty
())
{
setText
(
node
.
getSmali
());
}
}
}
jadx-gui/src/main/resources/i18n/Messages_en_US.properties
View file @
031582dd
...
...
@@ -44,6 +44,8 @@ tabs.copy_class_name=Copy Name
tabs.close
=
Close
tabs.closeOthers
=
Close Others
tabs.closeAll
=
Close All
tabs.code
=
Code
tabs.smali
=
Smali
nav.back
=
Back
nav.forward
=
Forward
...
...
jadx-gui/src/main/resources/i18n/Messages_es_ES.properties
View file @
031582dd
...
...
@@ -44,6 +44,8 @@ tabs.copy_class_name=Copy Name
tabs.close
=
Cerrar
tabs.closeOthers
=
Cerrar otros
tabs.closeAll
=
Cerrar todo
#tabs.code=
#tabs.smali=
nav.back
=
Atrás
nav.forward
=
Adelante
...
...
jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties
View file @
031582dd
...
...
@@ -44,6 +44,8 @@ tabs.copy_class_name=复制类名
tabs.close
=
关闭
tabs.closeOthers
=
关闭其他文件
tabs.closeAll
=
全部关闭
#tabs.code=
#tabs.smali=
nav.back
=
后退
nav.forward
=
前进
...
...
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