Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
keyescgm
jadx
提交
492a3f69
J
jadx
项目概览
keyescgm
/
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,发现更多精彩内容 >>
未验证
提交
492a3f69
编写于
2月 02, 2020
作者:
Y
Yaroslav Yadrov
提交者:
GitHub
2月 02, 2020
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat(deobf): add classname parsing for Kotlin metadata (PR #842, #758)
上级
1ce8fa8b
变更
9
隐藏空白更改
内联
并排
Showing
9 changed file
with
83 addition
and
4 deletion
+83
-4
jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java
jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java
+8
-0
jadx-core/src/main/java/jadx/api/JadxArgs.java
jadx-core/src/main/java/jadx/api/JadxArgs.java
+10
-0
jadx-core/src/main/java/jadx/core/deobf/Deobfuscator.java
jadx-core/src/main/java/jadx/core/deobf/Deobfuscator.java
+46
-3
jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java
jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java
+5
-0
jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java
...i/src/main/java/jadx/gui/settings/JadxSettingsWindow.java
+10
-1
jadx-gui/src/main/resources/i18n/Messages_de_DE.properties
jadx-gui/src/main/resources/i18n/Messages_de_DE.properties
+1
-0
jadx-gui/src/main/resources/i18n/Messages_en_US.properties
jadx-gui/src/main/resources/i18n/Messages_en_US.properties
+1
-0
jadx-gui/src/main/resources/i18n/Messages_es_ES.properties
jadx-gui/src/main/resources/i18n/Messages_es_ES.properties
+1
-0
jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties
jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties
+1
-0
未找到文件。
jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java
浏览文件 @
492a3f69
...
@@ -85,6 +85,9 @@ public class JadxCLIArgs {
...
@@ -85,6 +85,9 @@ public class JadxCLIArgs {
@Parameter
(
names
=
{
"--deobf-use-sourcename"
},
description
=
"use source file name as class name alias"
)
@Parameter
(
names
=
{
"--deobf-use-sourcename"
},
description
=
"use source file name as class name alias"
)
protected
boolean
deobfuscationUseSourceNameAsAlias
=
false
;
protected
boolean
deobfuscationUseSourceNameAsAlias
=
false
;
@Parameter
(
names
=
{
"--deobf-parse-kotlin-metadata"
},
description
=
"parse kotlin metadata to class and package names"
)
protected
boolean
deobfuscationParseKotlinMetadata
=
false
;
@Parameter
(
@Parameter
(
names
=
{
"--rename-flags"
},
names
=
{
"--rename-flags"
},
description
=
"what to rename, comma-separated,"
description
=
"what to rename, comma-separated,"
...
@@ -194,6 +197,7 @@ public class JadxCLIArgs {
...
@@ -194,6 +197,7 @@ public class JadxCLIArgs {
args
.
setDeobfuscationMinLength
(
deobfuscationMinLength
);
args
.
setDeobfuscationMinLength
(
deobfuscationMinLength
);
args
.
setDeobfuscationMaxLength
(
deobfuscationMaxLength
);
args
.
setDeobfuscationMaxLength
(
deobfuscationMaxLength
);
args
.
setUseSourceNameAsClassAlias
(
deobfuscationUseSourceNameAsAlias
);
args
.
setUseSourceNameAsClassAlias
(
deobfuscationUseSourceNameAsAlias
);
args
.
setParseKotlinMetadata
(
deobfuscationParseKotlinMetadata
);
args
.
setEscapeUnicode
(
escapeUnicode
);
args
.
setEscapeUnicode
(
escapeUnicode
);
args
.
setRespectBytecodeAccModifiers
(
respectBytecodeAccessModifiers
);
args
.
setRespectBytecodeAccModifiers
(
respectBytecodeAccessModifiers
);
args
.
setExportAsGradleProject
(
exportAsGradleProject
);
args
.
setExportAsGradleProject
(
exportAsGradleProject
);
...
@@ -275,6 +279,10 @@ public class JadxCLIArgs {
...
@@ -275,6 +279,10 @@ public class JadxCLIArgs {
return
deobfuscationUseSourceNameAsAlias
;
return
deobfuscationUseSourceNameAsAlias
;
}
}
public
boolean
isDeobfuscationParseKotlinMetadata
()
{
return
deobfuscationParseKotlinMetadata
;
}
public
boolean
isEscapeUnicode
()
{
public
boolean
isEscapeUnicode
()
{
return
escapeUnicode
;
return
escapeUnicode
;
}
}
...
...
jadx-core/src/main/java/jadx/api/JadxArgs.java
浏览文件 @
492a3f69
...
@@ -49,6 +49,7 @@ public class JadxArgs {
...
@@ -49,6 +49,7 @@ public class JadxArgs {
private
boolean
deobfuscationOn
=
false
;
private
boolean
deobfuscationOn
=
false
;
private
boolean
deobfuscationForceSave
=
false
;
private
boolean
deobfuscationForceSave
=
false
;
private
boolean
useSourceNameAsClassAlias
=
false
;
private
boolean
useSourceNameAsClassAlias
=
false
;
private
boolean
parseKotlinMetadata
=
false
;
private
int
deobfuscationMinLength
=
0
;
private
int
deobfuscationMinLength
=
0
;
private
int
deobfuscationMaxLength
=
Integer
.
MAX_VALUE
;
private
int
deobfuscationMaxLength
=
Integer
.
MAX_VALUE
;
...
@@ -230,6 +231,14 @@ public class JadxArgs {
...
@@ -230,6 +231,14 @@ public class JadxArgs {
this
.
useSourceNameAsClassAlias
=
useSourceNameAsClassAlias
;
this
.
useSourceNameAsClassAlias
=
useSourceNameAsClassAlias
;
}
}
public
boolean
isParseKotlinMetadata
()
{
return
parseKotlinMetadata
;
}
public
void
setParseKotlinMetadata
(
boolean
parseKotlinMetadata
)
{
this
.
parseKotlinMetadata
=
parseKotlinMetadata
;
}
public
int
getDeobfuscationMinLength
()
{
public
int
getDeobfuscationMinLength
()
{
return
deobfuscationMinLength
;
return
deobfuscationMinLength
;
}
}
...
@@ -355,6 +364,7 @@ public class JadxArgs {
...
@@ -355,6 +364,7 @@ public class JadxArgs {
+
", deobfuscationOn="
+
deobfuscationOn
+
", deobfuscationOn="
+
deobfuscationOn
+
", deobfuscationForceSave="
+
deobfuscationForceSave
+
", deobfuscationForceSave="
+
deobfuscationForceSave
+
", useSourceNameAsClassAlias="
+
useSourceNameAsClassAlias
+
", useSourceNameAsClassAlias="
+
useSourceNameAsClassAlias
+
", parseKotlinMetadata="
+
parseKotlinMetadata
+
", deobfuscationMinLength="
+
deobfuscationMinLength
+
", deobfuscationMinLength="
+
deobfuscationMinLength
+
", deobfuscationMaxLength="
+
deobfuscationMaxLength
+
", deobfuscationMaxLength="
+
deobfuscationMaxLength
+
", escapeUnicode="
+
escapeUnicode
+
", escapeUnicode="
+
escapeUnicode
...
...
jadx-core/src/main/java/jadx/core/deobf/Deobfuscator.java
浏览文件 @
492a3f69
...
@@ -37,6 +37,9 @@ public class Deobfuscator {
...
@@ -37,6 +37,9 @@ public class Deobfuscator {
public
static
final
String
CLASS_NAME_SEPARATOR
=
"."
;
public
static
final
String
CLASS_NAME_SEPARATOR
=
"."
;
public
static
final
String
INNER_CLASS_SEPARATOR
=
"$"
;
public
static
final
String
INNER_CLASS_SEPARATOR
=
"$"
;
public
static
final
String
KOTLIN_METADATA_ANNOTATION
=
"kotlin.Metadata"
;
public
static
final
String
KOTLIN_METADATA_D2_PARAMETER
=
"d2"
;
public
static
final
String
KOTLIN_METADATA_CLASSNAME_REGEX
=
"(L.*;)"
;
private
final
JadxArgs
args
;
private
final
JadxArgs
args
;
@NotNull
@NotNull
...
@@ -57,6 +60,7 @@ public class Deobfuscator {
...
@@ -57,6 +60,7 @@ public class Deobfuscator {
private
final
int
maxLength
;
private
final
int
maxLength
;
private
final
int
minLength
;
private
final
int
minLength
;
private
final
boolean
useSourceNameAsAlias
;
private
final
boolean
useSourceNameAsAlias
;
private
final
boolean
parseKotlinMetadata
;
private
int
pkgIndex
=
0
;
private
int
pkgIndex
=
0
;
private
int
clsIndex
=
0
;
private
int
clsIndex
=
0
;
...
@@ -70,6 +74,7 @@ public class Deobfuscator {
...
@@ -70,6 +74,7 @@ public class Deobfuscator {
this
.
minLength
=
args
.
getDeobfuscationMinLength
();
this
.
minLength
=
args
.
getDeobfuscationMinLength
();
this
.
maxLength
=
args
.
getDeobfuscationMaxLength
();
this
.
maxLength
=
args
.
getDeobfuscationMaxLength
();
this
.
useSourceNameAsAlias
=
args
.
isUseSourceNameAsClassAlias
();
this
.
useSourceNameAsAlias
=
args
.
isUseSourceNameAsClassAlias
();
this
.
parseKotlinMetadata
=
args
.
isParseKotlinMetadata
();
this
.
deobfPresets
=
new
DeobfPresets
(
this
,
deobfMapFile
);
this
.
deobfPresets
=
new
DeobfPresets
(
this
,
deobfMapFile
);
}
}
...
@@ -392,6 +397,18 @@ public class Deobfuscator {
...
@@ -392,6 +397,18 @@ public class Deobfuscator {
private
String
makeClsAlias
(
ClassNode
cls
)
{
private
String
makeClsAlias
(
ClassNode
cls
)
{
ClassInfo
classInfo
=
cls
.
getClassInfo
();
ClassInfo
classInfo
=
cls
.
getClassInfo
();
String
metadataClassName
=
""
;
String
metadataPackageName
=
""
;
if
(
this
.
parseKotlinMetadata
)
{
String
rawClassName
=
getRawClassNameFromMetadata
(
cls
);
if
(
rawClassName
!=
null
)
{
metadataClassName
=
rawClassName
.
substring
(
rawClassName
.
lastIndexOf
(
"."
)
+
1
,
rawClassName
.
length
()
-
1
);
if
(
rawClassName
.
lastIndexOf
(
"."
)
!=
-
1
)
{
metadataPackageName
=
rawClassName
.
substring
(
1
,
rawClassName
.
lastIndexOf
(
"."
));
}
}
}
String
alias
=
null
;
String
alias
=
null
;
if
(
this
.
useSourceNameAsAlias
)
{
if
(
this
.
useSourceNameAsAlias
)
{
...
@@ -399,14 +416,40 @@ public class Deobfuscator {
...
@@ -399,14 +416,40 @@ public class Deobfuscator {
}
}
if
(
alias
==
null
)
{
if
(
alias
==
null
)
{
String
clsName
=
classInfo
.
getShortName
();
if
(
metadataClassName
.
isEmpty
())
{
alias
=
String
.
format
(
"C%04d%s"
,
clsIndex
++,
prepareNamePart
(
clsName
));
String
clsName
=
classInfo
.
getShortName
();
alias
=
String
.
format
(
"C%04d%s"
,
clsIndex
++,
prepareNamePart
(
clsName
));
}
else
{
alias
=
metadataClassName
;
}
}
PackageNode
pkg
;
if
(
metadataPackageName
.
isEmpty
())
{
pkg
=
getPackageNode
(
classInfo
.
getPackage
(),
true
);
}
else
{
pkg
=
getPackageNode
(
metadataPackageName
,
true
);
}
}
PackageNode
pkg
=
getPackageNode
(
classInfo
.
getPackage
(),
true
);
clsMap
.
put
(
classInfo
,
new
DeobfClsInfo
(
this
,
cls
,
pkg
,
alias
));
clsMap
.
put
(
classInfo
,
new
DeobfClsInfo
(
this
,
cls
,
pkg
,
alias
));
return
alias
;
return
alias
;
}
}
@Nullable
private
String
getRawClassNameFromMetadata
(
ClassNode
cls
)
{
if
(
cls
.
getAnnotation
(
KOTLIN_METADATA_ANNOTATION
)
!=
null
&&
cls
.
getAnnotation
(
KOTLIN_METADATA_ANNOTATION
).
getValues
().
get
(
KOTLIN_METADATA_D2_PARAMETER
)
!=
null
&&
cls
.
getAnnotation
(
KOTLIN_METADATA_ANNOTATION
).
getValues
().
get
(
KOTLIN_METADATA_D2_PARAMETER
)
instanceof
List
)
{
Object
rawClassNameObject
=
((
List
)
cls
.
getAnnotation
(
KOTLIN_METADATA_ANNOTATION
).
getValues
().
get
(
KOTLIN_METADATA_D2_PARAMETER
)).
get
(
0
);
if
(
rawClassNameObject
instanceof
String
)
{
String
rawClassName
=
((
String
)
rawClassNameObject
).
trim
().
replace
(
"/"
,
"."
);
if
(
rawClassName
.
length
()
>
1
&&
rawClassName
.
matches
(
KOTLIN_METADATA_CLASSNAME_REGEX
))
{
return
rawClassName
;
}
}
}
return
null
;
}
@Nullable
@Nullable
private
String
getAliasFromSourceFile
(
ClassNode
cls
)
{
private
String
getAliasFromSourceFile
(
ClassNode
cls
)
{
SourceFileAttr
sourceFileAttr
=
cls
.
get
(
AType
.
SOURCE_FILE
);
SourceFileAttr
sourceFileAttr
=
cls
.
get
(
AType
.
SOURCE_FILE
);
...
...
jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java
浏览文件 @
492a3f69
...
@@ -279,6 +279,10 @@ public class JadxSettings extends JadxCLIArgs {
...
@@ -279,6 +279,10 @@ public class JadxSettings extends JadxCLIArgs {
this
.
deobfuscationUseSourceNameAsAlias
=
deobfuscationUseSourceNameAsAlias
;
this
.
deobfuscationUseSourceNameAsAlias
=
deobfuscationUseSourceNameAsAlias
;
}
}
public
void
setDeobfuscationParseKotlinMetadata
(
boolean
deobfuscationParseKotlinMetadata
)
{
this
.
deobfuscationParseKotlinMetadata
=
deobfuscationParseKotlinMetadata
;
}
public
void
updateRenameFlag
(
JadxArgs
.
RenameEnum
flag
,
boolean
enabled
)
{
public
void
updateRenameFlag
(
JadxArgs
.
RenameEnum
flag
,
boolean
enabled
)
{
if
(
enabled
)
{
if
(
enabled
)
{
renameFlags
.
add
(
flag
);
renameFlags
.
add
(
flag
);
...
@@ -387,6 +391,7 @@ public class JadxSettings extends JadxCLIArgs {
...
@@ -387,6 +391,7 @@ public class JadxSettings extends JadxCLIArgs {
if
(
fromVersion
==
0
)
{
if
(
fromVersion
==
0
)
{
setDeobfuscationMinLength
(
3
);
setDeobfuscationMinLength
(
3
);
setDeobfuscationUseSourceNameAsAlias
(
true
);
setDeobfuscationUseSourceNameAsAlias
(
true
);
setDeobfuscationParseKotlinMetadata
(
true
);
setDeobfuscationForceSave
(
true
);
setDeobfuscationForceSave
(
true
);
setThreadsCount
(
1
);
setThreadsCount
(
1
);
setReplaceConsts
(
true
);
setReplaceConsts
(
true
);
...
...
jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java
浏览文件 @
492a3f69
...
@@ -167,15 +167,24 @@ public class JadxSettingsWindow extends JDialog {
...
@@ -167,15 +167,24 @@ public class JadxSettingsWindow extends JDialog {
needReload
();
needReload
();
});
});
JCheckBox
deobfKotlinMetadata
=
new
JCheckBox
();
deobfKotlinMetadata
.
setSelected
(
settings
.
isDeobfuscationParseKotlinMetadata
());
deobfKotlinMetadata
.
addItemListener
(
e
->
{
settings
.
setDeobfuscationParseKotlinMetadata
(
e
.
getStateChange
()
==
ItemEvent
.
SELECTED
);
needReload
();
});
SettingsGroup
deobfGroup
=
new
SettingsGroup
(
NLS
.
str
(
"preferences.deobfuscation"
));
SettingsGroup
deobfGroup
=
new
SettingsGroup
(
NLS
.
str
(
"preferences.deobfuscation"
));
deobfGroup
.
addRow
(
NLS
.
str
(
"preferences.deobfuscation_on"
),
deobfOn
);
deobfGroup
.
addRow
(
NLS
.
str
(
"preferences.deobfuscation_on"
),
deobfOn
);
deobfGroup
.
addRow
(
NLS
.
str
(
"preferences.deobfuscation_force"
),
deobfForce
);
deobfGroup
.
addRow
(
NLS
.
str
(
"preferences.deobfuscation_force"
),
deobfForce
);
deobfGroup
.
addRow
(
NLS
.
str
(
"preferences.deobfuscation_min_len"
),
minLenSpinner
);
deobfGroup
.
addRow
(
NLS
.
str
(
"preferences.deobfuscation_min_len"
),
minLenSpinner
);
deobfGroup
.
addRow
(
NLS
.
str
(
"preferences.deobfuscation_max_len"
),
maxLenSpinner
);
deobfGroup
.
addRow
(
NLS
.
str
(
"preferences.deobfuscation_max_len"
),
maxLenSpinner
);
deobfGroup
.
addRow
(
NLS
.
str
(
"preferences.deobfuscation_source_alias"
),
deobfSourceAlias
);
deobfGroup
.
addRow
(
NLS
.
str
(
"preferences.deobfuscation_source_alias"
),
deobfSourceAlias
);
deobfGroup
.
addRow
(
NLS
.
str
(
"preferences.deobfuscation_kotlin_metadata"
),
deobfKotlinMetadata
);
deobfGroup
.
end
();
deobfGroup
.
end
();
Collection
<
JComponent
>
connectedComponents
=
Arrays
.
asList
(
deobfForce
,
minLenSpinner
,
maxLenSpinner
,
deobfSourceAlias
);
Collection
<
JComponent
>
connectedComponents
=
Arrays
.
asList
(
deobfForce
,
minLenSpinner
,
maxLenSpinner
,
deobfSourceAlias
,
deobfKotlinMetadata
);
deobfOn
.
addItemListener
(
e
->
enableComponentList
(
connectedComponents
,
e
.
getStateChange
()
==
ItemEvent
.
SELECTED
));
deobfOn
.
addItemListener
(
e
->
enableComponentList
(
connectedComponents
,
e
.
getStateChange
()
==
ItemEvent
.
SELECTED
));
enableComponentList
(
connectedComponents
,
settings
.
isDeobfuscationOn
());
enableComponentList
(
connectedComponents
,
settings
.
isDeobfuscationOn
());
return
deobfGroup
;
return
deobfGroup
;
...
...
jadx-gui/src/main/resources/i18n/Messages_de_DE.properties
浏览文件 @
492a3f69
...
@@ -118,6 +118,7 @@ preferences.deobfuscation_force=Deobfuscationskartendatei umschreiben erzwingen
...
@@ -118,6 +118,7 @@ preferences.deobfuscation_force=Deobfuscationskartendatei umschreiben erzwingen
preferences.deobfuscation_min_len
=
Minimale Namenlänge
preferences.deobfuscation_min_len
=
Minimale Namenlänge
preferences.deobfuscation_max_len
=
Maximale Namenlänge
preferences.deobfuscation_max_len
=
Maximale Namenlänge
preferences.deobfuscation_source_alias
=
Quelldateiname als Klassennamen-Alias verwenden
preferences.deobfuscation_source_alias
=
Quelldateiname als Klassennamen-Alias verwenden
preferences.deobfuscation_kotlin_metadata
=
Analysieren Sie Kotlin-Metadaten nach Klassen- und Paketnamen
preferences.save
=
Speichern
preferences.save
=
Speichern
preferences.cancel
=
Abbrechen
preferences.cancel
=
Abbrechen
preferences.reset
=
Zurücksetzen
preferences.reset
=
Zurücksetzen
...
...
jadx-gui/src/main/resources/i18n/Messages_en_US.properties
浏览文件 @
492a3f69
...
@@ -118,6 +118,7 @@ preferences.deobfuscation_force=Force rewrite deobfuscation map file
...
@@ -118,6 +118,7 @@ preferences.deobfuscation_force=Force rewrite deobfuscation map file
preferences.deobfuscation_min_len
=
Minimum name length
preferences.deobfuscation_min_len
=
Minimum name length
preferences.deobfuscation_max_len
=
Maximum name length
preferences.deobfuscation_max_len
=
Maximum name length
preferences.deobfuscation_source_alias
=
Use source file name as class name alias
preferences.deobfuscation_source_alias
=
Use source file name as class name alias
preferences.deobfuscation_kotlin_metadata
=
Parse Kotlin metadata for class and package names
preferences.save
=
Save
preferences.save
=
Save
preferences.cancel
=
Cancel
preferences.cancel
=
Cancel
preferences.reset
=
Reset
preferences.reset
=
Reset
...
...
jadx-gui/src/main/resources/i18n/Messages_es_ES.properties
浏览文件 @
492a3f69
...
@@ -118,6 +118,7 @@ preferences.deobfuscation_force=Forzar reescritura del fichero de ofuscación
...
@@ -118,6 +118,7 @@ preferences.deobfuscation_force=Forzar reescritura del fichero de ofuscación
preferences.deobfuscation_min_len
=
Longitud mínima del nombre
preferences.deobfuscation_min_len
=
Longitud mínima del nombre
preferences.deobfuscation_max_len
=
Longitud máxima del nombre
preferences.deobfuscation_max_len
=
Longitud máxima del nombre
preferences.deobfuscation_source_alias
=
Usar el nombre del source como alias para la clase
preferences.deobfuscation_source_alias
=
Usar el nombre del source como alias para la clase
preferences.deobfuscation_kotlin_metadata
=
Parse Kotlin metadatos para nombres de clase y paquete
preferences.save
=
Guardar
preferences.save
=
Guardar
preferences.cancel
=
Cancelar
preferences.cancel
=
Cancelar
preferences.reset
=
Reestablecer
preferences.reset
=
Reestablecer
...
...
jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties
浏览文件 @
492a3f69
...
@@ -118,6 +118,7 @@ preferences.deobfuscation_force=强制覆盖反混淆映射文件
...
@@ -118,6 +118,7 @@ preferences.deobfuscation_force=强制覆盖反混淆映射文件
preferences.deobfuscation_min_len
=
最小命名长度
preferences.deobfuscation_min_len
=
最小命名长度
preferences.deobfuscation_max_len
=
最大命名长度
preferences.deobfuscation_max_len
=
最大命名长度
preferences.deobfuscation_source_alias
=
使用资源名作为类的别名
preferences.deobfuscation_source_alias
=
使用资源名作为类的别名
preferences.deobfuscation_kotlin_metadata
=
解析Kotlin元数据以获得类和包名
preferences.save
=
保存
preferences.save
=
保存
preferences.cancel
=
取消
preferences.cancel
=
取消
preferences.reset
=
重置
preferences.reset
=
重置
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录