Browse Source

bunch of rework and swap to eclipse for more advanced work

tags/v0.1
parent
commit
2be6db8452
No known key found for this signature in database
32 changed files with 715 additions and 134 deletions
  1. +1
    -0
      .gitignore
  2. BIN
      .gradle/5.0/fileChanges/last-build.bin
  3. BIN
      .gradle/5.0/fileContent/fileContent.lock
  4. BIN
      .gradle/5.0/fileHashes/fileHashes.bin
  5. BIN
      .gradle/5.0/fileHashes/fileHashes.lock
  6. +0
    -0
      .gradle/5.0/gc.properties
  7. BIN
      .gradle/5.0/taskHistory/taskHistory.bin
  8. BIN
      .gradle/5.0/taskHistory/taskHistory.lock
  9. BIN
      .gradle/buildOutputCleanup/buildOutputCleanup.lock
  10. +2
    -0
      .gradle/buildOutputCleanup/cache.properties
  11. BIN
      .gradle/buildOutputCleanup/outputFiles.bin
  12. +0
    -0
      .gradle/vcs-1/gc.properties
  13. +33
    -0
      build.gradle
  14. +15
    -0
      data/README.txt
  15. +50
    -0
      data/buildLanguage.xml
  16. +73
    -0
      data/languages/base.sinc
  17. +57
    -71
      data/languages/kh2ai.sinc
  18. +2
    -0
      data/languages/kh2ai.slaspec
  19. +35
    -0
      data/languages/syscalls.sinc
  20. +99
    -48
      data/manuals/kh2ai.tex
  21. +6
    -0
      data/sleighArgs.txt
  22. +5
    -0
      extension.properties
  23. BIN
      ghidra-kh2ai.zip
  24. +8
    -0
      main.workflow
  25. +4
    -15
      notes.txt
  26. +57
    -0
      src/main/help/help/TOC_Source.xml
  27. +58
    -0
      src/main/help/help/shared/Frontpage.css
  28. +23
    -0
      src/main/help/help/topics/ghidra_kh2ai/help.html
  29. +78
    -0
      src/main/java/ghidra_kh2ai/ghidra_kh2aiAnalyzer.java
  30. +105
    -0
      src/main/java/ghidra_kh2ai/ghidra_kh2aiLoader.java
  31. +2
    -0
      src/main/resources/images/README.txt
  32. +2
    -0
      src/test/java/README.test.txt

+ 1
- 0
.gitignore View File

