Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
qq_39073359
jadx
提交
691bf8fa
J
jadx
项目概览
qq_39073359
/
jadx
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
J
jadx
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
691bf8fa
编写于
9月 07, 2020
作者:
S
Skylot
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
fix: checks for casts in field access, move method inline to visitor (#962)
Signed-off-by:
N
Skylot
<
skylot@gmail.com
>
上级
89b4ae6a
变更
15
隐藏空白更改
内联
并排
Showing
15 changed file
with
373 addition
and
114 deletion
+373
-114
jadx-core/src/main/java/jadx/core/Consts.java
jadx-core/src/main/java/jadx/core/Consts.java
+1
-0
jadx-core/src/main/java/jadx/core/Jadx.java
jadx-core/src/main/java/jadx/core/Jadx.java
+5
-2
jadx-core/src/main/java/jadx/core/ProcessClass.java
jadx-core/src/main/java/jadx/core/ProcessClass.java
+5
-1
jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
+0
-67
jadx-core/src/main/java/jadx/core/dex/attributes/AFlag.java
jadx-core/src/main/java/jadx/core/dex/attributes/AFlag.java
+3
-1
jadx-core/src/main/java/jadx/core/dex/attributes/nodes/MethodInlineAttr.java
...java/jadx/core/dex/attributes/nodes/MethodInlineAttr.java
+27
-2
jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
+27
-0
jadx-core/src/main/java/jadx/core/dex/nodes/LoadStage.java
jadx-core/src/main/java/jadx/core/dex/nodes/LoadStage.java
+7
-0
jadx-core/src/main/java/jadx/core/dex/visitors/FixAccessModifiers.java
.../main/java/jadx/core/dex/visitors/FixAccessModifiers.java
+1
-1
jadx-core/src/main/java/jadx/core/dex/visitors/InlineMethods.java
...e/src/main/java/jadx/core/dex/visitors/InlineMethods.java
+132
-0
jadx-core/src/main/java/jadx/core/dex/visitors/MarkMethodsForInline.java
...ain/java/jadx/core/dex/visitors/MarkMethodsForInline.java
+48
-34
jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java
...core/src/main/java/jadx/core/dex/visitors/ModVisitor.java
+49
-4
jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeCompare.java
...ava/jadx/core/dex/visitors/typeinference/TypeCompare.java
+5
-0
jadx-core/src/main/java/jadx/core/utils/InsnRemover.java
jadx-core/src/main/java/jadx/core/utils/InsnRemover.java
+2
-2
jadx-core/src/test/java/jadx/tests/integration/types/TestFieldCast.java
...test/java/jadx/tests/integration/types/TestFieldCast.java
+61
-0
未找到文件。
jadx-core/src/main/java/jadx/core/Consts.java
浏览文件 @
691bf8fa
...
...
@@ -2,6 +2,7 @@ package jadx.core;
public
class
Consts
{
public
static
final
boolean
DEBUG
=
false
;
public
static
final
boolean
DEBUG_WITH_ERRORS
=
false
;
// TODO: fix errors
public
static
final
boolean
DEBUG_USAGE
=
false
;
public
static
final
boolean
DEBUG_TYPE_INFERENCE
=
false
;
public
static
final
boolean
DEBUG_OVERLOADED_CASTS
=
false
;
...
...
jadx-core/src/main/java/jadx/core/Jadx.java
浏览文件 @
691bf8fa
...
...
@@ -25,8 +25,9 @@ import jadx.core.dex.visitors.FixAccessModifiers;
import
jadx.core.dex.visitors.GenericTypesVisitor
;
import
jadx.core.dex.visitors.IDexTreeVisitor
;
import
jadx.core.dex.visitors.InitCodeVariables
;
import
jadx.core.dex.visitors.InlineMethods
;
import
jadx.core.dex.visitors.MarkFinallyVisitor
;
import
jadx.core.dex.visitors.M
ethodInlineVisitor
;
import
jadx.core.dex.visitors.M
arkMethodsForInline
;
import
jadx.core.dex.visitors.MethodInvokeVisitor
;
import
jadx.core.dex.visitors.ModVisitor
;
import
jadx.core.dex.visitors.MoveInlineVisitor
;
...
...
@@ -119,6 +120,7 @@ public class Jadx {
passes
.
add
(
new
DebugInfoApplyVisitor
());
}
passes
.
add
(
new
InlineMethods
());
passes
.
add
(
new
GenericTypesVisitor
());
passes
.
add
(
new
ShadowFieldVisitor
());
passes
.
add
(
new
DeboxingVisitor
());
...
...
@@ -144,9 +146,10 @@ public class Jadx {
passes
.
add
(
new
FixAccessModifiers
());
passes
.
add
(
new
ProcessAnonymous
());
passes
.
add
(
new
ClassModifier
());
passes
.
add
(
new
MethodInlineVisitor
());
passes
.
add
(
new
LoopRegionVisitor
());
passes
.
add
(
new
MarkMethodsForInline
());
passes
.
add
(
new
ProcessVariables
());
passes
.
add
(
new
PrepareForCodeGen
());
if
(
args
.
isCfgOutput
())
{
...
...
jadx-core/src/main/java/jadx/core/ProcessClass.java
浏览文件 @
691bf8fa
...
...
@@ -59,7 +59,11 @@ public final class ProcessClass {
cls
.
setState
(
NOT_LOADED
);
}
try
{
cls
.
getDependencies
().
forEach
(
ProcessClass:
:
process
);
for
(
ClassNode
depCls
:
cls
.
getDependencies
())
{
depCls
.
startProcessStage
();
process
(
depCls
);
}
cls
.
startCodegenStage
();
process
(
cls
);
ICodeInfo
code
=
CodeGen
.
generate
(
cls
);
...
...
jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
浏览文件 @
691bf8fa
package
jadx.core.codegen
;
import
java.util.ArrayList
;
import
java.util.EnumSet
;
import
java.util.Iterator
;
import
java.util.List
;
...
...
@@ -10,14 +9,12 @@ import org.jetbrains.annotations.Nullable;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
jadx.core.Consts
;
import
jadx.core.deobf.NameMapper
;
import
jadx.core.dex.attributes.AFlag
;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.attributes.nodes.FieldReplaceAttr
;
import
jadx.core.dex.attributes.nodes.GenericInfoAttr
;
import
jadx.core.dex.attributes.nodes.LoopLabelAttr
;
import
jadx.core.dex.attributes.nodes.MethodInlineAttr
;
import
jadx.core.dex.attributes.nodes.SkipMethodArgsAttr
;
import
jadx.core.dex.info.ClassInfo
;
import
jadx.core.dex.info.FieldInfo
;
...
...
@@ -43,7 +40,6 @@ import jadx.core.dex.instructions.args.InsnArg;
import
jadx.core.dex.instructions.args.InsnWrapArg
;
import
jadx.core.dex.instructions.args.LiteralArg
;
import
jadx.core.dex.instructions.args.Named
;
import
jadx.core.dex.instructions.args.NamedArg
;
import
jadx.core.dex.instructions.args.RegisterArg
;
import
jadx.core.dex.instructions.args.SSAVar
;
import
jadx.core.dex.instructions.mods.ConstructorInsn
;
...
...
@@ -705,12 +701,7 @@ public class InsnGen {
private
void
makeInvoke
(
InvokeNode
insn
,
CodeWriter
code
)
throws
CodegenException
{
MethodInfo
callMth
=
insn
.
getCallMth
();
// inline method
MethodNode
callMthNode
=
mth
.
root
().
deepResolveMethod
(
callMth
);
if
(
callMthNode
!=
null
&&
inlineMethod
(
callMthNode
,
insn
,
code
))
{
return
;
}
int
k
=
0
;
InvokeType
type
=
insn
.
getInvokeType
();
...
...
@@ -844,64 +835,6 @@ public class InsnGen {
return
true
;
}
private
boolean
inlineMethod
(
MethodNode
callMthNode
,
InvokeNode
insn
,
CodeWriter
code
)
throws
CodegenException
{
MethodInlineAttr
mia
=
callMthNode
.
get
(
AType
.
METHOD_INLINE
);
if
(
mia
==
null
)
{
return
false
;
}
InsnNode
inl
=
mia
.
getInsn
();
if
(
Consts
.
DEBUG
)
{
code
.
add
(
"/* inline method: "
).
add
(
callMthNode
.
toString
()).
add
(
"*/"
).
startLine
();
}
if
(
forceAssign
(
inl
,
insn
,
callMthNode
))
{
ArgType
varType
=
callMthNode
.
getReturnType
();
useType
(
code
,
varType
);
code
.
add
(
' '
);
code
.
add
(
mgen
.
getNameGen
().
assignNamedArg
(
new
NamedArg
(
"unused"
,
varType
)));
code
.
add
(
" = "
);
}
if
(
callMthNode
.
getMethodInfo
().
getArgumentsTypes
().
isEmpty
())
{
makeInsn
(
inl
,
code
,
Flags
.
BODY_ONLY
);
}
else
{
// remap args
InsnArg
[]
regs
=
new
InsnArg
[
callMthNode
.
getRegsCount
()];
int
[]
regNums
=
mia
.
getArgsRegNums
();
for
(
int
i
=
0
;
i
<
regNums
.
length
;
i
++)
{
InsnArg
arg
=
insn
.
getArg
(
i
);
regs
[
regNums
[
i
]]
=
arg
;
}
// replace args
InsnNode
inlCopy
=
inl
.
copyWithoutResult
();
List
<
RegisterArg
>
inlArgs
=
new
ArrayList
<>();
inlCopy
.
getRegisterArgs
(
inlArgs
);
for
(
RegisterArg
r
:
inlArgs
)
{
int
regNum
=
r
.
getRegNum
();
if
(
regNum
>=
regs
.
length
)
{
LOG
.
warn
(
"Unknown register number {} in method call: {} from {}"
,
r
,
callMthNode
,
mth
);
}
else
{
InsnArg
repl
=
regs
[
regNum
];
if
(
repl
==
null
)
{
LOG
.
warn
(
"Not passed register {} in method call: {} from {}"
,
r
,
callMthNode
,
mth
);
}
else
{
inlCopy
.
replaceArg
(
r
,
repl
);
}
}
}
makeInsn
(
inlCopy
,
code
,
Flags
.
BODY_ONLY
);
}
return
true
;
}
private
boolean
forceAssign
(
InsnNode
inlineInsn
,
InvokeNode
parentInsn
,
MethodNode
callMthNode
)
{
if
(
parentInsn
.
getResult
()
!=
null
)
{
return
false
;
}
if
(
parentInsn
.
contains
(
AFlag
.
WRAPPED
))
{
return
false
;
}
return
!
callMthNode
.
isVoidReturn
();
}
private
void
makeTernary
(
TernaryInsn
insn
,
CodeWriter
code
,
Set
<
Flags
>
state
)
throws
CodegenException
{
boolean
wrap
=
state
.
contains
(
Flags
.
BODY_ONLY
);
if
(
wrap
)
{
...
...
jadx-core/src/main/java/jadx/core/dex/attributes/AFlag.java
浏览文件 @
691bf8fa
...
...
@@ -22,7 +22,9 @@ public enum AFlag {
HIDDEN
,
// instruction used inside other instruction but not listed in args
RESTART_CODEGEN
,
RESTART_CODEGEN
,
// codegen must be executed again
RELOAD_AT_CODEGEN_STAGE
,
// class can't be analyzed at 'process' stage => unload before 'codegen' stage
DONT_RENAME
,
// do not rename during deobfuscation
ADDED_TO_REGION
,
...
...
jadx-core/src/main/java/jadx/core/dex/attributes/nodes/MethodInlineAttr.java
浏览文件 @
691bf8fa
package
jadx.core.dex.attributes.nodes
;
import
java.util.List
;
import
java.util.Objects
;
import
jadx.core.Consts
;
import
jadx.core.dex.attributes.AFlag
;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.attributes.IAttribute
;
import
jadx.core.dex.instructions.args.RegisterArg
;
...
...
@@ -10,7 +13,10 @@ import jadx.core.dex.nodes.MethodNode;
public
class
MethodInlineAttr
implements
IAttribute
{
public
static
void
markForInline
(
MethodNode
mth
,
InsnNode
replaceInsn
)
{
private
static
final
MethodInlineAttr
INLINE_NOT_NEEDED
=
new
MethodInlineAttr
(
null
,
null
);
public
static
MethodInlineAttr
markForInline
(
MethodNode
mth
,
InsnNode
replaceInsn
)
{
Objects
.
requireNonNull
(
replaceInsn
);
List
<
RegisterArg
>
allArgRegs
=
mth
.
getAllArgRegs
();
int
argsCount
=
allArgRegs
.
size
();
int
[]
regNums
=
new
int
[
argsCount
];
...
...
@@ -18,7 +24,19 @@ public class MethodInlineAttr implements IAttribute {
RegisterArg
reg
=
allArgRegs
.
get
(
i
);
regNums
[
i
]
=
reg
.
getRegNum
();
}
mth
.
addAttr
(
new
MethodInlineAttr
(
replaceInsn
,
regNums
));
MethodInlineAttr
mia
=
new
MethodInlineAttr
(
replaceInsn
,
regNums
);
mth
.
addAttr
(
mia
);
if
(
Consts
.
DEBUG
)
{
mth
.
addAttr
(
AType
.
COMMENTS
,
"Removed for inline"
);
}
else
{
mth
.
add
(
AFlag
.
DONT_GENERATE
);
}
return
mia
;
}
public
static
MethodInlineAttr
inlineNotNeeded
(
MethodNode
mth
)
{
mth
.
addAttr
(
INLINE_NOT_NEEDED
);
return
INLINE_NOT_NEEDED
;
}
private
final
InsnNode
insn
;
...
...
@@ -33,6 +51,10 @@ public class MethodInlineAttr implements IAttribute {
this
.
argsRegNums
=
argsRegNums
;
}
public
boolean
notNeeded
()
{
return
insn
==
null
;
}
public
InsnNode
getInsn
()
{
return
insn
;
}
...
...
@@ -48,6 +70,9 @@ public class MethodInlineAttr implements IAttribute {
@Override
public
String
toString
()
{
if
(
notNeeded
())
{
return
"INLINE_NOT_NEEDED"
;
}
return
"INLINE: "
+
insn
;
}
}
jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
浏览文件 @
691bf8fa
...
...
@@ -65,6 +65,7 @@ public class ClassNode extends NotificationAttrNode implements ILoadable, ICodeN
private
ClassNode
parentClass
;
private
volatile
ProcessState
state
=
ProcessState
.
NOT_LOADED
;
private
LoadStage
loadStage
=
LoadStage
.
NONE
;
/** Top level classes used in this class (only for top level classes, empty for inners) */
private
List
<
ClassNode
>
dependencies
=
Collections
.
emptyList
();
...
...
@@ -288,6 +289,7 @@ public class ClassNode extends NotificationAttrNode implements ILoadable, ICodeN
fields
.
forEach
(
FieldNode:
:
unloadAttributes
);
unloadAttributes
();
setState
(
NOT_LOADED
);
this
.
loadStage
=
LoadStage
.
NONE
;
this
.
smali
=
null
;
}
...
...
@@ -577,6 +579,30 @@ public class ClassNode extends NotificationAttrNode implements ILoadable, ICodeN
this
.
state
=
state
;
}
public
LoadStage
getLoadStage
()
{
return
loadStage
;
}
public
void
startProcessStage
()
{
this
.
loadStage
=
LoadStage
.
PROCESS_STAGE
;
}
public
void
startCodegenStage
()
{
this
.
loadStage
=
LoadStage
.
CODEGEN_STAGE
;
if
(
contains
(
AFlag
.
RELOAD_AT_CODEGEN_STAGE
))
{
unload
();
remove
(
AFlag
.
RELOAD_AT_CODEGEN_STAGE
);
}
}
public
void
reloadAtCodegenStage
()
{
ClassNode
topCls
=
this
.
getTopParentClass
();
if
(
topCls
.
getLoadStage
()
==
LoadStage
.
CODEGEN_STAGE
)
{
throw
new
JadxRuntimeException
(
"Class not yet loaded at codegen stage"
);
}
topCls
.
add
(
AFlag
.
RELOAD_AT_CODEGEN_STAGE
);
}
public
List
<
ClassNode
>
getDependencies
()
{
return
dependencies
;
}
...
...
@@ -632,4 +658,5 @@ public class ClassNode extends NotificationAttrNode implements ILoadable, ICodeN
public
String
toString
()
{
return
clsInfo
.
getFullName
();
}
}
jadx-core/src/main/java/jadx/core/dex/nodes/LoadStage.java
0 → 100644
浏览文件 @
691bf8fa
package
jadx.core.dex.nodes
;
public
enum
LoadStage
{
NONE
,
PROCESS_STAGE
,
// dependencies not yet loaded
CODEGEN_STAGE
,
// all dependencies loaded
}
jadx-core/src/main/java/jadx/core/dex/visitors/FixAccessModifiers.java
浏览文件 @
691bf8fa
...
...
@@ -83,7 +83,7 @@ public class FixAccessModifiers extends AbstractVisitor {
if
(!
accessFlags
.
isPublic
())
{
// if class is used in inlinable method => make it public
for
(
MethodNode
useMth
:
cls
.
getUseInMth
())
{
boolean
canInline
=
M
ethodInlineVisitor
.
canInline
(
useMth
)
||
useMth
.
contains
(
AType
.
METHOD_INLINE
);
boolean
canInline
=
M
arkMethodsForInline
.
canInline
(
useMth
)
||
useMth
.
contains
(
AType
.
METHOD_INLINE
);
if
(
canInline
&&
!
useMth
.
getUseIn
().
isEmpty
())
{
return
AccessFlags
.
PUBLIC
;
}
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/InlineMethods.java
0 → 100644
浏览文件 @
691bf8fa
package
jadx.core.dex.visitors
;
import
java.util.ArrayList
;
import
java.util.List
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
jadx.core.dex.attributes.AFlag
;
import
jadx.core.dex.attributes.nodes.MethodInlineAttr
;
import
jadx.core.dex.info.MethodInfo
;
import
jadx.core.dex.instructions.InsnType
;
import
jadx.core.dex.instructions.InvokeNode
;
import
jadx.core.dex.instructions.args.ArgType
;
import
jadx.core.dex.instructions.args.InsnArg
;
import
jadx.core.dex.instructions.args.RegisterArg
;
import
jadx.core.dex.instructions.args.SSAVar
;
import
jadx.core.dex.nodes.BlockNode
;
import
jadx.core.dex.nodes.InsnNode
;
import
jadx.core.dex.nodes.MethodNode
;
import
jadx.core.dex.visitors.typeinference.TypeInferenceVisitor
;
import
jadx.core.utils.BlockUtils
;
import
jadx.core.utils.exceptions.JadxException
;
import
jadx.core.utils.exceptions.JadxRuntimeException
;
@JadxVisitor
(
name
=
"InlineMethods"
,
desc
=
"Inline methods (previously marked in MarkMethodsForInline)"
,
runAfter
=
TypeInferenceVisitor
.
class
,
runBefore
=
ModVisitor
.
class
)
public
class
InlineMethods
extends
AbstractVisitor
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
InlineMethods
.
class
);
@Override
public
void
visit
(
MethodNode
mth
)
throws
JadxException
{
if
(
mth
.
isNoCode
())
{
return
;
}
for
(
BlockNode
block
:
mth
.
getBasicBlocks
())
{
for
(
InsnNode
insn
:
block
.
getInstructions
())
{
if
(
insn
.
getType
()
==
InsnType
.
INVOKE
)
{
processInvokeInsn
(
mth
,
block
,
((
InvokeNode
)
insn
));
}
}
}
}
private
void
processInvokeInsn
(
MethodNode
mth
,
BlockNode
block
,
InvokeNode
insn
)
{
MethodInfo
callMthInfo
=
insn
.
getCallMth
();
MethodNode
callMth
=
mth
.
root
().
deepResolveMethod
(
callMthInfo
);
if
(
callMth
==
null
)
{
return
;
}
try
{
// TODO: sort inner classes process order by dependencies!
MethodInlineAttr
mia
=
MarkMethodsForInline
.
process
(
callMth
);
if
(
mia
==
null
)
{
// method not yet loaded => will retry at codegen stage
mth
.
getParentClass
().
reloadAtCodegenStage
();
return
;
}
if
(
mia
.
notNeeded
())
{
return
;
}
inlineMethod
(
mth
,
callMth
,
mia
,
block
,
insn
);
}
catch
(
Exception
e
)
{
throw
new
JadxRuntimeException
(
"Failed to process method for inline"
,
e
);
}
}
private
void
inlineMethod
(
MethodNode
mth
,
MethodNode
callMth
,
MethodInlineAttr
mia
,
BlockNode
block
,
InvokeNode
insn
)
{
InsnNode
inlCopy
=
mia
.
getInsn
().
copyWithoutResult
();
RegisterArg
resultArg
=
insn
.
getResult
();
if
(
resultArg
!=
null
)
{
inlCopy
.
setResult
(
resultArg
.
duplicate
());
}
else
if
(
isAssignNeeded
(
mia
.
getInsn
(),
insn
,
callMth
))
{
// add fake result to make correct java expression (see test TestGetterInlineNegative)
inlCopy
.
setResult
(
makeFakeArg
(
mth
,
callMth
.
getReturnType
(),
"unused"
));
}
if
(!
callMth
.
getMethodInfo
().
getArgumentsTypes
().
isEmpty
())
{
// remap args
InsnArg
[]
regs
=
new
InsnArg
[
callMth
.
getRegsCount
()];
int
[]
regNums
=
mia
.
getArgsRegNums
();
for
(
int
i
=
0
;
i
<
regNums
.
length
;
i
++)
{
InsnArg
arg
=
insn
.
getArg
(
i
);
regs
[
regNums
[
i
]]
=
arg
;
}
// replace args
List
<
RegisterArg
>
inlArgs
=
new
ArrayList
<>();
inlCopy
.
getRegisterArgs
(
inlArgs
);
for
(
RegisterArg
r
:
inlArgs
)
{
int
regNum
=
r
.
getRegNum
();
if
(
regNum
>=
regs
.
length
)
{
LOG
.
warn
(
"Unknown register number {} in method call: {} from {}"
,
r
,
callMth
,
mth
);
}
else
{
InsnArg
repl
=
regs
[
regNum
];
if
(
repl
==
null
)
{
LOG
.
warn
(
"Not passed register {} in method call: {} from {}"
,
r
,
callMth
,
mth
);
}
else
{
inlCopy
.
replaceArg
(
r
,
repl
);
}
}
}
}
if
(!
BlockUtils
.
replaceInsn
(
mth
,
block
,
insn
,
inlCopy
))
{
mth
.
addWarnComment
(
"Failed to inline method: "
+
callMth
);
}
}
private
boolean
isAssignNeeded
(
InsnNode
inlineInsn
,
InvokeNode
parentInsn
,
MethodNode
callMthNode
)
{
if
(
parentInsn
.
getResult
()
!=
null
)
{
return
false
;
}
if
(
parentInsn
.
contains
(
AFlag
.
WRAPPED
))
{
return
false
;
}
if
(
inlineInsn
.
getType
()
==
InsnType
.
IPUT
)
{
return
false
;
}
return
!
callMthNode
.
isVoidReturn
();
}
private
RegisterArg
makeFakeArg
(
MethodNode
mth
,
ArgType
varType
,
String
name
)
{
RegisterArg
fakeArg
=
RegisterArg
.
reg
(
0
,
varType
);
SSAVar
ssaVar
=
mth
.
makeNewSVar
(
fakeArg
);
InitCodeVariables
.
initCodeVar
(
ssaVar
);
fakeArg
.
setName
(
name
);
ssaVar
.
setType
(
varType
);
return
fakeArg
;
}
}
jadx-core/src/main/java/jadx/core/dex/visitors/M
ethodInlineVisitor
.java
→
jadx-core/src/main/java/jadx/core/dex/visitors/M
arkMethodsForInline
.java
浏览文件 @
691bf8fa
...
...
@@ -3,6 +3,8 @@ package jadx.core.dex.visitors;
import
java.util.ArrayList
;
import
java.util.List
;
import
org.jetbrains.annotations.Nullable
;
import
jadx.api.plugins.input.data.AccessFlags
;
import
jadx.core.Consts
;
import
jadx.core.dex.attributes.AFlag
;
...
...
@@ -17,30 +19,50 @@ import jadx.core.dex.instructions.args.InsnArg;
import
jadx.core.dex.instructions.args.InsnWrapArg
;
import
jadx.core.dex.instructions.args.RegisterArg
;
import
jadx.core.dex.nodes.BlockNode
;
import
jadx.core.dex.nodes.FieldNode
;
import
jadx.core.dex.nodes.InsnNode
;
import
jadx.core.dex.nodes.MethodNode
;
import
jadx.core.utils.exceptions.JadxException
;
@JadxVisitor
(
name
=
"
InlineMethods
"
,
desc
=
"
Inline synthetic static methods
"
,
name
=
"
MarkMethodsForInline
"
,
desc
=
"
Mark synthetic static methods for inline
"
,
runAfter
=
{
FixAccessModifiers
.
class
,
ClassModifier
.
class
}
)
public
class
M
ethodInlineVisitor
extends
AbstractVisitor
{
public
class
M
arkMethodsForInline
extends
AbstractVisitor
{
@Override
public
void
visit
(
MethodNode
mth
)
throws
JadxException
{
if
(
canInline
(
mth
)
&&
mth
.
getBasicBlocks
().
size
()
==
2
)
{
BlockNode
returnBlock
=
mth
.
getBasicBlocks
().
get
(
1
);
if
(
returnBlock
.
contains
(
AFlag
.
RETURN
)
||
returnBlock
.
getInstructions
().
isEmpty
())
{
BlockNode
firstBlock
=
mth
.
getBasicBlocks
().
get
(
0
);
inlineMth
(
mth
,
firstBlock
,
returnBlock
);
process
(
mth
);
}
/**
* @return null if method can't be analyzed (not loaded)
*/
@Nullable
public
static
MethodInlineAttr
process
(
MethodNode
mth
)
{
MethodInlineAttr
mia
=
mth
.
get
(
AType
.
METHOD_INLINE
);
if
(
mia
!=
null
)
{
return
mia
;
}
if
(
canInline
(
mth
))
{
List
<
BlockNode
>
blocks
=
mth
.
getBasicBlocks
();
if
(
blocks
==
null
)
{
return
null
;
}
if
(
blocks
.
size
()
==
2
)
{
BlockNode
returnBlock
=
blocks
.
get
(
1
);
if
(
returnBlock
.
contains
(
AFlag
.
RETURN
)
||
returnBlock
.
getInstructions
().
isEmpty
())
{
MethodInlineAttr
inlined
=
inlineMth
(
mth
,
blocks
.
get
(
0
),
returnBlock
);
if
(
inlined
!=
null
)
{
return
inlined
;
}
}
}
}
return
MethodInlineAttr
.
inlineNotNeeded
(
mth
);
}
public
static
boolean
canInline
(
MethodNode
mth
)
{
...
...
@@ -51,41 +73,36 @@ public class MethodInlineVisitor extends AbstractVisitor {
return
accessFlags
.
isSynthetic
()
&&
accessFlags
.
isStatic
();
}
private
static
void
inlineMth
(
MethodNode
mth
,
BlockNode
firstBlock
,
BlockNode
returnBlock
)
{
@Nullable
private
static
MethodInlineAttr
inlineMth
(
MethodNode
mth
,
BlockNode
firstBlock
,
BlockNode
returnBlock
)
{
List
<
InsnNode
>
insnList
=
firstBlock
.
getInstructions
();
if
(
insnList
.
isEmpty
())
{
// synthetic field getter
BlockNode
block
=
mth
.
getBasicBlocks
().
get
(
1
);
InsnNode
insn
=
block
.
getInstructions
().
get
(
0
);
// set arg from 'return' instruction
addInlineAttr
(
mth
,
InsnNode
.
wrapArg
(
insn
.
getArg
(
0
)));
return
;
return
addInlineAttr
(
mth
,
InsnNode
.
wrapArg
(
insn
.
getArg
(
0
)));
}
// synthetic field setter or method invoke
if
(
insnList
.
size
()
==
1
)
{
addInlineAttr
(
mth
,
insnList
.
get
(
0
));
return
;
return
addInlineAttr
(
mth
,
insnList
.
get
(
0
));
}
// TODO: inline field arithmetics. Disabled tests: TestAnonymousClass3a and TestAnonymousClass5
return
null
;
}
private
static
void
addInlineAttr
(
MethodNode
mth
,
InsnNode
insn
)
{
if
(
fixVisibilityOfInlineCode
(
mth
,
insn
))
{
if
(
Consts
.
DEBUG
)
{
mth
.
addAttr
(
AType
.
COMMENTS
,
"Removed for inline"
);
}
else
{
InsnNode
copy
=
insn
.
copyWithoutResult
();
// unbind SSA variables from copy instruction
List
<
RegisterArg
>
regArgs
=
new
ArrayList
<>();
copy
.
getRegisterArgs
(
regArgs
);
for
(
RegisterArg
regArg
:
regArgs
)
{
copy
.
replaceArg
(
regArg
,
regArg
.
duplicate
(
regArg
.
getRegNum
(),
null
));
}
MethodInlineAttr
.
markForInline
(
mth
,
copy
);
mth
.
add
(
AFlag
.
DONT_GENERATE
);
}
private
static
MethodInlineAttr
addInlineAttr
(
MethodNode
mth
,
InsnNode
insn
)
{
if
(!
fixVisibilityOfInlineCode
(
mth
,
insn
))
{
return
null
;
}
InsnNode
copy
=
insn
.
copyWithoutResult
();
// unbind SSA variables from copy instruction
List
<
RegisterArg
>
regArgs
=
new
ArrayList
<>();
copy
.
getRegisterArgs
(
regArgs
);
for
(
RegisterArg
regArg
:
regArgs
)
{
copy
.
replaceArg
(
regArg
,
regArg
.
duplicate
(
regArg
.
getRegNum
(),
null
));
}
return
MethodInlineAttr
.
markForInline
(
mth
,
copy
);
}
private
static
boolean
fixVisibilityOfInlineCode
(
MethodNode
mth
,
InsnNode
insn
)
{
...
...
@@ -109,10 +126,7 @@ public class MethodInlineVisitor extends AbstractVisitor {
if
(
insn
instanceof
IndexInsnNode
)
{
Object
indexObj
=
((
IndexInsnNode
)
insn
).
getIndex
();
if
(
indexObj
instanceof
FieldInfo
)
{
FieldNode
fieldNode
=
mth
.
root
().
deepResolveField
(((
FieldInfo
)
indexObj
));
if
(
fieldNode
!=
null
)
{
FixAccessModifiers
.
changeVisibility
(
fieldNode
,
newVisFlag
);
}
// field access must be already fixed in ModVisitor.fixFieldUsage method
return
true
;
}
}
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java
浏览文件 @
691bf8fa
...
...
@@ -4,6 +4,7 @@ import java.util.Collections;
import
java.util.LinkedHashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Objects
;
import
org.jetbrains.annotations.Nullable
;
import
org.slf4j.Logger
;
...
...
@@ -18,6 +19,7 @@ import jadx.core.dex.attributes.AType;
import
jadx.core.dex.attributes.AttrNode
;
import
jadx.core.dex.attributes.annotations.AnnotationsList
;
import
jadx.core.dex.attributes.nodes.FieldReplaceAttr
;
import
jadx.core.dex.info.AccessInfo
;
import
jadx.core.dex.info.FieldInfo
;
import
jadx.core.dex.info.MethodInfo
;
import
jadx.core.dex.instructions.ArithNode
;
...
...
@@ -148,7 +150,7 @@ public class ModVisitor extends AbstractVisitor {
case
IPUT:
case
IGET:
fix
TypeForFieldAccess
(
mth
,
(
IndexInsnNode
)
insn
);
fix
FieldUsage
(
mth
,
(
IndexInsnNode
)
insn
);
break
;
default
:
...
...
@@ -159,7 +161,10 @@ public class ModVisitor extends AbstractVisitor {
}
}
private
static
void
fixTypeForFieldAccess
(
MethodNode
mth
,
IndexInsnNode
insn
)
{
/**
* If field is not visible from use site => cast to origin class
*/
private
static
void
fixFieldUsage
(
MethodNode
mth
,
IndexInsnNode
insn
)
{
InsnArg
instanceArg
=
insn
.
getArg
(
insn
.
getType
()
==
InsnType
.
IGET
?
0
:
1
);
if
(
instanceArg
.
contains
(
AFlag
.
SUPER
))
{
return
;
...
...
@@ -170,12 +175,25 @@ public class ModVisitor extends AbstractVisitor {
FieldInfo
fieldInfo
=
(
FieldInfo
)
insn
.
getIndex
();
ArgType
clsType
=
fieldInfo
.
getDeclClass
().
getType
();
ArgType
instanceType
=
instanceArg
.
getType
();
TypeCompareEnum
result
=
mth
.
root
().
getTypeCompare
().
compareTypes
(
instanceType
,
clsType
);
if
(
result
.
isEqual
()
||
(
result
==
TypeCompareEnum
.
NARROW_BY_GENERIC
&&
!
instanceType
.
isGenericType
()))
{
if
(
Objects
.
equals
(
clsType
,
instanceType
))
{
// cast not needed
return
;
}
FieldNode
fieldNode
=
mth
.
root
().
resolveField
(
fieldInfo
);
if
(
fieldNode
==
null
)
{
// unknown field
TypeCompareEnum
result
=
mth
.
root
().
getTypeCompare
().
compareTypes
(
instanceType
,
clsType
);
if
(
result
.
isEqual
()
||
(
result
==
TypeCompareEnum
.
NARROW_BY_GENERIC
&&
!
instanceType
.
isGenericType
()))
{
return
;
}
}
else
if
(
isFieldVisibleInMethod
(
fieldNode
,
mth
))
{
return
;
}
// insert cast
IndexInsnNode
castInsn
=
new
IndexInsnNode
(
InsnType
.
CAST
,
clsType
,
1
);
castInsn
.
addArg
(
instanceArg
.
duplicate
());
castInsn
.
add
(
AFlag
.
SYNTHETIC
);
castInsn
.
add
(
AFlag
.
EXPLICIT_CAST
);
InsnArg
castArg
=
InsnArg
.
wrapInsnIntoArg
(
castInsn
);
...
...
@@ -184,6 +202,33 @@ public class ModVisitor extends AbstractVisitor {
InsnRemover
.
unbindArgUsage
(
mth
,
instanceArg
);
}
private
static
boolean
isFieldVisibleInMethod
(
FieldNode
field
,
MethodNode
mth
)
{
AccessInfo
accessFlags
=
field
.
getAccessFlags
();
if
(
accessFlags
.
isPublic
())
{
return
true
;
}
ClassNode
useCls
=
mth
.
getParentClass
();
ClassNode
fieldCls
=
field
.
getParentClass
();
boolean
sameScope
=
Objects
.
equals
(
useCls
,
fieldCls
)
&&
!
mth
.
getAccessFlags
().
isStatic
();
if
(
sameScope
)
{
return
true
;
}
if
(
accessFlags
.
isPrivate
())
{
return
false
;
}
// package-private or protected
if
(
Objects
.
equals
(
useCls
.
getClassInfo
().
getPackage
(),
fieldCls
.
getClassInfo
().
getPackage
()))
{
// same package
return
true
;
}
if
(
accessFlags
.
isPackagePrivate
())
{
return
false
;
}
// protected
TypeCompareEnum
result
=
mth
.
root
().
getTypeCompare
().
compareTypes
(
useCls
,
fieldCls
);
return
result
==
TypeCompareEnum
.
NARROW
;
// true if use class is subclass of field class
}
private
static
void
replaceConstKeys
(
ClassNode
parentClass
,
SwitchInsn
insn
)
{
int
[]
keys
=
insn
.
getKeys
();
int
len
=
keys
.
length
;
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeCompare.java
浏览文件 @
691bf8fa
...
...
@@ -12,6 +12,7 @@ import org.slf4j.LoggerFactory;
import
jadx.core.dex.instructions.args.ArgType
;
import
jadx.core.dex.instructions.args.ArgType.WildcardBound
;
import
jadx.core.dex.instructions.args.PrimitiveType
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.core.dex.nodes.RootNode
;
import
jadx.core.utils.exceptions.JadxRuntimeException
;
...
...
@@ -37,6 +38,10 @@ public class TypeCompare {
this
.
reversedComparator
=
comparator
.
reversed
();
}
public
TypeCompareEnum
compareTypes
(
ClassNode
first
,
ClassNode
second
)
{
return
compareObjects
(
first
.
getType
(),
second
.
getType
());
}
/**
* Compare two type and return result for first argument (narrow, wider or conflict)
*/
...
...
jadx-core/src/main/java/jadx/core/utils/InsnRemover.java
浏览文件 @
691bf8fa
...
...
@@ -135,7 +135,7 @@ public class InsnRemover {
mth
.
removeSVar
(
ssaVar
);
return
;
}
if
(
Consts
.
DEBUG
)
{
// TODO: enable this
if
(
Consts
.
DEBUG
_WITH_ERRORS
)
{
throw
new
JadxRuntimeException
(
"Can't remove SSA var, still in use, count: "
+
useCount
+
", list:"
+
NL
+
" "
+
ssaVar
.
getUseList
().
stream
()
.
map
(
arg
->
arg
+
" from "
+
arg
.
getParentInsn
())
...
...
@@ -172,7 +172,7 @@ public class InsnRemover {
break
;
}
}
if
(!
found
&&
Consts
.
DEBUG
)
{
// TODO: enable this
if
(!
found
&&
Consts
.
DEBUG
_WITH_ERRORS
)
{
throw
new
JadxRuntimeException
(
"Can't remove insn:"
+
NL
+
" "
+
rem
+
NL
+
" not found in list:"
...
...
jadx-core/src/test/java/jadx/tests/integration/types/TestFieldCast.java
0 → 100644
浏览文件 @
691bf8fa
package
jadx.tests.integration.types
;
import
org.junit.jupiter.api.Test
;
import
jadx.tests.api.IntegrationTest
;
import
static
jadx
.
tests
.
api
.
utils
.
assertj
.
JadxAssertions
.
assertThat
;
/**
* Issue #962
*/
public
class
TestFieldCast
extends
IntegrationTest
{
public
static
class
TestCls
{
public
static
class
A
{
public
boolean
publicField
;
boolean
packagePrivateField
;
protected
boolean
protectedField
;
private
boolean
privateField
;
}
public
static
class
B
extends
A
{
public
void
test
()
{
((
A
)
this
).
publicField
=
false
;
((
A
)
this
).
protectedField
=
false
;
((
A
)
this
).
packagePrivateField
=
false
;
((
A
)
this
).
privateField
=
false
;
// cast to 'A' needed only here
}
}
public
static
class
C
{
public
void
test
(
B
b
)
{
((
A
)
b
).
publicField
=
false
;
((
A
)
b
).
protectedField
=
false
;
((
A
)
b
).
packagePrivateField
=
false
;
((
A
)
b
).
privateField
=
false
;
// cast to 'A' needed only here
}
}
private
static
class
D
{
public
<
T
extends
B
>
void
test
(
T
t
)
{
((
A
)
t
).
publicField
=
false
;
((
A
)
t
).
protectedField
=
false
;
((
A
)
t
).
packagePrivateField
=
false
;
((
A
)
t
).
privateField
=
false
;
// cast to 'A' needed only here
}
}
}
@Test
public
void
test
()
{
noDebugInfo
();
assertThat
(
getClassNode
(
TestCls
.
class
))
.
code
()
.
containsOne
(
"((A) this)"
)
.
containsOne
(
"((A) b)"
)
.
containsOne
(
"((A) t)"
)
.
doesNotContain
(
"unused ="
)
.
doesNotContain
(
"access modifiers changed"
);
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录