* improve smali printer to show bytecode * set insnStart position before start decoding * swithed line 62 and line 63, to get the proper bytes, insnStart must to be set before start to decode. Co-authored-by: tobias <tobias.hotmail.com>
This commit is contained in:
@@ -54,6 +54,7 @@ public class JadxSettings extends JadxCLIArgs {
|
||||
private boolean checkForUpdates = false;
|
||||
private List<Path> recentProjects = new ArrayList<>();
|
||||
private String fontStr = "";
|
||||
private String smaliFontStr = "";
|
||||
private String editorThemePath = "";
|
||||
private LangLocale langLocale = NLS.defaultLocale();
|
||||
private boolean autoStartJobs = false;
|
||||
@@ -68,6 +69,7 @@ public class JadxSettings extends JadxCLIArgs {
|
||||
private int srhResourceSkipSize = 1000;
|
||||
private String srhResourceFileExt = ".xml|.html|.js|.json|.txt";
|
||||
private boolean keepCommonDialogOpen = false;
|
||||
private boolean smaliAreaShowBytecode = false;
|
||||
|
||||
/**
|
||||
* UI setting: the width of the tree showing the classes, resources, ...
|
||||
@@ -377,6 +379,27 @@ public class JadxSettings extends JadxCLIArgs {
|
||||
}
|
||||
}
|
||||
|
||||
public Font getSmaliFont() {
|
||||
if (smaliFontStr.isEmpty()) {
|
||||
return DEFAULT_FONT;
|
||||
}
|
||||
try {
|
||||
return FontUtils.loadByStr(smaliFontStr);
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Failed to load font: {} for smali, reset to default", smaliFontStr, e);
|
||||
setSmaliFont(DEFAULT_FONT);
|
||||
return DEFAULT_FONT;
|
||||
}
|
||||
}
|
||||
|
||||
public void setSmaliFont(@Nullable Font font) {
|
||||
if (font == null) {
|
||||
this.smaliFontStr = "";
|
||||
} else {
|
||||
this.smaliFontStr = FontUtils.convertToStr(font);
|
||||
}
|
||||
}
|
||||
|
||||
public void setLogLevel(LogHelper.LogLevelEnum level) {
|
||||
this.logLevel = level;
|
||||
}
|
||||
@@ -430,6 +453,14 @@ public class JadxSettings extends JadxCLIArgs {
|
||||
return keepCommonDialogOpen;
|
||||
}
|
||||
|
||||
public void setSmaliAreaShowBytecode(boolean yes) {
|
||||
smaliAreaShowBytecode = yes;
|
||||
}
|
||||
|
||||
public boolean getSmaliAreaShowBytecode() {
|
||||
return smaliAreaShowBytecode;
|
||||
}
|
||||
|
||||
private void upgradeSettings(int fromVersion) {
|
||||
LOG.debug("upgrade settings from version: {} to {}", fromVersion, CURRENT_SETTINGS_VERSION);
|
||||
if (fromVersion == 0) {
|
||||
|
||||
@@ -7,8 +7,7 @@ import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
@@ -292,6 +291,7 @@ public class JadxSettingsWindow extends JDialog {
|
||||
|
||||
private SettingsGroup makeEditorGroup() {
|
||||
JButton fontBtn = new JButton(NLS.str("preferences.select_font"));
|
||||
JButton smaliFontBtn = new JButton(NLS.str("preferences.select_smali_font"));
|
||||
|
||||
EditorTheme[] editorThemes = EditorTheme.getAllThemes();
|
||||
JComboBox<EditorTheme> themesCbx = new JComboBox<>(editorThemes);
|
||||
@@ -311,6 +311,7 @@ public class JadxSettingsWindow extends JDialog {
|
||||
SettingsGroup group = new SettingsGroup(NLS.str("preferences.editor"));
|
||||
JLabel fontLabel = group.addRow(getFontLabelStr(), fontBtn);
|
||||
group.addRow(NLS.str("preferences.theme"), themesCbx);
|
||||
JLabel smaliFontLabel = group.addRow(getSmaliFontLabelStr(), smaliFontBtn);
|
||||
|
||||
fontBtn.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
@@ -327,6 +328,22 @@ public class JadxSettingsWindow extends JDialog {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
smaliFontBtn.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
JFontChooser fontChooser = new JPreferredFontChooser();
|
||||
fontChooser.setSelectedFont(settings.getSmaliFont());
|
||||
int result = fontChooser.showDialog(JadxSettingsWindow.this);
|
||||
if (result == JFontChooser.OK_OPTION) {
|
||||
Font font = fontChooser.getSelectedFont();
|
||||
LOG.debug("Selected Font: {} for smali", font);
|
||||
settings.setSmaliFont(font);
|
||||
mainWindow.loadSettings();
|
||||
smaliFontLabel.setText(getSmaliFontLabelStr());
|
||||
}
|
||||
}
|
||||
});
|
||||
return group;
|
||||
}
|
||||
|
||||
@@ -336,6 +353,12 @@ public class JadxSettingsWindow extends JDialog {
|
||||
return NLS.str("preferences.font") + ": " + font.getFontName() + ' ' + fontStyleName + ' ' + font.getSize();
|
||||
}
|
||||
|
||||
private String getSmaliFontLabelStr() {
|
||||
Font font = settings.getSmaliFont();
|
||||
String fontStyleName = FontUtils.convertFontStyleToString(font.getStyle());
|
||||
return NLS.str("preferences.smali_font") + ": " + font.getFontName() + ' ' + fontStyleName + ' ' + font.getSize();
|
||||
}
|
||||
|
||||
private SettingsGroup makeDecompilationGroup() {
|
||||
JCheckBox fallback = new JCheckBox();
|
||||
fallback.setSelected(settings.isFallbackMode());
|
||||
@@ -578,4 +601,42 @@ public class JadxSettingsWindow extends JDialog {
|
||||
add(Box.createVerticalGlue());
|
||||
}
|
||||
}
|
||||
|
||||
private static class JPreferredFontChooser extends JFontChooser {
|
||||
private static final String[] PREFERRED_FONTS = new String[] {
|
||||
"Monospaced", "Consolas", "Courier", "Courier New",
|
||||
"Lucida Sans Typewriter", "Lucida Console",
|
||||
"SimSun", "SimHei",
|
||||
};
|
||||
|
||||
private String[] filteredFonts;
|
||||
|
||||
@Override
|
||||
protected String[] getFontFamilies() {
|
||||
if (filteredFonts == null) {
|
||||
GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
Set<String> fontSet = new HashSet<>();
|
||||
Collections.addAll(fontSet, env.getAvailableFontFamilyNames());
|
||||
ArrayList<String> found = new ArrayList<>(PREFERRED_FONTS.length);
|
||||
for (String font : PREFERRED_FONTS) {
|
||||
if (fontSet.contains(font)) {
|
||||
found.add(font);
|
||||
}
|
||||
}
|
||||
if (found.size() == PREFERRED_FONTS.length) {
|
||||
filteredFonts = PREFERRED_FONTS;
|
||||
} else if (found.size() > 0) {
|
||||
filteredFonts = new String[found.size()];
|
||||
for (int i = 0; i < found.size(); i++) {
|
||||
filteredFonts[i] = found.get(i);
|
||||
}
|
||||
} else {
|
||||
// this machine is crazy.
|
||||
LOG.warn("Can't found any preferred fonts for smali, use all available.");
|
||||
filteredFonts = env.getAvailableFontFamilyNames();
|
||||
}
|
||||
}
|
||||
return filteredFonts;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,6 +107,10 @@ public class JClass extends JLoadableNode {
|
||||
return cls.getSmali();
|
||||
}
|
||||
|
||||
public String getSmaliV2() {
|
||||
return cls.getClassNode().getSmaliV2();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSyntaxName() {
|
||||
return SyntaxConstants.SYNTAX_STYLE_JAVA;
|
||||
|
||||
@@ -55,9 +55,10 @@ public abstract class AbstractCodeArea extends RSyntaxTextArea {
|
||||
contentPanel.getTabbedPane().getOpenTabs().values().forEach(v -> {
|
||||
if (v instanceof AbstractCodeContentPanel) {
|
||||
AbstractCodeArea codeArea = ((AbstractCodeContentPanel) v).getCodeArea();
|
||||
codeArea.setLineWrap(wrap);
|
||||
if (codeArea.isVisible()) {
|
||||
codeArea.repaint();
|
||||
setCodeAreaLineWrap(codeArea, wrap);
|
||||
if (v instanceof ClassCodeContentPanel) {
|
||||
codeArea = ((ClassCodeContentPanel) v).getSmaliCodeArea();
|
||||
setCodeAreaLineWrap(codeArea, wrap);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -116,6 +117,13 @@ public abstract class AbstractCodeArea extends RSyntaxTextArea {
|
||||
});
|
||||
}
|
||||
|
||||
private void setCodeAreaLineWrap(AbstractCodeArea codeArea, boolean wrap) {
|
||||
codeArea.setLineWrap(wrap);
|
||||
if (codeArea.isVisible()) {
|
||||
codeArea.repaint();
|
||||
}
|
||||
}
|
||||
|
||||
private String highlightCaretWord(String lastText, int pos) {
|
||||
String text = getWordByPosition(pos);
|
||||
if (StringUtils.isEmpty(text)) {
|
||||
|
||||
@@ -1,26 +1,106 @@
|
||||
package jadx.gui.ui.codearea;
|
||||
|
||||
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import org.fife.ui.rsyntaxtextarea.*;
|
||||
|
||||
import jadx.gui.settings.JadxSettings;
|
||||
import jadx.gui.treemodel.JClass;
|
||||
import jadx.gui.treemodel.JNode;
|
||||
import jadx.gui.treemodel.TextNode;
|
||||
import jadx.gui.ui.ContentPanel;
|
||||
import jadx.gui.utils.NLS;
|
||||
|
||||
public final class SmaliArea extends AbstractCodeArea {
|
||||
private static final long serialVersionUID = 1334485631870306494L;
|
||||
|
||||
private final JNode textNode;
|
||||
|
||||
private SmaliV2Style smaliV2Style;
|
||||
private boolean curVersion = false;
|
||||
private final JCheckBoxMenuItem cbUseSmaliV2;
|
||||
|
||||
SmaliArea(ContentPanel contentPanel) {
|
||||
super(contentPanel);
|
||||
this.textNode = new TextNode(node.getName());
|
||||
setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
|
||||
|
||||
cbUseSmaliV2 = new JCheckBoxMenuItem(NLS.str("popup.bytecode_col"), shouldUseSmaliPrinterV2());
|
||||
cbUseSmaliV2.setAction(new AbstractAction(NLS.str("popup.bytecode_col")) {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
|
||||
boolean usingV2 = shouldUseSmaliPrinterV2();
|
||||
JadxSettings settings = getContentPanel().getTabbedPane().getMainWindow().getSettings();
|
||||
settings.setSmaliAreaShowBytecode(!usingV2);
|
||||
contentPanel.getTabbedPane().getOpenTabs().values().forEach(v -> {
|
||||
if (v instanceof ClassCodeContentPanel) {
|
||||
((ClassCodeContentPanel) v).getSmaliCodeArea().refresh();
|
||||
}
|
||||
});
|
||||
settings.sync();
|
||||
}
|
||||
});
|
||||
getPopupMenu().add(cbUseSmaliV2);
|
||||
if (shouldUseSmaliPrinterV2()) {
|
||||
loadV2Style();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Font getFont() {
|
||||
if (smaliV2Style != null && shouldUseSmaliPrinterV2()) {
|
||||
return smaliV2Style.getFont();
|
||||
}
|
||||
return super.getFont();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Font getFontForTokenType(int type) {
|
||||
if (shouldUseSmaliPrinterV2()) {
|
||||
return smaliV2Style.getFont();
|
||||
}
|
||||
return super.getFontForTokenType(type);
|
||||
}
|
||||
|
||||
private boolean shouldUseSmaliPrinterV2() {
|
||||
return getContentPanel().getTabbedPane().getMainWindow().getSettings().getSmaliAreaShowBytecode();
|
||||
}
|
||||
|
||||
private void loadV2Style() {
|
||||
if (smaliV2Style == null) {
|
||||
smaliV2Style = new SmaliV2Style(this);
|
||||
addPropertyChangeListener(SYNTAX_SCHEME_PROPERTY, evt -> {
|
||||
if (smaliV2Style.refreshTheme() && shouldUseSmaliPrinterV2()) {
|
||||
setSyntaxScheme(smaliV2Style);
|
||||
}
|
||||
});
|
||||
}
|
||||
setSyntaxScheme(smaliV2Style);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
if (getText().isEmpty()) {
|
||||
setText(node.getSmali());
|
||||
boolean useSmaliV2 = shouldUseSmaliPrinterV2();
|
||||
if (useSmaliV2 != cbUseSmaliV2.getState()) {
|
||||
cbUseSmaliV2.setState(useSmaliV2);
|
||||
}
|
||||
if (getText().isEmpty() || curVersion != useSmaliV2) {
|
||||
curVersion = useSmaliV2;
|
||||
if (!useSmaliV2) {
|
||||
if (getSyntaxScheme() == smaliV2Style) {
|
||||
Theme theme = getContentPanel().getTabbedPane().getMainWindow().getEditorTheme();
|
||||
setSyntaxScheme(theme.scheme);
|
||||
}
|
||||
setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
|
||||
setText(node.getSmali());
|
||||
} else {
|
||||
loadV2Style();
|
||||
setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_ASSEMBLER_6502);
|
||||
setText(((JClass) node).getSmaliV2());
|
||||
}
|
||||
setCaretPosition(0);
|
||||
}
|
||||
}
|
||||
@@ -35,4 +115,57 @@ public final class SmaliArea extends AbstractCodeArea {
|
||||
// this area contains only smali without other node attributes
|
||||
return textNode;
|
||||
}
|
||||
|
||||
private static class SmaliV2Style extends SyntaxScheme {
|
||||
|
||||
SmaliArea smaliArea;
|
||||
Theme curTheme;
|
||||
|
||||
public SmaliV2Style(SmaliArea smaliArea) {
|
||||
super(true);
|
||||
this.smaliArea = smaliArea;
|
||||
curTheme = smaliArea.getContentPanel().getTabbedPane().getMainWindow().getEditorTheme();
|
||||
updateTheme();
|
||||
}
|
||||
|
||||
public Font getFont() {
|
||||
return smaliArea.getContentPanel().getTabbedPane().getMainWindow().getSettings().getSmaliFont();
|
||||
}
|
||||
|
||||
public boolean refreshTheme() {
|
||||
Theme theme = smaliArea.getContentPanel().getTabbedPane().getMainWindow().getEditorTheme();
|
||||
boolean refresh = theme != curTheme;
|
||||
if (refresh) {
|
||||
curTheme = theme;
|
||||
updateTheme();
|
||||
}
|
||||
return refresh;
|
||||
}
|
||||
|
||||
private void updateTheme() {
|
||||
Style[] mainStyles = curTheme.scheme.getStyles();
|
||||
Style[] styles = new Style[mainStyles.length];
|
||||
for (int i = 0; i < mainStyles.length; i++) {
|
||||
Style mainStyle = mainStyles[i];
|
||||
if (mainStyle == null) {
|
||||
styles[i] = new Style();
|
||||
} else {
|
||||
// font will be hijacked by getFont & getFontForTokenType,
|
||||
// so it doesn't need to be set here.
|
||||
styles[i] = new Style(mainStyle.foreground, mainStyle.background, null);
|
||||
}
|
||||
}
|
||||
setStyles(styles);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreDefaults(Font baseFont) {
|
||||
restoreDefaults(baseFont, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreDefaults(Font baseFont, boolean fontStyles) {
|
||||
// Note: it's a hook for continue using the editor theme, better don't remove it.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,9 +115,11 @@ preferences.excludedPackages.editDialog=<html>Liste der durch Leerzeichen getren
|
||||
preferences.cfg=Methoden generieren CFG-Grafiken (im 'Punkt'-Format)
|
||||
preferences.raw_cfg=RAW CFG-Grafiken generieren
|
||||
preferences.font=Schrift ändern
|
||||
#preferences.smali_font=
|
||||
preferences.theme=Thema ändern
|
||||
preferences.start_jobs=Autom. Hintergrunddekompilierung starten
|
||||
preferences.select_font=Ändern
|
||||
#preferences.select_smali_font=
|
||||
preferences.deobfuscation_on=Deobfuscation aktivieren
|
||||
preferences.deobfuscation_force=Deobfuscationskartendatei umschreiben erzwingen
|
||||
preferences.deobfuscation_min_len=Minimale Namenlänge
|
||||
@@ -154,6 +156,7 @@ msg.cmd_select_class_error=Klasse\n%s auswählen nicht möglich\nSie existiert n
|
||||
#msg.rename_node_disabled=
|
||||
#msg.rename_node_failed=
|
||||
|
||||
#popup.bytecode_col=
|
||||
#popup.line_wrap=
|
||||
popup.undo=Rückgängig
|
||||
popup.redo=Wiederholen
|
||||
|
||||
@@ -115,9 +115,11 @@ preferences.excludedPackages.editDialog=<html>List of space separated package na
|
||||
preferences.cfg=Generate methods CFG graphs (in 'dot' format)
|
||||
preferences.raw_cfg=Generate RAW CFG graphs
|
||||
preferences.font=Editor font
|
||||
preferences.smali_font=Smali Editor font
|
||||
preferences.theme=Editor theme
|
||||
preferences.start_jobs=Auto start background decompilation
|
||||
preferences.select_font=Change
|
||||
preferences.select_smali_font=Change
|
||||
preferences.deobfuscation_on=Enable deobfuscation
|
||||
preferences.deobfuscation_force=Force rewrite deobfuscation map file
|
||||
preferences.deobfuscation_min_len=Minimum name length
|
||||
@@ -154,6 +156,7 @@ msg.cmd_select_class_error=Failed to select the class\n%s\nThe class does not ex
|
||||
msg.rename_node_disabled=Can't rename this node
|
||||
msg.rename_node_failed=Can't rename %s
|
||||
|
||||
popup.bytecode_col=Show Bytecode
|
||||
popup.line_wrap=Line Wrap
|
||||
popup.undo=Undo
|
||||
popup.redo=Redo
|
||||
|
||||
@@ -115,9 +115,11 @@ preferences.threads=Número de hilos a procesar
|
||||
preferences.cfg=Generar methods CFG graphs (in 'dot' format)
|
||||
preferences.raw_cfg=Generate RAW CFG graphs
|
||||
preferences.font=Fuente del editor
|
||||
#preferences.smali_font=
|
||||
preferences.theme=Tema del editor
|
||||
preferences.start_jobs=Inicio autom. descompilación de fondo
|
||||
preferences.select_font=Seleccionar
|
||||
#preferences.select_smali_font=
|
||||
preferences.deobfuscation_on=Activar desobfuscación
|
||||
preferences.deobfuscation_force=Forzar reescritura del fichero de ofuscación
|
||||
preferences.deobfuscation_min_len=Longitud mínima del nombre
|
||||
@@ -154,6 +156,7 @@ msg.index_not_initialized=Índice no inicializado, ¡la bósqueda se desactivar
|
||||
#msg.rename_node_disabled=
|
||||
#msg.rename_node_failed=
|
||||
|
||||
#popup.bytecode_col=
|
||||
#popup.line_wrap=
|
||||
popup.undo=Deshacer
|
||||
popup.redo=Rehacer
|
||||
|
||||
@@ -115,9 +115,11 @@ preferences.excludedPackages.editDialog=<html>RAM 절약을 위해 디컴파일
|
||||
preferences.cfg=메소드 CFG 그래프 생성 ('dot' 포맷)
|
||||
preferences.raw_cfg=RAW CFG 그래프 생성
|
||||
preferences.font=에디터 글씨체
|
||||
#preferences.smali_font=
|
||||
preferences.theme=에디터 테마
|
||||
preferences.start_jobs=백그라운드에서 디컴파일 자동 시작
|
||||
preferences.select_font=변경
|
||||
#preferences.select_smali_font=
|
||||
preferences.deobfuscation_on=난독 해제 활성화
|
||||
preferences.deobfuscation_force=난독 해제 맵 파일 다시 쓰기
|
||||
preferences.deobfuscation_min_len=최소 이름 길이
|
||||
@@ -154,6 +156,7 @@ msg.cmd_select_class_error=클래스를 선택하지 못했습니다.\n%s\n클
|
||||
msg.rename_node_disabled=이 노드의 이름을 바꿀 수 없습니다.
|
||||
msg.rename_node_failed=%s의 이름을 바꿀 수 없습니다.
|
||||
|
||||
#popup.bytecode_col=
|
||||
popup.line_wrap=줄 바꿈
|
||||
popup.undo=실행 취소
|
||||
popup.redo=다시 실행
|
||||
|
||||
@@ -115,9 +115,11 @@ preferences.excludedPackages.editDialog=<html>将不被解压或索引的以空
|
||||
preferences.cfg=生成方法的 CFG 图(以 .dot 格式保存)
|
||||
preferences.raw_cfg=生成原始的 CFG 图
|
||||
preferences.font=编辑器字体
|
||||
#preferences.smali_font=
|
||||
preferences.theme=编辑器主题
|
||||
preferences.start_jobs=自动进行后台反编译
|
||||
preferences.select_font=更改
|
||||
#preferences.select_smali_font=
|
||||
preferences.deobfuscation_on=启用反混淆
|
||||
preferences.deobfuscation_force=强制覆盖反混淆映射文件
|
||||
preferences.deobfuscation_min_len=最小命名长度
|
||||
@@ -154,6 +156,7 @@ msg.cmd_select_class_error=无法选择类\n%s\n该类不存在。
|
||||
#msg.rename_node_disabled=
|
||||
#msg.rename_node_failed=
|
||||
|
||||
#popup.bytecode_col=
|
||||
#popup.line_wrap=
|
||||
popup.undo=撤销
|
||||
popup.redo=重做
|
||||
|
||||
Reference in New Issue
Block a user