@@ -9,3 +9,4 @@
.gdb_history
*.zip
*.kate-swp
bin/*

BIN
.gradle/5.0/fileChanges/last-build.bin View File


BIN
.gradle/5.0/fileContent/fileContent.lock View File


BIN
.gradle/5.0/fileHashes/fileHashes.bin View File


BIN
.gradle/5.0/fileHashes/fileHashes.lock View File


+ 0
- 0
.gradle/5.0/gc.properties View File


BIN
.gradle/5.0/taskHistory/taskHistory.bin View File


BIN
.gradle/5.0/taskHistory/taskHistory.lock View File


BIN
.gradle/buildOutputCleanup/buildOutputCleanup.lock View File


+ 2
- 0
.gradle/buildOutputCleanup/cache.properties View File

@@ -0,0 +1,2 @@
#Sun Dec 22 10:20:50 CET 2019
gradle.version=5.0

BIN
.gradle/buildOutputCleanup/outputFiles.bin View File


+ 0
- 0
.gradle/vcs-1/gc.properties View File


+ 33
- 0
build.gradle View File

@@ -0,0 +1,33 @@
// Builds a Ghidra Extension for a given Ghidra installation.
//
// An absolute path to the Ghidra installation directory must be supplied either by setting the
// GHIDRA_INSTALL_DIR environment variable or Gradle project property:
//
// > export GHIDRA_INSTALL_DIR=<Absolute path to Ghidra>
// > gradle
//
// or
//
// > gradle -PGHIDRA_INSTALL_DIR=<Absolute path to Ghidra>
//
// Gradle should be invoked from the directory of the project to build. Please see the
// application.gradle.version property in <GHIDRA_INSTALL_DIR>/Ghidra/application.properties
// for the correction version of Gradle to use for the Ghidra installation you specify.

//----------------------START "DO NOT MODIFY" SECTION------------------------------
def ghidraInstallDir

if (System.env.GHIDRA_INSTALL_DIR) {
ghidraInstallDir = System.env.GHIDRA_INSTALL_DIR
}
else if (project.hasProperty("GHIDRA_INSTALL_DIR")) {
ghidraInstallDir = project.getProperty("GHIDRA_INSTALL_DIR")
}

if (ghidraInstallDir) {
apply from: new File(ghidraInstallDir).getCanonicalPath() + "/support/buildExtension.gradle"
}
else {
throw new GradleException("GHIDRA_INSTALL_DIR is not defined!")
}
//----------------------END "DO NOT MODIFY" SECTION-------------------------------

+ 15
- 0
data/README.txt View File

@@ -0,0 +1,15 @@
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.

+ 50
- 0
data/buildLanguage.xml View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>

<!--
+ Compile sleigh languages within this module.
+ Sleigh compiler options are read from the sleighArgs.txt file.
+ Eclipse: right-click on this file and choose menu item "Run As->Ant Build"
-->
<project name="privateBuildDeveloper" default="sleighCompile">
<property name="sleigh.compile.class" value="ghidra.pcodeCPort.slgh_compile.SleighCompile"/>

<!--Import optional ant properties. GhidraDev Eclipse plugin produces this so this file can find the Ghidra installation-->
<import file="../.antProperties.xml" optional="false" />
<target name="sleighCompile">
<!-- If language module is detached from installation, get Ghidra installation directory path from imported properties -->
<property name="framework.path" value="${ghidra.install.dir}/Ghidra/Framework"/>
<path id="sleigh.class.path">
<fileset dir="${framework.path}/SoftwareModeling/lib">
<include name="*.jar"/>
</fileset>
<fileset dir="${framework.path}/Generic/lib">
<include name="*.jar"/>
</fileset>
<fileset dir="${framework.path}/Utility/lib">
<include name="*.jar"/>
</fileset>
</path>
<available classname="${sleigh.compile.class}" classpathref="sleigh.class.path" property="sleigh.compile.exists"/>
<fail unless="sleigh.compile.exists" />
<java classname="${sleigh.compile.class}"
classpathref="sleigh.class.path"
fork="true"
failonerror="true">
<jvmarg value="-Xmx2048M"/>
<arg value="-i"/>
<arg value="sleighArgs.txt"/>
<arg value="-a"/>
<arg value="./languages"/>
</java>
</target>

</project>

+ 73
- 0
data/languages/base.sinc View File

@@ -0,0 +1,73 @@
define space ram type=ram_space size=4 wordsize=1 default;
define space register type=register_space size=4;

# this is obviously wrong and will need to be edited when i understand how
# internal regs are used besides stack
define register offset=0 size=4 [
r0 r1 r2 r3 r4 r5 r6
r7 r8 pc sp ra broken
];

define token instr(16)
opcode = (0, 3)
ssub_opc = (6, 15)
sub_opc = (4, 5)
iarg = (14, 15);

define token instr_ext(32)
opcode_ext = (0, 3)
sub_opc_ext = (4, 5)
opesub = (6, 7)
_opesub = (6, 7)
rn = (6, 7)
ope3 = (6, 15)
full_ext = (0, 31)
full_rel = (0, 31) signed
# the label thingy
ope2 = (16, 31)
_ope2 = (16, 31)
ope2s = (16, 31) signed;

# relocated labels
LABEL8: reloc is ope2s [ reloc = inst_start+(ope2s*2)+4; ] { export *:4 reloc; }
LABEL02: reloc is ope2s [ reloc = 0x10+(ope2s*2); ] { export *:4 reloc; }
#LABELV: reloc is full_rel [ reloc = 0x10+(full_rel*2); ] { export *:4 reloc; }
NOT_LABEL03: reloc is ope2s [ reloc = 0x10+(ope2s*2); ] { tmp:4 = reloc:4; export tmp; }
#CLABEL: reloc is full_ext [ reloc = 0x10+(full_ext*2); ] { export *:4 reloc; }

# if i'm not mistaken 0x1da4d8 1 and 2 uses two regs
# one of them or more is a status reg so i'll have to double check how it's used
attach variables [ rn ] [ r0 r1 r2 r3 ];

# exit values
attach values [ iarg ] [ 1 2 _ _ ];


define pcodeop system_call;
define pcodeop fmod;
define pcodeop exit;
define pcodeop cos;
define pcodeop sin;
define pcodeop radians_to_degrees;
define pcodeop degrees_to_radians;


macro push(v) {
*[ram]:4 sp = v;
sp = sp + 4;
}

macro pop(v) {
sp = sp - 4;
v = *[ram]:4 sp;
}

macro to_address(v) {
if(v!=0) goto <address>;
v=0;
goto <end>;
<address>
v=0x10+(v*2);
<end>
}


+ 57
- 71
data/languages/kh2ai.sinc View File

@@ -1,62 +1,4 @@

define space ram type=ram_space size=4 wordsize=1 default;
define space register type=register_space size=4;

# this is obviously wrong and will need to be edited when i understand how
# internal regs are used besides stack
define register offset=0 size=4 [
r0 r1 r2 r3 r4 r5 r6
r7 r8 pc sp ra broken
];

define token instr(16)
opcode = (0, 3)
ssub_opc = (6, 15)
sub_opc = (4, 5)
iarg = (14, 15);

define token instr_ext(32)
opcode_ext = (0, 3)
sub_opc_ext = (4, 5)
opesub = (6, 7)
rn = (6, 7)
ope3 = (6, 15)
full_ext = (0, 31)
# the label thingy
ope2 = (16, 31)
ope2s = (16, 31) signed;

# relocated labels
LABEL8: reloc is ope2s [ reloc = inst_start+(ope2s*2)+4; ] { export *:4 reloc; }
LABEL02: reloc is ope2s [ reloc = 0x10+(ope2s*2); ] { export *:4 reloc; }

# if i'm not mistaken 0x1da4d8 1 and 2 uses two regs
# one of them or more is a status reg so i'll have to double check how it's used
attach variables [ rn ] [ _ r0 r1 _ ];

# exit values
attach values [ iarg ] [ 1 2 _ _ ];


define pcodeop system_call;
define pcodeop fmod;
define pcodeop exit;
define pcodeop cos;
define pcodeop sin;
define pcodeop radians_to_degrees;
define pcodeop degrees_to_radians;


macro push(v) {
*[ram]:4 sp = v;
sp = sp + 4;
}

macro pop(v) {
sp = sp - 4;
v = *[ram]:4 sp;
}

#
#
# Instructions
@@ -67,24 +9,33 @@ macro pop(v) {
# 0x1 =========

# standard push
:push full_ext is opcode=0 & ( sub_opc=1 | sub_opc=0 ) ; full_ext {
# so this is how the game does it, it pushes a value, normal stuff. THE. THING.
# IS. it can sometime push an address too, that a syscall relocates. so we're
# going to have to be hacky to get the entire file to be analyzed. sad day.

# ssub_opc is always equal 0, we just define it in a more specific fashion to
# prefer push.v over _push.v, which is dynamically created by the analyzer
:push.v full_ext is opcode=0 & ( sub_opc=1 | sub_opc=0 ) ; full_ext {
push(full_ext:4);
}

#:pushc CLABEL is opcode=0 & ( sub_opc=1 | sub_opc=0 ) ; CLABEL & full_ext {
# push(full_ext:4);
#}


#push and add
:push2_unk0 is opcode_ext=0 & sub_opc_ext=2 & opesub=0 {
}

# push and add to pointer
:pushap rn, ope2 is opcode_ext=0 & sub_opc_ext=2 & opesub=1 & ope2 & rn {
:push.ap rn, ope2 is opcode_ext=0 & sub_opc_ext=2 & opesub=1 & ope2 & rn {
}

:push2_unk2 is opcode_ext=0 & sub_opc_ext=2 & opesub=2 {
}

:push LABEL02 is opcode_ext=0 & sub_opc_ext=2 & opesub=3 & LABEL02 {
# this is wrong! it pushes the pointer, not the data
:push.l LABEL02 is opcode_ext=0 & sub_opc_ext=2 & opesub=3 & LABEL02 {
push(LABEL02:4);
}

@@ -93,30 +44,52 @@ macro pop(v) {
}

#push and add
:pusha rn, ope2 is opcode_ext=0 & sub_opc_ext=3 & opesub=1 & ope2 & rn {
:push.a rn, ope2 is opcode_ext=0 & sub_opc_ext=3 & opesub=1 & ope2 & rn {
}

#push and add
:push3_unk2 is opcode_ext=0 & sub_opc_ext=3 & opesub=2 {
}

#push and add
:push3_unk3 is opcode_ext=0 & sub_opc_ext=3 & opesub=3 {
# never used in practice... push pointer as data and not label
:push.ln NOT_LABEL03 is opcode_ext=0 & sub_opc_ext=3 & opesub=3 & NOT_LABEL03 {
push(NOT_LABEL03);
}

# 0x1 =========


# sometimes it has arguments, to check!
:pop is opcode_ext=1 {
# this is a pop_at!!!!!
:popat_unk0 is opcode_ext=1 & ope3=0 & ope2 & rn {
}

:popat rn, ope2 is opcode_ext=1 & ope3=1 & ope2 & rn {
}

:popat_unk2 is opcode_ext=1 & ope3=2 & ope2 & rn {
}

# no shit this isn't used in practice
:popat LABEL02 is opcode_ext=1 & ope3=3 & LABEL02 {
push(LABEL02:4);
}


:unk2 is opcode_ext=2 ; opcode{
:unk2_unk0 is opcode_ext=2 & ope3=0; opcode{
}

:unk2_unk1 is opcode_ext=2 & ope3=1; opcode{
}

:unk2_unk2 is opcode_ext=2 & ope3=2; opcode{
}

:unk2_unk3 is opcode_ext=2 & ope3=3; opcode{
}

# push and add to stack
:pushas ope2 is opcode_ext=3 & ope2{
:push.as ope2 is opcode_ext=3 & ope2{
local tmp:4 = sp;
pop(tmp);
tmp=tmp+ope2;
@@ -486,11 +459,11 @@ macro pop(v) {

# push cached -> push last cached pushed element to stack
# don't ask me, this entire ISA is cursed
:pushca is opcode=9 & ssub_opc=3{
:push.ca is opcode=9 & ssub_opc=3{
}

# push copy -> push last pushed element to stack
:pushc is opcode=9 & ssub_opc=5{
:push.c is opcode=9 & ssub_opc=5{
}

# sinus; arg in radians
@@ -531,7 +504,20 @@ macro pop(v) {

# 0x9 =========

#syscall
#:syscall opesub,ope2 is opcode_ext=0xA & opesub & ope2 {
# if (opesub:4==1) goto <table1>;
# <table1>
# if (ope2:4==6) goto <_syscall1_6>;
# # unknown args or no changes necessary
# system_call(opesub:4,ope2:4);
# goto <done>;
# <_syscall1_6>
# syscall1_6();
# goto <done>;
# <done>
#}


:syscall opesub,ope2 is opcode_ext=0xA & opesub & ope2 {
system_call(opesub:4,ope2:4);
}

+ 2
- 0
data/languages/kh2ai.slaspec View File

@@ -1,4 +1,6 @@
define endian=little;
define alignment=2;

@include "base.sinc"
@include "syscalls.sinc"
@include "kh2ai.sinc"

+ 35
- 0
data/languages/syscalls.sinc View File

@@ -0,0 +1,35 @@
define pcodeop system_call1_6;

macro syscall1_6() {
local tmp:4 = sp;
pop(tmp);
local tmp2:4 = sp;
pop(tmp2);
local tmp3:4 = sp;
pop(tmp3);
local tmp4:4 = sp;
pop(tmp4);
local tmp5:4 = sp;
pop(tmp5);
local tmp6:4 = sp;
pop(tmp6);
local tmp7:4 = sp;
pop(tmp7);
local tmp8:4 = sp;
pop(tmp8);
local tmp9:4 = sp;
pop(tmp9);
local tmp10:4 = sp;
pop(tmp10);
to_address(tmp2);
to_address(tmp3);
to_address(tmp4);
to_address(tmp5);
to_address(tmp6);
to_address(tmp7);
to_address(tmp8);
to_address(tmp9);
to_address(tmp10);
system_call1_6(tmp, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9, tmp10);
}

+ 99
- 48
data/manuals/kh2ai.tex View File

@@ -57,6 +57,9 @@
}

\newcommand{\ISA}[7]{
\StrLen{#4}[\exclen]
\StrLen{#6}[\notelen]

\section{\huge #1}
\Lineless \\
\textbf{Operation Code} \\ \\
@@ -65,12 +68,16 @@
\hspace*{0.5cm} #2 \\ \\
\textbf{Description} \\
\hspace*{0.5cm} #3 \\ \\
\ifthenelse{\equal{\exclen}{0}}{}{
\textbf{Exceptions} \\
\hspace*{0.5cm} #4 \\ \\
}
\textbf{Operations} \\
\hspace*{0.5cm} #5 \\ \\
\ifthenelse{\equal{notelen}{0}}{}{
\textbf{Programming notes} \\
\hspace*{0.5cm} #6 \\ \\
}
\newpage
}

@@ -129,6 +136,13 @@

\Main{Kh2Ai ISA}{\version}

Blabla
It is also worthy to note that some operations that otherwise do the same thing
are given a different mnemonic depending on the context to be easier to write an
assembler. An example of this can be seen in the PUSH.V and PUSH.L operations,
which, while they both push a value to the stack, one of them is 48bits long and
pushes a raw value while the other is 32bits long and does a relocation on the
encoded address before pushing it, making the different naming needed.

\Chapter{Notational Convention}

@@ -148,101 +162,116 @@

\ISA{POP: pop}{b}{c}{d}{e}{f}{01000000010010010000111111010000}

\ISA{CFTI: Convert Float To Int}{b}{c}{d}{e}{f}{01000000010010010000111111010000}
\ISA{CFTI: Convert Float To Int}{CFTI}{c}{d}{e}{f}{01000000010010010000111111010000}

\ISA{NEG: convert to NEGative signed number}{b}{c}{d}{e}{f}{01000000010010010000111111010000}
\ISA{NEG: convert to NEGative signed number}{NEG}{c}{d}{e}{f}{01000000010010010000111111010000}

\ISA{INV: INVert an unsigned value}{b}{c}{d}{e}{f}{01000000010010010000111111010000}
\ISA{INV: INVert an unsigned value}{INV}{c}{d}{e}{f}{01000000010010010000111111010000}

\ISA{EQZ: conditional is EQual Zero}{b}{c}{d}{e}{f}{01000000010010010000111111010000}
\ISA{EQZ: conditional is EQual Zero}{EQZ}{c}{d}{e}{f}{01000000010010010000111111010000}

\ISA{ABS: convert to ABSolute value}{b}{c}{d}{e}{f}{01000000010010010000111111010000}
\ISA{ABS: convert to ABSolute value}{ABS}{c}{d}{e}{f}{01000000010010010000111111010000}

\ISA{MSB: return Most Significant Bit}{b}{c}{d}{e}{f}{01000000010010010000111111010000}
\ISA{MSB: return Most Significant Bit}{MSB}{c}{d}{e}{f}{01000000010010010000111111010000}

\ISA{INFO: conditional INFerior to One}{b}{c}{d}{e}{f}{01000000010010010000111111010000}
\ISA{INFO: conditional INFerior to One}{INFO}{c}{d}{e}{f}{01000000010010010000111111010000}

\ISA{NEQZ: conditional Not Equal to Zero}{b}{c}{d}{e}{f}{01000000010010010000111111010000}
\ISA{NEQZ: conditional Not Equal to Zero}{NEQZ}{c}{d}{e}{f}{01000000010010010000111111010000}

\ISA{MSB: return Most Significant Bit Inverted}{b}{c}{d}{e}{f}{01000000010010010000111111010000}
\ISA{MSBI: return Most Significant Bit Inverted}{MSBI}{c}{d}{e}{f}{01000000010010010000111111010000}

\ISA{IPOS: Conditional Is POSitive}{b}{c}{d}{e}{f}{01000000010010010000111111010000}
\ISA{IPOS: Conditional Is POSitive}{IPOS}{c}{d}{e}{f}{01000000010010010000111111010000}

\ISA{CITF: Convert Int To Float}{b}{c}{d}{e}{f}{01000000010010010000111111010000}
\ISA{CITF: Convert Int To Float}{CITF}{c}{d}{e}{f}{01000000010010010000111111010000}

\ISA{NEGF: convert to NEGative Float}{b}{c}{d}{e}{f}{01000000010010010000111111010000}
\ISA{NEGF: convert to NEGative Float}{NEGF}{c}{d}{e}{f}{01000000010010010000111111010000}

\ISA{ABS: convert to ABSolute Float}{b}{c}{d}{e}{f}{01000000010010010000111111010000}
\ISA{ABS: convert to ABSolute Float}{ABS}{c}{d}{e}{f}{01000000010010010000111111010000}

\ISA{INFZF: Conditional INFerior to Zero Float}{b}{c}{d}{e}{f}{01000000010010010000111111010000}
\ISA{INFZF: Conditional INFerior to Zero Float}{INFZF}{c}{d}{e}{f}{01000000010010010000111111010000}

\ISA{INFOEZF: Conditional INFerior Or Equal to Zero Float}{b}{c}{d}{e}{f}{01000000010010010000111111010000}
\ISA{INFOEZF: Conditional INFerior Or Equal to Zero Float}{INFOEZF}{c}{d}{e}{f}{01000000010010010000111111010000}

\ISA{EQZF: conditional is EQual Zero Float}{b}{c}{d}{e}{f}{01000000010010010000111111010000}
\ISA{EQZF: conditional is EQual Zero Float}{EQZF}{c}{d}{e}{f}{01000000010010010000111111010000}

\ISA{NEQZF: conditional Not Equal to Zero Float}{b}{c}{d}{e}{f}{01000000010010010000111111010000}
\ISA{NEQZF: conditional Not Equal to Zero Float}{NEQZF}{c}{d}{e}{f}{01000000010010010000111111010000}

\ISA{SUPOEZF: conditional SUPerior Or Equal to Zero Float}{b}{c}{d}{e}{f}{01000000010010010000111111010000}
\ISA{SUPOEZF: conditional SUPerior Or Equal to Zero Float}{SUPOEZF}{c}{d}{e}{f}{01000000010010010000111111010000}

\ISA{SUPZF: conditional SUPerior to Zero Float}{b}{c}{d}{e}{f}{01000000010010010000111111010000}
\ISA{SUPZF: conditional SUPerior to Zero Float}{SUPZF}{c}{d}{e}{f}{01000000010010010000111111010000}

\ISA{ADD: ADDition}{b}{c}{d}{e}{f}{11000010000000001}
\ISA{ADD: ADDition}{ADD}{c}{d}{e}{f}{11000010000000001}

\ISA{SUB: SUBstraction}{b}{c}{d}{e}{f}{11000010000000001}
\ISA{SUB: SUBstraction}{SUB}{c}{d}{e}{f}{11000010000000001}

\ISA{MUL: MULtiplication}{b}{c}{d}{e}{f}{11000010000000010}
\ISA{MUL: MULtiplication}{MUL}{c}{d}{e}{f}{11000010000000010}

\ISA{DIV: DIVision}{b}{c}{d}{e}{f}{11000010000000011}
\ISA{DIV: DIVision}{DIV}{c}{d}{e}{f}{11000010000000011}

\ISA{MOD: MODulo}{b}{c}{d}{e}{f}{11000010000000100}
\ISA{MOD: MODulo}{MOD}{c}{d}{e}{f}{11000010000000100}

\ISA{AND: logical AND}{b}{c}{d}{e}{f}{11000010000000101}
\ISA{AND: logical AND}{AND}{c}{d}{e}{f}{11000010000000101}

\ISA{OR: logical OR}{b}{c}{d}{e}{f}{11000010000000110}
\ISA{OR: logical OR}{OR}{c}{d}{e}{f}{11000010000000110}

\ISA{XOR: logical eXclusive OR}{b}{c}{d}{e}{f}{11000010000000111}
\ISA{XOR: logical eXclusive OR}{XOR}{c}{d}{e}{f}{11000010000000111}

\ISA{SLL: Shift Logical Left}{b}{c}{d}{e}{f}{11000010000001000}
\ISA{SLL: Shift Logical Left}{SLL}{c}{d}{e}{f}{11000010000001000}

\ISA{SRA: Shift Right Arithmetic}{b}{c}{d}{e}{f}{11000010000001001}
\ISA{SRA: Shift Right Arithmetic}{SRA}{c}{d}{e}{f}{11000010000001001}

\ISA{NEQZV: conditional Not EQual to Zero with stack Values}{b}{c}{d}{e}{f}{1100001000001010}
\ISA{NEQZV: conditional Not EQual to Zero with stack Values}{NEQZV}{c}{d}{e}{f}{1100001000001010}

\ISA{EQZV: conditional EQual to Zero with stack Values}{b}{c}{d}{e}{f}{11000010000001011}
\ISA{EQZV: conditional EQual to Zero with stack Values}{EQZV}{c}{d}{e}{f}{11000010000001011}

\ISA{ADDF: ADDition with Float values}{b}{c}{d}{e}{f}{11000010000000000}
\ISA{ADDF: ADDition with Float values}{ADDF}{Retrieves the last 2 values pushed on
to the stack and apply an addition onto them, pushing back the result to the
stack.}{d}{e}{This function exclusively deals with floating numbers}{11000010000000000}

\ISA{SUBF: SUBstraction with Float values}{b}{c}{d}{e}{f}{11000010000000001}
\ISA{SUBF: SUBstraction with Float values}{SUBF}{Retrieves the last 2 values pushed on
to the stack and apply a substraction onto them, pushing back the result to the
stack.}{}{}{This function exclusively deals with floating numbers}{11000010000000001}

\ISA{MULF: MULtiplication with Float values}{b}{c}{d}{e}{f}{11000010000000010}
\ISA{MULF: MULtiplication with Float values}{MULF}{Retrieves the last 2 values pushed on
to the stack and apply a multiplication onto them, pushing back the result to the
stack.}{}{}{This function exclusively deals with floating numbers}{11000010000000010}

\ISA{DIVF: DIVision with Float values}{b}{c}{d}{e}{f}{11000010000000011}
\ISA{DIVF: DIVision with Float values}{DIVF}{Retrieves the last 2 values pushed on
to the stack and apply a division onto them, pushing back the result to the
stack.}{}{}{This function exclusively deals with floating numbers}{11000010000000011}

\ISA{MODF: MODulo with Float values}{b}{c}{d}{e}{f}{11000010000000100}
\ISA{MODF: MODulo with Float values}{MODF}{Retrieves the last 2 values pushed on
to the stack and apply a modulo onto them, pushing back the result to the
stack.}{}{}{This function exclusively deals with floating numbers}{11000010000000100}

\ISA{JMP: JuMP}{b}{c}{d}{e}{f}{TODO}

\ISA{EXIT: EXIT}{r=exit value}{c}{d}{e}{f}{100100000000000r}
\ISA{EXIT: EXIT}{EXIT ri}{Completely stops the execution flow of the AI Parser
with return code ri}{}{}{}{100100000000000r}

% bitfields below are all verified
\ISA{RET: RETurn}{b}{c}{d}{e}{f}{1000100100000000}
\ISA{RET: RETurn}{RET}{Stops the execution flow and return back to the last
saved function call}{}{}{}{1000100100000000}

\ISA{PUSHCA: PUSH CAched value}{b}{c}{d}{e}{f}{1100100100000000}
\ISA{PUSH.CA: PUSH CAched value}{PUSHCA}{c}{d}{e}{f}{1100100100000000}

\ISA{PUSHC: PUSH Copy}{b}{c}{d}{e}{f}{0100100100000001}
\ISA{PUSH.C: PUSH Copy}{PUSHC}{c}{d}{e}{f}{0100100100000001}

\ISA{SIN: SINus}{b}{c}{d}{e}{f}{1000100100000001}
\ISA{SIN: SINus}{SIN}{Retrieves the latest value pushed to the stack and apply a
sinus onto it, pushing it to the stack}{}{}{Radians are used as input.
Radians used are modulo $[\pi-2\pi]$}{1000100100000001}

\ISA{COS: COSinus}{Retrieves the latest value pushed to the stack and apply a
cosinus onto it, pushing it to the stack}{None}{d}{e}{Radians are used as input.
Radians used are modulo pi-2pi}{1100100100000001}
\ISA{COS: COSinus}{COS}{Retrieves the latest value pushed to the stack and apply a
cosinus onto it, pushing it to the stack}{}{}{Radians are used as input.
Radians used are modulo $[\pi-2\pi]$}{1100100100000001}

\ISA{DEGR: DEGrees to Radians}{Retrieves the last element pushed to the stack
and converts it to radians, pushing it to the stack}{None}{d}{e}{Radians used
are modulo pi-2pi}{0000100100000010}
\ISA{DEGR: DEGrees to Radians}{DEGR}{Retrieves the last element pushed to the stack
and converts it to radians, pushing it to the stack}{}{}{Radians used
are modulo $[\pi-2\pi]$}{0000100100000010}

\ISA{RADD: RADians to Degrees}{RADD}{Retrieves the last element pushed to the
stack and converts it to degrees, pushing it to the stack}{None}{e}{Radians used are modulo pi-2pi}{0100100100000010}
stack and converts it to degrees, pushing it to the stack}{}{}
{Radians used are modulo $[\pi-2\pi]$}{0100100100000010}

\ISA{SYSCALL: SYStem CALL}{b}{c}{d}{e}{f}{TODO}

@@ -255,4 +284,26 @@ None of them are currently documented, they are available at address 0x0034dd00
of SLPM\_666.75, and there is 738 elements if I'm not mistaken. Either try to
guess their arguments


\Chapter{Known issues}
As this is very much a work-in-progress project, much of the ISA has yet to
stabilize before getting a stable documentation and some issues still exist. You
will find below some of those.

\section{Syscall function pointers doesn't get recognized}

Sometimes, a syscall will take function pointers as arguments using data. KH2AI
has an opcode reserved for pushing to the stack pointers but the data opcode is
preferred due to the syscall treating the address, and as such being able to
recognize if an address is NULL, while the parser would relocate directly the
address and make it impossible for the syscall to know if a pointer was NULL.
Unfortunately for us, this currently means that it is impossible for ghidra to
distinguish some function pointers from data, and will be reworked in a further
release.
It is currently encouraged to create the functions yourself inside ghidra to
continue analysis. The address relocation formula is $16+(addr<<1)$ . This will
be fixed in a further release by creating a new analysis plugin, but is
currently out-of-scope for the initial release.


\end{document}

+ 6
- 0
data/sleighArgs.txt View File

@@ -0,0 +1,6 @@
# Add sleigh compiler options to this file (one per line) which will
# be used when compiling each language within this module.
# All options should start with a '-' character.
#
# IMPORTANT: The -a option should NOT be specified
#

+ 5
- 0
extension.properties View File

@@ -0,0 +1,5 @@
name=@extname@
description=A processor for Kingdom Hearts 2 AI.
author=Gauvain "GovanifY" Roussel-Tarbouriech <gauvain@govanify.com>
createdOn=
version=@extversion@

BIN
ghidra-kh2ai.zip View File


+ 8
- 0
main.workflow View File

@@ -0,0 +1,8 @@
workflow "Build Extension" {
on = "push"
resolves = ["buildExtension"]
}

action "buildExtension" {
uses = "govanify/ghidra-buildExtension@master"
}

+ 4
- 15
notes.txt View File

@@ -69,22 +69,11 @@ t3[right]=tmp-4

=============================================================================================================
TODO:
0x0: reverse unknowns + fix oush label vs val
0x1: is that a pop? also args
0x2: to reverse
0x4: to reverse
0x0: reverse unknowns + fix push label vs val
0x1: pop, reverse unknowns(get_arg)
0x2: to reverse(FUN_002fdd68)
0x4: to reverse(FUN_002fdd68)
0xB: to reverse
-----
0x8: figure out first arg of jmp, offset?
0x7: figure out args and diff between 3 jmp

==============
SOMETHING IS UNALIGNED IN ONE OF THOSE OPCODES!!!!:
push3_unk0,push2_unk0,push(not label), unk2,unk4,rela,jmp7_unk{1_2}


push3_unk0: ext
push2_unk0: to check
unk2: most likely not
unk4: most likely not
rela:

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

@@ -0,0 +1,57 @@
<?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
<tocdef>
-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.

<tocref>
-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.
-->


<tocroot>
<!-- 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" />
</tocref>
-->
</tocroot>

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

@@ -0,0 +1,58 @@
/* ###
* 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.
*/
/*
WARNING!
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; }

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

@@ -0,0 +1,23 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<HTML>
<HEAD>
<META name="generator" content=
"HTML Tidy for Java (vers. 2009-12-01), see jtidy.sourceforge.net">
<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">
</HEAD>

<BODY>
<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>
</BODY>
</HTML>

+ 78
- 0
src/main/java/ghidra_kh2ai/ghidra_kh2aiAnalyzer.java View File

@@ -0,0 +1,78 @@
/* ###
* 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_kh2ai;

import ghidra.app.services.AbstractAnalyzer;
import ghidra.app.services.AnalyzerType;
import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.Options;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.listing.Program;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import ghidra.program.model.lang.Processor;
/**
* TODO: Provide class-level documentation that describes what this analyzer does.
*/
public class ghidra_kh2aiAnalyzer extends AbstractAnalyzer {

public ghidra_kh2aiAnalyzer() {

// 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);
}

@Override
public boolean getDefaultEnablement(Program program) {

// TODO: Return true if analyzer should be enabled by default

return true;
}

@Override
public boolean canAnalyze(Program program) {

boolean canAnalyze = program.getLanguage().getProcessor().equals(
Processor.findOrPossiblyCreateProcessor("kh2_ai"));

if (!canAnalyze) {
return false;
}
return false;
}

@Override
public void registerOptions(Options options, Program program) {

// TODO: If this analyzer has custom options, register them here

options.registerOption("Option name goes here", false, null,
"Option description goes here");
}

@Override
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException {

// TODO: Perform analysis when things get added to the 'program'. Return true if the
// analysis succeeded.

return false;
}
}

