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
aa691af6
Commit
aa691af6
authored
Jan 07, 2015
by
Skylot
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
core: replace resources ids with names from '.arsc' file
parent
e0ffb018
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
261 additions
and
17 deletions
+261
-17
JadxDecompiler.java
jadx-core/src/main/java/jadx/api/JadxDecompiler.java
+2
-0
ResourceFile.java
jadx-core/src/main/java/jadx/api/ResourceFile.java
+5
-1
ResourcesLoader.java
jadx-core/src/main/java/jadx/api/ResourcesLoader.java
+31
-14
ClassNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
+18
-0
FieldNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/FieldNode.java
+7
-0
ResRefField.java
jadx-core/src/main/java/jadx/core/dex/nodes/ResRefField.java
+15
-0
RootNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java
+84
-0
ResTableParser.java
jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java
+3
-0
ResourceStorage.java
...-core/src/main/java/jadx/core/xmlgen/ResourceStorage.java
+9
-0
IntegrationTest.java
jadx-core/src/test/java/jadx/tests/api/IntegrationTest.java
+13
-2
TestRFieldRestore.java
.../java/jadx/tests/integration/inner/TestRFieldRestore.java
+35
-0
TestRFieldRestore2.java
...java/jadx/tests/integration/inner/TestRFieldRestore2.java
+39
-0
No files found.
jadx-core/src/main/java/jadx/api/JadxDecompiler.java
View file @
aa691af6
...
...
@@ -253,6 +253,8 @@ public final class JadxDecompiler {
root
=
new
RootNode
();
LOG
.
info
(
"loading ..."
);
root
.
load
(
inputFiles
);
root
.
loadResources
(
getResources
());
root
.
initAppResClass
();
}
void
processClass
(
ClassNode
cls
)
{
...
...
jadx-core/src/main/java/jadx/api/ResourceFile.java
View file @
aa691af6
...
...
@@ -49,13 +49,17 @@ public class ResourceFile {
}
public
CodeWriter
getContent
()
{
return
ResourcesLoader
.
loadContent
(
decompiler
,
zipRef
,
type
);
return
ResourcesLoader
.
loadContent
(
decompiler
,
this
);
}
void
setZipRef
(
ZipRef
zipRef
)
{
this
.
zipRef
=
zipRef
;
}
ZipRef
getZipRef
()
{
return
zipRef
;
}
@Override
public
String
toString
()
{
return
"ResourceFile{name='"
+
name
+
'\''
+
", type="
+
type
+
"}"
;
...
...
jadx-core/src/main/java/jadx/api/ResourcesLoader.java
View file @
aa691af6
...
...
@@ -41,7 +41,12 @@ public final class ResourcesLoader {
return
list
;
}
static
CodeWriter
loadContent
(
JadxDecompiler
jadxRef
,
ZipRef
zipRef
,
ResourceType
type
)
{
public
static
interface
ResourceDecoder
{
Object
decode
(
long
size
,
InputStream
is
)
throws
IOException
;
}
public
static
Object
decodeStream
(
ResourceFile
rf
,
ResourceDecoder
decoder
)
throws
JadxException
{
ZipRef
zipRef
=
rf
.
getZipRef
();
if
(
zipRef
==
null
)
{
return
null
;
}
...
...
@@ -50,18 +55,13 @@ public final class ResourcesLoader {
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
);
if
(
entry
==
null
)
{
throw
new
IOException
(
"Zip entry not found: "
+
zipRef
);
}
}
catch
(
IOException
e
)
{
LOG
.
error
(
"Error load: "
+
zipRef
,
e
);
inputStream
=
new
BufferedInputStream
(
zipFile
.
getInputStream
(
entry
));
return
decoder
.
decode
(
entry
.
getSize
(),
inputStream
);
}
catch
(
Exception
e
)
{
throw
new
JadxException
(
"Error load: "
+
zipRef
,
e
);
}
finally
{
try
{
if
(
zipFile
!=
null
)
{
...
...
@@ -74,10 +74,27 @@ public final class ResourcesLoader {
LOG
.
debug
(
"Error close zip file: "
+
zipRef
,
e
);
}
}
}
static
CodeWriter
loadContent
(
final
JadxDecompiler
jadxRef
,
final
ResourceFile
rf
)
{
try
{
return
(
CodeWriter
)
decodeStream
(
rf
,
new
ResourceDecoder
()
{
@Override
public
Object
decode
(
long
size
,
InputStream
is
)
throws
IOException
{
if
(
size
>
LOAD_SIZE_LIMIT
)
{
return
new
CodeWriter
().
add
(
"File too big, size: "
+
String
.
format
(
"%.2f KB"
,
size
/
1024
.));
}
return
loadContent
(
jadxRef
,
rf
.
getType
(),
is
);
}
});
}
catch
(
JadxException
e
)
{
LOG
.
error
(
"Decode error"
,
e
);
}
return
null
;
}
private
static
CodeWriter
decode
(
JadxDecompiler
jadxRef
,
ResourceType
type
,
private
static
CodeWriter
loadContent
(
JadxDecompiler
jadxRef
,
ResourceType
type
,
InputStream
inputStream
)
throws
IOException
{
switch
(
type
)
{
case
MANIFEST:
...
...
@@ -103,7 +120,7 @@ public final class ResourcesLoader {
addEntry
(
list
,
file
,
entry
);
}
}
catch
(
IOException
e
)
{
LOG
.
debug
(
"Not a zip file:
"
+
file
.
getAbsolutePath
());
LOG
.
debug
(
"Not a zip file:
{}"
,
file
.
getAbsolutePath
());
}
finally
{
if
(
zip
!=
null
)
{
try
{
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
View file @
aa691af6
...
...
@@ -35,6 +35,7 @@ import com.android.dex.ClassData;
import
com.android.dex.ClassData.Field
;
import
com.android.dex.ClassData.Method
;
import
com.android.dex.ClassDef
;
import
com.android.dx.rop.code.AccessFlags
;
public
class
ClassNode
extends
LineAttrNode
implements
ILoadable
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
ClassNode
.
class
);
...
...
@@ -126,6 +127,17 @@ public class ClassNode extends LineAttrNode implements ILoadable {
}
}
// empty synthetic class
public
ClassNode
(
DexNode
dex
,
ClassInfo
clsInfo
)
{
this
.
dex
=
dex
;
this
.
clsInfo
=
clsInfo
;
this
.
interfaces
=
Collections
.
emptyList
();
this
.
methods
=
Collections
.
emptyList
();
this
.
fields
=
Collections
.
emptyList
();
this
.
accessFlags
=
new
AccessInfo
(
AccessFlags
.
ACC_PUBLIC
|
AccessFlags
.
ACC_SYNTHETIC
,
AFType
.
CLASS
);
this
.
parentClass
=
this
;
}
private
void
loadAnnotations
(
ClassDef
cls
)
{
int
offset
=
cls
.
getAnnotationsOffset
();
if
(
offset
!=
0
)
{
...
...
@@ -266,6 +278,12 @@ public class ClassNode extends LineAttrNode implements ILoadable {
if
(
field
==
null
&&
searchGlobal
)
{
field
=
dex
.
getConstFields
().
get
(
obj
);
}
if
(
field
==
null
&&
obj
instanceof
Integer
)
{
String
str
=
dex
.
root
().
getResourcesNames
().
get
(
obj
);
if
(
str
!=
null
)
{
return
new
ResRefField
(
dex
,
str
);
}
}
return
field
;
}
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/FieldNode.java
View file @
aa691af6
...
...
@@ -23,6 +23,13 @@ public class FieldNode extends LineAttrNode {
this
.
accFlags
=
new
AccessInfo
(
field
.
getAccessFlags
(),
AFType
.
FIELD
);
}
public
FieldNode
(
ClassNode
cls
,
FieldInfo
fieldInfo
,
int
accessFlags
)
{
this
.
parent
=
cls
;
this
.
fieldInfo
=
fieldInfo
;
this
.
type
=
fieldInfo
.
getType
();
this
.
accFlags
=
new
AccessInfo
(
accessFlags
,
AFType
.
FIELD
);
}
public
FieldInfo
getFieldInfo
()
{
return
fieldInfo
;
}
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/ResRefField.java
0 → 100644
View file @
aa691af6
package
jadx
.
core
.
dex
.
nodes
;
import
jadx.core.dex.info.FieldInfo
;
import
jadx.core.dex.instructions.args.ArgType
;
import
com.android.dx.rop.code.AccessFlags
;
public
class
ResRefField
extends
FieldNode
{
public
ResRefField
(
DexNode
dex
,
String
str
)
{
super
(
dex
.
root
().
getAppResClass
(),
new
FieldInfo
(
dex
.
root
().
getAppResClass
().
getClassInfo
(),
str
,
ArgType
.
INT
),
AccessFlags
.
ACC_PUBLIC
);
}
}
jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java
View file @
aa691af6
package
jadx
.
core
.
dex
.
nodes
;
import
jadx.api.ResourceFile
;
import
jadx.api.ResourceType
;
import
jadx.api.ResourcesLoader
;
import
jadx.core.clsp.ClspGraph
;
import
jadx.core.dex.info.ClassInfo
;
import
jadx.core.dex.instructions.args.ArgType
;
import
jadx.core.utils.ErrorsCounter
;
import
jadx.core.utils.exceptions.DecodeException
;
import
jadx.core.utils.exceptions.JadxException
;
import
jadx.core.utils.files.InputFile
;
import
jadx.core.xmlgen.ResTableParser
;
import
jadx.core.xmlgen.ResourceStorage
;
import
jadx.core.xmlgen.entry.ResourceEntry
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
org.jetbrains.annotations.Nullable
;
import
org.slf4j.Logger
;
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
List
<
DexNode
>
dexNodes
;
private
Map
<
Integer
,
String
>
resourcesNames
=
new
HashMap
<
Integer
,
String
>();
@Nullable
private
String
appPackage
;
private
ClassNode
appResClass
;
public
void
load
(
List
<
InputFile
>
dexFiles
)
throws
DecodeException
{
dexNodes
=
new
ArrayList
<
DexNode
>(
dexFiles
.
size
());
...
...
@@ -49,6 +68,58 @@ public class RootNode {
initInnerClasses
(
classes
);
}
public
void
loadResources
(
List
<
ResourceFile
>
resources
)
{
ResourceFile
arsc
=
null
;
for
(
ResourceFile
rf
:
resources
)
{
if
(
rf
.
getType
()
==
ResourceType
.
ARSC
)
{
arsc
=
rf
;
break
;
}
}
if
(
arsc
==
null
)
{
LOG
.
debug
(
"'.arsc' file not found"
);
return
;
}
final
ResTableParser
parser
=
new
ResTableParser
();
try
{
ResourcesLoader
.
decodeStream
(
arsc
,
new
ResourcesLoader
.
ResourceDecoder
()
{
@Override
public
Object
decode
(
long
size
,
InputStream
is
)
throws
IOException
{
parser
.
decode
(
is
);
return
null
;
}
});
}
catch
(
JadxException
e
)
{
LOG
.
error
(
"Failed to parse '.arsc' file"
,
e
);
return
;
}
ResourceStorage
resStorage
=
parser
.
getResStorage
();
appPackage
=
resStorage
.
getAppPackage
();
for
(
ResourceEntry
entry
:
resStorage
.
getResources
())
{
resourcesNames
.
put
(
entry
.
getId
(),
entry
.
getTypeName
()
+
"."
+
entry
.
getKeyName
());
}
}
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
;
}
}
}
if
(
resCls
!=
null
)
{
appResClass
=
resCls
;
return
;
}
appResClass
=
new
ClassNode
(
dexNodes
.
get
(
0
),
ClassInfo
.
fromName
(
"R"
));
}
private
static
void
initClassPath
(
List
<
ClassNode
>
classes
)
throws
IOException
,
DecodeException
{
if
(!
ArgType
.
isClspSet
())
{
ClspGraph
clsp
=
new
ClspGraph
();
...
...
@@ -111,4 +182,17 @@ public class RootNode {
public
ErrorsCounter
getErrorsCounter
()
{
return
errorsCounter
;
}
public
Map
<
Integer
,
String
>
getResourcesNames
()
{
return
resourcesNames
;
}
@Nullable
public
String
getAppPackage
()
{
return
appPackage
;
}
public
ClassNode
getAppResClass
()
{
return
appResClass
;
}
}
jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java
View file @
aa691af6
...
...
@@ -132,6 +132,9 @@ public class ResTableParser extends CommonBinaryParser {
}
PackageChunk
pkg
=
new
PackageChunk
(
id
,
name
,
typeStrings
,
keyStrings
);
if
(
id
==
0x7F
)
{
resStorage
.
setAppPackage
(
name
);
}
while
(
is
.
getPos
()
<
endPos
)
{
long
chunkStart
=
is
.
getPos
();
...
...
jadx-core/src/main/java/jadx/core/xmlgen/ResourceStorage.java
View file @
aa691af6
...
...
@@ -19,6 +19,7 @@ public class ResourceStorage {
};
private
final
List
<
ResourceEntry
>
list
=
new
ArrayList
<
ResourceEntry
>();
private
String
appPackage
;
public
Collection
<
ResourceEntry
>
getResources
()
{
return
list
;
...
...
@@ -40,4 +41,12 @@ public class ResourceStorage {
}
return
list
.
get
(
index
);
}
public
String
getAppPackage
()
{
return
appPackage
;
}
public
void
setAppPackage
(
String
appPackage
)
{
this
.
appPackage
=
appPackage
;
}
}
jadx-core/src/test/java/jadx/tests/api/IntegrationTest.java
View file @
aa691af6
...
...
@@ -8,6 +8,7 @@ import jadx.core.dex.attributes.AFlag;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.core.dex.nodes.MethodNode
;
import
jadx.core.dex.nodes.RootNode
;
import
jadx.core.dex.visitors.DepthTraversal
;
import
jadx.core.dex.visitors.IDexTreeVisitor
;
import
jadx.core.utils.exceptions.JadxException
;
...
...
@@ -26,8 +27,10 @@ import java.net.URISyntaxException;
import
java.net.URL
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Collections
;
import
java.util.Iterator
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.jar.JarOutputStream
;
import
static
org
.
hamcrest
.
CoreMatchers
.
containsString
;
...
...
@@ -47,9 +50,10 @@ public abstract class IntegrationTest extends TestUtils {
protected
boolean
outputCFG
=
false
;
protected
boolean
isFallback
=
false
;
protected
boolean
deleteTmpFiles
=
true
;
protected
boolean
withDebugInfo
=
true
;
protected
Map
<
Integer
,
String
>
resMap
=
Collections
.
emptyMap
();
protected
String
outDir
=
"test-out-tmp"
;
protected
boolean
compile
=
true
;
...
...
@@ -72,7 +76,10 @@ public abstract class IntegrationTest extends TestUtils {
}
catch
(
JadxException
e
)
{
fail
(
e
.
getMessage
());
}
ClassNode
cls
=
JadxInternalAccess
.
getRoot
(
d
).
searchClassByName
(
clsName
);
RootNode
root
=
JadxInternalAccess
.
getRoot
(
d
);
root
.
getResourcesNames
().
putAll
(
resMap
);
ClassNode
cls
=
root
.
searchClassByName
(
clsName
);
assertNotNull
(
"Class not found: "
+
clsName
,
cls
);
assertEquals
(
cls
.
getFullName
(),
clsName
);
...
...
@@ -340,6 +347,10 @@ public abstract class IntegrationTest extends TestUtils {
return
files
;
}
public
void
setResMap
(
Map
<
Integer
,
String
>
resMap
)
{
this
.
resMap
=
resMap
;
}
protected
void
noDebugInfo
()
{
this
.
withDebugInfo
=
false
;
}
...
...
jadx-core/src/test/java/jadx/tests/integration/inner/TestRFieldRestore.java
0 → 100644
View file @
aa691af6
package
jadx
.
tests
.
integration
.
inner
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.tests.api.IntegrationTest
;
import
java.util.HashMap
;
import
java.util.Map
;
import
org.junit.Test
;
import
static
jadx
.
tests
.
api
.
utils
.
JadxMatchers
.
containsOne
;
import
static
org
.
junit
.
Assert
.
assertThat
;
public
class
TestRFieldRestore
extends
IntegrationTest
{
public
static
class
TestCls
{
public
int
test
()
{
return
2131230730
;
}
}
@Test
public
void
test
()
{
// unknown R class
disableCompilation
();
Map
<
Integer
,
String
>
map
=
new
HashMap
<
Integer
,
String
>();
map
.
put
(
2131230730
,
"id.Button"
);
setResMap
(
map
);
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
String
code
=
cls
.
getCode
().
toString
();
assertThat
(
code
,
containsOne
(
"return R.id.Button;"
));
}
}
jadx-core/src/test/java/jadx/tests/integration/inner/TestRFieldRestore2.java
0 → 100644
View file @
aa691af6
package
jadx
.
tests
.
integration
.
inner
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.tests.api.IntegrationTest
;
import
java.util.HashMap
;
import
java.util.Map
;
import
org.junit.Test
;
import
static
jadx
.
tests
.
api
.
utils
.
JadxMatchers
.
containsOne
;
import
static
org
.
junit
.
Assert
.
assertThat
;
public
class
TestRFieldRestore2
extends
IntegrationTest
{
public
static
class
TestCls
{
public
static
class
R
{
}
public
int
test
()
{
return
2131230730
;
}
}
@Test
public
void
test
()
{
// unknown id.Button
disableCompilation
();
Map
<
Integer
,
String
>
map
=
new
HashMap
<
Integer
,
String
>();
map
.
put
(
2131230730
,
"id.Button"
);
setResMap
(
map
);
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
String
code
=
cls
.
getCode
().
toString
();
assertThat
(
code
,
containsOne
(
"return R.id.Button;"
));
}
}
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