mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
GT-3481 - Gnu Demangler - Checkpoint 2 - Most docs and tests done;
analyzer test remains
This commit is contained in:
parent
b774ecb2d6
commit
b4ce3012d7
55 changed files with 854 additions and 1283 deletions
|
@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
|
|||
li { font-family:times new roman; font-size:14pt; }
|
||||
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
|
||||
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
|
||||
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
|
||||
|
||||
/*
|
||||
|
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
|
|||
td { font-family:times new roman; font-size:14pt; vertical-align: top; }
|
||||
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
|
||||
|
||||
code { color: black; font-family: courier new; font-size: 14pt; }
|
||||
/*
|
||||
Code-like formatting for things such as file system paths and proper names of classes,
|
||||
methods, etc. To apply this to a file path, use this syntax:
|
||||
<CODE CLASS="path">...</CODE>
|
||||
*/
|
||||
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
|
|
|
@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
|
|||
li { font-family:times new roman; font-size:14pt; }
|
||||
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
|
||||
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
|
||||
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
|
||||
|
||||
/*
|
||||
|
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
|
|||
td { font-family:times new roman; font-size:14pt; vertical-align: top; }
|
||||
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
|
||||
|
||||
code { color: black; font-family: courier new; font-size: 14pt; }
|
||||
/*
|
||||
Code-like formatting for things such as file system paths and proper names of classes,
|
||||
methods, etc. To apply this to a file path, use this syntax:
|
||||
<CODE CLASS="path">...</CODE>
|
||||
*/
|
||||
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
|
|
|
@ -82,7 +82,6 @@ ghidra_scripts/world.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END
|
|||
src/main/help/help/TOC_Source.xml||GHIDRA||||END|
|
||||
src/main/help/help/shared/arrow.gif||GHIDRA||||END|
|
||||
src/main/help/help/shared/close16.gif||GHIDRA||||END|
|
||||
src/main/help/help/shared/helpWarning.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
|
||||
src/main/help/help/shared/menu16.gif||GHIDRA||||END|
|
||||
src/main/help/help/shared/note-red.png||Oxygen Icons - LGPL 3.0|||renamed from flag-red.png|END|
|
||||
src/main/help/help/shared/note.png||Oxygen Icons - LGPL 3.0|||renamed from flag-green.png|END|
|
||||
|
|
|
@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
|
|||
li { font-family:times new roman; font-size:14pt; }
|
||||
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
|
||||
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
|
||||
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
|
||||
|
||||
/*
|
||||
|
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
|
|||
td { font-family:times new roman; font-size:14pt; vertical-align: top; }
|
||||
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
|
||||
|
||||
code { color: black; font-family: courier new; font-size: 14pt; }
|
||||
/*
|
||||
Code-like formatting for things such as file system paths and proper names of classes,
|
||||
methods, etc. To apply this to a file path, use this syntax:
|
||||
<CODE CLASS="path">...</CODE>
|
||||
*/
|
||||
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 1.3 KiB |
|
@ -5,7 +5,7 @@
|
|||
<META name="generator" content=
|
||||
"HTML Tidy for Java (vers. 2009-12-01), see jtidy.sourceforge.net">
|
||||
|
||||
<TITLE>Auto-analysis</TITLE>
|
||||
<TITLE>Auto Analysis</TITLE>
|
||||
<META http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<LINK rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
|
||||
</HEAD>
|
||||
|
@ -24,7 +24,7 @@
|
|||
|
||||
<BLOCKQUOTE>
|
||||
<OL>
|
||||
<LI>User Disassembles</LI>
|
||||
<LI>The user triggers disassembly</LI>
|
||||
|
||||
<LI>Function Analyzer - looks at all calls and creates Functions</LI>
|
||||
|
||||
|
@ -34,9 +34,8 @@
|
|||
<LI>Operand Analyzer - looks at scalar operands for possible address references</LI>
|
||||
|
||||
<LI>Data Reference Analyzer - looks at references for possible strings or pointers to
|
||||
code.<BR>
|
||||
References to code are disassembled.<BR>
|
||||
..... Cycle repeats with 2) as additional code is disassembled.</LI>
|
||||
code. References to code are disassembled.<BR>
|
||||
.....The cycle repeats with 2) as additional code is disassembled.</LI>
|
||||
</OL>
|
||||
|
||||
<P>One program change might cause several Analyzers to become active, however only one
|
||||
|
@ -210,46 +209,46 @@
|
|||
<H4><B>Options</B></H4>
|
||||
|
||||
<UL>
|
||||
<LI><B>Create strings containing existing strings</B> - if checked, strings will be
|
||||
<LI><B>Create Strings Containing Existing Strings</B> - if checked, strings will be
|
||||
created even if they contain existing substrings (existing strings will be cleared). The
|
||||
string will be created only if existing strings (a) are wholly contained within the
|
||||
potential string, (b) do not share the same starting address as the potential string, (c)
|
||||
share the same ending address as the potential string, and (d) are the same datatype as
|
||||
the potential string to be created).</LI>
|
||||
|
||||
<LI><B>Create strings containing references</B> - if checked, strings that contain, but
|
||||
<LI><B>Create Strings Containing References</B> - if checked, strings that contain, but
|
||||
do not start with, one or more references will be created.</LI>
|
||||
|
||||
<LI><B>Force model reload</B> - if checked, forces the model to be reloaded every time
|
||||
<LI><B>Force Model Reload</B> - if checked, forces the model to be reloaded every time
|
||||
the analyzer is run (in cases where the user wishes to see the effect of changing a model
|
||||
without restarting Ghidra).</LI>
|
||||
|
||||
<LI><B>Minimum string length</B> - specifies the smallest number of characters in a
|
||||
<LI><B>Minimum String Length</B> - specifies the smallest number of characters in a
|
||||
string for it to be considered a valid string. For this analyzer, null termination
|
||||
characters are ignored for the purposes of counting characters. Note that smaller numbers
|
||||
will result in a larger number of false positives. String length must be at least 4.</LI>
|
||||
|
||||
<LI><B>Model file</B> - Specifies the model file built using the BuildStringModels class
|
||||
<LI><B>Model File</B> - Specifies the model file built using the BuildStringModels class
|
||||
(default is 'StringModel.sng'). Note that the location of the model file does not need to
|
||||
be specified, as models should always be placed in the
|
||||
'Ghidra/Features/Base/data/stringngrams' directory.</LI>
|
||||
<CODE CLASS="path"><GHIDRA_INSTALL_DIR>/Ghidra/Features/Base/data/stringngrams/</CODE> directory.</LI>
|
||||
|
||||
<LI><B>Require null termination for string</B> - if checked, only null-terminated strings
|
||||
<LI><B>Require Null Termination for String</B> - if checked, only null-terminated strings
|
||||
are created.</LI>
|
||||
|
||||
<LI><B>Search only in accessible memory blocks</B> - if checked, searches only in memory
|
||||
<LI><B>Search Only in Accessible Memory Blocks</B> - if checked, searches only in memory
|
||||
blocks that have at least one of the Read (R), Write (W), or Execute (X) permissions set
|
||||
to true. Enabling this option ensures strings are not created in areas such as overlays
|
||||
or debug sections.</LI>
|
||||
|
||||
<LI><B>String end alignment</B> - specifies the byte alignment requirement for the end of
|
||||
<LI><B>String End Alignment</B> - specifies the byte alignment requirement for the end of
|
||||
the string. An alignment of 1 means the string can end at any address. Alignments greater
|
||||
than 1 require that (a) the 'require null termination' option be enabled, and (b) if the
|
||||
null-terminated string does not end at an aligned boundary, that there exist enough
|
||||
trailing '0' bytes following the string to allow alignment. If neither (a) nor (b) apply,
|
||||
end alignment is not enforced.</LI>
|
||||
|
||||
<LI><B>String start alignment</B> - specifies the byte alignment requirement for the
|
||||
<LI><B>String Start Alignment</B> - specifies the byte alignment requirement for the
|
||||
start of the string. An alignment of 1 means that strings can start at any address. An
|
||||
alignment of 2 means that strings must start on an even address. An alignment of 4 means
|
||||
that strings must start on an address that is a multiple of 4.</LI>
|
||||
|
@ -344,7 +343,99 @@
|
|||
name and create a new primary symbol for the demangled name. It will also assign the
|
||||
appropriate datatypes to the parameters and return type.</P>
|
||||
|
||||
<P><U>Started By:</U> New defined functions</P>
|
||||
<P>
|
||||
The default demangler options are:
|
||||
<TABLE BORDER="1">
|
||||
<TR>
|
||||
<TH WIDTH="25%">Name</TH>
|
||||
<TH WIDTH="75%">Description</TH>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>Apply Function Signatures
|
||||
</TD>
|
||||
<TD>
|
||||
Apply any recovered function signature type information
|
||||
in addition to the function name
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>Only Demangle Known Mangled Symbols
|
||||
</TD>
|
||||
<TD>
|
||||
Only demangle symbols that follow known compiler mangling patterns.
|
||||
Leaving this option off may cause non-mangled symbols to get demangled.
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
</P>
|
||||
|
||||
<P><A name="Gnu_Demangler_Options">
|
||||
<BR>
|
||||
<BR>
|
||||
<B>The GNU Demangler</B> adds the following analysis options:
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>
|
||||
<U><B>Use Deprecated Demangler</B></U> -
|
||||
By default, GCC symbols will be demangled using the most up-to-date demangler
|
||||
that Ghidra contains (<B>version 2.33.1</B> as of this writing). Turning this
|
||||
option on will also invoke the now deprecated previous version of the demangler
|
||||
(<B>version 2.24</B>) if the preferred demangler cannot demangle a given symbol.
|
||||
</P>
|
||||
<P>
|
||||
Support for older demangling styles was removed in <CODE>c++filt (v2.32)</CODE>.
|
||||
Specifically, the following formats are no longer supported:
|
||||
<CODE>Lucid, ARM, HP, and EDG</CODE>. To use these formats, you must enable
|
||||
usage of the deprecated demangler, which is <B>version 2.24</B>. Further, you
|
||||
may have to pass the required external demangler options using the Ghidra
|
||||
option below.
|
||||
</P>
|
||||
<P>
|
||||
|
||||
<U><B>Use External Demangler Options</B></U> -
|
||||
|
||||
This allows users to pass settings to the demangler. As an example, you can enter
|
||||
in this Ghidra option text field the following text to use the <CODE>rust</CODE>
|
||||
format: <CODE>-s rust</CODE>. This is not needed for
|
||||
normal operation. To see a full list of supported options, query each demangler
|
||||
directly sing the <CODE>--help</CODE> switch.
|
||||
</P>
|
||||
<P>
|
||||
The GNU demanglers can be found at:
|
||||
<CODE CLASS="path">
|
||||
<GHIDRA_INSTALL_DIR>/GPL/DemanglerGnu/build/os/<OS>/
|
||||
</CODE><BR>
|
||||
</P>
|
||||
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>
|
||||
The available programs are:
|
||||
<UL>
|
||||
<LI><CODE>demangler_gnu_v2_33_1</CODE></LI>
|
||||
<LI><CODE>demangler_gnu_v2_24</CODE></LI>
|
||||
</UL>
|
||||
</P>
|
||||
<P style="background-color: #FFF0E0;">
|
||||
<IMG SRC="../../shared/warning.png" />When using an external GNU demangler,
|
||||
please understand the risks associated with using that version of the
|
||||
software. The <CODE>demangler_gnu_v2_24</CODE> version of the
|
||||
demangler is a modified version of GNU's <CODE>c++filt (v2.24)</CODE>. The
|
||||
original version has known vulnerabilities which have been mitigated in
|
||||
the version created for Ghidra.
|
||||
</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P>
|
||||
<IMG SRC="../../shared/tip.png" />The Demangler Analyzer is designed to be extensible.
|
||||
You can extend <CODE>ghidra.app.plugin.core.analysis.AbstractDemanglerAnalyzer</CODE>
|
||||
to add your demangler analyzer callback. This allows you to precisely control
|
||||
which demanglers get called, as well as which options are used.
|
||||
</P>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P STYLE="margin-top: 30px;"><U>Started By:</U> New defined functions</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="Auto_Analysis_Option_Byte"></A>Entry Point Analyzer</H3>
|
||||
|
|
|
@ -72,7 +72,7 @@ public class DemanglerCmd extends BackgroundCommand {
|
|||
private boolean doDemangle(Demangler demangler, Program program, TaskMonitor monitor) {
|
||||
|
||||
try {
|
||||
demangledObject = demangler.demangle(mangled, options.demangleOnlyKnownPatterns());
|
||||
demangledObject = demangler.demangle(mangled, options);
|
||||
}
|
||||
catch (DemangledException e) {
|
||||
if (e.isInvalidMangledName()) {
|
||||
|
|
|
@ -25,7 +25,20 @@ import ghidra.program.model.symbol.*;
|
|||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
// TODO docme
|
||||
/**
|
||||
* The base demangler analyzer. Implementations of this analyzer will attempt to demangle
|
||||
* symbols in the binary being analyzed.
|
||||
*
|
||||
* <P>Default implementations of this class exist for Microsoft and GNU. These two analyzers will
|
||||
* only be enabled when the program being analyzed has an architecture that fits each respective
|
||||
* analyzer. Users can subclass this analyzer to easily control the demangling behavior from
|
||||
* the analyzer UI.
|
||||
*
|
||||
* <P>This analyzer will call each implementation's
|
||||
* {@link #doDemangle(String, DemanglerOptions, MessageLog)} method for each symbol.
|
||||
* See the various protected methods of this class for points at which behavior can be overridden.
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
|
||||
|
||||
public AbstractDemanglerAnalyzer(String name, String description) {
|
||||
|
@ -35,7 +48,7 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
|
|||
|
||||
@Override
|
||||
public boolean canAnalyze(Program program) {
|
||||
// override this to be enable for a binary containing symbols you wisht to process
|
||||
// override this to control program-specific enablement
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -78,13 +91,38 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
|
|||
return true;
|
||||
}
|
||||
|
||||
// TODO callback before demangling begins...
|
||||
/**
|
||||
* The implementation-specific demangling callback
|
||||
*
|
||||
* @param mangled the mangled string
|
||||
* @param options the demangler options
|
||||
* @param log the error log
|
||||
* @return the demangled object; null if demangling was unsuccessful
|
||||
* @throws DemangledException if there is a problem demangling or building the result
|
||||
*/
|
||||
protected abstract DemangledObject doDemangle(String mangled, DemanglerOptions options,
|
||||
MessageLog log) throws DemangledException;
|
||||
|
||||
/**
|
||||
* Called before each analysis request to ensure that the current options (which may have
|
||||
* user-defined input) will work with the current demangler
|
||||
*
|
||||
* @param options the current options in use
|
||||
* @param log the error log into which error message can be written
|
||||
* @return true if valid
|
||||
*/
|
||||
protected boolean validateOptions(DemanglerOptions options, MessageLog log) {
|
||||
// override to validate custom options for a particular demangler
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean skipSymbol(Symbol symbol) {
|
||||
/**
|
||||
* True if this analyzer should <b>not</b> attempt to demangle the given symbol
|
||||
*
|
||||
* @param symbol the symbol
|
||||
* @return true to skip the symbol
|
||||
*/
|
||||
protected boolean skipSymbol(Symbol symbol) {
|
||||
if (symbol.getSource() == SourceType.DEFAULT) {
|
||||
return true;
|
||||
}
|
||||
|
@ -111,9 +149,13 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
|
|||
return false;
|
||||
}
|
||||
|
||||
protected abstract DemangledObject doDemangle(String mangled, DemanglerOptions options,
|
||||
MessageLog log) throws DemangledException;
|
||||
|
||||
/**
|
||||
* Creates the options for the demangler used by implementations of this analyzer. This will
|
||||
* be called before each {@link #added(Program, AddressSetView, TaskMonitor, MessageLog)}
|
||||
* call processes symbols.
|
||||
*
|
||||
* @return the options
|
||||
*/
|
||||
protected DemanglerOptions getOptions() {
|
||||
// note: these can be stored in the analyzer subclass and updated when the
|
||||
// analysis options change
|
||||
|
@ -124,6 +166,15 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
|
|||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* This calss's default demangle method. This may be overridden to change how errors are
|
||||
* handled.
|
||||
*
|
||||
* @param mangled the mangled string
|
||||
* @param options the demangler options
|
||||
* @param log the error log
|
||||
* @return the demangled object; null if unsuccessful
|
||||
*/
|
||||
protected DemangledObject demangle(String mangled, DemanglerOptions options,
|
||||
MessageLog log) {
|
||||
|
||||
|
@ -148,6 +199,16 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
|
|||
return demangled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the given demangled object to the program
|
||||
*
|
||||
* @param program the program
|
||||
* @param address the apply address
|
||||
* @param demangled the demangled object
|
||||
* @param options the options used during the apply
|
||||
* @param log the error log
|
||||
* @param monitor the task monitor
|
||||
*/
|
||||
protected void apply(Program program, Address address, DemangledObject demangled,
|
||||
DemanglerOptions options, MessageLog log, TaskMonitor monitor) {
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ public class AnalysisOptionsDialog extends DialogComponentProvider implements
|
|||
setOkButtonText("Analyze");
|
||||
okButton.setMnemonic('A');
|
||||
setOkEnabled(true);
|
||||
setPreferredSize(800, 400);
|
||||
setPreferredSize(1000, 600);
|
||||
setRememberSize(true);
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,7 @@ public class AnalysisOptionsDialog extends DialogComponentProvider implements
|
|||
// analysis panel has finished being constructed, so protect against
|
||||
// that before calling the update method.
|
||||
if (panel != null) {
|
||||
panel.updateOptionForAllPrograms(evt.getPropertyName(), (Boolean)evt.getNewValue());
|
||||
panel.updateOptionForAllPrograms(evt.getPropertyName(), (Boolean) evt.getNewValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,20 +16,18 @@
|
|||
package ghidra.app.plugin.core.analysis;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.beans.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import javax.swing.table.*;
|
||||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
|
||||
import docking.help.Help;
|
||||
import docking.help.HelpService;
|
||||
import docking.options.editor.GenericOptionsComponent;
|
||||
import docking.widgets.OptionDialog;
|
||||
import docking.widgets.label.GLabel;
|
||||
|
@ -39,11 +37,11 @@ import ghidra.app.services.Analyzer;
|
|||
import ghidra.framework.options.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.ColorUtils;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.util.layout.VerticalLayout;
|
||||
|
||||
class AnalysisPanel extends JPanel implements PropertyChangeListener {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final String PROTOTYPE = " (Prototype)";
|
||||
|
||||
|
@ -132,12 +130,7 @@ class AnalysisPanel extends JPanel implements PropertyChangeListener {
|
|||
AutoAnalysisManager manager = AutoAnalysisManager.getAnalysisManager(programs.get(0));
|
||||
|
||||
List<String> propertyNames = analysisOptions.getOptionNames();
|
||||
Collections.sort(propertyNames, new Comparator<String>() {
|
||||
@Override
|
||||
public int compare(String o1, String o2) {
|
||||
return o1.compareToIgnoreCase(o2);
|
||||
}
|
||||
});
|
||||
Collections.sort(propertyNames, (o1, o2) -> o1.compareToIgnoreCase(o2));
|
||||
for (String analyzerName : propertyNames) {
|
||||
if (analyzerName.indexOf('.') == -1) {
|
||||
if (analysisOptions.getType(analyzerName) != OptionType.BOOLEAN_TYPE) {
|
||||
|
@ -217,26 +210,11 @@ class AnalysisPanel extends JPanel implements PropertyChangeListener {
|
|||
|
||||
private JPanel buildButtonPanel() {
|
||||
JButton selectAllButton = new JButton("Select All");
|
||||
selectAllButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
selectAll();
|
||||
}
|
||||
});
|
||||
selectAllButton.addActionListener(e -> selectAll());
|
||||
JButton deselectAllButton = new JButton("Deselect All");
|
||||
deselectAllButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
deselectAll();
|
||||
}
|
||||
});
|
||||
deselectAllButton.addActionListener(e -> deselectAll());
|
||||
JButton restoreDefaultsButton = new JButton("Restore Defaults");
|
||||
restoreDefaultsButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
restoreDefaults();
|
||||
}
|
||||
});
|
||||
restoreDefaultsButton.addActionListener(e -> restoreDefaults());
|
||||
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
|
||||
buttonPanel.add(selectAllButton);
|
||||
buttonPanel.add(deselectAllButton);
|
||||
|
@ -343,9 +321,7 @@ class AnalysisPanel extends JPanel implements PropertyChangeListener {
|
|||
private void buildTable() {
|
||||
table = new GTable(model);
|
||||
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
|
||||
@Override
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
table.getSelectionModel().addListSelectionListener(e -> {
|
||||
if (e.getValueIsAdjusting()) {
|
||||
return;
|
||||
}
|
||||
|
@ -361,7 +337,6 @@ class AnalysisPanel extends JPanel implements PropertyChangeListener {
|
|||
}
|
||||
String analyzerName = analyzerNames.get(selectedRow);
|
||||
setAnalyzerSelected(analyzerName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -532,6 +507,8 @@ class AnalysisPanel extends JPanel implements PropertyChangeListener {
|
|||
noOptionsPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5));
|
||||
noOptionsPanel.add(new GLabel("No options available."));
|
||||
|
||||
HelpService help = Help.getHelpService();
|
||||
|
||||
for (Options optionsGroup : optionGroups) {
|
||||
String analyzerName = optionsGroup.getName();
|
||||
|
||||
|
@ -550,10 +527,18 @@ class AnalysisPanel extends JPanel implements PropertyChangeListener {
|
|||
List<GenericOptionsComponent> optionComponents = new ArrayList<>();
|
||||
|
||||
for (String childOptionName : optionNames) {
|
||||
|
||||
EditorState childState =
|
||||
editorStateFactory.getEditorState(optionsGroup, childOptionName, this);
|
||||
GenericOptionsComponent comp =
|
||||
GenericOptionsComponent.createOptionComponent(childState);
|
||||
|
||||
HelpLocation helpLoc = analysisOptions
|
||||
.getHelpLocation(analyzerName + Options.DELIMITER_STRING + childOptionName);
|
||||
if (helpLoc != null) {
|
||||
help.registerHelp(comp, helpLoc);
|
||||
}
|
||||
|
||||
optionsContainer.add(comp);
|
||||
optionComponents.add(comp);
|
||||
analyzerManagedComponentsMap.get(analyzerName).add(comp);
|
||||
|
|
|
@ -49,7 +49,7 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
|
|||
"analyzer was disabled or not present.";
|
||||
|
||||
private final static String OPTION_FUNCTION_NONRETURN_THRESHOLD =
|
||||
"Function non-return threshold";
|
||||
"Function Non-return Threshold";
|
||||
|
||||
private static final String OPTION_DESCRIPTION_FUNCTION_NONRETURN_THRESHOLD =
|
||||
"Enter the number of indications for a given function before it is considered non-returning.";
|
||||
|
@ -60,12 +60,12 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
|
|||
|
||||
private static final String OPTION_NAME_REPAIR_DAMAGE = "Repair Flow Damage";
|
||||
private static final String OPTION_DESCRIPTION_REPAIR_DAMAGE =
|
||||
"If checked, repair any flow after a call to found non-returning functions.";
|
||||
"Signals to repair any flow after a call to found non-returning functions.";
|
||||
private static final boolean OPTION_DEFAULT_REPAIR_DAMAGE_ENABLED = true;
|
||||
|
||||
private static final String OPTION_NAME_CREATE_BOOKMARKS = "Create Analysis Bookmarks";
|
||||
private static final String OPTION_DESCRIPTION_CREATE_BOOKMARKS =
|
||||
"If checked, an analysis bookmark will created on each function marked as non-returning.";
|
||||
"Signals to create an analysis bookmark on each function marked as non-returning.";
|
||||
private static final boolean OPTION_DEFAULT_CREATE_BOOKMARKS_ENABLED = true;
|
||||
|
||||
private boolean repairDamageEnabled = OPTION_DEFAULT_REPAIR_DAMAGE_ENABLED;
|
||||
|
@ -164,7 +164,8 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
|
|||
|
||||
// entries including data flow referenced from instructions will be repaired
|
||||
|
||||
ClearFlowAndRepairCmd cmd = new ClearFlowAndRepairCmd(clearInstSet, protectedSet, true, false, true);
|
||||
ClearFlowAndRepairCmd cmd =
|
||||
new ClearFlowAndRepairCmd(clearInstSet, protectedSet, true, false, true);
|
||||
cmd.applyTo(program, monitor);
|
||||
}
|
||||
|
||||
|
@ -364,7 +365,8 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
|
|||
continue;
|
||||
}
|
||||
Instruction oinst = cp.getListing().getInstructionAt(fromAddress);
|
||||
if ( oinst == null || !checkNonReturningIndicators(oinst, noReturnSet, blockModel)) {
|
||||
if (oinst == null ||
|
||||
!checkNonReturningIndicators(oinst, noReturnSet, blockModel)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -393,7 +395,8 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
|
|||
return hadSuspiciousFunctions;
|
||||
}
|
||||
|
||||
private boolean targetOnlyCallsNoReturn(Program cp, Address target, AddressSet noReturnSet) throws CancelledException {
|
||||
private boolean targetOnlyCallsNoReturn(Program cp, Address target, AddressSet noReturnSet)
|
||||
throws CancelledException {
|
||||
|
||||
SimpleBlockModel model = new SimpleBlockModel(cp);
|
||||
|
||||
|
@ -402,7 +405,7 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
|
|||
// if hit call, check noReturn, if is stop following
|
||||
// if hit place that is called, then stop, and return no-good
|
||||
|
||||
Stack<Address> todo = new Stack<Address>();
|
||||
Stack<Address> todo = new Stack<>();
|
||||
todo.push(target);
|
||||
AddressSet visited = new AddressSet();
|
||||
boolean hitNoReturn = false;
|
||||
|
@ -491,7 +494,7 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
|
|||
// get the address of the next function after this instruction
|
||||
Address nextFuncAddr = null;
|
||||
if (fallThru != null) {
|
||||
FunctionIterator functions = program.getFunctionManager().getFunctions(fallThru,true);
|
||||
FunctionIterator functions = program.getFunctionManager().getFunctions(fallThru, true);
|
||||
if (functions.hasNext()) {
|
||||
nextFuncAddr = functions.next().getEntryPoint();
|
||||
}
|
||||
|
@ -518,7 +521,8 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
|
|||
/* check for codeblock containing a function */
|
||||
if (nextFuncAddr != null && block.contains(nextFuncAddr)) {
|
||||
NoReturnLocations location =
|
||||
new NoReturnLocations(target, fallThru, "Function defined in instruction after call");
|
||||
new NoReturnLocations(target, fallThru,
|
||||
"Function defined in instruction after call");
|
||||
reasonList.add(location);
|
||||
return true;
|
||||
}
|
||||
|
@ -598,7 +602,8 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
|
|||
|
||||
protected void fixCallingFunctionBody(Program cp, Address entry) throws CancelledException {
|
||||
if (createBookmarksEnabled) {
|
||||
cp.getBookmarkManager().setBookmark(entry, BookmarkType.ANALYSIS,
|
||||
cp.getBookmarkManager()
|
||||
.setBookmark(entry, BookmarkType.ANALYSIS,
|
||||
"Non-Returning Function", "Non-Returning Function Found");
|
||||
}
|
||||
AddressSet fixedSet = new AddressSet();
|
||||
|
@ -673,7 +678,7 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
|
|||
// must do an operation, or assign to non-unique
|
||||
for (PcodeOp pCode : pcode) {
|
||||
int opcode = pCode.getOpcode();
|
||||
switch(opcode) {
|
||||
switch (opcode) {
|
||||
case PcodeOp.LOAD:
|
||||
case PcodeOp.STORE:
|
||||
case PcodeOp.CALLOTHER:
|
||||
|
@ -710,7 +715,7 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
|
|||
@Override
|
||||
public void registerOptions(Options options, Program prog) {
|
||||
HelpLocation helpLocation = new HelpLocation("AutoAnalysisPlugin",
|
||||
"Auto_Analysis_Option_Instruction" + getAnalysisType());
|
||||
"Auto_Analysis_Option_Instructions");
|
||||
|
||||
options.registerOption(OPTION_FUNCTION_NONRETURN_THRESHOLD,
|
||||
OPTION_DEFAULT_EVIDENCE_THRESHOLD, helpLocation,
|
||||
|
|
|
@ -27,57 +27,23 @@ import ghidra.app.cmd.function.CreateFunctionCmd;
|
|||
import ghidra.app.cmd.function.CreateThunkFunctionCmd;
|
||||
import ghidra.app.plugin.core.disassembler.AddressTable;
|
||||
import ghidra.app.plugin.core.function.FunctionAnalyzer;
|
||||
import ghidra.app.services.AbstractAnalyzer;
|
||||
import ghidra.app.services.AnalysisPriority;
|
||||
import ghidra.app.services.AnalyzerType;
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.app.util.PseudoDisassembler;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.app.util.opinion.PeLoader;
|
||||
import ghidra.framework.cmd.BackgroundCommand;
|
||||
import ghidra.framework.cmd.Command;
|
||||
import ghidra.framework.cmd.CompoundBackgroundCommand;
|
||||
import ghidra.framework.cmd.*;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.program.disassemble.Disassembler;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressIterator;
|
||||
import ghidra.program.model.address.AddressOutOfBoundsException;
|
||||
import ghidra.program.model.address.AddressOverflowException;
|
||||
import ghidra.program.model.address.AddressSet;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.address.SegmentedAddressSpace;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.FunctionDefinition;
|
||||
import ghidra.program.model.data.Pointer;
|
||||
import ghidra.program.model.data.PointerDataType;
|
||||
import ghidra.program.model.data.StringDataType;
|
||||
import ghidra.program.model.data.Undefined;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.lang.RegisterValue;
|
||||
import ghidra.program.model.listing.BookmarkType;
|
||||
import ghidra.program.model.listing.CodeUnit;
|
||||
import ghidra.program.model.listing.CodeUnitIterator;
|
||||
import ghidra.program.model.listing.Data;
|
||||
import ghidra.program.model.listing.FlowOverride;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.FunctionManager;
|
||||
import ghidra.program.model.listing.Instruction;
|
||||
import ghidra.program.model.listing.Listing;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.DumbMemBufferImpl;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
import ghidra.program.model.pcode.Varnode;
|
||||
import ghidra.program.model.reloc.RelocationTable;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.program.model.symbol.FlowType;
|
||||
import ghidra.program.model.symbol.OffsetReference;
|
||||
import ghidra.program.model.symbol.RefType;
|
||||
import ghidra.program.model.symbol.Reference;
|
||||
import ghidra.program.model.symbol.ReferenceIterator;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
@ -328,7 +294,8 @@ public class OperandReferenceAnalyzer extends AbstractAnalyzer {
|
|||
// New information from the thunked function (noreturn, callfixup, etc...)
|
||||
// may affect callers to the function, so tell analyzers about it.
|
||||
// TODO: this should be done by the Auto Thunking mechanisms...
|
||||
if ((!func.isThunk() && CreateThunkFunctionCmd.isThunk(program, func))) {
|
||||
if ((!func.isThunk() &&
|
||||
CreateThunkFunctionCmd.isThunk(program, func))) {
|
||||
CreateFunctionCmd createFunctionCmd = new CreateFunctionCmd(null,
|
||||
func.getEntryPoint(), null, SourceType.ANALYSIS, false, true);
|
||||
if (createFunctionCmd.applyTo(program)) {
|
||||
|
@ -533,7 +500,8 @@ public class OperandReferenceAnalyzer extends AbstractAnalyzer {
|
|||
AddressIterator foundIter = foundCodeBookmarkLocations.getAddresses(true);
|
||||
while (foundIter.hasNext()) {
|
||||
Address target = foundIter.next();
|
||||
program.getBookmarkManager().setBookmark(target, BookmarkType.ANALYSIS,
|
||||
program.getBookmarkManager()
|
||||
.setBookmark(target, BookmarkType.ANALYSIS,
|
||||
"Found Code", "Found code from operand reference");
|
||||
}
|
||||
}
|
||||
|
@ -622,7 +590,8 @@ public class OperandReferenceAnalyzer extends AbstractAnalyzer {
|
|||
instr.setFlowOverride(FlowOverride.CALL_RETURN);
|
||||
// Get rid of any bad disassembly bookmark
|
||||
AddressSet set = new AddressSet(toAddr);
|
||||
program.getBookmarkManager().removeBookmarks(set, BookmarkType.ERROR,
|
||||
program.getBookmarkManager()
|
||||
.removeBookmarks(set, BookmarkType.ERROR,
|
||||
Disassembler.ERROR_BOOKMARK_CATEGORY, monitor);
|
||||
}
|
||||
|
||||
|
@ -808,7 +777,8 @@ public class OperandReferenceAnalyzer extends AbstractAnalyzer {
|
|||
|
||||
if (lastGoodTable != null) {
|
||||
instr.removeOperandReference(opIndex, target);
|
||||
program.getReferenceManager().addOffsetMemReference(instr.getMinAddress(),
|
||||
program.getReferenceManager()
|
||||
.addOffsetMemReference(instr.getMinAddress(),
|
||||
lastGoodTable.getTopAddress(), -((i + 3) * entryLen), RefType.DATA,
|
||||
SourceType.ANALYSIS, opIndex);
|
||||
}
|
||||
|
@ -1266,7 +1236,7 @@ public class OperandReferenceAnalyzer extends AbstractAnalyzer {
|
|||
@Override
|
||||
public void registerOptions(Options options, Program program) {
|
||||
HelpLocation helpLocation = new HelpLocation("AutoAnalysisPlugin",
|
||||
"Auto_Analysis_Option_Instruction" + getAnalysisType());
|
||||
"Auto_Analysis_Option_Instructions");
|
||||
|
||||
if (minimumAddressTableSize == -1) {
|
||||
calculateMinimumAddressTableSize(program);
|
||||
|
|
|
@ -64,8 +64,7 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
|
|||
@Override
|
||||
public void registerOptions(Options options, Program program) {
|
||||
HelpLocation helpLocation =
|
||||
new HelpLocation("AutoAnalysisPlugin", "Auto_Analysis_Option_Instruction" +
|
||||
getAnalysisType());
|
||||
new HelpLocation("AutoAnalysisPlugin", "Auto_Analysis_Option_Instructions");
|
||||
|
||||
options.registerOption(OPTION_NAME_RESPECT_EXECUTE_FLAG, respectExecuteFlags, helpLocation,
|
||||
OPTION_DESCRIPTION_RESPECT_EXECUTE_FLAG);
|
||||
|
@ -73,7 +72,8 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
|
|||
|
||||
@Override
|
||||
public void optionsChanged(Options options, Program program) {
|
||||
respectExecuteFlags = options.getBoolean(OPTION_NAME_RESPECT_EXECUTE_FLAG, respectExecuteFlags);
|
||||
respectExecuteFlags =
|
||||
options.getBoolean(OPTION_NAME_RESPECT_EXECUTE_FLAG, respectExecuteFlags);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -83,8 +83,8 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
|
|||
|
||||
monitor.initialize(addressSet.getNumAddresses());
|
||||
|
||||
Set<Address> doNowSet = new HashSet<Address>();
|
||||
Set<Address> doLaterSet = new HashSet<Address>();
|
||||
Set<Address> doNowSet = new HashSet<>();
|
||||
Set<Address> doLaterSet = new HashSet<>();
|
||||
|
||||
executeSet = program.getMemory().getExecuteSet();
|
||||
|
||||
|
@ -100,8 +100,8 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
|
|||
// Someone created them as a placeholder
|
||||
// Disassemble them
|
||||
// Remember them so the function body can be fixed later
|
||||
Set<Address> dummyFunctionSet = new HashSet<Address>();
|
||||
Set<Address> redoFunctionSet = new HashSet<Address>();
|
||||
Set<Address> dummyFunctionSet = new HashSet<>();
|
||||
Set<Address> redoFunctionSet = new HashSet<>();
|
||||
findDummyFunctions(program, addressSet, dummyFunctionSet, redoFunctionSet);
|
||||
|
||||
// disassemble dummy functions now, re-create the function bodies later
|
||||
|
@ -157,7 +157,8 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
|
|||
EntryPointAnalyzer entryPointAnalyzer = new EntryPointAnalyzer();
|
||||
entryPointAnalyzer.setPriority(AnalysisPriority.REFERENCE_ANALYSIS.before());
|
||||
analysisManager.scheduleOneTimeAnalysis(entryPointAnalyzer, toAddressSet(doLaterSet));
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// came back in, just do it now
|
||||
doDisassembly(program, monitor, doLaterSet);
|
||||
}
|
||||
|
@ -195,7 +196,7 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
|
|||
|
||||
private void fixDummyFunctionBodies(Program program, TaskMonitor monitor,
|
||||
Set<Address> redoFunctionSet) throws CancelledException {
|
||||
Set<Address> recreateFunctionSet = new HashSet<Address>();
|
||||
Set<Address> recreateFunctionSet = new HashSet<>();
|
||||
for (Address entry : redoFunctionSet) {
|
||||
Function function = program.getFunctionManager().getFunctionAt(entry);
|
||||
if (function == null) {
|
||||
|
@ -219,7 +220,8 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
|
|||
if (!foundNonJumpRef) {
|
||||
// check if we have been thunked
|
||||
Address[] functionThunkAddresses = function.getFunctionThunkAddresses();
|
||||
foundNonJumpRef = functionThunkAddresses != null && functionThunkAddresses.length != 0;
|
||||
foundNonJumpRef =
|
||||
functionThunkAddresses != null && functionThunkAddresses.length != 0;
|
||||
}
|
||||
|
||||
// if found non-jump ref, or is external
|
||||
|
@ -232,7 +234,8 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
|
|||
while (referencesTo.hasNext()) {
|
||||
Reference reference = referencesTo.next();
|
||||
Function func =
|
||||
program.getFunctionManager().getFunctionContaining(
|
||||
program.getFunctionManager()
|
||||
.getFunctionContaining(
|
||||
reference.getFromAddress());
|
||||
if (func != null) {
|
||||
recreateFunctionSet.add(func.getEntryPoint());
|
||||
|
@ -340,7 +343,8 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
|
|||
int defaultPointerSize = program.getDefaultPointerSize();
|
||||
try {
|
||||
Data data =
|
||||
program.getListing().createData(entry,
|
||||
program.getListing()
|
||||
.createData(entry,
|
||||
PointerDataType.getPointer(null, defaultPointerSize));
|
||||
Object value = data.getValue();
|
||||
if (value instanceof Address) {
|
||||
|
@ -401,7 +405,7 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
|
|||
private void disassembleCodeMapMarkers(Program program, TaskMonitor monitor) {
|
||||
AddressSetPropertyMap codeProp = program.getAddressSetPropertyMap("CodeMap");
|
||||
if (codeProp != null) {
|
||||
Set<Address> codeSet = new HashSet<Address>();
|
||||
Set<Address> codeSet = new HashSet<>();
|
||||
AddressIterator aiter = codeProp.getAddresses();
|
||||
while (aiter.hasNext()) {
|
||||
codeSet.add(aiter.next());
|
||||
|
|
|
@ -41,17 +41,17 @@ public class SharedReturnAnalyzer extends AbstractAnalyzer {
|
|||
"analyzer was disabled or not present.";
|
||||
|
||||
private final static String OPTION_NAME_ASSUME_CONTIGUOUS_FUNCTIONS =
|
||||
"Assume contiguous functions only";
|
||||
"Assume Contiguous Functions oOnly";
|
||||
|
||||
private final static String OPTION_NAME_CONSIDER_CONDITIONAL_BRANCHES_FUNCTIONS =
|
||||
"Allow conditional Jumps";
|
||||
"Allow Conditional Jumps";
|
||||
|
||||
private static final String OPTION_DESCRIPTION_ASSUME_CONTIGUOUS_FUNCTIONS =
|
||||
"Select this check box to assume all function bodies are contiguous " +
|
||||
"Signals to assume all function bodies are contiguous " +
|
||||
"and all jumps across other functions should be treated as a call-return.";
|
||||
|
||||
private static final String OPTION_DESCRIPTION_CONSIDER_CONDITIONAL_BRANCHES_FUNCTIONS =
|
||||
"Select this check box to allow conditional jumps to be consider for " +
|
||||
"Signals to allow conditional jumps to be consider for " +
|
||||
"shared return jumps to other functions.";
|
||||
|
||||
private final static boolean OPTION_DEFAULT_ASSUME_CONTIGUOUS_FUNCTIONS_ENABLED = false;
|
||||
|
@ -71,11 +71,7 @@ public class SharedReturnAnalyzer extends AbstractAnalyzer {
|
|||
setSupportsOneTimeAnalysis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a function has been added. Looks at address for call
|
||||
* reference
|
||||
* @throws CancelledException
|
||||
*/
|
||||
@Override
|
||||
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
|
||||
throws CancelledException {
|
||||
|
||||
|
@ -86,6 +82,7 @@ public class SharedReturnAnalyzer extends AbstractAnalyzer {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getDefaultEnablement(Program program) {
|
||||
Language language = program.getLanguage();
|
||||
|
||||
|
@ -98,7 +95,7 @@ public class SharedReturnAnalyzer extends AbstractAnalyzer {
|
|||
@Override
|
||||
public void registerOptions(Options options, Program program) {
|
||||
HelpLocation helpLocation = new HelpLocation("AutoAnalysisPlugin",
|
||||
"Auto_Analysis_Option_Instruction" + getAnalysisType());
|
||||
"Auto_Analysis_Option_Instructions");
|
||||
|
||||
options.registerOption(OPTION_NAME_ASSUME_CONTIGUOUS_FUNCTIONS,
|
||||
OPTION_DEFAULT_ASSUME_CONTIGUOUS_FUNCTIONS_ENABLED, helpLocation,
|
||||
|
|
|
@ -38,37 +38,37 @@ public class StringsAnalyzer extends AbstractAnalyzer {
|
|||
"This analyzer searches for valid ASCII strings and automatically creates them in the binary.";
|
||||
|
||||
// Option Names
|
||||
private static final String MODELFILE_OPTION_NAME = "Model file";
|
||||
private static final String MODELFILE_OPTION_NAME = "Model File";
|
||||
private static final String MODELFILE_OPTION_DESCRIPTION =
|
||||
"Model file built using Ghidra's BuildStringModels class. Any model files for this analyzer " +
|
||||
"should be located in the Ghidra/Features/Base/data/stringngrams directory and " +
|
||||
"end in \".sng\".";
|
||||
|
||||
private static final String FORCE_MODEL_RELOAD_OPTION_NAME = "Force model reload";
|
||||
private static final String FORCE_MODEL_RELOAD_OPTION_NAME = "Force Model Reload";
|
||||
private static final String FORCE_MODEL_RELOAD_OPTION_DESCRIPTION =
|
||||
"When checked, forces reload of model files every time the analyzer is run. When unchecked, " +
|
||||
"model files will only be reloaded when Ghidra is restarted or when model file option " +
|
||||
"name is changed.";
|
||||
|
||||
private static final String MINIMUM_STRING_LENGTH_OPTION_NAME = "Minimum string length";
|
||||
private static final String MINIMUM_STRING_LENGTH_OPTION_NAME = "Minimum String Length";
|
||||
private static final String MINIMUM_STRING_LENGTH_OPTION_DESCRIPTION =
|
||||
"The smallest number of characters in a string to be considered a valid string. " +
|
||||
"(Smaller numbers will give more false positives). String length must be 4 " +
|
||||
"or greater.";
|
||||
|
||||
private static final String REQUIRE_NULL_TERMINATION_OPTION_NAME =
|
||||
"Require null termination for string";
|
||||
"Require Null Termination for String";
|
||||
private static final String REQUIRE_NULL_TERMINATION_OPTION_DESCRIPTION =
|
||||
"If set to true, requires all strings to end in null.";
|
||||
|
||||
private static final String ALLOW_STRING_CREATION_WITH_MIDDLE_REF_NAME =
|
||||
"Create strings containing references";
|
||||
"Create Strings Containing References";
|
||||
private static final String ALLOW_STRING_CREATION_WITH_MIDDLE_REF_DESCRIPTION =
|
||||
"If checked, allows a string that contains, but does not start with, one or more references" +
|
||||
" to be created.";
|
||||
|
||||
private static final String ALLOW_STRING_CREATION_WITH_EXISTING_SUBSTR_NAME =
|
||||
"Create strings containing existing strings";
|
||||
"Create Strings Containing Existing Strings";
|
||||
private static final String ALLOW_STRING_CREATION_WITH_EXISTING_SUBSTR_DESCRIPTION =
|
||||
"If checked, allows a string to be created even if it contains existing strings (existing " +
|
||||
"strings will be cleared). The string will be created only if existing strings (a) " +
|
||||
|
@ -76,7 +76,7 @@ public class StringsAnalyzer extends AbstractAnalyzer {
|
|||
"address as the potential string, (c) share the same ending address as the potential " +
|
||||
"string, and (d) are the same datatype as the potential string.";
|
||||
|
||||
private static final String START_ALIGNMENT_OPTION_NAME = "String start alignment";
|
||||
private static final String START_ALIGNMENT_OPTION_NAME = "String Start Alignment";
|
||||
private static final String START_ALIGNMENT_OPTION_DESCRIPTION =
|
||||
"Specifies an alignment requirement for the start of the string. An alignment of 1 " +
|
||||
"means the string can start at any address. An alignment of 2 means the string " +
|
||||
|
@ -92,7 +92,7 @@ public class StringsAnalyzer extends AbstractAnalyzer {
|
|||
"alignment is not enforced.";
|
||||
|
||||
private static final String SEARCH_ONLY_ACCESSIBLE_MEM_BLOCKS_NAME =
|
||||
"Search only in accessible memory blocks";
|
||||
"Search Only in Accessible Memory Blocks";
|
||||
private static final String SEARCH_ONLY_ACCESSIBLE_MEM_BLOCKS_DESCRIPTION =
|
||||
"If checked, this " +
|
||||
"analyzer only searches in memory blocks that have at least one of the Read (R), Write " +
|
||||
|
|
|
@ -26,15 +26,48 @@ public interface Demangler extends ExtensionPoint {
|
|||
|
||||
public boolean canDemangle(Program program);
|
||||
|
||||
// TODO deprecate
|
||||
@Deprecated
|
||||
/**
|
||||
* Deprecated. Use {@link #demangle(String)} or
|
||||
* {@link #demangle(String, DemanglerOptions)}.
|
||||
*
|
||||
* @param mangled the mangled string
|
||||
* @param demangleOnlyKnownPatterns true signals to avoid demangling strings that do
|
||||
* not fit known demangled patterns for this demangler
|
||||
* @return the result
|
||||
* @throws DemangledException if the string cannot be demangled
|
||||
* @deprecated see above
|
||||
*/
|
||||
@Deprecated(since = "9.2", forRemoval = true)
|
||||
public DemangledObject demangle(String mangled, boolean demangleOnlyKnownPatterns)
|
||||
throws DemangledException;
|
||||
|
||||
// TODO docme
|
||||
/**
|
||||
* Attempts to demangle the given string using the default options
|
||||
* ({@link #createDefaultOptions()}
|
||||
*
|
||||
* @param mangled the mangled string
|
||||
* @return the result
|
||||
* @throws DemangledException if the string cannot be demangled
|
||||
*/
|
||||
public default DemangledObject demangle(String mangled) throws DemangledException {
|
||||
return demangle(mangled, createDefaultOptions());
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to demangle the given string using the given options
|
||||
*
|
||||
* @param mangled the mangled string
|
||||
* @param options the options
|
||||
* @return the result
|
||||
* @throws DemangledException if the string cannot be demangled
|
||||
*/
|
||||
public DemangledObject demangle(String mangled, DemanglerOptions options)
|
||||
throws DemangledException;
|
||||
|
||||
/**
|
||||
* Creates default options for this particular demangler
|
||||
* @return the options
|
||||
*/
|
||||
public default DemanglerOptions createDefaultOptions() {
|
||||
return new DemanglerOptions();
|
||||
}
|
||||
|
|
|
@ -47,9 +47,7 @@ public class DemanglerUtil {
|
|||
List<Demangler> demanglers = getDemanglers();
|
||||
for (Demangler demangler : demanglers) {
|
||||
try {
|
||||
// not sure if we should be doing all symbols, but this is what it used to do
|
||||
boolean onlyKnownTypes = false;
|
||||
DemangledObject demangledObject = demangler.demangle(mangled, onlyKnownTypes);
|
||||
DemangledObject demangledObject = demangler.demangle(mangled);
|
||||
if (demangledObject != null) {
|
||||
return demangledObject;
|
||||
}
|
||||
|
@ -82,9 +80,7 @@ public class DemanglerUtil {
|
|||
continue;
|
||||
}
|
||||
|
||||
// not sure if we should be doing all symbols, but this is what it used to do
|
||||
boolean onlyKnownTypes = false;
|
||||
DemangledObject demangledObject = demangler.demangle(mangled, onlyKnownTypes);
|
||||
DemangledObject demangledObject = demangler.demangle(mangled);
|
||||
if (demangledObject != null) {
|
||||
return demangledObject;
|
||||
}
|
||||
|
|
|
@ -1,72 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//@category CodeAnalysis
|
||||
|
||||
import ghidra.app.analyzers.LibHashDB;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.xml.NonThreadedXmlPullParserImpl;
|
||||
import ghidra.xml.XmlPullParser;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import org.xml.sax.*;
|
||||
|
||||
public class BuildFuncDB extends GhidraScript {
|
||||
|
||||
@Override
|
||||
protected void run() throws Exception {
|
||||
|
||||
//If the file is already there, it adds more function records to it. If not, it creates and populates the file.
|
||||
File dbFile =
|
||||
Application.getModuleDataSubDirectory("BytePatterns", "lib/db.xml").getFile(true);
|
||||
LibHashDB db = new LibHashDB();
|
||||
if (dbFile.exists()) {
|
||||
db.restoreXml(getParser(dbFile));
|
||||
}
|
||||
|
||||
LibHashDB dbCurrent = new LibHashDB(this.currentProgram);
|
||||
db.mergeWith(dbCurrent);
|
||||
FileWriter fwrite = new FileWriter(dbFile);
|
||||
db.saveXml(fwrite);
|
||||
fwrite.close();
|
||||
return;
|
||||
}
|
||||
|
||||
private static XmlPullParser getParser(File xmlfile) throws SAXException, IOException {
|
||||
ErrorHandler handler = new ErrorHandler() {
|
||||
@Override
|
||||
public void warning(SAXParseException exception) throws SAXException {
|
||||
throw exception;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(SAXParseException exception) throws SAXException {
|
||||
throw exception;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fatalError(SAXParseException exception) throws SAXException {
|
||||
throw exception;
|
||||
}
|
||||
};
|
||||
|
||||
XmlPullParser parser;
|
||||
parser = new NonThreadedXmlPullParserImpl(xmlfile, handler, false);
|
||||
return parser;
|
||||
}
|
||||
}
|
|
@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
|
|||
li { font-family:times new roman; font-size:14pt; }
|
||||
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
|
||||
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
|
||||
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
|
||||
|
||||
/*
|
||||
|
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
|
|||
td { font-family:times new roman; font-size:14pt; vertical-align: top; }
|
||||
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
|
||||
|
||||
code { color: black; font-family: courier new; font-size: 14pt; }
|
||||
/*
|
||||
Code-like formatting for things such as file system paths and proper names of classes,
|
||||
methods, etc. To apply this to a file path, use this syntax:
|
||||
<CODE CLASS="path">...</CODE>
|
||||
*/
|
||||
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
|
|
|
@ -1,111 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.analyzers;
|
||||
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.xml.XmlPullParser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.TreeSet;
|
||||
|
||||
public class LibHashDB {
|
||||
|
||||
private TreeSet<LibraryRecord> libraries;
|
||||
|
||||
//Empty Constructor
|
||||
public LibHashDB() {
|
||||
this.libraries = new TreeSet<LibraryRecord>();
|
||||
}
|
||||
|
||||
//Construct a DB from the current program, with a record for every function.
|
||||
public LibHashDB(Program prgm) throws CancelledException {
|
||||
this.libraries = new TreeSet<LibraryRecord>();
|
||||
this.libraries.add(new LibraryRecord(prgm));
|
||||
}
|
||||
|
||||
//Merge another DB into this one.
|
||||
public void mergeWith(LibHashDB toMergeIn) {
|
||||
this.libraries.addAll(toMergeIn.libraries);
|
||||
}
|
||||
|
||||
//Add a library to the database.
|
||||
public void addLibrary(LibraryRecord libRec) {
|
||||
this.libraries.add(libRec);
|
||||
return;
|
||||
}
|
||||
|
||||
public TreeSet<FuncRecord> getRecords() {
|
||||
TreeSet<FuncRecord> results = new TreeSet<FuncRecord>();
|
||||
for (LibraryRecord lib : this.libraries) {
|
||||
results.addAll(lib.getRecords());
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
//Find an entry of the database based on actual underlying function.
|
||||
public ArrayList<FuncRecord> query(Function func) throws CancelledException {
|
||||
FuncRecord queryHash = new FuncRecord(func);
|
||||
ArrayList<FuncRecord> result = this.query(queryHash.hashValue); //Use the hash query method instead.
|
||||
for (FuncRecord entry : result) {
|
||||
if (entry.func == func) {
|
||||
ArrayList<FuncRecord> newResult = new ArrayList<FuncRecord>();
|
||||
newResult.add(entry);
|
||||
return newResult;
|
||||
}
|
||||
}
|
||||
return result; //Return all matches.
|
||||
}
|
||||
|
||||
//Find an entry of the database based on hash. Returns all records with that hash.
|
||||
public ArrayList<FuncRecord> query(Long hash) {
|
||||
ArrayList<FuncRecord> result = new ArrayList<FuncRecord>(); //Set up the result.
|
||||
FuncRecord temp = new FuncRecord();
|
||||
temp.hashValue = hash;
|
||||
for (LibraryRecord libRec : this.libraries) { //Search each library for a record matching the hash.
|
||||
result.addAll(libRec.query(hash));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//DB is made up of libraries. To get a DB from a file/parser, look for the "funcDB" tag, and then pass the buck to the LibraryRecord class.
|
||||
public void restoreXml(XmlPullParser parser) {
|
||||
parser.start("funcDB"); //The XML tag for an entire DB.
|
||||
while (parser.peek().isStart()) {
|
||||
LibraryRecord libRec = new LibraryRecord();
|
||||
libRec.restoreXml(parser); //Pass the buck.
|
||||
this.addLibrary(libRec); //DB is a collection of library records.
|
||||
}
|
||||
parser.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//Save DB to an XML file.
|
||||
public void saveXml(Writer fwrite) throws IOException {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append("<funcDB>\n"); //The XML tag for the entire DB.
|
||||
fwrite.append(buf.toString());
|
||||
for (LibraryRecord libRec : this.libraries) {
|
||||
libRec.saveXml(fwrite); //Write out each library in XML.
|
||||
}
|
||||
fwrite.append("</funcDB>\n"); //Finish up.
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -1,271 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.analyzers;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import org.xml.sax.*;
|
||||
|
||||
import ghidra.app.cmd.label.*;
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.framework.cmd.Command;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import ghidra.xml.NonThreadedXmlPullParserImpl;
|
||||
import ghidra.xml.XmlPullParser;
|
||||
|
||||
public class LibraryHashAnalyzer extends AbstractAnalyzer {
|
||||
private static final String NAME = "Library Hash Identification";
|
||||
private static final String DESCRIPTION =
|
||||
"Analyzes program for statically linked library functions (e.g., printf, scanf, etc.).";
|
||||
|
||||
private final static String OPTION_NAME_MEM_SEARCH = "Analyze undefined bytes";
|
||||
private final static String OPTION_NAME_DISASSEMBLE = "Disassemble matches in undefined bytes";
|
||||
|
||||
private static final String OPTION_DESCRIPTION_MEM_SEARCH =
|
||||
"Search for known library signatures in undefined bytes.";
|
||||
private static final String OPTION_DESCRIPTION_DISASSEMBLE =
|
||||
"Disassemble any library functions found while searching undefined bytes.";
|
||||
|
||||
private final static boolean OPTION_DEFAULT_MEM_SEARCH = true;
|
||||
private final static boolean OPTION_DEFAULT_DISASSEMBLE = true;
|
||||
|
||||
private boolean memSearchOption = OPTION_DEFAULT_MEM_SEARCH;
|
||||
private boolean disassembleOption = OPTION_DEFAULT_DISASSEMBLE;
|
||||
|
||||
public LibraryHashAnalyzer() {
|
||||
super(NAME, DESCRIPTION, AnalyzerType.BYTE_ANALYZER);
|
||||
setPrototype();
|
||||
setPriority(AnalysisPriority.DATA_TYPE_PROPOGATION.before());
|
||||
setSupportsOneTimeAnalysis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAnalyze(Program program) {
|
||||
// TODO: for now, this can't analyze anything!
|
||||
// WARNING: this will cause this analyzer not to show up for anything!
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) {
|
||||
this.identifyLibraryFunctions(set, program, monitor);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerOptions(Options options, Program program) {
|
||||
options.registerOption(OPTION_NAME_MEM_SEARCH, memSearchOption, null,
|
||||
OPTION_DESCRIPTION_MEM_SEARCH);
|
||||
options.registerOption(OPTION_NAME_DISASSEMBLE, disassembleOption, null,
|
||||
OPTION_DESCRIPTION_DISASSEMBLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.app.services.Analyzer#optionsChanged(ghidra.framework.options.Options, Program)
|
||||
*/
|
||||
@Override
|
||||
public void optionsChanged(Options options, Program program) {
|
||||
memSearchOption = options.getBoolean(OPTION_NAME_MEM_SEARCH, memSearchOption);
|
||||
disassembleOption = options.getBoolean(OPTION_NAME_DISASSEMBLE, disassembleOption);
|
||||
}
|
||||
|
||||
private void identifyLibraryFunctions(AddressSetView set, Program p, TaskMonitor monitor) {
|
||||
//Get the library from the xml database file.
|
||||
File libraryFile;
|
||||
try {
|
||||
libraryFile = Application.getModuleDataFile("lib/db.xml").getFile(true);
|
||||
}
|
||||
catch (FileNotFoundException e1) {
|
||||
Msg.error(this, "Cannot find db.xml file--not hashing functions", e1);
|
||||
return;
|
||||
}
|
||||
|
||||
LibHashDB db = new LibHashDB();
|
||||
//Handler is for the XML parser.
|
||||
ErrorHandler handler = new ErrorHandler() {
|
||||
@Override
|
||||
public void warning(SAXParseException exception) throws SAXException {
|
||||
throw exception;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(SAXParseException exception) throws SAXException {
|
||||
throw exception;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fatalError(SAXParseException exception) throws SAXException {
|
||||
throw exception;
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
InputStream hstream = new FileInputStream(libraryFile);
|
||||
//Create the parser.
|
||||
XmlPullParser parser = new NonThreadedXmlPullParserImpl(hstream,
|
||||
"Function Database parser", handler, false);
|
||||
hstream.close();
|
||||
//Create the database.
|
||||
db.restoreXml(parser);
|
||||
|
||||
HashMap<FuncRecord, FuncRecord> pinning = new HashMap<FuncRecord, FuncRecord>(); //Matching between query and library functions.
|
||||
LibHashDB qdb = new LibHashDB(p);
|
||||
FunctionIterator funcIter = p.getListing().getFunctions(true);
|
||||
|
||||
//If a signature is unique in the libraries and in the query, we may as well match them.
|
||||
while (funcIter.hasNext()) {
|
||||
Function func = funcIter.next();
|
||||
ArrayList<FuncRecord> libResponse = db.query(func);
|
||||
if (libResponse.size() != 1) { //Check uniqueness in libraries.
|
||||
continue;
|
||||
}
|
||||
FuncRecord libVal = libResponse.get(0);
|
||||
|
||||
ArrayList<FuncRecord> queResponse = qdb.query(libVal.hashValue);
|
||||
if (queResponse.size() != 1) { //Check uniqueness in query.
|
||||
continue;
|
||||
}
|
||||
FuncRecord queVal = queResponse.get(0);
|
||||
|
||||
pinning.put(queVal, libVal);
|
||||
}
|
||||
|
||||
PriorityQueue<FuncRecord> q = new PriorityQueue<FuncRecord>(pinning.keySet());
|
||||
HashSet<FuncRecord> seen = new HashSet<FuncRecord>();
|
||||
|
||||
while (q.size() > 0) {
|
||||
FuncRecord current = q.remove(); //A query record which is already matched.
|
||||
seen.add(current);
|
||||
Iterator<FuncRecord> qit = current.children.iterator();
|
||||
FuncRecord partner = pinning.get(current);
|
||||
Iterator<FuncRecord> lit = partner.children.iterator();
|
||||
while (qit.hasNext()) {
|
||||
FuncRecord qKid = qit.next(); //Child on the query side.
|
||||
if (!lit.hasNext()) {
|
||||
break;
|
||||
}
|
||||
FuncRecord lKid = lit.next(); //Child to match on the library side.
|
||||
//Should we add a second seen set for the lKids?
|
||||
if (qKid.hashValue != lKid.hashValue || seen.contains(qKid)) {
|
||||
continue;
|
||||
}
|
||||
//Match 'em and put 'em in the queue.
|
||||
//This little check is unnecessary, except that calls can be incorrectly disassembled.
|
||||
if (qKid.children.size() != lKid.children.size()) {
|
||||
continue;
|
||||
}
|
||||
pinning.put(qKid, lKid);
|
||||
this.addSymbol(p, qKid.func.getEntryPoint(), lKid.funcName, false);
|
||||
q.add(qKid);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
File outFile = new File(dataDir, "testy.txt");
|
||||
File outFile2 = new File(dataDir, "testy2.txt");
|
||||
FileWriter writer = new FileWriter(outFile);
|
||||
FileWriter writer2 = new FileWriter(outFile2);
|
||||
writer.write("Matched: " + pinning.size() + "\n");
|
||||
writer2.write("Unmatched:\n");
|
||||
for(FuncRecord key : qdb.getRecords()){
|
||||
if(pinning.containsKey(key)){
|
||||
writer.write(key.toString() + "\n");
|
||||
}
|
||||
else{
|
||||
writer2.write(key.toString() + "\n");
|
||||
}
|
||||
}
|
||||
writer.close();
|
||||
writer2.close();
|
||||
*/
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void analysisEnded(Program program) {
|
||||
// don't care
|
||||
}
|
||||
|
||||
private void addSymbol(Program program, Address addr, String name, boolean localscope) {
|
||||
|
||||
SymbolTable st = program.getSymbolTable();
|
||||
Symbol existSym = st.getPrimarySymbol(addr);
|
||||
|
||||
Command cmd = null;
|
||||
|
||||
if (existSym == null) { //Symbol didn't exist
|
||||
cmd = new AddLabelCmd(addr, name, localscope, SourceType.IMPORTED); //So we prepare to add it.
|
||||
}
|
||||
else if (!existSym.getName().equals(name)) { //There is a symbol there with the wrong name.
|
||||
if (existSym.getSource() == SourceType.DEFAULT || //It's got a non-smart name.
|
||||
(existSym.getSource() == SourceType.ANALYSIS &&
|
||||
existSym.getSymbolType().equals(SymbolType.FUNCTION))) {
|
||||
cmd = new RenameLabelCmd(addr, existSym.getName(), name, //Prepare to rename it.
|
||||
existSym.getParentNamespace(), SourceType.IMPORTED);
|
||||
}
|
||||
else {
|
||||
cmd = new AddLabelCmd(addr, name, localscope, SourceType.IMPORTED); //Our name is better?
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd != null && cmd.applyTo(program)) { //Apply the name, make sure it worked.
|
||||
Msg.debug(this, "Created symbol for library function " + name + " at address " + addr);
|
||||
|
||||
Namespace space = st.getNamespace(addr);
|
||||
if (!localscope) {
|
||||
space = null;
|
||||
}
|
||||
|
||||
cmd = new SetLabelPrimaryCmd(addr, name, space);
|
||||
cmd.applyTo(program);
|
||||
|
||||
cmd = new DemanglerCmd(addr, name);
|
||||
if (cmd.applyTo(program)) {
|
||||
Msg.debug(this, "Demangled library function " + name);
|
||||
}
|
||||
|
||||
//resolved.add(addr);
|
||||
}
|
||||
|
||||
/*
|
||||
program.getBookmarkManager().setBookmark(addr, "Analysis",
|
||||
LibraryIdentificationConstants.LIB_BOOKMARK_CATEGORY, "Library function");
|
||||
if (disassembleOption) {
|
||||
PseudoDisassembler pdis = new PseudoDisassembler(program);
|
||||
// make sure it is a disassembly
|
||||
if (pdis.isValidSubroutine(addr, false)) {
|
||||
disassembleSet.addRange(addr, addr);
|
||||
}
|
||||
}
|
||||
*/
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
|
|||
li { font-family:times new roman; font-size:14pt; }
|
||||
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
|
||||
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
|
||||
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
|
||||
|
||||
/*
|
||||
|
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
|
|||
td { font-family:times new roman; font-size:14pt; vertical-align: top; }
|
||||
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
|
||||
|
||||
code { color: black; font-family: courier new; font-size: 14pt; }
|
||||
/*
|
||||
Code-like formatting for things such as file system paths and proper names of classes,
|
||||
methods, etc. To apply this to a file path, use this syntax:
|
||||
<CODE CLASS="path">...</CODE>
|
||||
*/
|
||||
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
|
|
|
@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
|
|||
li { font-family:times new roman; font-size:14pt; }
|
||||
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
|
||||
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
|
||||
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
|
||||
|
||||
/*
|
||||
|
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
|
|||
td { font-family:times new roman; font-size:14pt; vertical-align: top; }
|
||||
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
|
||||
|
||||
code { color: black; font-family: courier new; font-size: 14pt; }
|
||||
/*
|
||||
Code-like formatting for things such as file system paths and proper names of classes,
|
||||
methods, etc. To apply this to a file path, use this syntax:
|
||||
<CODE CLASS="path">...</CODE>
|
||||
*/
|
||||
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
|
|
|
@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
|
|||
li { font-family:times new roman; font-size:14pt; }
|
||||
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
|
||||
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
|
||||
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
|
||||
|
||||
/*
|
||||
|
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
|
|||
td { font-family:times new roman; font-size:14pt; vertical-align: top; }
|
||||
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
|
||||
|
||||
code { color: black; font-family: courier new; font-size: 14pt; }
|
||||
/*
|
||||
Code-like formatting for things such as file system paths and proper names of classes,
|
||||
methods, etc. To apply this to a file path, use this syntax:
|
||||
<CODE CLASS="path">...</CODE>
|
||||
*/
|
||||
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
|
|
|
@ -110,7 +110,7 @@ public class DecompilerFunctionAnalyzer extends AbstractAnalyzer {
|
|||
@Override
|
||||
public void registerOptions(Options options, Program program) {
|
||||
HelpLocation helpLocation = new HelpLocation("AutoAnalysisPlugin",
|
||||
"Auto_Analysis_Option_Instruction" + getAnalysisType());
|
||||
"Decompiler_Parameter_ID_Analyzer");
|
||||
|
||||
options.registerOption(OPTION_NAME_CLEAR_LEVEL, SourceType.ANALYSIS, helpLocation,
|
||||
OPTION_DESCRIPTION_CLEAR_LEVEL);
|
||||
|
|
|
@ -24,12 +24,12 @@
|
|||
|
||||
*/
|
||||
|
||||
body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px;} /* some padding to improve readability */
|
||||
body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 10px; } /* some padding to improve readability */
|
||||
li { font-family:times new roman; font-size:14pt; }
|
||||
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
|
||||
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; }
|
||||
h4 { margin-left: 10px; font-family:times new roman; font-size:14pt; font-style:italic; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
|
||||
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
|
||||
|
||||
/*
|
||||
P tag code. Most of the help files nest P tags inside of blockquote tags (the was the
|
||||
|
@ -40,12 +40,25 @@ h4 { margin-left: 10px; font-family:times new roman; font-size:14pt; font-style:
|
|||
*/
|
||||
p { margin-left: 40px; font-family:times new roman; font-size:14pt; }
|
||||
blockquote p { margin-left: 10px; }
|
||||
|
||||
p.providedbyplugin { color:#7f7f7f; margin-left: 10px; font-size:14pt; margin-top:100px }
|
||||
p.ProvidedByPlugin { color:#7f7f7f; margin-left: 10px; font-size:14pt; margin-top:100px }
|
||||
p.relatedtopic { color:#800080; margin-left: 10px; font-size:14pt; }
|
||||
p.RelatedTopic { color:#800080; margin-left: 10px; font-size:14pt; }
|
||||
|
||||
|
||||
/*
|
||||
We wish for a tables to have space between it and the preceding element, so that text
|
||||
is not too close to the top of the table. Also, nest the table a bit so that it is clear
|
||||
the table relates to the preceding text.
|
||||
*/
|
||||
table { margin-left: 20px; margin-top: 10px; width: 80%;}
|
||||
td { font-family:times new roman; font-size:14pt; vertical-align: top; }
|
||||
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
|
||||
code { color: black; font-family: courier new; font-size: 14pt; }
|
||||
|
||||
/*
|
||||
Code-like formatting for things such as file system paths and proper names of classes,
|
||||
methods, etc. To apply this to a file path, use this syntax:
|
||||
<CODE CLASS="path">...</CODE>
|
||||
*/
|
||||
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
|
|
|
@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
|
|||
li { font-family:times new roman; font-size:14pt; }
|
||||
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
|
||||
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
|
||||
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
|
||||
|
||||
/*
|
||||
|
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
|
|||
td { font-family:times new roman; font-size:14pt; vertical-align: top; }
|
||||
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
|
||||
|
||||
code { color: black; font-family: courier new; font-size: 14pt; }
|
||||
/*
|
||||
Code-like formatting for things such as file system paths and proper names of classes,
|
||||
methods, etc. To apply this to a file path, use this syntax:
|
||||
<CODE CLASS="path">...</CODE>
|
||||
*/
|
||||
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
|
|
|
@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
|
|||
li { font-family:times new roman; font-size:14pt; }
|
||||
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
|
||||
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
|
||||
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
|
||||
|
||||
/*
|
||||
|
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
|
|||
td { font-family:times new roman; font-size:14pt; vertical-align: top; }
|
||||
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
|
||||
|
||||
code { color: black; font-family: courier new; font-size: 14pt; }
|
||||
/*
|
||||
Code-like formatting for things such as file system paths and proper names of classes,
|
||||
methods, etc. To apply this to a file path, use this syntax:
|
||||
<CODE CLASS="path">...</CODE>
|
||||
*/
|
||||
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
|
|
|
@ -19,17 +19,10 @@
|
|||
|
||||
//
|
||||
//@category Examples.Demangler
|
||||
import java.io.*;
|
||||
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.app.util.demangler.DemangledObject;
|
||||
import ghidra.app.util.demangler.DemanglerOptions;
|
||||
import ghidra.app.util.demangler.gnu.GnuDemanglerNativeProcess;
|
||||
import ghidra.app.util.demangler.gnu.GnuDemanglerParser;
|
||||
import ghidra.app.util.opinion.ElfLoader;
|
||||
import ghidra.app.util.opinion.MachoLoader;
|
||||
import ghidra.framework.*;
|
||||
import ghidra.program.model.lang.CompilerSpec;
|
||||
import ghidra.app.util.demangler.gnu.GnuDemangler;
|
||||
import ghidra.app.util.demangler.gnu.GnuDemanglerOptions;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
|
||||
public class DemangleElfWithOptionScript extends GhidraScript {
|
||||
|
@ -37,8 +30,9 @@ public class DemangleElfWithOptionScript extends GhidraScript {
|
|||
@Override
|
||||
protected void run() throws Exception {
|
||||
|
||||
GnuDemangler demangler = new GnuDemangler();
|
||||
if (!demangler.canDemangle(currentProgram)) {
|
||||
String executableFormat = currentProgram.getExecutableFormat();
|
||||
if (!canDemangle(executableFormat)) {
|
||||
println("Cannot use the elf demangling options for executable format: " +
|
||||
executableFormat);
|
||||
return;
|
||||
|
@ -55,81 +49,22 @@ public class DemangleElfWithOptionScript extends GhidraScript {
|
|||
|
||||
String mangled = symbol.getName();
|
||||
|
||||
Process process = createProcess(executableFormat);
|
||||
GnuDemanglerOptions options = new GnuDemanglerOptions();
|
||||
options.setDoDisassembly(false);
|
||||
options.setDemanglerApplicationArguments("-s auto");
|
||||
|
||||
InputStream in = process.getInputStream();
|
||||
OutputStream out = process.getOutputStream();
|
||||
/*
|
||||
// for older formats use the deprecated demangler
|
||||
options.setDemanglerName(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
|
||||
options.setDemanglerApplicationArguments("-s arm");
|
||||
*/
|
||||
|
||||
BufferedReader input = new BufferedReader(new InputStreamReader(in));
|
||||
PrintWriter output = new PrintWriter(out);
|
||||
|
||||
output.println(mangled);
|
||||
output.flush();
|
||||
String demangled = input.readLine();
|
||||
println("demangled: " + demangled);
|
||||
|
||||
GnuDemanglerParser parser = new GnuDemanglerParser(null);
|
||||
DemangledObject demangledObject = parser.parse(mangled, demangled);
|
||||
DemangledObject demangledObject = demangler.demangle(mangled, options);
|
||||
if (demangledObject == null) {
|
||||
println("Could not demangle: " + mangled);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO change to GnuDemanglerOptions
|
||||
DemanglerOptions options = new DemanglerOptions();
|
||||
options.setDoDisassembly(false);
|
||||
options.setApplySignature(true);
|
||||
options.setDemangleOnlyKnownPatterns(true);
|
||||
|
||||
if (!demangledObject.applyTo(currentProgram, currentAddress, options, monitor)) {
|
||||
println("Failed to apply demangled data for " + mangled);
|
||||
}
|
||||
println("Succesfully demangled " + mangled + " to " + demangled);
|
||||
}
|
||||
|
||||
private boolean canDemangle(String executableFormat) {
|
||||
|
||||
//check if language is GCC - this is not altogether correct !
|
||||
// Objective-C and other non-GCC based symbols may be handled improperly
|
||||
|
||||
if (isELF(executableFormat) || isMacho(executableFormat)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
CompilerSpec compilerSpec = currentProgram.getCompilerSpec();
|
||||
if (compilerSpec.getCompilerSpecID()
|
||||
.getIdAsString()
|
||||
.toLowerCase()
|
||||
.indexOf("windows") == -1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isELF(String executableFormat) {
|
||||
return executableFormat != null && executableFormat.indexOf(ElfLoader.ELF_NAME) != -1;
|
||||
}
|
||||
|
||||
private boolean isMacho(String executableFormat) {
|
||||
return executableFormat != null && executableFormat.indexOf(MachoLoader.MACH_O_NAME) != -1;
|
||||
}
|
||||
|
||||
/// TODO this is here because we did not support program arguments. replace this code
|
||||
private Process createProcess(String executableName) throws Exception {
|
||||
|
||||
String demanglerName = GnuDemanglerNativeProcess.DEMANGLER_GNU;
|
||||
OperatingSystem OS = Platform.CURRENT_PLATFORM.getOperatingSystem();
|
||||
String demanglerExe =
|
||||
(OS == OperatingSystem.WINDOWS) ? demanglerName + ".exe" : demanglerName;
|
||||
File commandPath = Application.getOSFile("GnuDemangler", demanglerExe);
|
||||
|
||||
//
|
||||
// This is where special options are to be passed. Put your own here as necessary.
|
||||
//
|
||||
String[] command = new String[] { commandPath.getAbsolutePath(), "-s", "arm" };
|
||||
|
||||
Process process = Runtime.getRuntime().exec(command);
|
||||
|
||||
return process;
|
||||
println("Succesfully demangled " + mangled + " to " + demangledObject);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,8 +95,9 @@ public class VxWorksSymTab_5_4 extends GhidraScript {
|
|||
Address vxSymTbl = vxNumSymEntriesAddr.subtract(vxNumSymEntries * SYM_ENTRY_SIZE);
|
||||
for (int i = 0; i < vxNumSymEntries; i++) {
|
||||
|
||||
if (monitor.isCancelled())
|
||||
if (monitor.isCancelled()) {
|
||||
return; // check for cancel button
|
||||
}
|
||||
println("i=" + i); // visual counter
|
||||
|
||||
// Extract symbol table entry values
|
||||
|
@ -112,15 +113,19 @@ public class VxWorksSymTab_5_4 extends GhidraScript {
|
|||
Address a;
|
||||
String symName;
|
||||
for (a = symNameAddr; mem.getByte(a) != 0; a = a.add(1)) {
|
||||
if (getDataAt(a) != null)
|
||||
if (getDataAt(a) != null) {
|
||||
removeDataAt(a);
|
||||
if (getInstructionAt(a) != null)
|
||||
}
|
||||
if (getInstructionAt(a) != null) {
|
||||
removeInstructionAt(a);
|
||||
}
|
||||
if (getDataAt(a) != null)
|
||||
}
|
||||
if (getDataAt(a) != null) {
|
||||
removeDataAt(a);
|
||||
if (getInstructionAt(a) != null)
|
||||
}
|
||||
if (getInstructionAt(a) != null) {
|
||||
removeInstructionAt(a);
|
||||
}
|
||||
|
||||
// Turn *symNameAddr into a string and store it in symName
|
||||
try {
|
||||
|
@ -137,7 +142,7 @@ public class VxWorksSymTab_5_4 extends GhidraScript {
|
|||
String symDemangledName = null;
|
||||
try {
|
||||
// if successful, symDemangledName will be non-NULL
|
||||
symDemangledName = demangler.demangle(symName, true).getSignature(false);
|
||||
symDemangledName = demangler.demangle(symName).getSignature(false);
|
||||
}
|
||||
catch (DemangledException e) {
|
||||
// if symName wasn't a mangled name, silently continue
|
||||
|
|
|
@ -138,7 +138,7 @@ public class VxWorksSymTab_6_1 extends GhidraScript {
|
|||
String symDemangledName = null;
|
||||
try {
|
||||
// if successful, symDemangledName will be non-NULL
|
||||
symDemangledName = demangler.demangle(symName, true).getSignature(false);
|
||||
symDemangledName = demangler.demangle(symName).getSignature(false);
|
||||
}
|
||||
catch (DemangledException e) {
|
||||
// if symName wasn't a mangled name, silently continue
|
||||
|
|
|
@ -50,13 +50,7 @@ import ghidra.app.util.demangler.DemangledException;
|
|||
import ghidra.app.util.demangler.gnu.GnuDemangler;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSet;
|
||||
import ghidra.program.model.data.ArrayDataType;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.DataTypeComponent;
|
||||
import ghidra.program.model.data.DataTypeConflictHandler;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.PointerDataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.Data;
|
||||
import ghidra.program.model.listing.Instruction;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
|
@ -143,7 +137,8 @@ public class VxWorksSymTab_Finder extends GhidraScript {
|
|||
// Add SYMBOL data type to Program DataTypeManager
|
||||
// (if data type already exists, replace it)
|
||||
public void createGhidraType() {
|
||||
currentProgram.getDataTypeManager().addDataType(dt,
|
||||
currentProgram.getDataTypeManager()
|
||||
.addDataType(dt,
|
||||
DataTypeConflictHandler.REPLACE_HANDLER);
|
||||
}
|
||||
}
|
||||
|
@ -351,8 +346,7 @@ public class VxWorksSymTab_Finder extends GhidraScript {
|
|||
}
|
||||
}
|
||||
|
||||
if (_byte == 0x00)
|
||||
{
|
||||
if (_byte == 0x00) {
|
||||
return true; // Scan stopped at null.
|
||||
}
|
||||
return false; // Scan stopped at invalid char.
|
||||
|
@ -657,7 +651,8 @@ public class VxWorksSymTab_Finder extends GhidraScript {
|
|||
|
||||
if (demangled != null) {
|
||||
new DemanglerCmd(addr, mangled).applyTo(currentProgram, monitor);
|
||||
currentProgram.getSymbolTable().removeSymbolSpecial(
|
||||
currentProgram.getSymbolTable()
|
||||
.removeSymbolSpecial(
|
||||
getSymbol(mangled, currentProgram.getGlobalNamespace()));
|
||||
}
|
||||
|
||||
|
@ -772,7 +767,7 @@ public class VxWorksSymTab_Finder extends GhidraScript {
|
|||
// Demangle symName
|
||||
String symDemangledName = null;
|
||||
try {
|
||||
symDemangledName = demangler.demangle(symName, true).getSignature(false);
|
||||
symDemangledName = demangler.demangle(symName).getSignature(false);
|
||||
}
|
||||
catch (DemangledException e) { // report demangling error
|
||||
if (!e.isInvalidMangledName()) {
|
||||
|
|
|
@ -22,11 +22,13 @@ import org.apache.commons.lang3.StringUtils;
|
|||
import ghidra.app.util.demangler.*;
|
||||
import ghidra.app.util.demangler.gnu.*;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.framework.options.*;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
/**
|
||||
* A version of the demangler analyzer to handle GNU GCC symbols
|
||||
*/
|
||||
public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
||||
|
||||
private static final String NAME = "Demangler GNU";
|
||||
|
@ -35,7 +37,7 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
|||
"the name and apply datatypes to parameters.";
|
||||
|
||||
private static final String OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS =
|
||||
"Only Demangle Known Mangled Symbols";
|
||||
"Demangle Only Known Mangled Symbols";
|
||||
private static final String OPTION_DESCRIPTION_USE_KNOWN_PATTERNS =
|
||||
"Only demangle symbols that follow known compiler mangling patterns. " +
|
||||
"Leaving this option off may cause non-mangled symbols to get demangled.";
|
||||
|
@ -44,14 +46,20 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
|||
private static final String OPTION_DESCRIPTION_APPLY_SIGNATURE =
|
||||
"Apply any recovered function signature, in addition to the function name";
|
||||
|
||||
// note: we use 'Z' as a trick to be below the other options
|
||||
private static final String OPTION_NAME_GNU_DEMANGLER = "Z GNU Demangler";
|
||||
static final String OPTION_NAME_USE_DEPRECATED_DEMANGLER = "Use Deprecated Demangler";
|
||||
private static final String OPTION_DESCRIPTION_DEPRECATED_DEMANGLER =
|
||||
"Signals to use the deprecated demangler when the modern demangler cannot demangle a " +
|
||||
"given string";
|
||||
|
||||
private static final String OPTION_NAME_DEMANGLER_PARAMETERS =
|
||||
"Use External Demangler Options";
|
||||
private static final String OPTION_DESCRIPTION_DEMANGLER_PARAMETERS =
|
||||
"Signals to use pass the given parameters to the demangler program";
|
||||
|
||||
private boolean doSignatureEnabled = true;
|
||||
private boolean demangleOnlyKnownPatterns = false;
|
||||
private GnuDemanglerOptionsPropertyEditor gnuOptionsEditor =
|
||||
new GnuDemanglerOptionsPropertyEditor();
|
||||
private GnuDemanglerWrappedOption gnuWrappedOptions;
|
||||
private boolean useDeprecatedDemangler = false;
|
||||
private String demanglerParameters = "";
|
||||
|
||||
private GnuDemangler demangler = new GnuDemangler();
|
||||
|
||||
|
@ -67,28 +75,20 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
|||
|
||||
@Override
|
||||
public void registerOptions(Options options, Program program) {
|
||||
options.registerOption(OPTION_NAME_APPLY_SIGNATURE, doSignatureEnabled, null,
|
||||
OPTION_DESCRIPTION_APPLY_SIGNATURE);
|
||||
|
||||
options.registerOption(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, false, null,
|
||||
OPTION_DESCRIPTION_USE_KNOWN_PATTERNS);
|
||||
|
||||
options.registerOptionsEditor(null);
|
||||
|
||||
HelpLocation help = new HelpLocation("AutoAnalysisPlugin", "Demangler_Analyzer");
|
||||
options.registerOption(OPTION_NAME_GNU_DEMANGLER, OptionType.CUSTOM_TYPE,
|
||||
new GnuDemanglerWrappedOption(), help, "Advanced GNU demangler options",
|
||||
gnuOptionsEditor);
|
||||
options.registerOption(OPTION_NAME_APPLY_SIGNATURE, doSignatureEnabled, help,
|
||||
OPTION_DESCRIPTION_APPLY_SIGNATURE);
|
||||
|
||||
CustomOption customOption = options.getCustomOption(OPTION_NAME_GNU_DEMANGLER,
|
||||
new GnuDemanglerWrappedOption());
|
||||
if (!(customOption instanceof GnuDemanglerWrappedOption)) {
|
||||
customOption = new GnuDemanglerWrappedOption();
|
||||
Msg.debug(this, "Unexpected custom option type for GNU Demangler: " +
|
||||
customOption.getClass());
|
||||
}
|
||||
gnuWrappedOptions = (GnuDemanglerWrappedOption) customOption;
|
||||
options.registerOption(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, demangleOnlyKnownPatterns,
|
||||
help,
|
||||
OPTION_DESCRIPTION_USE_KNOWN_PATTERNS);
|
||||
|
||||
options.registerOption(OPTION_NAME_USE_DEPRECATED_DEMANGLER, useDeprecatedDemangler, help,
|
||||
OPTION_DESCRIPTION_DEPRECATED_DEMANGLER);
|
||||
|
||||
options.registerOption(OPTION_NAME_DEMANGLER_PARAMETERS, demanglerParameters, help,
|
||||
OPTION_DESCRIPTION_DEMANGLER_PARAMETERS);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -97,9 +97,11 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
|||
demangleOnlyKnownPatterns =
|
||||
options.getBoolean(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, demangleOnlyKnownPatterns);
|
||||
|
||||
gnuWrappedOptions =
|
||||
(GnuDemanglerWrappedOption) options.getCustomOption(OPTION_NAME_GNU_DEMANGLER,
|
||||
new GnuDemanglerWrappedOption());
|
||||
useDeprecatedDemangler =
|
||||
options.getBoolean(OPTION_NAME_USE_DEPRECATED_DEMANGLER, useDeprecatedDemangler);
|
||||
|
||||
demanglerParameters =
|
||||
options.getString(OPTION_NAME_DEMANGLER_PARAMETERS, demanglerParameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -109,15 +111,7 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
|||
options.setDoDisassembly(true);
|
||||
options.setApplySignature(doSignatureEnabled);
|
||||
options.setDemangleOnlyKnownPatterns(demangleOnlyKnownPatterns);
|
||||
|
||||
options.setUseDeprecatedDemangler(gnuWrappedOptions.useDeprecatedDemangler());
|
||||
|
||||
String text = null;
|
||||
if (gnuWrappedOptions.useDemanglerParameters()) {
|
||||
text = gnuWrappedOptions.getDemanglerParametersText();
|
||||
}
|
||||
options.setDemanglerApplicationArguments(text);
|
||||
|
||||
options.setDemanglerApplicationArguments(demanglerParameters);
|
||||
return options;
|
||||
}
|
||||
|
||||
|
@ -144,7 +138,7 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
|||
log.appendException(e);
|
||||
}
|
||||
|
||||
if (options.useDeprecatedDemangler()) {
|
||||
if (useDeprecatedDemangler) {
|
||||
// see if the options work in the deprecated demangler
|
||||
GnuDemanglerOptions deprecatedOptions = options.withDeprecatedDemangler();
|
||||
String deprecatedName = deprecatedOptions.getDemanglerName();
|
||||
|
@ -176,7 +170,7 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
|||
demangled = demangler.demangle(mangled, options);
|
||||
}
|
||||
catch (DemangledException e) {
|
||||
if (!options.useDeprecatedDemangler()) {
|
||||
if (!useDeprecatedDemangler) {
|
||||
throw e; // let our parent handle this
|
||||
}
|
||||
}
|
||||
|
@ -185,7 +179,7 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
|||
return demangled;
|
||||
}
|
||||
|
||||
if (options.useDeprecatedDemangler()) {
|
||||
if (useDeprecatedDemangler) {
|
||||
GnuDemanglerOptions newOptions = options.withDeprecatedDemangler();
|
||||
demangled = demangler.demangle(mangled, newOptions);
|
||||
}
|
||||
|
|
|
@ -1,179 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.core.analysis;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.beans.PropertyEditorSupport;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
|
||||
import docking.widgets.checkbox.GCheckBox;
|
||||
import ghidra.framework.options.CustomOptionsEditor;
|
||||
import ghidra.util.layout.HorizontalLayout;
|
||||
import ghidra.util.layout.VerticalLayout;
|
||||
|
||||
public class GnuDemanglerOptionsPropertyEditor extends PropertyEditorSupport
|
||||
implements CustomOptionsEditor {
|
||||
|
||||
private static final String USE_DEPRECATED_DEMANGLER = "Use Deprecated Demangler";
|
||||
private static final String USE_DEMANGLER_PARAMETERS = "Use Demangler Program Parameters";
|
||||
|
||||
private static final String USE_DEPRECATED_DEMANGLER_TOOLTIP =
|
||||
"Signals to use the deprecated demangler when the modern demangler cannot demangle a " +
|
||||
"given string";
|
||||
private static final String USE_DEMANGLER_PARAMETERS_TOOLTIP =
|
||||
"Signals to use pass the given parameters to the demangler program";
|
||||
|
||||
private static final String[] NAMES =
|
||||
{ USE_DEPRECATED_DEMANGLER, USE_DEMANGLER_PARAMETERS };
|
||||
|
||||
private static final String[] DESCRIPTIONS = { USE_DEPRECATED_DEMANGLER_TOOLTIP,
|
||||
USE_DEMANGLER_PARAMETERS_TOOLTIP };
|
||||
|
||||
private GnuDemanglerWrappedOption wrappedOption;
|
||||
|
||||
private Component editorComponent;
|
||||
|
||||
private GCheckBox useDeprecatedDemanglerBox;
|
||||
private GCheckBox useDemanglerParametersBox;
|
||||
private JTextField demanglerParametersTextField;
|
||||
|
||||
public GnuDemanglerOptionsPropertyEditor() {
|
||||
editorComponent = buildEditor();
|
||||
}
|
||||
|
||||
private Component buildEditor() {
|
||||
|
||||
// we want to have a panel with our options so that we may group them together
|
||||
JPanel panel = new JPanel(new VerticalLayout(3));
|
||||
|
||||
useDeprecatedDemanglerBox = new GCheckBox(USE_DEPRECATED_DEMANGLER);
|
||||
useDeprecatedDemanglerBox.setSelected(false);
|
||||
useDeprecatedDemanglerBox.setToolTipText(USE_DEPRECATED_DEMANGLER_TOOLTIP);
|
||||
useDeprecatedDemanglerBox.addItemListener(e -> firePropertyChange());
|
||||
panel.add(useDeprecatedDemanglerBox);
|
||||
|
||||
createParameterComponent(panel);
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
private void createParameterComponent(Container parent) {
|
||||
|
||||
JPanel textFieldPanel = new JPanel(new HorizontalLayout(0));
|
||||
JTextField textField = new JTextField(15);
|
||||
useDemanglerParametersBox = new GCheckBox(USE_DEMANGLER_PARAMETERS);
|
||||
useDemanglerParametersBox.setToolTipText(USE_DEMANGLER_PARAMETERS_TOOLTIP);
|
||||
useDemanglerParametersBox.addItemListener(e -> {
|
||||
textField.setEnabled(useDemanglerParametersBox.isSelected());
|
||||
firePropertyChange();
|
||||
});
|
||||
|
||||
textField.getDocument().addDocumentListener(new DocumentListener() {
|
||||
@Override
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
firePropertyChange();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
firePropertyChange();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeUpdate(DocumentEvent e) {
|
||||
firePropertyChange();
|
||||
}
|
||||
});
|
||||
|
||||
textField.setEnabled(false);
|
||||
|
||||
textFieldPanel.add(useDemanglerParametersBox);
|
||||
textFieldPanel.add(Box.createHorizontalStrut(10));
|
||||
textFieldPanel.add(textField);
|
||||
|
||||
parent.add(textFieldPanel);
|
||||
|
||||
demanglerParametersTextField = textField;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Object value) {
|
||||
|
||||
if (!(value instanceof GnuDemanglerWrappedOption)) {
|
||||
return;
|
||||
}
|
||||
|
||||
wrappedOption = (GnuDemanglerWrappedOption) value;
|
||||
setLocalValues(wrappedOption);
|
||||
firePropertyChange();
|
||||
}
|
||||
|
||||
private void setLocalValues(GnuDemanglerWrappedOption newOption) {
|
||||
|
||||
if (newOption.useDeprecatedDemangler() != useDeprecatedDemanglerBox.isSelected()) {
|
||||
useDeprecatedDemanglerBox.setSelected(newOption.useDeprecatedDemangler());
|
||||
}
|
||||
|
||||
if (newOption.useDemanglerParameters() != useDemanglerParametersBox.isSelected()) {
|
||||
useDemanglerParametersBox.setSelected(newOption.useDemanglerParameters());
|
||||
}
|
||||
|
||||
String newText = newOption.getDemanglerParametersText();
|
||||
String currentText = demanglerParametersTextField.getText();
|
||||
if (!Objects.equals(newText, currentText)) {
|
||||
demanglerParametersTextField.setText(newText);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return cloneNamespaceValues();
|
||||
}
|
||||
|
||||
private GnuDemanglerWrappedOption cloneNamespaceValues() {
|
||||
|
||||
GnuDemanglerWrappedOption newOption = new GnuDemanglerWrappedOption();
|
||||
newOption.setUseDeprecatedDemangler(useDeprecatedDemanglerBox.isSelected());
|
||||
newOption.setUseDemanglerParameters(useDemanglerParametersBox.isSelected());
|
||||
newOption.setDemanglerParametersText(demanglerParametersTextField.getText());
|
||||
return newOption;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getOptionNames() {
|
||||
return NAMES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getOptionDescriptions() {
|
||||
return DESCRIPTIONS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getCustomEditor() {
|
||||
return editorComponent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsCustomEditor() {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,125 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.core.analysis;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import ghidra.framework.options.CustomOption;
|
||||
import ghidra.framework.options.SaveState;
|
||||
|
||||
/**
|
||||
* A simple java bean adapted to the {@link CustomOption} interface. The public
|
||||
* getters and setters are self-documenting.
|
||||
*/
|
||||
public class GnuDemanglerWrappedOption implements CustomOption {
|
||||
|
||||
private static final String USE_DEPRECATED_DEMANGLER = "USE_DEPRECATED_DEMANGLER";
|
||||
private static final String USE_DEMANGLER_PARAMETERS = "USE_DEMANGLER_PARAMETERS";
|
||||
private static final String DEMANGLER_PARAMETERS = "DEMANGLER_PARAMETERS";
|
||||
|
||||
private boolean useDeprecatedDemangler = false;
|
||||
private boolean useDemanglerParameters = false;
|
||||
private String demanglerParametersText = null;
|
||||
|
||||
public void setUseDeprecatedDemangler(boolean doUse) {
|
||||
this.useDeprecatedDemangler = doUse;
|
||||
}
|
||||
|
||||
public boolean useDeprecatedDemangler() {
|
||||
return useDeprecatedDemangler;
|
||||
}
|
||||
|
||||
public void setDemanglerParametersText(String text) {
|
||||
this.demanglerParametersText = text;
|
||||
}
|
||||
|
||||
public String getDemanglerParametersText() {
|
||||
return demanglerParametersText;
|
||||
}
|
||||
|
||||
public void setUseDemanglerParameters(boolean doUse) {
|
||||
this.useDemanglerParameters = doUse;
|
||||
}
|
||||
|
||||
public boolean useDemanglerParameters() {
|
||||
return useDemanglerParameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readState(SaveState state) {
|
||||
useDeprecatedDemangler =
|
||||
state.getBoolean(USE_DEPRECATED_DEMANGLER, useDemanglerParameters);
|
||||
useDemanglerParameters =
|
||||
state.getBoolean(USE_DEPRECATED_DEMANGLER, useDemanglerParameters);
|
||||
demanglerParametersText =
|
||||
state.getString(DEMANGLER_PARAMETERS, demanglerParametersText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeState(SaveState state) {
|
||||
state.putBoolean(USE_DEPRECATED_DEMANGLER, useDeprecatedDemangler);
|
||||
state.putBoolean(USE_DEMANGLER_PARAMETERS, useDemanglerParameters);
|
||||
state.putString(USE_DEMANGLER_PARAMETERS, demanglerParametersText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result +
|
||||
((demanglerParametersText == null) ? 0 : demanglerParametersText.hashCode());
|
||||
result = prime * result + (useDemanglerParameters ? 1231 : 1237);
|
||||
result = prime * result + (useDeprecatedDemangler ? 1231 : 1237);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GnuDemanglerWrappedOption other = (GnuDemanglerWrappedOption) obj;
|
||||
if (!Objects.equals(demanglerParametersText, other.demanglerParametersText)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (useDemanglerParameters != other.useDemanglerParameters) {
|
||||
return false;
|
||||
}
|
||||
if (useDeprecatedDemangler != other.useDeprecatedDemangler) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
//@formatter:off
|
||||
return "{\n" +
|
||||
"\tuseDeprecatedDemangler: " + useDeprecatedDemangler + ",\n" +
|
||||
"\tuseDemanglerParameters: " + useDemanglerParameters + ",\n" +
|
||||
"\tdemanglerParametersText: " + demanglerParametersText + ",\n" +
|
||||
"}";
|
||||
//@formatter:on
|
||||
}
|
||||
}
|
|
@ -60,6 +60,7 @@ public class GnuDemangler implements Demangler {
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated(since = "9.2", forRemoval = true)
|
||||
public DemangledObject demangle(String mangled, boolean demangleOnlyKnownPatterns)
|
||||
throws DemangledException {
|
||||
GnuDemanglerOptions options = new GnuDemanglerOptions();
|
||||
|
|
|
@ -27,6 +27,11 @@ import org.apache.commons.lang3.StringUtils;
|
|||
import ghidra.framework.Application;
|
||||
import ghidra.framework.Platform;
|
||||
|
||||
/**
|
||||
* A class that allows for the reuse of native demangler executable processes. This class will
|
||||
* cache the process by name and by any arguments passed to the process when started. Once
|
||||
* successfully started, the process will persist
|
||||
*/
|
||||
public class GnuDemanglerNativeProcess {
|
||||
public static final String DEMANGLER_GNU = GnuDemanglerOptions.GNU_DEMANGLER_DEFAULT;
|
||||
|
||||
|
@ -42,21 +47,35 @@ public class GnuDemanglerNativeProcess {
|
|||
private BufferedReader reader;
|
||||
private PrintWriter writer;
|
||||
|
||||
// TODO docme
|
||||
/**
|
||||
* Gets the default GNU demangler native process
|
||||
* @return the process
|
||||
* @throws IOException if the process cannot be started
|
||||
*/
|
||||
public static synchronized GnuDemanglerNativeProcess getDemanglerNativeProcess()
|
||||
throws IOException {
|
||||
return getDemanglerNativeProcess(DEMANGLER_GNU);
|
||||
}
|
||||
|
||||
// TODO docme
|
||||
/**
|
||||
* Gets the default GNU demangler native process
|
||||
* @param name the specific executable name to launch
|
||||
* @return the process
|
||||
* @throws IOException if the process cannot be started
|
||||
*/
|
||||
public static synchronized GnuDemanglerNativeProcess getDemanglerNativeProcess(String name)
|
||||
throws IOException {
|
||||
|
||||
return getDemanglerNativeProcess(name, DEFAULT_NATIVE_OPTIONS);
|
||||
}
|
||||
|
||||
// TODO docme
|
||||
// TODO we should probably age-off all demanglers by access time
|
||||
/**
|
||||
* Gets the default GNU demangler native process
|
||||
* @param name the specific executable name to launch
|
||||
* @param nativeOptions the arguments string to pass to the native demangler
|
||||
* @return the process
|
||||
* @throws IOException if the process cannot be started
|
||||
*/
|
||||
public static synchronized GnuDemanglerNativeProcess getDemanglerNativeProcess(String name,
|
||||
String nativeOptions)
|
||||
throws IOException {
|
||||
|
@ -66,15 +85,18 @@ public class GnuDemanglerNativeProcess {
|
|||
options = DEFAULT_NATIVE_OPTIONS;
|
||||
}
|
||||
|
||||
String key = name + nativeOptions;
|
||||
String key = getKey(name, options);
|
||||
GnuDemanglerNativeProcess nativeProcess = processesByName.get(key);
|
||||
if (nativeProcess == null) {
|
||||
nativeProcess = new GnuDemanglerNativeProcess(name, options);
|
||||
processesByName.put(key, nativeProcess);
|
||||
}
|
||||
return nativeProcess;
|
||||
}
|
||||
|
||||
private static String getKey(String name, String options) {
|
||||
return name + ' ' + options;
|
||||
}
|
||||
|
||||
private GnuDemanglerNativeProcess(String applicationName, String options) throws IOException {
|
||||
this.applicationName = applicationName;
|
||||
this.options = options;
|
||||
|
@ -95,7 +117,6 @@ public class GnuDemanglerNativeProcess {
|
|||
catch (IOException e) {
|
||||
dispose();
|
||||
if (!restart) {
|
||||
processesByName.remove(applicationName);
|
||||
throw new IOException("Demangler process is not running.", e);
|
||||
}
|
||||
createProcess();
|
||||
|
@ -109,7 +130,11 @@ public class GnuDemanglerNativeProcess {
|
|||
return reader.readLine();
|
||||
}
|
||||
|
||||
private void dispose() {
|
||||
public void dispose() {
|
||||
|
||||
String key = getKey(applicationName, options);
|
||||
processesByName.remove(key);
|
||||
|
||||
try {
|
||||
if (process != null) {
|
||||
process.destroy();
|
||||
|
@ -139,6 +164,8 @@ public class GnuDemanglerNativeProcess {
|
|||
checkForError(command);
|
||||
|
||||
isDisposed = false;
|
||||
String key = getKey(applicationName, options);
|
||||
processesByName.put(key, this);
|
||||
}
|
||||
|
||||
private String[] buildCommand() throws FileNotFoundException {
|
||||
|
|
|
@ -15,12 +15,19 @@
|
|||
*/
|
||||
package ghidra.app.util.demangler.gnu;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ghidra.app.util.demangler.DemanglerOptions;
|
||||
|
||||
/**
|
||||
* GNU demangler options
|
||||
*/
|
||||
public class GnuDemanglerOptions extends DemanglerOptions {
|
||||
|
||||
/*
|
||||
Note!
|
||||
If you update the demangler versions, then you also must update the help (search the
|
||||
html files for the old version strings).
|
||||
*/
|
||||
|
||||
/**
|
||||
* Version 2.24 of the GNU demangler. This version supports older formats and older bugs.
|
||||
*/
|
||||
|
@ -38,7 +45,6 @@ public class GnuDemanglerOptions extends DemanglerOptions {
|
|||
|
||||
private String demanglerName = GNU_DEMANGLER_DEFAULT;
|
||||
private String demanglerApplicationArguments;
|
||||
private boolean useDeprecatedDemangler;
|
||||
|
||||
public GnuDemanglerOptions() {
|
||||
// use default values
|
||||
|
@ -51,48 +57,47 @@ public class GnuDemanglerOptions extends DemanglerOptions {
|
|||
GnuDemanglerOptions gCopy = (GnuDemanglerOptions) copy;
|
||||
demanglerName = gCopy.demanglerName;
|
||||
demanglerApplicationArguments = gCopy.demanglerApplicationArguments;
|
||||
useDeprecatedDemangler = gCopy.useDeprecatedDemangler;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO docme
|
||||
/**
|
||||
* Returns the external demangler executable name to be used for demangling. The
|
||||
* default value is {@link #GNU_DEMANGLER_DEFAULT}.
|
||||
* @return the name
|
||||
*/
|
||||
public String getDemanglerName() {
|
||||
return demanglerName;
|
||||
}
|
||||
|
||||
// TODO docme
|
||||
// TODO should we validate and or log a message it the name is unknown?
|
||||
/**
|
||||
* Sets the external demangler executable name to be used for demangling
|
||||
* @param name the name
|
||||
*/
|
||||
public void setDemanglerName(String name) {
|
||||
this.demanglerName = name;
|
||||
}
|
||||
|
||||
// TODO docme
|
||||
/**
|
||||
* Returns the current arguments to be passed to the external demangler executable
|
||||
* @return the arguments
|
||||
*/
|
||||
public String getDemanglerApplicationArguments() {
|
||||
return demanglerApplicationArguments;
|
||||
}
|
||||
|
||||
// TODO docme
|
||||
/**
|
||||
* Sets the arguments to be passed to the external demangler executable
|
||||
* @param args the arguments
|
||||
*/
|
||||
public void setDemanglerApplicationArguments(String args) {
|
||||
this.demanglerApplicationArguments = args;
|
||||
}
|
||||
|
||||
// TODO docme
|
||||
// TODO mabye rename to hasNativeApplicationOptions()
|
||||
public boolean hasDemanglerApplicationArguments() {
|
||||
return !StringUtils.isBlank(demanglerApplicationArguments);
|
||||
}
|
||||
|
||||
// TODO docme
|
||||
public void setUseDeprecatedDemangler(boolean doUse) {
|
||||
this.useDeprecatedDemangler = doUse;
|
||||
}
|
||||
|
||||
// TODO docme
|
||||
public boolean useDeprecatedDemangler() {
|
||||
return useDeprecatedDemangler;
|
||||
}
|
||||
|
||||
// TODO docme
|
||||
/**
|
||||
* A convenience method to copy the state of this options object, changing the
|
||||
* demangler executable name to the deprecated demangler
|
||||
* @return the new options
|
||||
*/
|
||||
public GnuDemanglerOptions withDeprecatedDemangler() {
|
||||
GnuDemanglerOptions newOptions = new GnuDemanglerOptions(this);
|
||||
newOptions.setDemanglerName(GNU_DEMANGLER_V2_24);
|
||||
|
@ -107,7 +112,6 @@ public class GnuDemanglerOptions extends DemanglerOptions {
|
|||
"\tapplySignature: " + applySignature() + ",\n" +
|
||||
"\tdemangleOnlyKnownPatterns: " + demangleOnlyKnownPatterns() + ",\n" +
|
||||
"\tdemanglerName: " + demanglerName + ",\n" +
|
||||
"\tuseDeprecatedDemangler: " + useDeprecatedDemangler + ",\n" +
|
||||
"\tdemanglerApplicationArguments: " + demanglerApplicationArguments + ",\n" +
|
||||
"}";
|
||||
//@formatter:on
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.core.analysis;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ghidra.app.cmd.label.AddLabelCmd;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.program.database.ProgramBuilder;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
|
||||
import ghidra.test.ToyProgramBuilder;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.RollbackException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class GnuDemanglerAnalyzerTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||
|
||||
private GnuDemanglerAnalyzer analyzer = new GnuDemanglerAnalyzer();
|
||||
private ProgramDB program;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
ProgramBuilder builder = new ToyProgramBuilder("test", true);
|
||||
builder.createMemory(".text", "0x0100", 0x100);
|
||||
program = builder.getProgram();
|
||||
registerOptions();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeprectedDemangledString() throws Exception {
|
||||
|
||||
//
|
||||
// The below demangles to MsoDAL::VertFrame::__dt( (void))
|
||||
// note the (void) syntax
|
||||
//
|
||||
// from program Microsoft Entourage
|
||||
//
|
||||
String mangled = "__dt__Q26MsoDAL9VertFrameFv";
|
||||
|
||||
Address addr = addr("0x110");
|
||||
createSymbol(addr, mangled);
|
||||
|
||||
setOption(GnuDemanglerAnalyzer.OPTION_NAME_USE_DEPRECATED_DEMANGLER, true);
|
||||
|
||||
MessageLog log = new MessageLog();
|
||||
analyzer.added(program, program.getMemory(), TaskMonitor.DUMMY, log);
|
||||
}
|
||||
|
||||
private void setOption(String optionNameUseDeprecatedDemangler, boolean b) {
|
||||
|
||||
Options options = program.getOptions("Analyzers");
|
||||
|
||||
for (String name : options.getOptionNames()) {
|
||||
|
||||
if (name.contains("Demangler GNU")) {
|
||||
Msg.out("found it: " + name);
|
||||
}
|
||||
else {
|
||||
Msg.out("no it: " + name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void createSymbol(Address addr, String mangled) {
|
||||
|
||||
AddLabelCmd cmd = new AddLabelCmd(addr, mangled, SourceType.ANALYSIS);
|
||||
int txId = program.startTransaction(cmd.getName());
|
||||
boolean commit = true;
|
||||
try {
|
||||
boolean status = cmd.applyTo(program);
|
||||
program.flushEvents();
|
||||
|
||||
if (!status) {
|
||||
fail("Could not apply command: " + cmd.getStatusMsg());
|
||||
}
|
||||
}
|
||||
catch (RollbackException e) {
|
||||
commit = false;
|
||||
throw e;
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(txId, commit);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeprectedDemangledString_WithArguments_Valid() {
|
||||
|
||||
fail();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeprectedDemangledString_WithArguments_Invalid() {
|
||||
|
||||
fail();
|
||||
}
|
||||
|
||||
private Address addr(String addr) {
|
||||
return program.getAddressFactory().getAddress(addr);
|
||||
}
|
||||
|
||||
private void registerOptions() {
|
||||
Options options = program.getOptions(Program.ANALYSIS_PROPERTIES);
|
||||
|
||||
Options analyzerOptions = options.getOptions(analyzer.getName());
|
||||
analyzer.registerOptions(analyzerOptions, program);
|
||||
}
|
||||
}
|
|
@ -1130,7 +1130,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||
String mangled = "uv__dup";
|
||||
|
||||
GnuDemangler demangler = new GnuDemangler();
|
||||
DemangledObject res = demangler.demangle(mangled, true);
|
||||
DemangledObject res = demangler.demangle(mangled);
|
||||
assertNull(res);
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,8 @@ import org.junit.Before;
|
|||
import org.junit.Test;
|
||||
|
||||
import generic.test.AbstractGenericTest;
|
||||
import ghidra.app.util.demangler.*;
|
||||
import ghidra.app.util.demangler.DemangledException;
|
||||
import ghidra.app.util.demangler.DemangledObject;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.TerminatedStringDataType;
|
||||
|
@ -54,7 +55,7 @@ public class GnuDemanglerTest extends AbstractGenericTest {
|
|||
demangler.canDemangle(program);// this perform initialization
|
||||
|
||||
// this throws an exception with the bug in place
|
||||
demangler.demangle(mangled, true);
|
||||
demangler.demangle(mangled);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -65,8 +66,10 @@ public class GnuDemanglerTest extends AbstractGenericTest {
|
|||
GnuDemangler demangler = new GnuDemangler();
|
||||
demangler.canDemangle(program);// this perform initialization
|
||||
|
||||
GnuDemanglerOptions options = new GnuDemanglerOptions();
|
||||
options.setDemangleOnlyKnownPatterns(false);
|
||||
try {
|
||||
demangler.demangle(mangled, false);
|
||||
demangler.demangle(mangled, options);
|
||||
fail("Demangle should have failed attempting to demangle a non-mangled string");
|
||||
}
|
||||
catch (DemangledException e) {
|
||||
|
@ -82,7 +85,7 @@ public class GnuDemanglerTest extends AbstractGenericTest {
|
|||
GnuDemangler demangler = new GnuDemangler();
|
||||
demangler.canDemangle(program);// this perform initialization
|
||||
|
||||
DemangledObject result = demangler.demangle(mangled, true);
|
||||
DemangledObject result = demangler.demangle(mangled);
|
||||
assertNull("Demangle did not skip a name that does not match a known mangled pattern",
|
||||
result);
|
||||
}
|
||||
|
@ -99,13 +102,13 @@ public class GnuDemanglerTest extends AbstractGenericTest {
|
|||
symbolTable.createLabel(addr("01001000"), mangled, SourceType.IMPORTED);
|
||||
|
||||
GnuDemangler demangler = new GnuDemangler();
|
||||
DemangledObject obj = demangler.demangle(mangled, true);
|
||||
DemangledObject obj = demangler.demangle(mangled);
|
||||
assertNotNull(obj);
|
||||
|
||||
//assertEquals("typeinfo for AP_HAL::HAL::Callbacks", obj.getSignature(false));
|
||||
|
||||
assertTrue(
|
||||
obj.applyTo(program, addr("01001000"), new DemanglerOptions(), TaskMonitor.DUMMY));
|
||||
obj.applyTo(program, addr("01001000"), new GnuDemanglerOptions(), TaskMonitor.DUMMY));
|
||||
|
||||
Symbol s = symbolTable.getPrimarySymbol(addr("01001000"));
|
||||
assertNotNull(s);
|
||||
|
@ -132,13 +135,13 @@ public class GnuDemanglerTest extends AbstractGenericTest {
|
|||
symbolTable.createLabel(addr("01001000"), mangled, SourceType.IMPORTED);
|
||||
|
||||
GnuDemangler demangler = new GnuDemangler();
|
||||
DemangledObject obj = demangler.demangle(mangled, true);
|
||||
DemangledObject obj = demangler.demangle(mangled);
|
||||
assertNotNull(obj);
|
||||
|
||||
assertEquals("typeinfo name for AP_HAL::HAL::Callbacks", obj.getSignature(false));
|
||||
|
||||
assertTrue(
|
||||
obj.applyTo(program, addr("01001000"), new DemanglerOptions(), TaskMonitor.DUMMY));
|
||||
obj.applyTo(program, addr("01001000"), new GnuDemanglerOptions(), TaskMonitor.DUMMY));
|
||||
|
||||
Symbol s = symbolTable.getPrimarySymbol(addr("01001000"));
|
||||
assertNotNull(s);
|
||||
|
|
|
@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
|
|||
li { font-family:times new roman; font-size:14pt; }
|
||||
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
|
||||
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
|
||||
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
|
||||
|
||||
/*
|
||||
|
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
|
|||
td { font-family:times new roman; font-size:14pt; vertical-align: top; }
|
||||
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
|
||||
|
||||
code { color: black; font-family: courier new; font-size: 14pt; }
|
||||
/*
|
||||
Code-like formatting for things such as file system paths and proper names of classes,
|
||||
methods, etc. To apply this to a file path, use this syntax:
|
||||
<CODE CLASS="path">...</CODE>
|
||||
*/
|
||||
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
|
|
|
@ -94,7 +94,7 @@ public class MicrosoftDemanglerScript extends GhidraScript {
|
|||
}
|
||||
|
||||
private void demangle(String mangled) throws Exception {
|
||||
DemangledObject demangled = demangler.demangle(mangled, true);
|
||||
DemangledObject demangled = demangler.demangle(mangled);
|
||||
printf("magled %s\ndemangled %s", mangled, demangled);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,9 @@ import ghidra.app.util.importer.MessageLog;
|
|||
import ghidra.framework.options.Options;
|
||||
import ghidra.program.model.listing.Program;
|
||||
|
||||
/**
|
||||
* A version of the demangler analyzer to handle microsoft symbols
|
||||
*/
|
||||
public class MicrosoftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
||||
|
||||
private static final String NAME = "Demangler Microsoft";
|
||||
|
|
|
@ -39,6 +39,7 @@ public class MicrosoftDemangler implements Demangler {
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated(since = "9.2", forRemoval = true)
|
||||
public DemangledObject demangle(String mangled, boolean demangleOnlyKnownPatterns)
|
||||
throws DemangledException {
|
||||
try {
|
||||
|
@ -82,36 +83,4 @@ public class MicrosoftDemangler implements Demangler {
|
|||
throw gde;
|
||||
}
|
||||
}
|
||||
|
||||
// /**
|
||||
// * This represents an odd symbol that looks mangled, but we don't know what to do with. It
|
||||
// * is of the form:
|
||||
// * ?BobsStuffIO@344text__@@U_text@@?W
|
||||
// *
|
||||
// * where the last character is preceded by a special character, such as ?, *, -, etc
|
||||
// */
|
||||
// private static Pattern INVALID_TRAILING_CHARS_PATTERN = Pattern.compile(".*@@[?*`%~+/-][A-Z]");
|
||||
|
||||
// private boolean isMangled(String mangled) {
|
||||
// int atpos = mangled.indexOf("@");
|
||||
// boolean isMangled = mangled.charAt(0) == '?' && atpos != -1;
|
||||
//
|
||||
// if (!isMangled) {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// if (mangled.endsWith("~")) {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// //
|
||||
// // Now check for some odd things that we've seen.
|
||||
// //
|
||||
// Matcher matcher = INVALID_TRAILING_CHARS_PATTERN.matcher(mangled);
|
||||
// if (matcher.matches()) {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// return true;
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -33,10 +33,6 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
|
|||
|
||||
private ProgramDB program;
|
||||
|
||||
public MicrosoftDemanglerTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
ToyProgramBuilder builder = new ToyProgramBuilder("test", true);
|
||||
|
@ -49,7 +45,7 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
|
|||
String mangled = "?Te@NS1@BobsStuff@@0QAY0BAA@$$CBIA";
|
||||
|
||||
MicrosoftDemangler demangler = new MicrosoftDemangler();
|
||||
DemangledObject demangledObject = demangler.demangle(mangled, true);
|
||||
DemangledObject demangledObject = demangler.demangle(mangled);
|
||||
|
||||
int txID = program.startTransaction("Test");
|
||||
|
||||
|
@ -67,7 +63,7 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
|
|||
String mangled = "??0_LocaleUpdate@@QAE@PAUlocaleinfo_struct@@@Z";
|
||||
|
||||
MicrosoftDemangler demangler = new MicrosoftDemangler();
|
||||
DemangledObject demangledObj = demangler.demangle(mangled, true);
|
||||
DemangledObject demangledObj = demangler.demangle(mangled);
|
||||
assertNotNull(demangledObj);
|
||||
}
|
||||
|
||||
|
@ -78,7 +74,7 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
|
|||
MicrosoftDemangler demangler = new MicrosoftDemangler();
|
||||
DemangledObject demangledObj = null;
|
||||
try {
|
||||
demangledObj = demangler.demangle(mangled, true);
|
||||
demangledObj = demangler.demangle(mangled);
|
||||
}
|
||||
catch (DemangledException e) {
|
||||
// Expected
|
||||
|
@ -94,7 +90,7 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
|
|||
MicrosoftDemangler demangler = new MicrosoftDemangler();
|
||||
DemangledObject demangledObj = null;
|
||||
try {
|
||||
demangledObj = demangler.demangle(mangled, true);
|
||||
demangledObj = demangler.demangle(mangled);
|
||||
}
|
||||
catch (DemangledException e) {
|
||||
// Expected
|
||||
|
@ -110,7 +106,7 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
|
|||
MicrosoftDemangler demangler = new MicrosoftDemangler();
|
||||
DemangledObject demangledObj = null;
|
||||
try {
|
||||
demangledObj = demangler.demangle(mangled, true);
|
||||
demangledObj = demangler.demangle(mangled);
|
||||
}
|
||||
catch (DemangledException e) {
|
||||
// Expected
|
||||
|
@ -126,7 +122,7 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
|
|||
MicrosoftDemangler demangler = new MicrosoftDemangler();
|
||||
DemangledObject demangledObj = null;
|
||||
try {
|
||||
demangledObj = demangler.demangle(mangled, true);
|
||||
demangledObj = demangler.demangle(mangled);
|
||||
}
|
||||
catch (DemangledException e) {
|
||||
// Expected
|
||||
|
@ -142,7 +138,7 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
|
|||
MicrosoftDemangler demangler = new MicrosoftDemangler();
|
||||
DemangledObject demangledObj = null;
|
||||
try {
|
||||
demangledObj = demangler.demangle(mangled, true);
|
||||
demangledObj = demangler.demangle(mangled);
|
||||
}
|
||||
catch (DemangledException e) {
|
||||
// Expected
|
||||
|
@ -158,7 +154,7 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
|
|||
MicrosoftDemangler demangler = new MicrosoftDemangler();
|
||||
DemangledObject demangledObj = null;
|
||||
try {
|
||||
demangledObj = demangler.demangle(mangled, true);
|
||||
demangledObj = demangler.demangle(mangled);
|
||||
}
|
||||
catch (DemangledException e) {
|
||||
// Expected
|
||||
|
@ -174,7 +170,7 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
|
|||
MicrosoftDemangler demangler = new MicrosoftDemangler();
|
||||
DemangledObject demangledObj = null;
|
||||
try {
|
||||
demangledObj = demangler.demangle(mangled, true);
|
||||
demangledObj = demangler.demangle(mangled);
|
||||
}
|
||||
catch (DemangledException e) {
|
||||
// Expected
|
||||
|
@ -190,7 +186,7 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
|
|||
MicrosoftDemangler demangler = new MicrosoftDemangler();
|
||||
DemangledObject demangledObj = null;
|
||||
try {
|
||||
demangledObj = demangler.demangle(mangled, true);
|
||||
demangledObj = demangler.demangle(mangled);
|
||||
}
|
||||
catch (DemangledException e) {
|
||||
// Expected
|
||||
|
@ -206,7 +202,7 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
|
|||
MicrosoftDemangler demangler = new MicrosoftDemangler();
|
||||
DemangledObject demangledObj = null;
|
||||
try {
|
||||
demangledObj = demangler.demangle(mangled, true);
|
||||
demangledObj = demangler.demangle(mangled);
|
||||
}
|
||||
catch (DemangledException e) {
|
||||
// Expected
|
||||
|
|
|
@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
|
|||
li { font-family:times new roman; font-size:14pt; }
|
||||
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
|
||||
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
|
||||
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
|
||||
|
||||
/*
|
||||
|
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
|
|||
td { font-family:times new roman; font-size:14pt; vertical-align: top; }
|
||||
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
|
||||
|
||||
code { color: black; font-family: courier new; font-size: 14pt; }
|
||||
/*
|
||||
Code-like formatting for things such as file system paths and proper names of classes,
|
||||
methods, etc. To apply this to a file path, use this syntax:
|
||||
<CODE CLASS="path">...</CODE>
|
||||
*/
|
||||
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
|
|
|
@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
|
|||
li { font-family:times new roman; font-size:14pt; }
|
||||
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
|
||||
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
|
||||
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
|
||||
|
||||
/*
|
||||
|
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
|
|||
td { font-family:times new roman; font-size:14pt; vertical-align: top; }
|
||||
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
|
||||
|
||||
code { color: black; font-family: courier new; font-size: 14pt; }
|
||||
/*
|
||||
Code-like formatting for things such as file system paths and proper names of classes,
|
||||
methods, etc. To apply this to a file path, use this syntax:
|
||||
<CODE CLASS="path">...</CODE>
|
||||
*/
|
||||
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
|
|
|
@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
|
|||
li { font-family:times new roman; font-size:14pt; }
|
||||
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
|
||||
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
|
||||
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
|
||||
|
||||
/*
|
||||
|
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
|
|||
td { font-family:times new roman; font-size:14pt; vertical-align: top; }
|
||||
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
|
||||
|
||||
code { color: black; font-family: courier new; font-size: 14pt; }
|
||||
/*
|
||||
Code-like formatting for things such as file system paths and proper names of classes,
|
||||
methods, etc. To apply this to a file path, use this syntax:
|
||||
<CODE CLASS="path">...</CODE>
|
||||
*/
|
||||
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
|
|
|
@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
|
|||
li { font-family:times new roman; font-size:14pt; }
|
||||
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
|
||||
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
|
||||
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
|
||||
|
||||
/*
|
||||
|
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
|
|||
td { font-family:times new roman; font-size:14pt; vertical-align: top; }
|
||||
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
|
||||
|
||||
code { color: black; font-family: courier new; font-size: 14pt; }
|
||||
/*
|
||||
Code-like formatting for things such as file system paths and proper names of classes,
|
||||
methods, etc. To apply this to a file path, use this syntax:
|
||||
<CODE CLASS="path">...</CODE>
|
||||
*/
|
||||
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
|
|
|
@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
|
|||
li { font-family:times new roman; font-size:14pt; }
|
||||
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
|
||||
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
|
||||
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
|
||||
|
||||
/*
|
||||
|
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
|
|||
td { font-family:times new roman; font-size:14pt; vertical-align: top; }
|
||||
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
|
||||
|
||||
code { color: black; font-family: courier new; font-size: 14pt; }
|
||||
/*
|
||||
Code-like formatting for things such as file system paths and proper names of classes,
|
||||
methods, etc. To apply this to a file path, use this syntax:
|
||||
<CODE CLASS="path">...</CODE>
|
||||
*/
|
||||
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,25 +15,29 @@
|
|||
*/
|
||||
package docking.options.editor;
|
||||
|
||||
import ghidra.framework.options.EditorState;
|
||||
|
||||
import java.awt.Dimension;
|
||||
|
||||
import ghidra.framework.options.EditorState;
|
||||
import ghidra.util.layout.HorizontalLayout;
|
||||
|
||||
/**
|
||||
* A custom OptionComponent that controls it's own display using the editor component of the
|
||||
* given EditorState.
|
||||
*/
|
||||
public class CustomOptionComponent extends GenericOptionsComponent {
|
||||
|
||||
protected CustomOptionComponent( EditorState editorState ) {
|
||||
super( editorState );
|
||||
protected CustomOptionComponent(EditorState editorState) {
|
||||
super(editorState);
|
||||
|
||||
// this layout allows us to easily left-align the single component in this container
|
||||
setLayout(new HorizontalLayout(0));
|
||||
|
||||
// this class is designed to let the editor component handle the display and editing
|
||||
add( editorState.getEditorComponent() );
|
||||
add(editorState.getEditorComponent());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dimension getPreferredAlignmentSize() {
|
||||
return new Dimension( 0, 0 );
|
||||
return new Dimension(0, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,8 @@ import org.junit.Before;
|
|||
import org.junit.Test;
|
||||
|
||||
import ghidra.app.cmd.label.DemanglerCmd;
|
||||
import ghidra.app.util.demangler.*;
|
||||
import ghidra.app.util.demangler.DemangledException;
|
||||
import ghidra.app.util.demangler.DemangledObject;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
|
||||
|
@ -58,13 +59,13 @@ public class GnuDemanglerIntegrationTest extends AbstractGhidraHeadlessIntegrati
|
|||
GnuDemangler demangler = new GnuDemangler();
|
||||
demangler.canDemangle(program);// this perform initialization
|
||||
|
||||
DemangledObject result = demangler.demangle(mangled, false);
|
||||
GnuDemanglerOptions options = new GnuDemanglerOptions();
|
||||
options.setDemangleOnlyKnownPatterns(false);
|
||||
DemangledObject result = demangler.demangle(mangled, options);
|
||||
assertNotNull(result);
|
||||
assertEquals("undefined MyNamespace::MyFunction($ParamNamespace::paramName *)",
|
||||
result.getSignature(false));
|
||||
|
||||
DemanglerOptions options = new DemanglerOptions();
|
||||
options.setDemangleOnlyKnownPatterns(false);
|
||||
DemanglerCmd cmd = new DemanglerCmd(addr("01001000"), mangled, options);
|
||||
|
||||
// this used to trigger an exception
|
||||
|
|
|
@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
|
|||
li { font-family:times new roman; font-size:14pt; }
|
||||
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
|
||||
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
|
||||
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
|
||||
|
||||
/*
|
||||
|
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
|
|||
td { font-family:times new roman; font-size:14pt; vertical-align: top; }
|
||||
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
|
||||
|
||||
code { color: black; font-family: courier new; font-size: 14pt; }
|
||||
/*
|
||||
Code-like formatting for things such as file system paths and proper names of classes,
|
||||
methods, etc. To apply this to a file path, use this syntax:
|
||||
<CODE CLASS="path">...</CODE>
|
||||
*/
|
||||
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
|
|
|
@ -24,12 +24,12 @@
|
|||
|
||||
*/
|
||||
|
||||
body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px;} /* some padding to improve readability */
|
||||
body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 10px; } /* some padding to improve readability */
|
||||
li { font-family:times new roman; font-size:14pt; }
|
||||
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
|
||||
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; }
|
||||
h4 { margin-left: 10px; font-family:times new roman; font-size:14pt; font-style:italic; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
|
||||
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
|
||||
|
||||
/*
|
||||
P tag code. Most of the help files nest P tags inside of blockquote tags (the was the
|
||||
|
@ -40,12 +40,25 @@ h4 { margin-left: 10px; font-family:times new roman; font-size:14pt; font-style:
|
|||
*/
|
||||
p { margin-left: 40px; font-family:times new roman; font-size:14pt; }
|
||||
blockquote p { margin-left: 10px; }
|
||||
|
||||
p.providedbyplugin { color:#7f7f7f; margin-left: 10px; font-size:14pt; margin-top:100px }
|
||||
p.ProvidedByPlugin { color:#7f7f7f; margin-left: 10px; font-size:14pt; margin-top:100px }
|
||||
p.relatedtopic { color:#800080; margin-left: 10px; font-size:14pt; }
|
||||
p.RelatedTopic { color:#800080; margin-left: 10px; font-size:14pt; }
|
||||
|
||||
|
||||
/*
|
||||
We wish for a tables to have space between it and the preceding element, so that text
|
||||
is not too close to the top of the table. Also, nest the table a bit so that it is clear
|
||||
the table relates to the preceding text.
|
||||
*/
|
||||
table { margin-left: 20px; margin-top: 10px; width: 80%;}
|
||||
td { font-family:times new roman; font-size:14pt; vertical-align: top; }
|
||||
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
|
||||
code { color: black; font-family: courier new; font-size: 14pt; }
|
||||
|
||||
/*
|
||||
Code-like formatting for things such as file system paths and proper names of classes,
|
||||
methods, etc. To apply this to a file path, use this syntax:
|
||||
<CODE CLASS="path">...</CODE>
|
||||
*/
|
||||
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue