Browse Source

java loader is done, now to the analyzer

Signed by: govanify GPG Key ID: DE62E1E2A6145556
10 changed files with 94 additions and 164 deletions
  1. +0
  2. +8
  3. +0
  4. +0
  5. +0
  6. +0
  7. +0
  8. +0
  9. +1
  10. +85

+ 0
- 1
.classpath View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="src" path="src/main/help"/>
<classpathentry kind="src" path="ghidra_scripts"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/openjdk-11"/>

+ 8
- 3
.gitignore View File

@ -1,14 +1,19 @@

+ 0
- 15
data/README.txt View File

@ -1,15 +0,0 @@
The "data" directory is intended to hold data files that will be used by this module and will
not end up in the .jar file, but will be present in the zip or tar file. Typically, data
files are placed here rather than in the resources directory if the user may need to edit them.
An optional data/languages directory can exist for the purpose of containing various Sleigh language
specification files and importer opinion files.
The data/buildLanguage.xml is used for building the contents of the data/languages directory.
The skel language definition has been commented-out within the skel.ldefs file so that the
skeleton language does not show-up within Ghidra.
See the Sleigh language documentation (docs/languages/index.html) for details Sleigh language
specification syntax.

+ 0
- 1
ghidra_scripts/README.txt View File

@ -1 +0,0 @@
Java source directory to hold module-specific Ghidra scripts.

ghidra_scripts/ → ghidra_scripts/ View File

+ 0
- 57
src/main/help/help/TOC_Source.xml View File

@ -1,57 +0,0 @@
<?xml version='1.0' encoding='ISO-8859-1' ?>
This is an XML file intended to be parsed by the Ghidra help system. It is loosely based
upon the JavaHelp table of contents document format. The Ghidra help system uses a
TOC_Source.xml file to allow a module with help to define how its contents appear in the
Ghidra help viewer's table of contents. The main document (in the Base module)
defines a basic structure for the
Ghidra table of contents system. Other TOC_Source.xml files may use this structure to insert
their files directly into this structure (and optionally define a substructure).
In this document, a tag can be either a <tocdef> or a <tocref>. The former is a definition
of an XML item that may have a link and may contain other <tocdef> and <tocref> children.
<tocdef> items may be referred to in other documents by using a <tocref> tag with the
appropriate id attribute value. Using these two tags allows any module to define a place
in the table of contents system (<tocdef>), which also provides a place for
other TOC_Source.xml files to insert content (<tocref>).
During the help build time, all TOC_Source.xml files will be parsed and validated to ensure
that all <tocref> tags point to valid <tocdef> tags. From these files will be generated
<module name>_TOC.xml files, which are table of contents files written in the format
desired by the JavaHelp system. Additionally, the genated files will be merged together
as they are loaded by the JavaHelp system. In the end, when displaying help in the Ghidra
help GUI, there will be on table of contents that has been created from the definitions in
all of the modules' TOC_Source.xml files.
Tags and Attributes
-id - the name of the definition (this must be unique across all TOC_Source.xml files)
-text - the display text of the node, as seen in the help GUI
-target** - the file to display when the node is clicked in the GUI
-sortgroup - this is a string that defines where a given node should appear under a given
parent. The string values will be sorted by the JavaHelp system using
a javax.text.RulesBasedCollator. If this attribute is not specified, then
the text of attribute will be used.
-id - The id of the <tocdef> that this reference points to
**The URL for the target is relative and should start with 'help/topics'. This text is
used by the Ghidra help system to provide a universal starting point for all links so that
they can be resolved at runtime, across modules.
<!-- Uncomment and adjust fields to add help topic to help system's Table of Contents
<tocref id="Ghidra Functionality">
<tocdef id="HelpAnchor" text="My Feature" target="help/topics/my_topic/help.html" />

+ 0
- 58
src/main/help/help/shared/Frontpage.css View File

@ -1,58 +0,0 @@
/* ###
* 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
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* See the License for the specific language governing permissions and
* limitations under the License.
This file is copied to all help directories. If you change this file, you must copy it
to each src/main/help/help/shared directory.
Java Help Note: JavaHelp does not accept sizes (like in 'margin-top') in anything but
px (pixel) or with no type marking.
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; 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
way it had been done in the beginning). The net effect is that the text is indented. In
modern HTML we would use CSS to do this. We need to support the Ghidra P tags, nested in
blockquote tags, as well as naked P tags. The following two lines accomplish this. Note
that the 'blockquote p' definition will inherit from the first 'p' definition.
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; }

+ 0
- 23
src/main/help/help/topics/ghidra_kh2ai/help.html View File

@ -1,23 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<META name="generator" content=
"HTML Tidy for Java (vers. 2009-12-01), see">
<META http-equiv="Content-Language" content="en-us">
<META http-equiv="Content-Type" content="text/html; charset=windows-1252">
<META name="GENERATOR" content="Microsoft FrontPage 4.0">
<META name="ProgId" content="FrontPage.Editor.Document">
<TITLE>Skeleton Help File for a Module</TITLE>
<LINK rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
<H1><a name="HelpAnchor"></a>Skeleton Help File for a Module</H1>
<P>This is a simple skeleton help topic. For a better description of what should and should not
go in here, see the "sample" Ghidra extension in the Extensions/Ghidra directory, or see your
favorite help topic. In general, language modules do not have their own help topics.</P>

+ 1
- 1
src/main/java/ghidra_kh2ai/ View File

@ -34,7 +34,7 @@ public class ghidra_kh2aiAnalyzer extends AbstractAnalyzer {
// TODO: Name the analyzer and give it a description.
super("Function pointers resolver", "This analyzer scans KH2 AI files for "
+ "function pointers pushed as values and resolves them.", AnalyzerType.BYTE_ANALYZER);
+ "function pointers pushed as values and resolves them.", AnalyzerType.INSTRUCTION_ANALYZER);

+ 85
- 5
src/main/java/ghidra_kh2ai/ View File

@ -32,17 +32,25 @@ import;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.FunctionManager;
import ghidra.program.model.listing.Listing;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.symbol.SourceType;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.SymbolTable;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.InvalidInputException;
import ghidra.util.task.TaskMonitor;
import ghidra.program.database.mem.FileBytes;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressOverflowException;
import ghidra.program.model.address.AddressSet;
@ -87,10 +95,10 @@ public class ghidra_kh2aiLoader extends AbstractLibrarySupportLoader {
return d;
catch (CodeUnitInsertionException e) {
Msg.warn(this, "ELF data markup conflict at " + address);
Msg.warn(this, "KH2AI data markup conflict at " + address);
catch (DataTypeConflictException e) {
Msg.error(this, "ELF data type markup conflict:" + e.getMessage());
Msg.error(this, "KH2AI data type markup conflict:" + e.getMessage());
return null;
@ -114,19 +122,78 @@ public class ghidra_kh2aiLoader extends AbstractLibrarySupportLoader {
return true;
public static final long arrToLong(byte[] b)
long l = 0;
l |= b[3] & 0xFF;
l <<= 8;
l |= b[2] & 0xFF;
l <<= 8;
l |= b[1] & 0xFF;
l <<= 8;
l |= b[0] & 0xFF;
return l;
// shamelessly stolen from Ghidra-Switch-Loader, creds to Adubbz
public void createOneByteFunction(Program program, String name, Address address, boolean isEntry)
Function function = null;
FunctionManager functionMgr = program.getFunctionManager();
function = functionMgr.getFunctionAt(address);
if (function == null) {
function = functionMgr.createFunction(null, address, new AddressSet(address), SourceType.IMPORTED);
catch (Exception e)
Msg.error(this, "Error while creating function at " + address + ": " + e.getMessage());
if (name != null)
createSymbol(program, address, name, false, null);
if (isEntry) {
catch (Exception e) {
Msg.error(this, "Error while creating symbol " + name + " at " + address + ": " + e.getMessage());
public Symbol createSymbol(Program program, Address addr, String name, boolean pinAbsolute, Namespace namespace) throws InvalidInputException
// TODO: At this point, we should be marking as data or code
SymbolTable symbolTable = program.getSymbolTable();
Symbol sym = symbolTable.createLabel(addr, name, namespace, SourceType.IMPORTED);
if (pinAbsolute && !sym.isPinned()) {
return sym;
protected void load(ByteProvider provider, LoadSpec loadSpec, List<Option> options,
Program program, TaskMonitor monitor, MessageLog log)
throws CancelledException, IOException {
Structure struct = new StructureDataType("header_item", 0);
// We create the header structure and add the static elements
Structure struct = new StructureDataType("header", 0);
struct.add(, 0x10, "filename", null);
struct.add(, 4, "unk1", null);
struct.add(, 4, "unk2", null);
struct.add(, 4, "unk3", null);
int off = 0;
ArrayList<Long> entrypoints = new ArrayList<Long>();
while (1==1) {
// gathers entrypoints/triggers into an arraylist and define the dynamic part of the header structure
byte[] first = provider.readBytes(0x1c+(off*8), 0x4);
byte[] second = provider.readBytes(0x1c+4+(off*8), 0x4);
if(checkZero(first) && checkZero(second)){
@ -134,11 +201,18 @@ public class ghidra_kh2aiLoader extends AbstractLibrarySupportLoader {
struct.add(, 4, "end_entry", null);
long fa = arrToLong(first);
long sa = arrToLong(second);
log.appendMsg("kh2ai: " + fa + " " + sa);
struct.add(, 4, "trigger"+(off+1), null);
struct.add(, 4, "entry"+(off+1), null);
log.appendMsg("kh2ai: " + entrypoints);
// we actually send the bytes over to the program and send off the header structure
MemoryBlockUtils mbu = new MemoryBlockUtils();
Address start = program.getAddressFactory().getDefaultAddressSpace().getAddress(0);
BinaryReader reader = new BinaryReader( provider, true );
@ -146,11 +220,17 @@ public class ghidra_kh2aiLoader extends AbstractLibrarySupportLoader {
try {
MemoryBlockUtils.createInitializedBlock(program, false, "ram", start, fileBytes, 0, provider.length(), "", "KH2AI Header", true, true, true, log);
} catch (AddressOverflowException e) {
// TODO Auto-generated catch block
createData(program, start, program.getListing(), struct);
// TODO: Load the bytes from 'provider' into the 'program'.
// we create one byte functions so that the analyzer knows that there's something there, labelling
// entrypoints in the format entry<trigger>
for (int i=0; i<entrypoints.size(); i+=2) {
long addr=0x10+(entrypoints.get(i+1)<<1);
Address entry = program.getAddressFactory().getDefaultAddressSpace().getAddress(addr);
createOneByteFunction(program, "entry"+entrypoints.get(i), entry, true);