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
3700ecb7
Commit
3700ecb7
authored
Jan 02, 2015
by
Skylot
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
core: add resources methods to jadx API
parent
811b0e7f
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
525 additions
and
185 deletions
+525
-185
JadxCLIArgs.java
jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java
+13
-5
DefaultJadxArgs.java
jadx-core/src/main/java/jadx/api/DefaultJadxArgs.java
+6
-1
IJadxArgs.java
jadx-core/src/main/java/jadx/api/IJadxArgs.java
+3
-1
JadxDecompiler.java
jadx-core/src/main/java/jadx/api/JadxDecompiler.java
+63
-25
ResourceFile.java
jadx-core/src/main/java/jadx/api/ResourceFile.java
+63
-0
ResourceType.java
jadx-core/src/main/java/jadx/api/ResourceType.java
+50
-0
ResourcesLoader.java
jadx-core/src/main/java/jadx/api/ResourcesLoader.java
+143
-0
BinaryXMLParser.java
...-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java
+179
-153
IntegrationTest.java
jadx-core/src/test/java/jadx/tests/api/IntegrationTest.java
+5
-0
No files found.
jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java
View file @
3700ecb7
...
...
@@ -32,6 +32,12 @@ public final class JadxCLIArgs implements IJadxArgs {
@Parameter
(
names
=
{
"-f"
,
"--fallback"
},
description
=
"make simple dump (using goto instead of 'if', 'for', etc)"
)
protected
boolean
fallbackMode
=
false
;
@Parameter
(
names
=
{
"-r"
,
"--no-res"
},
description
=
"do not decode resources"
)
protected
boolean
skipResources
=
false
;
@Parameter
(
names
=
{
"-s"
,
"--no-src"
},
description
=
"do not decompile source code"
)
protected
boolean
skipSources
=
false
;
@Parameter
(
names
=
{
"--show-bad-code"
},
description
=
"show inconsistent code (incorrectly decompiled)"
)
protected
boolean
showInconsistentCode
=
false
;
...
...
@@ -47,9 +53,6 @@ public final class JadxCLIArgs implements IJadxArgs {
@Parameter
(
names
=
{
"-h"
,
"--help"
},
description
=
"print this help"
,
help
=
true
)
protected
boolean
printHelp
=
false
;
@Parameter
(
names
=
{
"-x"
,
"--xml"
},
description
=
"try to decode the AndroidManifest.xml"
)
protected
boolean
xmlTest
=
false
;
private
final
List
<
File
>
input
=
new
ArrayList
<
File
>(
1
);
private
File
outputDir
;
...
...
@@ -168,8 +171,13 @@ public final class JadxCLIArgs implements IJadxArgs {
}
@Override
public
boolean
isXMLTest
()
{
return
xmlTest
;
public
boolean
isSkipResources
()
{
return
skipResources
;
}
@Override
public
boolean
isSkipSources
()
{
return
skipSources
;
}
@Override
...
...
jadx-core/src/main/java/jadx/api/DefaultJadxArgs.java
View file @
3700ecb7
...
...
@@ -40,7 +40,12 @@ public class DefaultJadxArgs implements IJadxArgs {
}
@Override
public
boolean
isXMLTest
()
{
public
boolean
isSkipResources
()
{
return
false
;
}
@Override
public
boolean
isSkipSources
()
{
return
false
;
}
}
jadx-core/src/main/java/jadx/api/IJadxArgs.java
View file @
3700ecb7
...
...
@@ -17,5 +17,7 @@ public interface IJadxArgs {
boolean
isVerbose
();
boolean
isXMLTest
();
boolean
isSkipResources
();
boolean
isSkipSources
();
}
jadx-core/src/main/java/jadx/api/JadxDecompiler.java
View file @
3700ecb7
...
...
@@ -2,6 +2,7 @@ package jadx.api;
import
jadx.core.Jadx
;
import
jadx.core.ProcessClass
;
import
jadx.core.codegen.CodeWriter
;
import
jadx.core.dex.info.ClassInfo
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.core.dex.nodes.RootNode
;
...
...
@@ -55,6 +56,9 @@ public final class JadxDecompiler {
private
RootNode
root
;
private
List
<
IDexTreeVisitor
>
passes
;
private
List
<
JavaClass
>
classes
;
private
List
<
ResourceFile
>
resources
;
private
BinaryXMLParser
xmlParser
;
public
JadxDecompiler
()
{
this
(
new
DefaultJadxArgs
());
...
...
@@ -82,6 +86,8 @@ public final class JadxDecompiler {
void
reset
()
{
ClassInfo
.
clearCache
();
classes
=
null
;
resources
=
null
;
xmlParser
=
null
;
root
=
null
;
}
...
...
@@ -108,27 +114,21 @@ public final class JadxDecompiler {
parse
();
}
public
void
parseAndSaveXML
()
{
if
(
this
.
args
.
isXMLTest
())
{
InputFile
inf
=
inputFiles
.
get
(
0
);
try
{
byte
[]
buffer
=
InputFile
.
loadXMLBuffer
(
inf
.
getFile
());
if
(
buffer
!=
null
)
{
File
out
=
new
File
(
outDir
,
"AndroidManifest.xml"
);
BinaryXMLParser
bxp
=
new
BinaryXMLParser
(
root
);
bxp
.
parse
(
buffer
,
out
);
}
}
catch
(
Exception
e
)
{
LOG
.
info
(
"Decompiling AndroidManifest.xml failed!"
,
e
);
}
}
public
void
save
()
{
save
(!
args
.
isSkipSources
(),
!
args
.
isSkipResources
());
}
public
void
save
()
{
parseAndSaveXML
();
public
void
saveSources
()
{
save
(
true
,
false
);
}
public
void
saveResources
()
{
save
(
false
,
true
);
}
private
void
save
(
boolean
saveSources
,
boolean
saveResources
)
{
try
{
ExecutorService
ex
=
getSaveExecutor
();
ExecutorService
ex
=
getSaveExecutor
(
saveSources
,
saveResources
);
ex
.
shutdown
();
ex
.
awaitTermination
(
1
,
TimeUnit
.
DAYS
);
}
catch
(
InterruptedException
e
)
{
...
...
@@ -137,6 +137,10 @@ public final class JadxDecompiler {
}
public
ExecutorService
getSaveExecutor
()
{
return
getSaveExecutor
(!
args
.
isSkipSources
(),
!
args
.
isSkipResources
());
}
private
ExecutorService
getSaveExecutor
(
boolean
saveSources
,
boolean
saveResources
)
{
if
(
root
==
null
)
{
throw
new
JadxRuntimeException
(
"No loaded files"
);
}
...
...
@@ -145,14 +149,31 @@ public final class JadxDecompiler {
LOG
.
info
(
"processing ..."
);
ExecutorService
executor
=
Executors
.
newFixedThreadPool
(
threadsCount
);
for
(
final
JavaClass
cls
:
getClasses
())
{
executor
.
execute
(
new
Runnable
()
{
@Override
public
void
run
()
{
cls
.
decompile
();
SaveCode
.
save
(
outDir
,
args
,
cls
.
getClassNode
());
}
});
if
(
saveSources
)
{
for
(
final
JavaClass
cls
:
getClasses
())
{
executor
.
execute
(
new
Runnable
()
{
@Override
public
void
run
()
{
cls
.
decompile
();
SaveCode
.
save
(
outDir
,
args
,
cls
.
getClassNode
());
}
});
}
}
if
(
saveResources
)
{
for
(
final
ResourceFile
resourceFile
:
getResources
())
{
executor
.
execute
(
new
Runnable
()
{
@Override
public
void
run
()
{
if
(
ResourceType
.
isSupportedForUnpack
(
resourceFile
.
getType
()))
{
CodeWriter
cw
=
resourceFile
.
getContent
();
if
(
cw
!=
null
)
{
cw
.
save
(
new
File
(
outDir
,
resourceFile
.
getName
()));
}
}
}
});
}
}
return
executor
;
}
...
...
@@ -172,6 +193,16 @@ public final class JadxDecompiler {
return
classes
;
}
public
List
<
ResourceFile
>
getResources
()
{
if
(
resources
==
null
)
{
if
(
root
==
null
)
{
return
Collections
.
emptyList
();
}
resources
=
new
ResourcesLoader
(
this
).
load
(
inputFiles
);
}
return
resources
;
}
public
List
<
JavaPackage
>
getPackages
()
{
List
<
JavaClass
>
classList
=
getClasses
();
if
(
classList
.
isEmpty
())
{
...
...
@@ -232,6 +263,13 @@ public final class JadxDecompiler {
return
root
;
}
BinaryXMLParser
getXmlParser
()
{
if
(
xmlParser
==
null
)
{
xmlParser
=
new
BinaryXMLParser
(
root
);
}
return
xmlParser
;
}
JavaClass
findJavaClass
(
ClassNode
cls
)
{
if
(
cls
==
null
)
{
return
null
;
...
...
jadx-core/src/main/java/jadx/api/ResourceFile.java
0 → 100644
View file @
3700ecb7
package
jadx
.
api
;
import
jadx.core.codegen.CodeWriter
;
import
java.io.File
;
public
class
ResourceFile
{
public
static
final
class
ZipRef
{
private
final
File
zipFile
;
private
final
String
entryName
;
public
ZipRef
(
File
zipFile
,
String
entryName
)
{
this
.
zipFile
=
zipFile
;
this
.
entryName
=
entryName
;
}
public
File
getZipFile
()
{
return
zipFile
;
}
public
String
getEntryName
()
{
return
entryName
;
}
@Override
public
String
toString
()
{
return
"ZipRef{"
+
zipFile
+
", '"
+
entryName
+
"'}"
;
}
}
private
final
JadxDecompiler
decompiler
;
private
final
String
name
;
private
final
ResourceType
type
;
private
ZipRef
zipRef
;
ResourceFile
(
JadxDecompiler
decompiler
,
String
name
,
ResourceType
type
)
{
this
.
decompiler
=
decompiler
;
this
.
name
=
name
;
this
.
type
=
type
;
}
public
String
getName
()
{
return
name
;
}
public
ResourceType
getType
()
{
return
type
;
}
public
CodeWriter
getContent
()
{
return
ResourcesLoader
.
loadContent
(
decompiler
,
zipRef
,
type
);
}
void
setZipRef
(
ZipRef
zipRef
)
{
this
.
zipRef
=
zipRef
;
}
@Override
public
String
toString
()
{
return
"ResourceFile{name='"
+
name
+
'\''
+
", type="
+
type
+
"}"
;
}
}
jadx-core/src/main/java/jadx/api/ResourceType.java
0 → 100644
View file @
3700ecb7
package
jadx
.
api
;
public
enum
ResourceType
{
CODE
(
".dex"
,
".class"
),
MANIFEST
(
"AndroidManifest.xml"
),
XML
(
".xml"
),
// TODO binary or not?
ARSC
(
".arsc"
),
// TODO decompile !!!
FONT
(
".ttf"
),
IMG
(
".png"
,
".gif"
,
".jpg"
),
LIB
(
".so"
),
UNKNOWN
;
private
String
[]
exts
;
ResourceType
(
String
...
exts
)
{
this
.
exts
=
exts
;
}
public
String
[]
getExts
()
{
return
exts
;
}
public
static
ResourceType
getFileType
(
String
fileName
)
{
for
(
ResourceType
type
:
ResourceType
.
values
())
{
for
(
String
ext
:
type
.
getExts
())
{
if
(
fileName
.
endsWith
(
ext
))
{
return
type
;
}
}
}
return
UNKNOWN
;
}
public
static
boolean
isSupportedForUnpack
(
ResourceType
type
)
{
switch
(
type
)
{
case
CODE:
case
ARSC:
case
LIB:
case
XML:
case
FONT:
case
IMG:
case
UNKNOWN:
return
false
;
case
MANIFEST:
return
true
;
}
return
false
;
}
}
jadx-core/src/main/java/jadx/api/ResourcesLoader.java
0 → 100644
View file @
3700ecb7
package
jadx
.
api
;
import
jadx.api.ResourceFile.ZipRef
;
import
jadx.core.codegen.CodeWriter
;
import
jadx.core.utils.files.InputFile
;
import
java.io.BufferedInputStream
;
import
java.io.ByteArrayOutputStream
;
import
java.io.File
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.util.ArrayList
;
import
java.util.Enumeration
;
import
java.util.List
;
import
java.util.zip.ZipEntry
;
import
java.util.zip.ZipFile
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
// TODO: move to core package
final
class
ResourcesLoader
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
ResourcesLoader
.
class
);
private
static
final
int
READ_BUFFER_SIZE
=
8
*
1024
;
private
static
final
int
LOAD_SIZE_LIMIT
=
500
*
1024
;
private
JadxDecompiler
jadxRef
;
ResourcesLoader
(
JadxDecompiler
jadxRef
)
{
this
.
jadxRef
=
jadxRef
;
}
List
<
ResourceFile
>
load
(
List
<
InputFile
>
inputFiles
)
{
List
<
ResourceFile
>
list
=
new
ArrayList
<
ResourceFile
>(
inputFiles
.
size
());
for
(
InputFile
file
:
inputFiles
)
{
loadFile
(
list
,
file
.
getFile
());
}
return
list
;
}
static
CodeWriter
loadContent
(
JadxDecompiler
jadxRef
,
ZipRef
zipRef
,
ResourceType
type
)
{
if
(
zipRef
==
null
)
{
return
null
;
}
ZipFile
zipFile
=
null
;
InputStream
inputStream
=
null
;
try
{
zipFile
=
new
ZipFile
(
zipRef
.
getZipFile
());
ZipEntry
entry
=
zipFile
.
getEntry
(
zipRef
.
getEntryName
());
if
(
entry
!=
null
)
{
if
(
entry
.
getSize
()
>
LOAD_SIZE_LIMIT
)
{
return
new
CodeWriter
().
add
(
"File too big, size: "
+
String
.
format
(
"%.2f KB"
,
entry
.
getSize
()
/
1024
.));
}
inputStream
=
new
BufferedInputStream
(
zipFile
.
getInputStream
(
entry
));
return
decode
(
jadxRef
,
type
,
inputStream
);
}
else
{
LOG
.
warn
(
"Zip entry not found: {}"
,
zipRef
);
}
}
catch
(
IOException
e
)
{
LOG
.
error
(
"Error load: "
+
zipRef
,
e
);
}
finally
{
try
{
if
(
zipFile
!=
null
)
{
zipFile
.
close
();
}
if
(
inputStream
!=
null
)
{
inputStream
.
close
();
}
}
catch
(
Exception
e
)
{
LOG
.
debug
(
"Error close zip file: "
+
zipRef
,
e
);
}
}
return
null
;
}
private
static
CodeWriter
decode
(
JadxDecompiler
jadxRef
,
ResourceType
type
,
InputStream
inputStream
)
throws
IOException
{
switch
(
type
)
{
case
MANIFEST:
case
XML:
return
jadxRef
.
getXmlParser
().
parse
(
inputStream
);
}
return
loadToCodeWriter
(
inputStream
);
}
private
void
loadFile
(
List
<
ResourceFile
>
list
,
File
file
)
{
if
(
file
==
null
)
{
return
;
}
ZipFile
zip
=
null
;
try
{
zip
=
new
ZipFile
(
file
);
Enumeration
<?
extends
ZipEntry
>
entries
=
zip
.
entries
();
while
(
entries
.
hasMoreElements
())
{
ZipEntry
entry
=
entries
.
nextElement
();
addEntry
(
list
,
file
,
entry
);
}
}
catch
(
IOException
e
)
{
LOG
.
debug
(
"Not a zip file: "
+
file
.
getAbsolutePath
());
}
finally
{
if
(
zip
!=
null
)
{
try
{
zip
.
close
();
}
catch
(
Exception
e
)
{
LOG
.
error
(
"Zip file close error: "
+
file
.
getAbsolutePath
(),
e
);
}
}
}
}
private
void
addEntry
(
List
<
ResourceFile
>
list
,
File
zipFile
,
ZipEntry
entry
)
{
if
(
entry
.
isDirectory
())
{
return
;
}
String
name
=
entry
.
getName
();
ResourceType
type
=
ResourceType
.
getFileType
(
name
);
ResourceFile
rf
=
new
ResourceFile
(
jadxRef
,
name
,
type
);
rf
.
setZipRef
(
new
ZipRef
(
zipFile
,
name
));
list
.
add
(
rf
);
// LOG.debug("Add resource entry: {}, size: {}", name, entry.getSize());
}
private
static
CodeWriter
loadToCodeWriter
(
InputStream
is
)
throws
IOException
{
CodeWriter
cw
=
new
CodeWriter
();
ByteArrayOutputStream
baos
=
new
ByteArrayOutputStream
(
READ_BUFFER_SIZE
);
byte
[]
buffer
=
new
byte
[
READ_BUFFER_SIZE
];
int
count
;
try
{
while
((
count
=
is
.
read
(
buffer
))
!=
-
1
)
{
baos
.
write
(
buffer
,
0
,
count
);
}
}
finally
{
try
{
is
.
close
();
}
catch
(
Exception
ignore
)
{
}
}
cw
.
add
(
baos
.
toString
(
"UTF-8"
));
return
cw
;
}
}
jadx-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java
View file @
3700ecb7
This diff is collapsed.
Click to expand it.
jadx-core/src/test/java/jadx/tests/api/IntegrationTest.java
View file @
3700ecb7
...
...
@@ -128,6 +128,11 @@ public abstract class IntegrationTest extends TestUtils {
public
int
getThreadsCount
()
{
return
1
;
}
@Override
public
boolean
isSkipResources
()
{
return
true
;
}
},
new
File
(
outDir
));
}
...
...
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