+ 105
- 0
src/main/java/ghidra_kh2ai/ghidra_kh2aiLoader.java View File

@@ -0,0 +1,105 @@
/* ###
* 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_kh2ai;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.*;

import ghidra.app.util.Option;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.importer.MessageLog;
import ghidra.app.util.opinion.AbstractLibrarySupportLoader;
import ghidra.app.util.opinion.LoadSpec;
import ghidra.app.util.opinion.QueryResult;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.listing.Program;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import ghidra.program.model.lang.LanguageCompilerSpecPair;

/**
* TODO: Provide class-level documentation that describes what this loader does.
*/
public class ghidra_kh2aiLoader extends AbstractLibrarySupportLoader {

@Override
public String getName() {

// TODO: Name the loader. This name must match the name of the loader in the .opinion
// files.

return "KH2 AI";
}

public boolean checkUTF8(byte[] barr){

CharsetDecoder decoder = Charset.forName("ASCII").newDecoder();
ByteBuffer buf = ByteBuffer.wrap(barr);

try {
decoder.decode(buf);

}
catch(CharacterCodingException e){
return false;
}

return true;
}

@Override
public Collection<LoadSpec> findSupportedLoadSpecs(ByteProvider provider) throws IOException {
List<LoadSpec> loadSpecs = new ArrayList<>();

// TODO: have a better check than this
if (checkUTF8(provider.readBytes(0,0x10)) == true) {
loadSpecs.add(new LoadSpec(this, 0,
new LanguageCompilerSpecPair("kh2_ai:le:32:default", "default"), true));
}
return loadSpecs;
}

@Override
protected void load(ByteProvider provider, LoadSpec loadSpec, List<Option> options,
Program program, TaskMonitor monitor, MessageLog log)
throws CancelledException, IOException {
// TODO: Load the bytes from 'provider' into the 'program'.
}

@Override
public List<Option> getDefaultOptions(ByteProvider provider, LoadSpec loadSpec,
DomainObject domainObject, boolean isLoadIntoProgram) {
List<Option> list =
super.getDefaultOptions(provider, loadSpec, domainObject, isLoadIntoProgram);

//list.add(new Option("Option name goes here", "Default option value goes here"));

return list;
}

@Override
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options, Program program) {

// If this loader has custom options, validate them here. Not all options require
// validation.

return super.validateOptions(provider, loadSpec, options, program);
}
}

+ 2
- 0
src/main/resources/images/README.txt View File

@@ -0,0 +1,2 @@
The "src/resources/images" directory is intended to hold all image/icon files used by
this module.

+ 2
- 0
src/test/java/README.test.txt View File

@@ -0,0 +1,2 @@
The "test" directory is intended to hold unit test cases. The package structure within
this folder should correspond to that found in the "src" folder.

Loading…
Cancel
Save