Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
极致猎手
jadx
提交
b57001d4
J
jadx
项目概览
极致猎手
/
jadx
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
1
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
J
jadx
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
1
Issue
1
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
未验证
提交
b57001d4
编写于
4月 10, 2022
作者:
S
Skylot
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
fix: use correct reference for replaced bridge constructor (#1441)
上级
83decc24
变更
10
显示空白变更内容
内联
并排
Showing
10 changed file
with
128 addition
and
30 deletion
+128
-30
jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
+13
-4
jadx-core/src/main/java/jadx/core/dex/attributes/AType.java
jadx-core/src/main/java/jadx/core/dex/attributes/AType.java
+3
-1
jadx-core/src/main/java/jadx/core/dex/attributes/nodes/MethodReplaceAttr.java
...ava/jadx/core/dex/attributes/nodes/MethodReplaceAttr.java
+31
-0
jadx-core/src/main/java/jadx/core/dex/visitors/ClassModifier.java
...e/src/main/java/jadx/core/dex/visitors/ClassModifier.java
+11
-2
jadx-core/src/main/java/jadx/core/dex/visitors/ProcessMethodsForInline.java
.../java/jadx/core/dex/visitors/ProcessMethodsForInline.java
+4
-3
jadx-core/src/main/java/jadx/core/dex/visitors/usage/UsageInfoVisitor.java
...n/java/jadx/core/dex/visitors/usage/UsageInfoVisitor.java
+11
-0
jadx-core/src/test/java/jadx/tests/api/IntegrationTest.java
jadx-core/src/test/java/jadx/tests/api/IntegrationTest.java
+2
-1
jadx-core/src/test/java/jadx/tests/api/utils/assertj/JadxClassNodeAssertions.java
...jadx/tests/api/utils/assertj/JadxClassNodeAssertions.java
+23
-0
jadx-core/src/test/java/jadx/tests/integration/inner/TestAnonymousClass14.java
...va/jadx/tests/integration/inner/TestAnonymousClass14.java
+21
-8
jadx-core/src/test/java/jadx/tests/integration/inner/TestOuterConstructorCall.java
...adx/tests/integration/inner/TestOuterConstructorCall.java
+9
-11
未找到文件。
jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
浏览文件 @
b57001d4
...
...
@@ -20,6 +20,7 @@ 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.MethodReplaceAttr
;
import
jadx.core.dex.attributes.nodes.SkipMethodArgsAttr
;
import
jadx.core.dex.info.ClassInfo
;
import
jadx.core.dex.info.FieldInfo
;
...
...
@@ -694,19 +695,27 @@ public class InsnGen {
throw
new
JadxRuntimeException
(
"Constructor 'self' invoke must be removed!"
);
}
MethodNode
callMth
=
mth
.
root
().
resolveMethod
(
insn
.
getCallMth
());
MethodNode
refMth
=
callMth
;
if
(
callMth
!=
null
)
{
MethodReplaceAttr
replaceAttr
=
callMth
.
get
(
AType
.
METHOD_REPLACE
);
if
(
replaceAttr
!=
null
)
{
refMth
=
replaceAttr
.
getReplaceMth
();
}
}
if
(
insn
.
isSuper
())
{
code
.
attachAnnotation
(
call
Mth
);
code
.
attachAnnotation
(
ref
Mth
);
code
.
add
(
"super"
);
}
else
if
(
insn
.
isThis
())
{
code
.
attachAnnotation
(
call
Mth
);
code
.
attachAnnotation
(
ref
Mth
);
code
.
add
(
"this"
);
}
else
{
code
.
add
(
"new "
);
if
(
callMth
==
null
||
call
Mth
.
contains
(
AFlag
.
DONT_GENERATE
))
{
if
(
refMth
==
null
||
ref
Mth
.
contains
(
AFlag
.
DONT_GENERATE
))
{
// use class reference if constructor method is missing (default constructor)
code
.
attachAnnotation
(
mth
.
root
().
resolveClass
(
insn
.
getCallMth
().
getDeclClass
()));
}
else
{
code
.
attachAnnotation
(
call
Mth
);
code
.
attachAnnotation
(
ref
Mth
);
}
mgen
.
getClassGen
().
addClsName
(
code
,
insn
.
getClassType
());
GenericInfoAttr
genericInfoAttr
=
insn
.
get
(
AType
.
GENERIC_INFO
);
...
...
jadx-core/src/main/java/jadx/core/dex/attributes/AType.java
浏览文件 @
b57001d4
...
...
@@ -21,6 +21,7 @@ import jadx.core.dex.attributes.nodes.LoopLabelAttr;
import
jadx.core.dex.attributes.nodes.MethodBridgeAttr
;
import
jadx.core.dex.attributes.nodes.MethodInlineAttr
;
import
jadx.core.dex.attributes.nodes.MethodOverrideAttr
;
import
jadx.core.dex.attributes.nodes.MethodReplaceAttr
;
import
jadx.core.dex.attributes.nodes.MethodTypeVarsAttr
;
import
jadx.core.dex.attributes.nodes.PhiListAttr
;
import
jadx.core.dex.attributes.nodes.RegDebugInfoAttr
;
...
...
@@ -65,11 +66,12 @@ public final class AType<T extends IJadxAttribute> implements IJadxAttrType<T> {
// method
public
static
final
AType
<
LocalVarsDebugInfoAttr
>
LOCAL_VARS_DEBUG_INFO
=
new
AType
<>();
public
static
final
AType
<
MethodInlineAttr
>
METHOD_INLINE
=
new
AType
<>();
public
static
final
AType
<
MethodReplaceAttr
>
METHOD_REPLACE
=
new
AType
<>();
public
static
final
AType
<
MethodBridgeAttr
>
BRIDGED_BY
=
new
AType
<>();
public
static
final
AType
<
SkipMethodArgsAttr
>
SKIP_MTH_ARGS
=
new
AType
<>();
public
static
final
AType
<
MethodOverrideAttr
>
METHOD_OVERRIDE
=
new
AType
<>();
public
static
final
AType
<
MethodTypeVarsAttr
>
METHOD_TYPE_VARS
=
new
AType
<>();
public
static
final
AType
<
AttrList
<
TryCatchBlockAttr
>>
TRY_BLOCKS_LIST
=
new
AType
<>();
public
static
final
AType
<
MethodBridgeAttr
>
BRIDGED_BY
=
new
AType
<>();
// region
public
static
final
AType
<
DeclareVariablesAttr
>
DECLARE_VARIABLES
=
new
AType
<>();
...
...
jadx-core/src/main/java/jadx/core/dex/attributes/nodes/MethodReplaceAttr.java
0 → 100644
浏览文件 @
b57001d4
package
jadx.core.dex.attributes.nodes
;
import
jadx.api.plugins.input.data.attributes.PinnedAttribute
;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.nodes.MethodNode
;
/**
* Calls of method should be replaced by provided method (used for synthetic methods redirect)
*/
public
class
MethodReplaceAttr
extends
PinnedAttribute
{
private
final
MethodNode
replaceMth
;
public
MethodReplaceAttr
(
MethodNode
replaceMth
)
{
this
.
replaceMth
=
replaceMth
;
}
public
MethodNode
getReplaceMth
()
{
return
replaceMth
;
}
@Override
public
AType
<
MethodReplaceAttr
>
getAttrType
()
{
return
AType
.
METHOD_REPLACE
;
}
@Override
public
String
toString
()
{
return
"REPLACED_BY: "
+
replaceMth
;
}
}
jadx-core/src/main/java/jadx/core/dex/visitors/ClassModifier.java
浏览文件 @
b57001d4
...
...
@@ -11,6 +11,7 @@ import jadx.api.plugins.input.data.AccessFlags;
import
jadx.core.Consts
;
import
jadx.core.dex.attributes.AFlag
;
import
jadx.core.dex.attributes.nodes.FieldReplaceAttr
;
import
jadx.core.dex.attributes.nodes.MethodReplaceAttr
;
import
jadx.core.dex.attributes.nodes.SkipMethodArgsAttr
;
import
jadx.core.dex.info.AccessInfo
;
import
jadx.core.dex.info.ClassInfo
;
...
...
@@ -31,6 +32,7 @@ import jadx.core.dex.nodes.ClassNode;
import
jadx.core.dex.nodes.FieldNode
;
import
jadx.core.dex.nodes.InsnNode
;
import
jadx.core.dex.nodes.MethodNode
;
import
jadx.core.dex.visitors.usage.UsageInfoVisitor
;
import
jadx.core.utils.BlockUtils
;
import
jadx.core.utils.InsnRemover
;
import
jadx.core.utils.exceptions.JadxException
;
...
...
@@ -155,7 +157,7 @@ public class ClassModifier extends AbstractVisitor {
return
;
}
// remove synthetic constructor for inner classes
if
(
af
.
isConstructor
(
))
{
if
(
mth
.
isConstructor
()
&&
mth
.
contains
(
AFlag
.
METHOD_CANDIDATE_FOR_INLINE
))
{
InsnNode
insn
=
BlockUtils
.
getOnlyOneInsnFromMth
(
mth
);
if
(
insn
!=
null
)
{
List
<
RegisterArg
>
args
=
mth
.
getArgRegs
();
...
...
@@ -210,7 +212,14 @@ public class ClassModifier extends AbstractVisitor {
SkipMethodArgsAttr
.
skipArg
(
mth
,
i
);
}
}
MethodInfo
callMth
=
constr
.
getCallMth
();
MethodNode
callMthNode
=
cls
.
root
().
resolveMethod
(
callMth
);
if
(
callMthNode
!=
null
)
{
mth
.
addAttr
(
new
MethodReplaceAttr
(
callMthNode
));
mth
.
add
(
AFlag
.
DONT_GENERATE
);
// code generation order should be already fixed for marked methods
UsageInfoVisitor
.
replaceMethodUsage
(
callMthNode
,
mth
);
}
}
}
}
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/ProcessMethodsForInline.java
浏览文件 @
b57001d4
...
...
@@ -45,16 +45,17 @@ public class ProcessMethodsForInline extends AbstractVisitor {
}
AccessInfo
accessFlags
=
mth
.
getAccessFlags
();
boolean
isSynthetic
=
accessFlags
.
isSynthetic
()
||
mth
.
getName
().
contains
(
"$"
);
return
isSynthetic
&&
accessFlags
.
isStatic
(
);
return
isSynthetic
&&
(
accessFlags
.
isStatic
()
||
mth
.
isConstructor
()
);
}
private
static
void
fixClassDependencies
(
MethodNode
mth
)
{
ClassNode
parentClass
=
mth
.
getTopParentClass
();
for
(
MethodNode
useInMth
:
mth
.
getUseIn
())
{
// remove possible cross dependency
to force class with inline method to be processed before its
// usage
// remove possible cross dependency
//
to force class with inline method to be processed before its
usage
ClassNode
useTopCls
=
useInMth
.
getTopParentClass
();
parentClass
.
setDependencies
(
ListUtils
.
safeRemoveAndTrim
(
parentClass
.
getDependencies
(),
useTopCls
));
useTopCls
.
addCodegenDep
(
parentClass
);
}
}
}
jadx-core/src/main/java/jadx/core/dex/visitors/usage/UsageInfoVisitor.java
浏览文件 @
b57001d4
package
jadx.core.dex.visitors.usage
;
import
java.util.Collections
;
import
java.util.List
;
import
jadx.api.plugins.input.data.ICallSite
;
import
jadx.api.plugins.input.data.ICodeReader
;
import
jadx.api.plugins.input.data.IMethodHandle
;
...
...
@@ -18,6 +21,7 @@ import jadx.core.dex.visitors.AbstractVisitor;
import
jadx.core.dex.visitors.JadxVisitor
;
import
jadx.core.dex.visitors.OverrideMethodVisitor
;
import
jadx.core.dex.visitors.rename.RenameVisitor
;
import
jadx.core.utils.ListUtils
;
import
jadx.core.utils.input.InsnDataUtils
;
@JadxVisitor
(
...
...
@@ -134,4 +138,11 @@ public class UsageInfoVisitor extends AbstractVisitor {
}
}
}
public
static
void
replaceMethodUsage
(
MethodNode
mergeIntoMth
,
MethodNode
sourceMth
)
{
List
<
MethodNode
>
mergedUsage
=
ListUtils
.
distinctMergeSortedLists
(
mergeIntoMth
.
getUseIn
(),
sourceMth
.
getUseIn
());
mergedUsage
.
remove
(
sourceMth
);
mergeIntoMth
.
setUseIn
(
mergedUsage
);
sourceMth
.
setUseIn
(
Collections
.
emptyList
());
}
}
jadx-core/src/test/java/jadx/tests/api/IntegrationTest.java
浏览文件 @
b57001d4
...
...
@@ -24,6 +24,7 @@ import java.util.jar.JarOutputStream;
import
java.util.stream.Collectors
;
import
java.util.stream.Stream
;
import
org.jetbrains.annotations.NotNull
;
import
org.jetbrains.annotations.Nullable
;
import
org.junit.jupiter.api.AfterEach
;
import
org.junit.jupiter.api.Assumptions
;
...
...
@@ -219,7 +220,7 @@ public abstract class IntegrationTest extends TestUtils {
return
sortedClsNodes
;
}
@N
ullable
@N
otNull
public
ClassNode
searchCls
(
List
<
ClassNode
>
list
,
String
clsName
)
{
for
(
ClassNode
cls
:
list
)
{
if
(
cls
.
getClassInfo
().
getFullName
().
equals
(
clsName
))
{
...
...
jadx-core/src/test/java/jadx/tests/api/utils/assertj/JadxClassNodeAssertions.java
浏览文件 @
b57001d4
package
jadx.tests.api.utils.assertj
;
import
java.util.Map
;
import
org.assertj.core.api.AbstractObjectAssert
;
import
org.assertj.core.api.Assertions
;
import
jadx.api.CodePosition
;
import
jadx.api.ICodeInfo
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.core.dex.nodes.ICodeNode
;
import
jadx.tests.api.IntegrationTest
;
import
static
jadx
.
tests
.
api
.
utils
.
assertj
.
JadxAssertions
.
assertThat
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
fail
;
public
class
JadxClassNodeAssertions
extends
AbstractObjectAssert
<
JadxClassNodeAssertions
,
ClassNode
>
{
public
JadxClassNodeAssertions
(
ClassNode
cls
)
{
...
...
@@ -52,4 +57,22 @@ public class JadxClassNodeAssertions extends AbstractObjectAssert<JadxClassNodeA
testInstance
.
runDecompiledAutoCheck
(
actual
);
return
this
;
}
public
void
checkCodeAnnotationFor
(
String
refStr
,
ICodeNode
node
)
{
checkCodeAnnotationFor
(
refStr
,
0
,
node
);
}
public
void
checkCodeAnnotationFor
(
String
refStr
,
int
refOffset
,
ICodeNode
node
)
{
ICodeInfo
code
=
actual
.
getCode
();
int
codePos
=
code
.
getCodeStr
().
indexOf
(
refStr
);
assertThat
(
codePos
).
describedAs
(
"String '%s' not found"
,
refStr
).
isNotEqualTo
(-
1
);
int
refPos
=
codePos
+
refOffset
;
for
(
Map
.
Entry
<
CodePosition
,
Object
>
entry
:
code
.
getAnnotations
().
entrySet
())
{
if
(
entry
.
getKey
().
getPos
()
==
refPos
)
{
Assertions
.
assertThat
(
entry
.
getValue
()).
isEqualTo
(
node
);
return
;
}
}
fail
(
"Annotation for reference string: '%s' at position %d not found"
,
refStr
,
refPos
);
}
}
jadx-core/src/test/java/jadx/tests/integration/inner/TestAnonymousClass14.java
浏览文件 @
b57001d4
...
...
@@ -2,12 +2,13 @@ package jadx.tests.integration.inner;
import
org.junit.jupiter.api.Test
;
import
jadx.api.CommentsLevel
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.core.dex.nodes.MethodNode
;
import
jadx.core.utils.ListUtils
;
import
jadx.tests.api.SmaliTest
;
import
static
org
.
hamcrest
.
MatcherAssert
.
assertThat
;
import
static
org
.
hamcrest
.
Matchers
.
containsString
;
import
static
org
.
hamcrest
.
Matchers
.
not
;
import
static
jadx
.
tests
.
api
.
utils
.
assertj
.
JadxAssertions
.
assertThat
;
public
class
TestAnonymousClass14
extends
SmaliTest
{
// @formatter:off
...
...
@@ -44,11 +45,23 @@ public class TestAnonymousClass14 extends SmaliTest {
@Test
public
void
test
()
{
ClassNode
clsNode
=
getClassNodeFromSmaliFiles
(
"inner"
,
"TestAnonymousClass14"
,
"OuterCls"
);
String
code
=
clsNode
.
getCode
().
toString
();
code
=
code
.
replaceAll
(
"/\\*.*?\\*/"
,
""
);
// remove block comments
getArgs
().
setCommentsLevel
(
CommentsLevel
.
WARN
);
ClassNode
outerCls
=
getClassNodeFromSmaliFiles
(
"OuterCls"
);
assertThat
(
outerCls
).
code
()
.
doesNotContain
(
"synthetic"
,
"AnonymousClass1"
)
.
describedAs
(
"only one constructor"
).
containsOne
(
"private TestCls("
)
.
describedAs
(
"constructor without args"
).
containsOne
(
"private TestCls() {"
);
assertThat
(
code
,
not
(
containsString
(
"AnonymousClass1"
)));
assertThat
(
code
,
not
(
containsString
(
"synthetic"
)));
MethodNode
makeTestClsMth
=
outerCls
.
searchMethodByShortName
(
"makeTestCls"
);
assertThat
(
makeTestClsMth
).
isNotNull
();
ClassNode
testCls
=
searchCls
(
outerCls
.
getInnerClasses
(),
"TestCls"
);
MethodNode
ctrMth
=
ListUtils
.
filterOnlyOne
(
testCls
.
getMethods
(),
m
->
m
.
isConstructor
()
&&
!
m
.
getAccessFlags
().
isSynthetic
());
assertThat
(
ctrMth
).
isNotNull
();
assertThat
(
ctrMth
.
getUseIn
()).
hasSize
(
1
);
assertThat
(
ctrMth
.
getUseIn
().
get
(
0
)).
isEqualTo
(
makeTestClsMth
);
assertThat
(
outerCls
).
checkCodeAnnotationFor
(
"new TestCls();"
,
4
,
ctrMth
);
}
}
jadx-core/src/test/java/jadx/tests/integration/inner/TestOuterConstructorCall.java
浏览文件 @
b57001d4
...
...
@@ -2,22 +2,20 @@ package jadx.tests.integration.inner;
import
org.junit.jupiter.api.Test
;
import
jadx.
core.dex.nodes.ClassNode
;
import
jadx.
api.CommentsLevel
;
import
jadx.tests.api.IntegrationTest
;
import
static
org
.
hamcrest
.
MatcherAssert
.
assertThat
;
import
static
org
.
hamcrest
.
Matchers
.
containsString
;
import
static
org
.
hamcrest
.
Matchers
.
not
;
import
static
jadx
.
tests
.
api
.
utils
.
assertj
.
JadxAssertions
.
assertThat
;
public
class
TestOuterConstructorCall
extends
IntegrationTest
{
@SuppressWarnings
({
"InnerClassMayBeStatic"
,
"unused"
})
public
static
class
TestCls
{
private
TestCls
(
Inner
inner
)
{
System
.
out
.
println
(
inner
);
}
private
class
Inner
{
@SuppressWarnings
(
"unused"
)
private
TestCls
test
()
{
return
new
TestCls
(
this
);
}
...
...
@@ -26,11 +24,11 @@ public class TestOuterConstructorCall extends IntegrationTest {
@Test
public
void
test
()
{
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
String
code
=
cls
.
getCode
().
toString
();
assertThat
(
code
,
containsString
(
"private class Inner {"
));
assertThat
(
code
,
containsString
(
"return new TestOuterConstructorCall$TestCls(this);"
));
assertThat
(
code
,
not
(
containsString
(
"synthetic"
))
);
getArgs
().
setCommentsLevel
(
CommentsLevel
.
WARN
);
assertThat
(
getClassNode
(
TestCls
.
class
))
.
code
()
.
containsOne
(
"class Inner {"
)
.
containsOne
(
"return new TestOuterConstructorCall$TestCls(this);"
)
.
doesNotContain
(
"synthetic"
,
"this$0"
);
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录