/Ghidra/application.properties
15 | // for the correction version of Gradle to use for the Ghidra installation you specify.
16 |
17 | //----------------------START "DO NOT MODIFY" SECTION------------------------------
18 | def ghidraInstallDir
19 |
20 | if (System.env.GHIDRA_INSTALL_DIR) {
21 | ghidraInstallDir = System.env.GHIDRA_INSTALL_DIR
22 | }
23 | else if (project.hasProperty("GHIDRA_INSTALL_DIR")) {
24 | ghidraInstallDir = project.getProperty("GHIDRA_INSTALL_DIR")
25 | }
26 |
27 | if (ghidraInstallDir) {
28 | apply from: new File(ghidraInstallDir).getCanonicalPath() + "/support/buildExtension.gradle"
29 | }
30 | else {
31 | throw new GradleException("GHIDRA_INSTALL_DIR is not defined!")
32 | }
33 | //----------------------END "DO NOT MODIFY" SECTION-------------------------------
34 |
--------------------------------------------------------------------------------
/XEXLoaderWV/data/README.txt:
--------------------------------------------------------------------------------
1 | The "data" directory is intended to hold data files that will be used by this module and will
2 | not end up in the .jar file, but will be present in the zip or tar file. Typically, data
3 | files are placed here rather than in the resources directory if the user may need to edit them.
4 |
5 | An optional data/languages directory can exist for the purpose of containing various Sleigh language
6 | specification files and importer opinion files.
7 |
8 | The data/build.xml is used for building the contents of the data/languages directory.
9 |
10 | The skel language definition has been commented-out within the skel.ldefs file so that the
11 | skeleton language does not show-up within Ghidra.
12 |
13 | See the Sleigh language documentation (docs/languages/sleigh.htm or sleigh.pdf) for details
14 | on Sleigh language specification syntax.
15 |
16 |
--------------------------------------------------------------------------------
/XEXLoaderWV/data/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/XEXLoaderWV/data/languages/skel.cspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/XEXLoaderWV/data/languages/skel.ldefs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
20 |
21 |
--------------------------------------------------------------------------------
/XEXLoaderWV/data/languages/skel.opinion:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
--------------------------------------------------------------------------------
/XEXLoaderWV/data/languages/skel.pspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/XEXLoaderWV/data/languages/skel.sinc:
--------------------------------------------------------------------------------
1 | # sleigh include file for Skeleton language instructions
2 |
3 | define token opbyte (8)
4 | op0_8 = (0,7)
5 | op6_2 = (6,7)
6 |
7 | dRegPair4_2 = (4,5)
8 | pRegPair4_2 = (4,5)
9 | sRegPair4_2 = (4,5)
10 | qRegPair4_2 = (4,5)
11 | qRegPair4_2a = (4,5)
12 | qRegPair4_2b = (4,5)
13 | rRegPair4_2 = (4,5)
14 |
15 | reg3_3 = (3,5)
16 | bits3_3 = (3,5)
17 |
18 | bits0_4 = (0,3)
19 |
20 | reg0_3 = (0,2)
21 | bits0_3 = (0,2)
22 | ;
23 |
24 | define token data8 (8)
25 | imm8 = (0,7)
26 | sign8 = (7,7)
27 | simm8 = (0,7) signed
28 | ;
29 |
30 | define token data16 (16)
31 | timm4 = (12,15)
32 | imm16 = (0,15)
33 | sign16 = (15,15)
34 | simm16 = (0,15) signed
35 | ;
36 |
37 | attach variables [ reg0_3 reg3_3 ] [ B C D E H L _ A ];
38 |
39 | attach variables [ sRegPair4_2 dRegPair4_2 ] [ BC DE HL SP ];
40 |
41 | attach variables [ qRegPair4_2 ] [ BC DE HL AF ];
42 | attach variables [ qRegPair4_2a ] [ B D H A ];
43 | attach variables [ qRegPair4_2b ] [ C E L F ];
44 |
45 | attach variables [ pRegPair4_2 ] [ BC DE IX SP ];
46 | attach variables [ rRegPair4_2 ] [ BC DE IY SP ];
47 |
48 | ################################################################
49 | # Macros
50 | ################################################################
51 |
52 | macro setResultFlags(result) {
53 | $(Z_flag) = (result == 0);
54 | $(S_flag) = (result s< 0);
55 | }
56 |
57 | macro setAddCarryFlags(op1,op2) {
58 | $(C_flag) = (carry(op1,zext($(C_flag))) || carry(op2,op1 + zext($(C_flag))));
59 | }
60 |
61 | macro setAddFlags(op1,op2) {
62 | $(C_flag) = carry(op1,op2);
63 | }
64 |
65 | macro setSubtractCarryFlags(op1,op2) {
66 | notC = ~$(C_flag);
67 | $(C_flag) = ((op1 < sext(notC)) || (op2 < (op1 - sext(notC))));
68 | }
69 |
70 | macro setSubtractFlags(op1,op2) {
71 | $(C_flag) = (op1 < op2);
72 | }
73 |
74 | macro push16(val16) {
75 | SP = SP - 2;
76 | *:2 SP = val16;
77 | }
78 |
79 | macro pop16(ret16) {
80 | ret16 = *:2 SP;
81 | SP = SP + 2;
82 | }
83 |
84 | macro push8(val8) {
85 | SP = SP - 1;
86 | ptr:2 = SP;
87 | *:1 ptr = val8;
88 | }
89 |
90 | macro pop8(ret8) {
91 | ptr:2 = SP;
92 | ret8 = *:1 ptr;
93 | SP = SP + 1;
94 | }
95 |
96 | ################################################################
97 |
98 | ixMem8: (IX+simm8) is IX & simm8 { ptr:2 = IX + simm8; export *:1 ptr; }
99 | ixMem8: (IX-val) is IX & simm8 & sign8=1 [ val = -simm8; ] { ptr:2 = IX + simm8; export *:1 ptr; }
100 |
101 | iyMem8: (IY+simm8) is IY & simm8 { ptr:2 = IY + simm8; export *:1 ptr; }
102 | iyMem8: (IY-val) is IY & simm8 & sign8=1 [ val = -simm8; ] { ptr:2 = IY + simm8; export *:1 ptr; }
103 |
104 | Addr16: imm16 is imm16 { export *:1 imm16; }
105 |
106 | Mem16: (imm16) is imm16 { export *:2 imm16; }
107 |
108 | RelAddr8: loc is simm8 [ loc = inst_next + simm8; ] { export *:1 loc; }
109 |
110 | cc: "NZ" is bits3_3=0x0 { c:1 = ($(Z_flag) == 0); export c; }
111 | cc: "Z" is bits3_3=0x1 { c:1 = $(Z_flag); export c; }
112 | cc: "NC" is bits3_3=0x2 { c:1 = ($(C_flag) == 0); export c; }
113 | cc: "C" is bits3_3=0x3 { c:1 = $(C_flag); export c; }
114 | cc: "PO" is bits3_3=0x4 { c:1 = ($(PV_flag) == 0); export c; }
115 | cc: "PE" is bits3_3=0x5 { c:1 = $(PV_flag); export c; }
116 | cc: "P" is bits3_3=0x6 { c:1 = ($(S_flag) == 0); export c; }
117 | cc: "M" is bits3_3=0x7 { c:1 = $(S_flag); export c; }
118 |
119 | cc2: "NZ" is bits3_3=0x4 { c:1 = ($(Z_flag) == 0); export c; }
120 | cc2: "Z" is bits3_3=0x5 { c:1 = $(Z_flag); export c; }
121 | cc2: "NC" is bits3_3=0x6 { c:1 = ($(C_flag) == 0); export c; }
122 | cc2: "C" is bits3_3=0x7 { c:1 = $(C_flag); export c; }
123 |
124 | ################################################################
125 |
126 |
127 | :LD IX,Mem16 is op0_8=0xdd & IX; op0_8=0x2a; Mem16 {
128 | IX = Mem16;
129 | }
130 |
131 | :LD IY,Mem16 is op0_8=0xfd & IY; op0_8=0x2a; Mem16 {
132 | IY = Mem16;
133 | }
134 |
135 | :LD Mem16,HL is op0_8=0x22 & HL; Mem16 {
136 | Mem16 = HL;
137 | }
138 |
139 | :LD Mem16,dRegPair4_2 is op0_8=0xed; op6_2=0x1 & dRegPair4_2 & bits0_4=0x3; Mem16 {
140 | Mem16 = dRegPair4_2;
141 | }
142 |
143 | :LD Mem16,IX is op0_8=0xdd & IX; op0_8=0x22; Mem16 {
144 | Mem16 = IX;
145 | }
146 |
147 | :LD Mem16,IY is op0_8=0xfd & IY; op0_8=0x22; Mem16 {
148 | Mem16 = IY;
149 | }
150 |
151 | :NEG is op0_8=0xed; op0_8=0x44 {
152 | $(PV_flag) = (A == 0x80);
153 | $(C_flag) = (A != 0);
154 | A = -A;
155 | setResultFlags(A);
156 | }
157 |
158 | :SET bits3_3,ixMem8 is op0_8=0xdd; op0_8=0xcb; ixMem8; op6_2=0x3 & bits3_3 & bits0_3=0x6 {
159 | mask:1 = (1 << bits3_3);
160 | val:1 = ixMem8;
161 | ixMem8 = val | mask;
162 | }
163 |
164 | :SET bits3_3,iyMem8 is op0_8=0xfd; op0_8=0xcb; iyMem8; op6_2=0x3 & bits3_3 & bits0_3=0x6 {
165 | mask:1 = (1 << bits3_3);
166 | val:1 = iyMem8;
167 | iyMem8 = val | mask;
168 | }
169 |
170 | :JP Addr16 is op0_8=0xc3; Addr16 {
171 | goto Addr16;
172 | }
173 |
174 | :JP cc,Addr16 is op6_2=0x3 & cc & bits0_3=0x2; Addr16 {
175 | if (!cc) goto Addr16;
176 | }
177 |
178 | :JR RelAddr8 is op0_8=0x18; RelAddr8 {
179 | goto RelAddr8;
180 | }
181 |
182 | :JR cc2,RelAddr8 is op6_2=0x0 & cc2 & bits0_3=0x0; RelAddr8 {
183 | if (cc2) goto RelAddr8;
184 | }
185 |
186 | :JP (HL) is op0_8=0xe9 & HL {
187 | goto [HL];
188 | }
189 |
190 | :JP (IX) is op0_8=0xdd & IX; op0_8=0xe9 {
191 | goto [IX];
192 | }
193 |
194 | :JP (IY) is op0_8=0xfd & IY; op0_8=0xe9 {
195 | goto [IY];
196 | }
197 |
198 | :CALL Addr16 is op0_8=0xcd; Addr16 {
199 | push16(&:2 inst_next);
200 | call Addr16;
201 | }
202 |
203 | :CALL cc,Addr16 is op6_2=0x3 & cc & bits0_3=0x4; Addr16 {
204 | if (!cc) goto inst_next;
205 | push16(&:2 inst_next);
206 | call Addr16;
207 | }
208 |
209 | :RET is op0_8=0xc9 {
210 | pop16(PC);
211 | ptr:2 = zext(PC);
212 | return [ptr];
213 | }
214 |
215 | :RET cc is op6_2=0x3 & cc & bits0_3=0x0 {
216 | if (!cc) goto inst_next;
217 | pop16(PC);
218 | ptr:2 = zext(PC);
219 | return [ptr];
220 | }
221 |
--------------------------------------------------------------------------------
/XEXLoaderWV/data/languages/skel.slaspec:
--------------------------------------------------------------------------------
1 | # sleigh specification file for Skeleton Processor
2 | # >> see docs/languages/sleigh.htm or sleigh.pdf for Sleigh syntax
3 | # Other language modules (see Ghidra/Processors) may provide better examples
4 | # when creating a new language module.
5 |
6 | define endian=little;
7 | define alignment=1;
8 |
9 | define space ram type=ram_space size=2 default;
10 |
11 | define space io type=ram_space size=2;
12 | define space register type=register_space size=1;
13 |
14 | define register offset=0x00 size=1 [ F A C B E D L H I R ];
15 | define register offset=0x00 size=2 [ AF BC DE HL ];
16 | define register offset=0x20 size=1 [ A_ F_ B_ C_ D_ E_ H_ L_ ]; # Alternate registers
17 | define register offset=0x20 size=2 [ AF_ BC_ DE_ HL_ ]; # Alternate registers
18 |
19 | define register offset=0x40 size=2 [ _ PC SP IX IY ];
20 |
21 | define register offset=0x50 size=1 [ rCBAR rCBR rBBR ];
22 |
23 | # Define context bits (if defined, size must be multiple of 4-bytes)
24 | define register offset=0xf0 size=4 contextreg;
25 |
26 | define context contextreg
27 | assume8bitIOSpace = (0,0)
28 | ;
29 |
30 | # Flag bits (?? manual is very confusing - could be typos!)
31 | @define C_flag "F[0,1]" # C: Carry
32 | @define N_flag "F[1,1]" # N: Add/Subtract
33 | @define PV_flag "F[2,1]" # PV: Parity/Overflow
34 | @define H_flag "F[4,1]" # H: Half Carry
35 | @define Z_flag "F[6,1]" # Z: Zero
36 | @define S_flag "F[7,1]" # S: Sign
37 |
38 | # Include contents of skel.sinc file
39 | @include "skel.sinc"
40 |
--------------------------------------------------------------------------------
/XEXLoaderWV/data/sleighArgs.txt:
--------------------------------------------------------------------------------
1 | # Add sleigh compiler options to this file (one per line) which will
2 | # be used when compiling each language within this module.
3 | # All options should start with a '-' character.
4 | #
5 | # IMPORTANT: The -a option should NOT be specified
6 | #
--------------------------------------------------------------------------------
/XEXLoaderWV/extension.properties:
--------------------------------------------------------------------------------
1 | name=@extname@
2 | description=The extension description can be customized by editing the extension.properties file.
3 | author=
4 | createdOn=
5 | version=@extversion@
6 |
--------------------------------------------------------------------------------
/XEXLoaderWV/ghidra_scripts/README.txt:
--------------------------------------------------------------------------------
1 | Java source directory to hold module-specific Ghidra scripts.
2 |
--------------------------------------------------------------------------------
/XEXLoaderWV/lib/README.txt:
--------------------------------------------------------------------------------
1 | The "lib" directory is intended to hold Jar files which this module
2 | is dependent upon. This directory may be eliminated from a specific
3 | module if no other Jar files are needed.
4 |
--------------------------------------------------------------------------------
/XEXLoaderWV/os/linux64/README.txt:
--------------------------------------------------------------------------------
1 | The "os/linux64" directory is intended to hold Linux native binaries
2 | which this module is dependent upon. This directory may be eliminated for a specific
3 | module if native binaries are not provided for the corresponding platform.
4 |
--------------------------------------------------------------------------------
/XEXLoaderWV/os/osx64/README.txt:
--------------------------------------------------------------------------------
1 | The "os/osx64" directory is intended to hold macOS (OS X) native binaries
2 | which this module is dependent upon. This directory may be eliminated for a specific
3 | module if native binaries are not provided for the corresponding platform.
4 |
--------------------------------------------------------------------------------
/XEXLoaderWV/os/win64/README.txt:
--------------------------------------------------------------------------------
1 | The "os/win64" directory is intended to hold MS Windows native binaries (.exe)
2 | which this module is dependent upon. This directory may be eliminated for a specific
3 | module if native binaries are not provided for the corresponding platform.
4 |
--------------------------------------------------------------------------------
/XEXLoaderWV/src/main/help/help/TOC_Source.xml:
--------------------------------------------------------------------------------
1 |
2 |
49 |
50 |
51 |
52 |
57 |
58 |
--------------------------------------------------------------------------------
/XEXLoaderWV/src/main/help/help/shared/Frontpage.css:
--------------------------------------------------------------------------------
1 | /* ###
2 | * IP: GHIDRA
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | /*
17 | WARNING!
18 | This file is copied to all help directories. If you change this file, you must copy it
19 | to each src/main/help/help/shared directory.
20 |
21 |
22 | Java Help Note: JavaHelp does not accept sizes (like in 'margin-top') in anything but
23 | px (pixel) or with no type marking.
24 |
25 | */
26 |
27 | body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 10px; } /* some padding to improve readability */
28 | li { font-family:times new roman; font-size:14pt; }
29 | h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
30 | h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
31 | h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; }
32 | h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
33 |
34 | /*
35 | P tag code. Most of the help files nest P tags inside of blockquote tags (the was the
36 | way it had been done in the beginning). The net effect is that the text is indented. In
37 | modern HTML we would use CSS to do this. We need to support the Ghidra P tags, nested in
38 | blockquote tags, as well as naked P tags. The following two lines accomplish this. Note
39 | that the 'blockquote p' definition will inherit from the first 'p' definition.
40 | */
41 | p { margin-left: 40px; font-family:times new roman; font-size:14pt; }
42 | blockquote p { margin-left: 10px; }
43 |
44 | p.providedbyplugin { color:#7f7f7f; margin-left: 10px; font-size:14pt; margin-top:100px }
45 | p.ProvidedByPlugin { color:#7f7f7f; margin-left: 10px; font-size:14pt; margin-top:100px }
46 | p.relatedtopic { color:#800080; margin-left: 10px; font-size:14pt; }
47 | p.RelatedTopic { color:#800080; margin-left: 10px; font-size:14pt; }
48 |
49 | /*
50 | We wish for a tables to have space between it and the preceding element, so that text
51 | is not too close to the top of the table. Also, nest the table a bit so that it is clear
52 | the table relates to the preceding text.
53 | */
54 | table { margin-left: 20px; margin-top: 10px; width: 80%;}
55 | td { font-family:times new roman; font-size:14pt; vertical-align: top; }
56 | th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
57 |
58 | code { color: black; font-family: courier new; font-size: 14pt; }
59 |
--------------------------------------------------------------------------------
/XEXLoaderWV/src/main/help/help/topics/xexloaderwv/help.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
7 |
8 |
9 |
10 |
11 |
12 | Skeleton Help File for a Module
13 |
14 |
15 |
16 |
17 | Skeleton Help File for a Module
18 |
19 | This is a simple skeleton help topic. For a better description of what should and should not
20 | go in here, see the "sample" Ghidra extension in the Extensions/Ghidra directory, or see your
21 | favorite help topic. In general, language modules do not have their own help topics.
22 |
23 |
24 |
--------------------------------------------------------------------------------
/XEXLoaderWV/src/main/java/xexloaderwv/BaseFileFormat.java:
--------------------------------------------------------------------------------
1 | package xexloaderwv;
2 |
3 | import java.util.ArrayList;
4 |
5 | import ghidra.app.util.bin.BinaryReader;
6 | import ghidra.app.util.bin.ByteArrayProvider;
7 |
8 | public class BaseFileFormat {
9 | public class BasicCompression
10 | {
11 | public int dataSize;
12 | public int zeroSize;
13 | }
14 |
15 | public class NormalCompression
16 | {
17 | public int windowSize;
18 | public int blockSize;
19 | public byte[] blockHash;
20 | }
21 |
22 | public short encryption;
23 | public short compression;
24 | public ArrayList basic;
25 | public NormalCompression normal;
26 |
27 | public BaseFileFormat(byte[] data) throws Exception
28 | {
29 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), false);
30 | encryption = b.readShort(4);
31 | compression = b.readShort(6);
32 | switch(compression)
33 | {
34 | case 1:
35 | basic = new ArrayList();
36 | int count = (data.length / 8) - 1;
37 | for(int i = 0; i < count; i++)
38 | {
39 | BasicCompression bc = new BasicCompression();
40 | bc.dataSize = b.readInt(0x8 + i * 8);
41 | bc.zeroSize = b.readInt(0xC + i * 8);
42 | basic.add(bc);
43 | }
44 | break;
45 | case 2:
46 | case 3:
47 | normal = new NormalCompression();
48 | normal.windowSize = b.readInt(0x8);
49 | normal.blockSize = b.readInt(0xC);
50 | normal.blockHash = b.readByteArray(0x10, 20);
51 | break;
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/XEXLoaderWV/src/main/java/xexloaderwv/DOSHeader.java:
--------------------------------------------------------------------------------
1 | package xexloaderwv;
2 |
3 | import ghidra.app.util.bin.BinaryReader;
4 | import ghidra.app.util.bin.ByteArrayProvider;
5 |
6 | public class DOSHeader {
7 | public short e_magic;
8 | public short e_cblp;
9 | public short e_cp;
10 | public short e_crlc;
11 | public short e_cparhdr;
12 | public short e_minalloc;
13 | public short e_maxalloc;
14 | public short e_ss;
15 | public short e_sp;
16 | public short e_csum;
17 | public short e_ip;
18 | public short e_cs;
19 | public short e_lfarlc;
20 | public short e_ovno;
21 | public short[] e_res = new short[4];
22 | public short e_oemid;
23 | public short e_oeminfo;
24 | public short[] e_res2 = new short[10];
25 | public int e_lfanew;
26 |
27 | public DOSHeader (byte[] data) throws Exception
28 | {
29 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), true);
30 | e_magic = b.readShort(0);
31 | e_cblp = b.readShort(2);
32 | e_cp = b.readShort(4);
33 | e_crlc = b.readShort(6);
34 | e_cparhdr = b.readShort(8);
35 | e_minalloc = b.readShort(10);
36 | e_maxalloc = b.readShort(12);
37 | e_ss = b.readShort(14);
38 | e_sp = b.readShort(16);
39 | e_csum = b.readShort(18);
40 | e_ip = b.readShort(20);
41 | e_cs = b.readShort(22);
42 | e_lfarlc = b.readShort(24);
43 | e_ovno = b.readShort(26);
44 | for(int i = 0; i < 4; i++)
45 | e_res[i] = b.readShort(28 + i * 2);
46 | e_oemid = b.readShort(36);
47 | e_oeminfo = b.readShort(38);
48 | for(int i = 0; i < 10; i++)
49 | e_res2[i] = b.readShort(40 + i * 2);
50 | e_lfanew = b.readInt(60);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/XEXLoaderWV/src/main/java/xexloaderwv/Helper.java:
--------------------------------------------------------------------------------
1 | package xexloaderwv;
2 |
3 | import java.nio.ByteBuffer;
4 |
5 | import javax.crypto.Cipher;
6 | import javax.crypto.spec.IvParameterSpec;
7 | import javax.crypto.spec.SecretKeySpec;
8 |
9 | import ghidra.app.util.bin.BinaryReader;
10 |
11 | public class Helper {
12 | public static byte[] hexStringToByteArray(String s) {
13 | int len = s.length();
14 | byte[] data = new byte[len / 2];
15 | for (int i = 0; i < len; i += 2) {
16 | data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
17 | + Character.digit(s.charAt(i+1), 16));
18 | }
19 | return data;
20 | }
21 |
22 | public static byte[] AESDecrypt(byte[] key, byte[] data) throws Exception
23 | {
24 | Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
25 | SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
26 | IvParameterSpec iv = new IvParameterSpec(new byte[16]);
27 | cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
28 | return cipher.doFinal(data);
29 | }
30 |
31 | public static byte[] ReadArray(BinaryReader b, int pos, int len) throws Exception
32 | {
33 | byte[] result = new byte[len];
34 | for(int i = 0; i < len; i++)
35 | result[i] = b.readByte(pos + i);
36 | return result;
37 | }
38 |
39 | public static long forceU32(int input) throws Exception
40 | {
41 | byte[] bytes = ByteBuffer.allocate(4).putInt(input).array();
42 | long value =
43 | ((bytes[3] & 0xFF) << 0) |
44 | ((bytes[2] & 0xFF) << 8) |
45 | ((bytes[1] & 0xFF) << 16) |
46 | ((long) (bytes[0] & 0xFF) << 24);
47 | return value;
48 | }
49 |
50 | public static int forceU16(short input) throws Exception
51 | {
52 | byte[] bytes = ByteBuffer.allocate(2).putShort(input).array();
53 | int value = ((bytes[1] & 0xFF) << 0) | ((bytes[0] & 0xFF) << 8);
54 | return value;
55 | }
56 |
57 | public static long GetBits(long buff, int start, int count)
58 | {
59 | long result = buff >> start;
60 | result &= 0xFFFFFFFFl >> 32 - count;
61 | return result;
62 | }
63 |
64 | public static String ReadCString(BinaryReader b, long pos) throws Exception
65 | {
66 | StringBuilder sb = new StringBuilder();
67 | while(true)
68 | {
69 | int c = b.readUnsignedByte(pos++);
70 | if(c == 0)
71 | break;
72 | sb.append((char)c);
73 | }
74 | return sb.toString();
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/XEXLoaderWV/src/main/java/xexloaderwv/ImportFunction.java:
--------------------------------------------------------------------------------
1 | package xexloaderwv;
2 |
3 | public class ImportFunction {
4 | public int address;
5 | public int ordinal;
6 | public int thunk;
7 | }
8 |
--------------------------------------------------------------------------------
/XEXLoaderWV/src/main/java/xexloaderwv/ImportLibrary.java:
--------------------------------------------------------------------------------
1 | package xexloaderwv;
2 | import java.util.ArrayList;
3 |
4 | public class ImportLibrary {
5 | public String name;
6 | public ArrayList records = new ArrayList();
7 | public ArrayList functions = new ArrayList();
8 | }
9 |
--------------------------------------------------------------------------------
/XEXLoaderWV/src/main/java/xexloaderwv/LoadPdbTask.java:
--------------------------------------------------------------------------------
1 | package xexloaderwv;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.lang.reflect.InvocationTargetException;
6 |
7 | import ghidra.app.plugin.core.analysis.*;
8 | import ghidra.app.plugin.core.datamgr.archive.DuplicateIdException;
9 | import ghidra.app.services.DataTypeManagerService;
10 | import ghidra.app.util.bin.format.pdb.PdbException;
11 | import ghidra.app.util.bin.format.pdb.PdbParser;
12 | import ghidra.app.util.bin.format.pdb2.pdbreader.AbstractPdb;
13 | import ghidra.app.util.bin.format.pdb2.pdbreader.PdbReaderOptions;
14 | import ghidra.app.util.importer.MessageLog;
15 | import ghidra.app.util.pdb.pdbapplicator.*;
16 | import ghidra.framework.options.Options;
17 | import ghidra.program.model.address.AddressSetView;
18 | import ghidra.program.model.listing.Program;
19 | import ghidra.util.exception.CancelledException;
20 | import ghidra.util.task.*;
21 |
22 | class LoadPdbTask extends Task {
23 | private File pdbFile;
24 | private DataTypeManagerService service;
25 | private final Program program;
26 | private final boolean useMsDiaParser;
27 | private final PdbApplicatorControl control; // PDB Universal Parser only
28 | private String resultMessages;
29 | private Exception resultException;
30 |
31 | LoadPdbTask(Program program, File pdbFile, boolean useMsDiaParser, PdbApplicatorControl control,
32 | DataTypeManagerService service) {
33 | super("Load PDB", true, false, true, true);
34 | this.program = program;
35 | this.pdbFile = pdbFile;
36 | this.useMsDiaParser = useMsDiaParser;
37 | this.control = control;
38 | this.service = service;
39 | }
40 |
41 | @Override
42 | public void run(TaskMonitor monitor) {
43 |
44 | WrappingTaskMonitor wrappedMonitor = new WrappingTaskMonitor(monitor) {
45 | @Override
46 | public void initialize(long max) {
47 | // don't let called clients change our monitor type; we don't show progress
48 | }
49 | };
50 |
51 | MessageLog log = new MessageLog();
52 | AnalysisWorker worker = new AnalysisWorker() {
53 |
54 | @Override
55 | public String getWorkerName() {
56 | return "Load PDB";
57 | }
58 |
59 | @Override
60 | public boolean analysisWorkerCallback(Program currentProgram, Object workerContext,
61 | TaskMonitor currentMonitor) throws CancelledException {
62 |
63 | try {
64 | if (useMsDiaParser) {
65 | if (!parseWithMsDiaParser(log, wrappedMonitor)) {
66 | return false;
67 | }
68 | }
69 | else if (!parseWithNewParser(log, wrappedMonitor)) {
70 | return false;
71 | }
72 | analyzeSymbols(currentMonitor, log);
73 | }
74 | catch (IOException e) {
75 | log.appendMsg("PDB IO Error: " + e.getMessage());
76 | }
77 | return false;
78 | }
79 | };
80 |
81 | try {
82 | AutoAnalysisManager.getAnalysisManager(program).scheduleWorker(worker, null, true,
83 | wrappedMonitor);
84 | }
85 | catch (InterruptedException | CancelledException e) {
86 | // ignore
87 | }
88 | catch (InvocationTargetException e) {
89 | resultException = e;
90 | }
91 | if (log.hasMessages()) {
92 | resultMessages = log.toString();
93 | }
94 |
95 | }
96 |
97 | String getResultMessages() {
98 | return resultMessages;
99 | }
100 |
101 | Exception getResultException() {
102 | return resultException;
103 | }
104 |
105 | private boolean parseWithMsDiaParser(MessageLog log, TaskMonitor monitor) throws IOException, CancelledException {
106 | PdbParser parser = new PdbParser(pdbFile, program, service, true, true, monitor);
107 | try
108 | {
109 | parser.parse();
110 | parser.openDataTypeArchives();
111 | parser.applyTo(log);
112 | return true;
113 | }
114 | catch (PdbException | DuplicateIdException e)
115 | {
116 | log.appendMsg("PDB Error: " + e.getMessage());
117 | }
118 | return false;
119 | }
120 |
121 | private boolean parseWithNewParser(MessageLog log, TaskMonitor monitor) throws IOException, CancelledException
122 | {
123 | PdbReaderOptions pdbReaderOptions = new PdbReaderOptions();
124 | PdbApplicatorOptions pdbApplicatorOptions = new PdbApplicatorOptions();
125 | pdbApplicatorOptions.setProcessingControl(control);
126 | try (AbstractPdb pdb = ghidra.app.util.bin.format.pdb2.pdbreader.PdbParser.parse(new File(pdbFile.getAbsolutePath()), pdbReaderOptions, monitor))
127 | {
128 | monitor.setMessage("PDB: Parsing " + pdbFile + "...");
129 | pdb.deserialize();
130 | DefaultPdbApplicator applicator = new DefaultPdbApplicator(pdb, program, program.getDataTypeManager(), program.getImageBase(), pdbApplicatorOptions, monitor, log);
131 | applicator.applyDataTypesAndMainSymbolsAnalysis();
132 | applicator.applyFunctionInternalsAnalysis();
133 | DefaultPdbApplicator.applyAnalysisReporting(program);
134 | return true;
135 | }
136 | catch (ghidra.app.util.bin.format.pdb2.pdbreader.PdbException e)
137 | {
138 | log.appendMsg("PDB Error: " + e.getMessage());
139 | }
140 | return false;
141 | }
142 |
143 | private void analyzeSymbols(TaskMonitor monitor, MessageLog log) {
144 |
145 | MicrosoftDemanglerAnalyzer demanglerAnalyzer = new MicrosoftDemanglerAnalyzer();
146 | String analyzerName = demanglerAnalyzer.getName();
147 | Options analysisProperties = program.getOptions(Program.ANALYSIS_PROPERTIES);
148 | String defaultValueAsString = analysisProperties.getValueAsString(analyzerName);
149 | boolean doDemangle = true;
150 | if (defaultValueAsString != null)
151 | doDemangle = Boolean.parseBoolean(defaultValueAsString);
152 | if (doDemangle)
153 | {
154 | AddressSetView addrs = program.getMemory();
155 | monitor.initialize(addrs.getNumAddresses());
156 | try
157 | {
158 | demanglerAnalyzer.added(program, addrs, monitor, log);
159 | }
160 | catch (CancelledException e)
161 | {
162 | }
163 | }
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/XEXLoaderWV/src/main/java/xexloaderwv/LzxDecompression.java:
--------------------------------------------------------------------------------
1 | package xexloaderwv;
2 |
3 | /*
4 | * Taken and adapted from https://github.com/takari/jdkget/blob/master/src/main/java/io/takari/jdkget/win/LzxDecompressionMethod.java
5 | */
6 |
7 | import java.io.ByteArrayInputStream;
8 | import java.io.ByteArrayOutputStream;
9 | import java.io.IOException;
10 | import java.io.InputStream;
11 | import java.io.OutputStream;
12 |
13 | import org.python.jline.internal.Log;
14 |
15 | public class LzxDecompression {
16 |
17 | private static final int LZX_MIN_MATCH = 2;
18 | private static final int LZX_MAX_MATCH = 257;
19 | private static final int LZX_NUM_CHARS = 256;
20 | private static final int LZX_BLOCKTYPE_INVALID = 0;
21 | private static final int LZX_BLOCKTYPE_VERBATIM = 1;
22 | private static final int LZX_BLOCKTYPE_ALIGNED = 2;
23 | private static final int LZX_BLOCKTYPE_UNCOMPRESSED = 3;
24 | private static final int LZX_PRETREE_NUM_ELEMENTS = 20;
25 | private static final int LZX_ALIGNED_NUM_ELEMENTS = 8;
26 | private static final int LZX_NUM_PRIMARY_LENGTHS = 7;
27 | private static final int LZX_NUM_SECONDARY_LENGTHS = 249;
28 | private static final int LZX_PRETREE_MAXSYMBOLS = LZX_PRETREE_NUM_ELEMENTS;
29 | private static final int LZX_PRETREE_TABLEBITS = 6;
30 | private static final int LZX_MAINTREE_MAXSYMBOLS = LZX_NUM_CHARS + 290 * 8;
31 | private static final int LZX_MAINTREE_TABLEBITS = 12;
32 | private static final int LZX_LENGTH_MAXSYMBOLS = LZX_NUM_SECONDARY_LENGTHS + 1;
33 | private static final int LZX_LENGTH_TABLEBITS = 12;
34 | private static final int LZX_ALIGNED_MAXSYMBOLS = LZX_ALIGNED_NUM_ELEMENTS;
35 | private static final int LZX_ALIGNED_TABLEBITS = 7;
36 | private static final int LZX_LENTABLE_SAFETY = 64;
37 | private static final int LZX_FRAME_SIZE = 32768;
38 | private static final int HUFF_MAXBITS = 16;
39 | private static final int BITBUF_WIDTH = 32;
40 |
41 | private static final int[] position_slots = { 30, 32, 34, 36, 38, 42, 50, 66, 98, 162, 290 };
42 | private static final int[] extra_bits = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10,
43 | 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16 };
44 | private static final int[] position_base = { 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384,
45 | 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768, 49152, 65536, 98304, 131072,
46 | 196608, 262144, 393216, 524288, 655360, 786432, 917504, 1048576, 1179648, 1310720, 1441792, 1572864,
47 | 1703936, 1835008, 1966080, 2097152, 2228224, 2359296, 2490368, 2621440, 2752512, 2883584, 3014656, 3145728,
48 | 3276800, 3407872, 3538944, 3670016, 3801088, 3932160, 4063232, 4194304, 4325376, 4456448, 4587520, 4718592,
49 | 4849664, 4980736, 5111808, 5242880, 5373952, 5505024, 5636096, 5767168, 5898240, 6029312, 6160384, 6291456,
50 | 6422528, 6553600, 6684672, 6815744, 6946816, 7077888, 7208960, 7340032, 7471104, 7602176, 7733248, 7864320,
51 | 7995392, 8126464, 8257536, 8388608, 8519680, 8650752, 8781824, 8912896, 9043968, 9175040, 9306112, 9437184,
52 | 9568256, 9699328, 9830400, 9961472, 10092544, 10223616, 10354688, 10485760, 10616832, 10747904, 10878976,
53 | 11010048, 11141120, 11272192, 11403264, 11534336, 11665408, 11796480, 11927552, 12058624, 12189696,
54 | 12320768, 12451840, 12582912, 12713984, 12845056, 12976128, 13107200, 13238272, 13369344, 13500416,
55 | 13631488, 13762560, 13893632, 14024704, 14155776, 14286848, 14417920, 14548992, 14680064, 14811136,
56 | 14942208, 15073280, 15204352, 15335424, 15466496, 15597568, 15728640, 15859712, 15990784, 16121856,
57 | 16252928, 16384000, 16515072, 16646144, 16777216, 16908288, 17039360, 17170432, 17301504, 17432576,
58 | 17563648, 17694720, 17825792, 17956864, 18087936, 18219008, 18350080, 18481152, 18612224, 18743296,
59 | 18874368, 19005440, 19136512, 19267584, 19398656, 19529728, 19660800, 19791872, 19922944, 20054016,
60 | 20185088, 20316160, 20447232, 20578304, 20709376, 20840448, 20971520, 21102592, 21233664, 21364736,
61 | 21495808, 21626880, 21757952, 21889024, 22020096, 22151168, 22282240, 22413312, 22544384, 22675456,
62 | 22806528, 22937600, 23068672, 23199744, 23330816, 23461888, 23592960, 23724032, 23855104, 23986176,
63 | 24117248, 24248320, 24379392, 24510464, 24641536, 24772608, 24903680, 25034752, 25165824, 25296896,
64 | 25427968, 25559040, 25690112, 25821184, 25952256, 26083328, 26214400, 26345472, 26476544, 26607616,
65 | 26738688, 26869760, 27000832, 27131904, 27262976, 27394048, 27525120, 27656192, 27787264, 27918336,
66 | 28049408, 28180480, 28311552, 28442624, 28573696, 28704768, 28835840, 28966912, 29097984, 29229056,
67 | 29360128, 29491200, 29622272, 29753344, 29884416, 30015488, 30146560, 30277632, 30408704, 30539776,
68 | 30670848, 30801920, 30932992, 31064064, 31195136, 31326208, 31457280, 31588352, 31719424, 31850496,
69 | 31981568, 32112640, 32243712, 32374784, 32505856, 32636928, 32768000, 32899072, 33030144, 33161216,
70 | 33292288, 33423360 };
71 |
72 | private InputStream input;
73 | private long offset;
74 | private long length;
75 | private byte[] window;
76 | private int window_size;
77 | private int ref_data_size;
78 | private int num_offsets;
79 | private int window_posn;
80 | private int frame_posn;
81 | private int frame;
82 | private int reset_interval;
83 | private int R0, R1, R2;
84 | private int block_length;
85 | private int block_remaining;
86 | private int block_type;
87 | private boolean header_read;
88 | private boolean input_end;
89 | private boolean is_delta;
90 | private byte[] inbuf;
91 | private HuffTable preTree;
92 | private HuffTable mainTree;
93 | private HuffTable lengthTree;
94 | private HuffTable alignedTree;
95 | private int intel_filesize;
96 | private int intel_curpos;
97 | private boolean intel_started;
98 | private final byte[] e8_buf = new byte[LZX_FRAME_SIZE];
99 | private byte[] o;
100 | private int o_off, o_end;
101 | private int i_off, i_end;
102 | private int bit_buffer;
103 | private int bits_left;
104 |
105 | public void resetState() {
106 | int i;
107 | R0 = 1;
108 | R1 = 1;
109 | R2 = 1;
110 | header_read = false;
111 | block_remaining = 0;
112 | block_type = LZX_BLOCKTYPE_INVALID;
113 | for (i = 0; i < LZX_MAINTREE_MAXSYMBOLS; i++)
114 | mainTree.len[i] = 0;
115 | for (i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++)
116 | lengthTree.len[i] = 0;
117 | }
118 |
119 | public void init(int window_bits, int resetInterval, int input_buffer_size, long output_length, boolean isDelta,
120 | byte[] windowData) {
121 | int windowSize = 1 << window_bits;
122 | if (isDelta) {
123 | if (window_bits < 17 || window_bits > 25)
124 | throw new IllegalArgumentException("window_bits");
125 | } else {
126 | if (window_bits < 15 || window_bits > 21)
127 | throw new IllegalArgumentException("window_bits");
128 | }
129 | if (resetInterval < 0 || output_length < 0) {
130 | throw new IllegalArgumentException("reset interval or output length < 0");
131 | }
132 | input_buffer_size = (input_buffer_size + 1) & -2;
133 | if (input_buffer_size < 2)
134 | throw new IllegalArgumentException("input_buffer_size");
135 | this.window_size = windowSize;
136 | this.window = new byte[windowSize];
137 | this.inbuf = new byte[input_buffer_size];
138 | this.offset = 0;
139 | this.length = output_length;
140 | this.ref_data_size = 0;
141 | if (windowData != null) {
142 | int delta = windowSize - windowData.length;
143 | for (int i = 0; i < windowData.length; i++)
144 | window[i + delta] = windowData[i];
145 | this.ref_data_size = window.length;
146 | }
147 | this.window_posn = 0;
148 | this.frame_posn = 0;
149 | this.frame = 0;
150 | this.reset_interval = resetInterval;
151 | this.intel_filesize = 0;
152 | this.intel_curpos = 0;
153 | this.intel_started = false;
154 | this.num_offsets = position_slots[window_bits - 15] << 3;
155 | this.is_delta = isDelta;
156 | this.o = this.e8_buf;
157 | this.o_off = this.o_end = 0;
158 | this.preTree = new HuffTable("pretree", LZX_PRETREE_MAXSYMBOLS, LZX_PRETREE_TABLEBITS);
159 | this.mainTree = new HuffTable("maintree", LZX_MAINTREE_MAXSYMBOLS, LZX_MAINTREE_TABLEBITS);
160 | this.lengthTree = new HuffTable("length", LZX_LENGTH_MAXSYMBOLS, LZX_LENGTH_TABLEBITS);
161 | this.alignedTree = new HuffTable("aligned", LZX_ALIGNED_MAXSYMBOLS, LZX_ALIGNED_TABLEBITS);
162 | resetState();
163 | this.i_off = this.i_end = 0;
164 | this.bit_buffer = 0;
165 | this.bits_left = 0;
166 | this.input_end = false;
167 | }
168 |
169 | public byte[] DecompressLZX(byte[] data) {
170 | return DecompressLZX(data, null, data.length * 100);
171 | }
172 |
173 | public byte[] DecompressLZX(byte[] data, byte[] windowData, long uncompressedSize) {
174 | InputStream in = new ByteArrayInputStream(data);
175 | ByteArrayOutputStream output = new ByteArrayOutputStream();
176 | LzxDecompression lzx = new LzxDecompression();
177 | lzx.init(15, 0, data.length, uncompressedSize, false, windowData);
178 | try {
179 | lzx.decompress(in, output, uncompressedSize);
180 | } catch (Exception e) {
181 | Log.error(e.getMessage());
182 | }
183 | return output.toByteArray();
184 | }
185 |
186 | public void decompress(InputStream in, OutputStream output, long out_bytes) throws IOException {
187 | this.input = in;
188 | int match_length, length_footer, extra, verbatim_bits, bytes_todo;
189 | int this_run, main_element, aligned_bits, j, rundest, runsrc;
190 | byte[] buf = new byte[12];
191 | int frame_size = 0, end_frame, match_offset;
192 | if (out_bytes < 0)
193 | throw new IllegalArgumentException();
194 | int i = o_end - o_off;
195 | if (i > out_bytes)
196 | i = (int) out_bytes;
197 | if (i > 0) {
198 | output.write(o, o_off, i);
199 | o_off += i;
200 | offset += i;
201 | out_bytes -= i;
202 | }
203 | if (out_bytes == 0)
204 | return;
205 | if (input_end) {
206 | if (bits_left != 16) {
207 | throw new IllegalStateException("previous pass overflowed " + bits_left + " bits");
208 | }
209 | if (bit_buffer != 0) {
210 | throw new IllegalStateException("non-empty overflowed buffer");
211 | }
212 | removeBits(bits_left);
213 | input_end = false;
214 | }
215 | long total = offset + out_bytes;
216 | end_frame = (int) (total / LZX_FRAME_SIZE) + (total % LZX_FRAME_SIZE > 0 ? 1 : 0);
217 | while (frame < end_frame) {
218 | if (reset_interval > 0 && ((frame % reset_interval) == 0)) {
219 | if (block_remaining > 0) {
220 | throw new IOException(String.format("%d bytes remaining at reset interval", block_remaining));
221 | }
222 | resetState();
223 | }
224 | if (is_delta) {
225 | ensureBits(16);
226 | removeBits(16);
227 | }
228 | if (!header_read) {
229 | j = 0;
230 | i = readBits(1);
231 | if (i > 0) {
232 | i = readBits(16);
233 | j = readBits(16);
234 | }
235 | intel_filesize = (i << 16) | j;
236 | header_read = true;
237 | }
238 | frame_size = LZX_FRAME_SIZE;
239 | if (length > 0 && (length - offset) < frame_size) {
240 | frame_size = (int) (length - offset);
241 | }
242 | bytes_todo = frame_posn + frame_size - window_posn;
243 | while (bytes_todo > 0) {
244 | if (block_remaining == 0) {
245 | if ((block_type == LZX_BLOCKTYPE_UNCOMPRESSED) && (block_length & 1) != 0) {
246 | readIfNeeded();
247 | i_off++;
248 | }
249 | block_type = readBits(3);
250 | i = readBits(16);
251 | j = readBits(8);
252 | block_remaining = block_length = (i << 8) | j;
253 | switch (block_type) {
254 | case LZX_BLOCKTYPE_ALIGNED:
255 | for (i = 0; i < 8; i++) {
256 | alignedTree.len[i] = (short) readBits(3);
257 | }
258 | alignedTree.buildTable();
259 | case LZX_BLOCKTYPE_VERBATIM:
260 | mainTree.readLengths(0, LZX_NUM_CHARS);
261 | mainTree.readLengths(LZX_NUM_CHARS, LZX_NUM_CHARS + num_offsets);
262 | mainTree.buildTable();
263 | if (mainTree.len[0xE8] != 0)
264 | intel_started = true;
265 | lengthTree.readLengths(0, LZX_NUM_SECONDARY_LENGTHS);
266 | lengthTree.buildTableMaybeEmpty();
267 | break;
268 |
269 | case LZX_BLOCKTYPE_UNCOMPRESSED:
270 | intel_started = true;
271 | if (bits_left == 0)
272 | ensureBits(16);
273 | bits_left = 0;
274 | bit_buffer = 0;
275 | for (i = 0; i < 12; i++) {
276 | readIfNeeded();
277 | buf[i] = inbuf[i_off++];
278 | }
279 | R0 = (buf[0] & 0xFF) | ((buf[1] & 0xFF) << 8) | ((buf[2] & 0xFF) << 16)
280 | | ((buf[3] & 0xFF) << 24);
281 | R1 = (buf[4] & 0xFF) | ((buf[5] & 0xFF) << 8) | ((buf[6] & 0xFF) << 16)
282 | | ((buf[7] & 0xFF) << 24);
283 | R2 = (buf[8] & 0xFF) | ((buf[9] & 0xFF) << 8) | ((buf[10] & 0xFF) << 16)
284 | | ((buf[11] & 0xFF) << 24);
285 | break;
286 |
287 | default:
288 | throw new IllegalStateException("bad block type");
289 | }
290 | }
291 | this_run = block_remaining;
292 | if (this_run > bytes_todo)
293 | this_run = bytes_todo;
294 | bytes_todo -= this_run;
295 | block_remaining -= this_run;
296 | switch (block_type) {
297 |
298 | case LZX_BLOCKTYPE_VERBATIM:
299 | while (this_run > 0) {
300 | main_element = mainTree.readHuffSym();
301 | // Log.info(String.format("-- this_run=0x%x main_element=0x%x", this_run,
302 | // main_element));
303 | if (main_element < LZX_NUM_CHARS) {
304 | window[window_posn++] = (byte) main_element;
305 | this_run--;
306 | } else {
307 | main_element -= LZX_NUM_CHARS;
308 | match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
309 | if (match_length == LZX_NUM_PRIMARY_LENGTHS) {
310 | if (lengthTree.empty) {
311 | throw new IllegalStateException("LENGTH symbol needed but tree is empty");
312 | }
313 | length_footer = lengthTree.readHuffSym();
314 | match_length += length_footer;
315 | }
316 | match_length += LZX_MIN_MATCH;
317 | switch ((match_offset = (main_element >>> 3))) {
318 | case 0:
319 | match_offset = R0;
320 | break;
321 | case 1:
322 | match_offset = R1;
323 | R1 = R0;
324 | R0 = match_offset;
325 | break;
326 | case 2:
327 | match_offset = R2;
328 | R2 = R0;
329 | R0 = match_offset;
330 | break;
331 | case 3:
332 | match_offset = 1;
333 | R2 = R1;
334 | R1 = R0;
335 | R0 = match_offset;
336 | break;
337 | default:
338 | extra = (match_offset >= 36) ? 17 : extra_bits[match_offset];
339 | verbatim_bits = readBits(extra);
340 | match_offset = position_base[match_offset] - 2 + verbatim_bits;
341 | R2 = R1;
342 | R1 = R0;
343 | R0 = match_offset;
344 | }
345 | if (match_length == LZX_MAX_MATCH && is_delta) {
346 | int extraLen = 0;
347 | ensureBits(3);
348 | if (peekBits(1) == 0) {
349 | removeBits(1);
350 | extraLen = readBits(8);
351 | } else if (peekBits(2) == 2) {
352 | removeBits(2);
353 | extraLen = readBits(10);
354 | extraLen += 0x100;
355 | } else if (peekBits(3) == 6) {
356 | removeBits(3);
357 | extraLen = readBits(12);
358 | extraLen += 0x500;
359 | } else {
360 | removeBits(3);
361 | extraLen = readBits(15);
362 | }
363 | match_length += extraLen;
364 | }
365 | if ((window_posn + match_length) > window_size) {
366 | throw new IOException("match ran over window wrap");
367 | }
368 | rundest = window_posn;
369 | i = match_length;
370 | if (match_offset > window_posn) {
371 | if (match_offset > offset && (match_offset - window_posn) > ref_data_size)
372 | throw new IOException("match offset beyond LZX stream");
373 | j = match_offset - window_posn;
374 | if (j > window_size) {
375 | throw new IOException("match offset beyond window boundaries");
376 | }
377 | runsrc = window_size - j;
378 | if (j < i) {
379 | i -= j;
380 | while (j-- > 0)
381 | window[rundest++] = window[runsrc++];
382 | runsrc = 0;
383 | }
384 | while (i-- > 0)
385 | window[rundest++] = window[runsrc++];
386 | } else {
387 | runsrc = rundest - match_offset;
388 | while (i-- > 0)
389 | window[rundest++] = window[runsrc++];
390 | }
391 | this_run -= match_length;
392 | window_posn += match_length;
393 | }
394 | }
395 | break;
396 |
397 | case LZX_BLOCKTYPE_ALIGNED:
398 | while (this_run > 0) {
399 | main_element = mainTree.readHuffSym();
400 | if (main_element < LZX_NUM_CHARS) {
401 | window[window_posn++] = (byte) main_element;
402 | this_run--;
403 | } else {
404 | main_element -= LZX_NUM_CHARS;
405 | match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
406 | if (match_length == LZX_NUM_PRIMARY_LENGTHS) {
407 | if (lengthTree.empty) {
408 | throw new IllegalStateException("LENGTH symbol needed but tree is empty");
409 | }
410 | length_footer = lengthTree.readHuffSym();
411 | match_length += length_footer;
412 | }
413 | match_length += LZX_MIN_MATCH;
414 | switch ((match_offset = (main_element >>> 3))) {
415 | case 0:
416 | match_offset = R0;
417 | break;
418 | case 1:
419 | match_offset = R1;
420 | R1 = R0;
421 | R0 = match_offset;
422 | break;
423 | case 2:
424 | match_offset = R2;
425 | R2 = R0;
426 | R0 = match_offset;
427 | break;
428 | default:
429 | extra = (match_offset >= 36) ? 17 : extra_bits[match_offset];
430 | match_offset = position_base[match_offset] - 2;
431 | if (extra > 3) {
432 | extra -= 3;
433 | verbatim_bits = readBits(extra);
434 | match_offset += (verbatim_bits << 3);
435 | aligned_bits = alignedTree.readHuffSym();
436 | match_offset += aligned_bits;
437 | } else if (extra == 3) {
438 | aligned_bits = alignedTree.readHuffSym();
439 | match_offset += aligned_bits;
440 | } else if (extra > 0) {
441 | verbatim_bits = readBits(extra);
442 | match_offset += verbatim_bits;
443 | } else {
444 | match_offset = 1;
445 | }
446 | R2 = R1;
447 | R1 = R0;
448 | R0 = match_offset;
449 | }
450 | if (match_length == LZX_MAX_MATCH && is_delta) {
451 | int extraLen = 0;
452 | ensureBits(3);
453 | if (peekBits(1) == 0) {
454 | removeBits(1);
455 | extraLen = readBits(8);
456 | } else if (peekBits(2) == 2) {
457 | removeBits(2);
458 | extraLen = readBits(10);
459 | extraLen += 0x100;
460 | } else if (peekBits(3) == 6) {
461 | removeBits(3);
462 | extraLen = readBits(12);
463 | extraLen += 0x500;
464 | } else {
465 | removeBits(3);
466 | extraLen = readBits(15);
467 | }
468 | match_length += extraLen;
469 | }
470 | if ((window_posn + match_length) > window_size) {
471 | throw new IOException("match ran over window wrap");
472 | }
473 | rundest = window_posn;
474 | i = match_length;
475 | if (match_offset > window_posn) {
476 | if (match_offset > offset && (match_offset - window_posn) > ref_data_size) {
477 | throw new IOException("match offset beyond LZX stream");
478 | }
479 | j = match_offset - window_posn;
480 | if (j > window_size) {
481 | throw new IOException("match offset beyond window boundaries");
482 | }
483 | runsrc = window_size - j;
484 | if (j < i) {
485 | i -= j;
486 | while (j-- > 0)
487 | window[rundest++] = window[runsrc++];
488 | runsrc = 0;
489 | }
490 | while (i-- > 0)
491 | window[rundest++] = window[runsrc++];
492 | } else {
493 | runsrc = rundest - match_offset;
494 | while (i-- > 0)
495 | window[rundest++] = window[runsrc++];
496 | }
497 |
498 | this_run -= match_length;
499 | window_posn += match_length;
500 | }
501 | }
502 | break;
503 | case LZX_BLOCKTYPE_UNCOMPRESSED:
504 | rundest = window_posn;
505 | window_posn += this_run;
506 | while (this_run > 0) {
507 | if ((i = i_end - i_off) == 0) {
508 | readIfNeeded();
509 | } else {
510 | if (i > this_run)
511 | i = this_run;
512 | System.arraycopy(inbuf, i_off, window, rundest, i);
513 | rundest += i;
514 | i_off += i;
515 | this_run -= i;
516 | }
517 | }
518 | break;
519 | default:
520 | throw new IllegalStateException("bad block type"); /* might as well */
521 | }
522 | if (this_run < 0) {
523 | if (-this_run > block_remaining) {
524 | throw new IOException(String.format("overrun went past end of block by %d (%d remaining)",
525 | -this_run, block_remaining));
526 | }
527 | block_remaining -= -this_run;
528 | }
529 |
530 | }
531 | if ((window_posn - frame_posn) != frame_size) {
532 | throw new IOException(String.format("decode beyond output frame limits! %d != %d",
533 | window_posn - frame_posn, frame_size));
534 | }
535 | if (bits_left > 0)
536 | ensureBits(16);
537 | if ((bits_left & 15) != 0)
538 | removeBits(bits_left & 15);
539 | if (o_off != o_end) {
540 | throw new IOException(String.format("%d avail bytes, new %d frame", o_end - o_off, frame_size));
541 | }
542 | if (intel_started && intel_filesize != 0 && (frame <= 32768) && (frame_size > 10)) {
543 | byte[] data = e8_buf;
544 | int datastart = 0;
545 | int dataend = frame_size - 10;
546 | int curpos = intel_curpos;
547 | int filesize = intel_filesize;
548 | int absOff, relOff;
549 | o = data;
550 | o_off = 0;
551 | o_end = frame_size;
552 | System.arraycopy(window, frame_posn, data, 0, frame_size);
553 | while (datastart < dataend) {
554 | if ((data[datastart++] & 0xFF) != 0xE8) {
555 | curpos++;
556 | continue;
557 | }
558 | absOff = (data[datastart] & 0xFF) | ((data[datastart + 1] & 0xFF) << 8)
559 | | ((data[datastart + 2] & 0xFF) << 16) | ((data[datastart + 3] & 0xFF) << 24);
560 | if ((absOff >= -curpos) && (absOff < filesize)) {
561 | relOff = (absOff >= 0) ? absOff - curpos : absOff + filesize;
562 | data[datastart + 0] = (byte) (relOff & 0xff);
563 | data[datastart + 1] = (byte) ((relOff >>> 8) & 0xff);
564 | data[datastart + 2] = (byte) ((relOff >>> 16) & 0xff);
565 | data[datastart + 3] = (byte) ((relOff >>> 24) & 0xff);
566 | }
567 | datastart += 4;
568 | curpos += 5;
569 | }
570 | intel_curpos += frame_size;
571 | } else {
572 | o = window;
573 | o_off = frame_posn;
574 | o_end = frame_posn + frame_size;
575 | if (intel_filesize != 0)
576 | intel_curpos += frame_size;
577 | }
578 | i = (out_bytes < frame_size) ? (int) out_bytes : frame_size;
579 | output.write(o, o_off, i);
580 | o_off += i;
581 | offset += i;
582 | out_bytes -= i;
583 | frame_posn += frame_size;
584 | frame++;
585 | if (window_posn == window_size)
586 | window_posn = 0;
587 | if (frame_posn == window_size)
588 | frame_posn = 0;
589 |
590 | }
591 | if (out_bytes > 0) {
592 | throw new IOException("bytes left to output");
593 | }
594 | }
595 |
596 | private static boolean makeDecodeTable(int nsyms, int nbits, short[] length, short[] table) {
597 |
598 | int sym, next_symbol;
599 | int leaf, fill;
600 | int bit_num;
601 | int pos = 0;
602 | int table_mask = 1 << nbits;
603 | int bit_mask = table_mask >>> 1;
604 | for (bit_num = 1; bit_num <= nbits; bit_num++) {
605 | for (sym = 0; sym < nsyms; sym++) {
606 | if (length[sym] != bit_num)
607 | continue;
608 | leaf = pos;
609 |
610 | if ((pos += bit_mask) > table_mask)
611 | return false;
612 | for (fill = bit_mask; fill-- > 0;)
613 | table[leaf++] = (short) sym;
614 | }
615 | bit_mask >>>= 1;
616 | }
617 | if (pos == table_mask)
618 | return true;
619 | for (sym = pos; sym < table_mask; sym++) {
620 | table[sym] = (short) -1;
621 | }
622 | next_symbol = ((table_mask >>> 1) < nsyms) ? nsyms : (table_mask >>> 1);
623 | pos <<= 16;
624 | table_mask <<= 16;
625 | bit_mask = 1 << 15;
626 | for (bit_num = nbits + 1; bit_num <= HUFF_MAXBITS; bit_num++) {
627 | for (sym = 0; sym < nsyms; sym++) {
628 | if (length[sym] != bit_num)
629 | continue;
630 | if (pos >= table_mask)
631 | return false;
632 | leaf = pos >>> 16;
633 | for (fill = 0; fill < (bit_num - nbits); fill++) {
634 | if (table[leaf] == -1) {
635 | table[(next_symbol << 1)] = (short) -1;
636 | table[(next_symbol << 1) + 1] = (short) -1;
637 | table[leaf] = (short) next_symbol++;
638 | }
639 | leaf = table[leaf] << 1;
640 | if (((pos >>> (15 - fill)) & 1) != 0)
641 | leaf++;
642 | }
643 | table[leaf] = (short) sym;
644 | pos += bit_mask;
645 | }
646 | bit_mask >>>= 1;
647 | }
648 | return pos == table_mask;
649 | }
650 |
651 | private void readLens(short[] lens, int first, int last) throws IOException {
652 | int x, y, z;
653 | for (x = 0; x < 20; x++) {
654 | y = readBits(4);
655 | preTree.len[x] = (short) y;
656 | }
657 | preTree.buildTable();
658 |
659 | for (x = first; x < last;) {
660 | z = preTree.readHuffSym();
661 | if (z == 17) {
662 | y = readBits(4);
663 | y += 4;
664 | while (y-- > 0)
665 | lens[x++] = 0;
666 | } else if (z == 18) {
667 | y = readBits(5);
668 | y += 20;
669 | while (y-- > 0)
670 | lens[x++] = 0;
671 | } else if (z == 19) {
672 | y = readBits(1);
673 | y += 4;
674 | z = preTree.readHuffSym();
675 | z = lens[x] - z;
676 | if (z < 0)
677 | z += 17;
678 | while (y-- > 0)
679 | lens[x++] = (short) z;
680 | } else {
681 | z = lens[x] - z;
682 | if (z < 0)
683 | z += 17;
684 | lens[x++] = (short) z;
685 | }
686 | }
687 | }
688 |
689 | private void ensureBits(int nbits) throws IOException {
690 | while (bits_left < (nbits)) {
691 | readBytes();
692 | }
693 | }
694 |
695 | private void readBytes() throws IOException {
696 | readIfNeeded();
697 | int b0 = inbuf[i_off++] & 0xff;
698 | readIfNeeded();
699 | int b1 = inbuf[i_off++] & 0xff;
700 | int val = (b1 << 8) | b0;
701 | injectBits(val, 16);
702 | }
703 |
704 | private void readIfNeeded() throws IOException {
705 | if (i_off >= i_end) {
706 | readInput();
707 | }
708 | }
709 |
710 | private void readInput() throws IOException {
711 | int l = inbuf.length;
712 | int read = input.read(inbuf, 0, l);
713 | if (read <= 0) {
714 | if (input_end)
715 | throw new IOException("out of input bytes");
716 | read = 2;
717 | inbuf[0] = inbuf[1] = 0;
718 | input_end = true;
719 | }
720 | i_off = 0;
721 | i_end = read;
722 | }
723 |
724 | private int readBits(int nbits) throws IOException {
725 | ensureBits(nbits);
726 | int val = peekBits(nbits);
727 | removeBits(nbits);
728 | return val;
729 | }
730 |
731 | private int peekBits(int nbits) {
732 | int result = bit_buffer >>> (BITBUF_WIDTH - nbits);
733 | return result;
734 | }
735 |
736 | private void removeBits(int nbits) {
737 | bit_buffer <<= nbits;
738 | bits_left -= nbits;
739 | }
740 |
741 | private void injectBits(int bitdata, int nbits) {
742 | bit_buffer |= bitdata << (BITBUF_WIDTH - nbits - bits_left);
743 | bits_left += nbits;
744 | }
745 |
746 | private class HuffTable {
747 | final String tbl;
748 | final int tableBits;
749 | final int maxSymbols;
750 | final short[] table;
751 | final short[] len;
752 | boolean empty;
753 |
754 | HuffTable(String tbl, int maxSymbols, int tableBits) {
755 | this.tbl = tbl;
756 | this.maxSymbols = maxSymbols;
757 | this.tableBits = tableBits;
758 | table = new short[(1 << tableBits) + (maxSymbols * 2)];
759 | len = new short[maxSymbols + LZX_LENTABLE_SAFETY];
760 | }
761 |
762 | void buildTable() {
763 | if (!makeDecodeTable(maxSymbols, tableBits, len, table)) {
764 | throw new IllegalStateException(String.format("failed to build %s table", tbl));
765 | }
766 | empty = false;
767 | }
768 |
769 | void buildTableMaybeEmpty() {
770 | empty = false;
771 | if (!makeDecodeTable(maxSymbols, tableBits, len, table)) {
772 | for (int i = 0; i < maxSymbols; i++) {
773 | if (len[i] > 0) {
774 | throw new IllegalStateException(String.format("failed to build %s table", tbl));
775 | }
776 | }
777 | empty = true;
778 | }
779 | }
780 |
781 | void readLengths(int first, int last) throws IOException {
782 | readLens(len, first, last);
783 | }
784 |
785 | int readHuffSym() throws IOException {
786 | ensureBits(HUFF_MAXBITS);
787 | int sym = table[peekBits(tableBits)] & 0xFFFF;
788 | if (sym >= maxSymbols)
789 | sym = huffTraverse(sym);
790 | removeBits(len[sym]);
791 | return sym;
792 | }
793 |
794 | int huffTraverse(int sym) {
795 | int i = 1 << (BITBUF_WIDTH - tableBits);
796 | do {
797 | if ((i >>>= 1) == 0) {
798 | throw new IllegalStateException("huffTraverse");
799 | }
800 | sym = table[(sym << 1) | (((bit_buffer & i) != 0) ? 1 : 0)];
801 | } while (sym >= maxSymbols);
802 | return sym;
803 | }
804 | }
805 | }
806 |
--------------------------------------------------------------------------------
/XEXLoaderWV/src/main/java/xexloaderwv/NTHeader.java:
--------------------------------------------------------------------------------
1 | package xexloaderwv;
2 |
3 | import java.util.ArrayList;
4 |
5 | import ghidra.app.util.bin.BinaryReader;
6 | import ghidra.app.util.bin.ByteArrayProvider;
7 |
8 | public class NTHeader {
9 | public int magic;
10 | public ImageFileHeader imgHeader;
11 | public ImageOptionalHeader optHeader;
12 | public ArrayList secHeaders = new ArrayList();
13 | public NTHeader (byte[] data, int pos) throws Exception
14 | {
15 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), true);
16 | magic = b.readInt(pos);
17 | imgHeader = new ImageFileHeader(data, pos + 4);
18 | optHeader = new ImageOptionalHeader(data, pos + 24);
19 | int secPos = pos + imgHeader.sizeOfOptionalHeader + 24;
20 | for(int i = 0; i < imgHeader.numberOfSections; i++)
21 | {
22 | secHeaders.add(new SectionHeader(data, secPos));
23 | secPos += 40;
24 | }
25 | }
26 |
27 | public class SectionHeader
28 | {
29 | public String Name;
30 | public int PhysicalAddressOrVirtualSize;
31 | public int VirtualAddress;
32 | public int SizeOfRawData;
33 | public int PointerToRawData;
34 | public int PointerToRelocations;
35 | public int PointerToLinenumbers;
36 | public short NumberOfRelocations;
37 | public short NumberOfLinenumbers;
38 | public int Characteristics;
39 | public SectionHeader(byte[] data, int pos) throws Exception
40 | {
41 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), true);
42 | Name = "";
43 | for(int i = 0; i < 8; i++)
44 | if(data[pos + i] != 0)
45 | Name += (char)data[pos + i];
46 | else
47 | break;
48 | PhysicalAddressOrVirtualSize = b.readInt(pos + 8);
49 | VirtualAddress = b.readInt(pos + 12);
50 | SizeOfRawData = b.readInt(pos + 16);
51 | PointerToRawData = b.readInt(pos + 20);
52 | PointerToRelocations = b.readInt(pos + 24);
53 | PointerToLinenumbers = b.readInt(pos + 28);
54 | NumberOfRelocations = b.readShort(pos + 32);
55 | NumberOfLinenumbers = b.readShort(pos + 34);
56 | Characteristics = b.readInt(pos + 36);
57 | }
58 | }
59 |
60 | public class ImageFileHeader
61 | {
62 | public short machine;
63 | public short numberOfSections;
64 | public int timeDateStamp;
65 | public int pointerToSymbolTable;
66 | public int numberOfSymbols;
67 | public short sizeOfOptionalHeader;
68 | public short characteristics;
69 | public ImageFileHeader(byte[] data, int pos) throws Exception
70 | {
71 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), true);
72 | machine = b.readShort(pos);
73 | numberOfSections = b.readShort(pos + 2);
74 | timeDateStamp = b.readInt(pos + 4);
75 | pointerToSymbolTable = b.readInt(pos + 8);
76 | numberOfSymbols = b.readInt(pos + 12);
77 | sizeOfOptionalHeader = b.readShort(pos + 16);
78 | characteristics = b.readShort(pos + 18);
79 | }
80 | }
81 |
82 | public class ImageOptionalHeader
83 | {
84 | public class ImageDataDirectory
85 | {
86 | public int virtualAddress;
87 | public int size;
88 | public ImageDataDirectory(byte[] data, int pos) throws Exception
89 | {
90 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), true);
91 | virtualAddress = b.readInt(pos);
92 | size = b.readInt(pos + 4);
93 | }
94 | }
95 |
96 |
97 | public short Magic;
98 | public byte MajorLinkerVersion;
99 | public byte MinorLinkerVersion;
100 | public int SizeOfCode;
101 | public int SizeOfInitializedData;
102 | public int SizeOfUninitializedData;
103 | public int AddressOfEntryPoint;
104 | public int BaseOfCode;
105 | public int BaseOfData;
106 | public int ImageBase;
107 | public int SectionAlignment;
108 | public int FileAlignment;
109 | public short MajorOperatingSystemVersion;
110 | public short MinorOperatingSystemVersion;
111 | public short MajorImageVersion;
112 | public short MinorImageVersion;
113 | public short MajorSubsystemVersion;
114 | public short MinorSubsystemVersion;
115 | public int Win32VersionValue;
116 | public int SizeOfImage;
117 | public int SizeOfHeaders;
118 | public int CheckSum;
119 | public short Subsystem;
120 | public short DllCharacteristics;
121 | public int SizeOfStackReserve;
122 | public int SizeOfStackCommit;
123 | public int SizeOfHeapReserve;
124 | public int SizeOfHeapCommit;
125 | public int LoaderFlags;
126 | public int NumberOfRvaAndSizes;
127 | public ArrayList dataDirectories = new ArrayList();
128 | public ImageOptionalHeader(byte[] data, int pos) throws Exception
129 | {
130 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), true);
131 | Magic = b.readShort(pos);
132 | MajorLinkerVersion = data[pos + 2];
133 | MinorLinkerVersion = data[pos + 3];
134 | SizeOfCode = b.readInt(pos + 4);
135 | SizeOfInitializedData = b.readInt(pos + 8);
136 | SizeOfUninitializedData = b.readInt(pos + 12);
137 | AddressOfEntryPoint = b.readInt(pos + 16);
138 | BaseOfCode = b.readInt(pos + 20);
139 | BaseOfData = b.readInt(pos + 24);
140 | ImageBase = b.readInt(pos + 28);
141 | SectionAlignment = b.readInt(pos + 32);
142 | FileAlignment = b.readInt(pos + 36);
143 | MajorOperatingSystemVersion = b.readShort(pos + 40);
144 | MinorOperatingSystemVersion = b.readShort(pos + 42);
145 | MajorImageVersion = b.readShort(pos + 44);
146 | MinorImageVersion = b.readShort(pos + 46);
147 | MajorSubsystemVersion = b.readShort(pos + 48);
148 | MinorSubsystemVersion = b.readShort(pos + 50);
149 | Win32VersionValue = b.readInt(pos + 52);
150 | SizeOfImage = b.readInt(pos + 56);
151 | SizeOfHeaders = b.readInt(pos + 60);
152 | CheckSum = b.readInt(pos + 64);
153 | Subsystem = b.readShort(pos + 68);
154 | DllCharacteristics = b.readShort(pos + 70);
155 | SizeOfStackReserve = b.readInt(pos + 72);
156 | SizeOfStackCommit = b.readInt(pos + 76);
157 | SizeOfHeapReserve = b.readInt(pos + 80);
158 | SizeOfHeapCommit = b.readInt(pos + 84);
159 | LoaderFlags = b.readInt(pos + 88);
160 | NumberOfRvaAndSizes = b.readInt(pos + 92);
161 | for(int i = 0; i < NumberOfRvaAndSizes; i++)
162 | dataDirectories.add(new ImageDataDirectory(data, pos + i * 8 + 96));
163 | }
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/XEXLoaderWV/src/main/java/xexloaderwv/PDBFile.java:
--------------------------------------------------------------------------------
1 | package xexloaderwv;
2 |
3 | import java.io.ByteArrayOutputStream;
4 | import java.io.OutputStream;
5 | import java.nio.file.Files;
6 | import java.nio.file.Path;
7 | import java.util.ArrayList;
8 |
9 | import org.python.jline.internal.Log;
10 |
11 | import ghidra.app.util.bin.BinaryReader;
12 | import ghidra.app.util.bin.ByteArrayProvider;
13 | import ghidra.program.model.listing.Program;
14 | import ghidra.util.task.TaskMonitor;
15 |
16 | public class PDBFile {
17 |
18 | public class RootStream
19 | {
20 | public int size;
21 | public int[] pages;
22 | }
23 |
24 | public class SymbolRecord
25 | {
26 | public short reclen;
27 | public short rectyp;
28 | public int pubsymflags;
29 | public int off;
30 | public short seg;
31 | public String name;
32 | public SymbolRecord(ByteArrayProvider input, int pos) throws Exception
33 | {
34 | BinaryReader b = new BinaryReader(input, true);
35 | reclen = (short)(b.readShort(pos) + 2);
36 | rectyp = b.readShort(pos + 2);
37 | pubsymflags = b.readInt(pos + 4);
38 | off = b.readInt(pos + 8);
39 | seg = b.readShort(pos + 12);
40 | name = b.readAsciiString(pos + 14);
41 | }
42 | }
43 |
44 | public int dPageBytes;
45 | public int dRootBytes;
46 | public int pAdIndexPages;
47 | public short symbolStreamIndex;
48 | public ArrayList rootStreams = new ArrayList();
49 | public ArrayList symbols = new ArrayList();
50 | public TPIStream tpi;
51 |
52 | public PDBFile(String path, TaskMonitor monitor, Program program) throws Exception
53 | {
54 | byte[] data = Files.readAllBytes(Path.of(path));
55 | ByteArrayProvider bap = new ByteArrayProvider(data);
56 | BinaryReader b = new BinaryReader(bap, true);
57 | dPageBytes = b.readInt(0x20);
58 | dRootBytes = b.readInt(0x2C);
59 | pAdIndexPages = b.readInt(0x34);
60 | int pos;
61 | pos = pAdIndexPages * dPageBytes;
62 | ArrayList pages = new ArrayList();
63 | int count = dRootBytes / dPageBytes;
64 | if ((dRootBytes / dPageBytes) != 0)
65 | count++;
66 | for(int i = 0; i < count; i++)
67 | {
68 | int v = b.readInt(pos);
69 | if(v != 0)
70 | pages.add(v);
71 | pos += 4;
72 | }
73 | ByteArrayOutputStream os = new ByteArrayOutputStream();
74 | for(Integer page : pages)
75 | CopyPage(page, bap, os);
76 | ReadRootStreams(os.toByteArray());
77 | ReadDBIData(GetStreamData(3, bap));
78 | ReadSymbolData(GetStreamData(symbolStreamIndex, bap), monitor);
79 | ReadTPIData(GetStreamData(2, bap), program, monitor);
80 | bap.close();
81 | }
82 |
83 | private void CopyPage(int page, ByteArrayProvider input, OutputStream output) throws Exception
84 | {
85 | byte[] buff = input.readBytes(page * dPageBytes, dPageBytes);
86 | output.write(buff);
87 | }
88 |
89 | private byte[] GetStreamData(int index, ByteArrayProvider input) throws Exception
90 | {
91 | RootStream rs = rootStreams.get(index);
92 | ByteArrayOutputStream os = new ByteArrayOutputStream();
93 | for(Integer page : rs.pages)
94 | CopyPage(page, input, os);
95 | return os.toByteArray();
96 | }
97 |
98 | private void ReadDBIData(byte[] data) throws Exception
99 | {
100 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), true);
101 | symbolStreamIndex = b.readShort(0x14);
102 | }
103 |
104 | private void ReadTPIData(byte[] data, Program program, TaskMonitor monitor) throws Exception
105 | {
106 | tpi = new TPIStream(data, monitor);
107 | }
108 |
109 | private void ReadSymbolData(byte[] data, TaskMonitor monitor) throws Exception
110 | {
111 | ByteArrayProvider bap = new ByteArrayProvider(data);
112 | int pos = 0;
113 | monitor.setMaximum(data.length);
114 | monitor.setMessage("Loading symbol records");
115 | try
116 | {
117 | while(pos < data.length)
118 | {
119 | if(monitor.isCancelled())
120 | return;
121 | monitor.setProgress(pos);
122 | SymbolRecord sym = new SymbolRecord(bap, pos);
123 | pos += sym.reclen;
124 | symbols.add(sym);
125 | }
126 | }
127 | catch (Exception e){}
128 | monitor.setProgress(0);
129 | bap.close();
130 | Log.info(String.format("XEX Loader: Processed %d symbols", symbols.size()));
131 | }
132 |
133 |
134 | private void ReadRootStreams(byte[] data) throws Exception
135 | {
136 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), true);
137 | int count = b.readInt(0);
138 | int pos = 4;
139 | for(int i = 0; i < count; i++)
140 | {
141 | RootStream rs = new RootStream();
142 | rs.size = b.readInt(pos);
143 | if(rs.size == -1)
144 | rs.size = 0;
145 | rootStreams.add(rs);
146 | pos += 4;
147 | }
148 | for(int i = 0; i < count; i++)
149 | {
150 | try
151 | {
152 | RootStream rs = rootStreams.get(i);
153 | int subcount = rs.size / dPageBytes;
154 | if ((rs.size % dPageBytes) != 0)
155 | subcount++;
156 | rs.pages = new int[subcount];
157 | for(int j = 0; j < subcount; j++)
158 | {
159 | rs.pages[j] = b.readInt(pos);
160 | pos += 4;
161 | }
162 | rootStreams.set(i, rs);
163 | }
164 | catch(Exception e) {}
165 | }
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/XEXLoaderWV/src/main/java/xexloaderwv/TPIStream.java:
--------------------------------------------------------------------------------
1 | package xexloaderwv;
2 |
3 | import java.util.ArrayList;
4 | import java.util.HashMap;
5 |
6 | import org.python.jline.internal.Log;
7 |
8 | import ghidra.app.util.bin.BinaryReader;
9 | import ghidra.app.util.bin.ByteArrayProvider;
10 | import ghidra.program.model.data.ByteDataType;
11 | import ghidra.program.model.data.DataType;
12 | import ghidra.program.model.data.DataTypeConflictHandler;
13 | import ghidra.program.model.data.DataTypeManager;
14 | import ghidra.program.model.data.DoubleDataType;
15 | import ghidra.program.model.data.EnumDataType;
16 | import ghidra.program.model.data.FloatDataType;
17 | import ghidra.program.model.data.IntegerDataType;
18 | import ghidra.program.model.data.TypedefDataType;
19 | import ghidra.program.model.data.LongDataType;
20 | import ghidra.program.model.data.PointerDataType;
21 | import ghidra.program.model.data.ShortDataType;
22 | import ghidra.program.model.data.StructureDataType;
23 | import ghidra.program.model.data.UnionDataType;
24 | import ghidra.program.model.data.ArrayDataType;
25 | import ghidra.program.model.listing.Program;
26 | import ghidra.util.task.TaskMonitor;
27 | import xexloaderwv.TypeRecord.BasicTypes;
28 | import xexloaderwv.TypeRecord.LR_Array;
29 | import xexloaderwv.TypeRecord.LR_Bitfield;
30 | import xexloaderwv.TypeRecord.LR_Class;
31 | import xexloaderwv.TypeRecord.LR_Enum;
32 | import xexloaderwv.TypeRecord.LR_MemberFunction;
33 | import xexloaderwv.TypeRecord.LR_Modifier;
34 | import xexloaderwv.TypeRecord.LR_Pointer;
35 | import xexloaderwv.TypeRecord.LR_Structure;
36 | import xexloaderwv.TypeRecord.LR_Union;
37 | import xexloaderwv.TypeRecord.LeafRecordKind;
38 | import xexloaderwv.TypeRecord.MR_BClass;
39 | import xexloaderwv.TypeRecord.MR_Member;
40 | import xexloaderwv.TypeRecord.MR_VFuncTab;
41 |
42 | public class TPIStream {
43 |
44 | public enum TPIVersion
45 | {
46 | V40 ("V40", 19950410), //0x01306B4A
47 | V41 ("V41", 19951122), //0x01306E12
48 | V50 ("V50", 19961031), //0x013094C7
49 | V70 ("V70", 19990903), //0x01310977
50 | V80 ("V80", 20040203); //0x0131CA0B
51 | private final String name;
52 | private final long value;
53 | private TPIVersion(String name, long value) { this.name = name; this.value = value; }
54 | public String getName() { return name; }
55 | public long getValue() { return value; }
56 | public static TPIVersion getByValue(long l)
57 | {
58 | for(TPIVersion v : TPIVersion.values())
59 | if(v.value == l)
60 | return v;
61 | return null;
62 | }
63 | }
64 | public TPIVersion Version;
65 | public long HeaderSize;
66 | public long TypeIndexBegin;
67 | public long TypeIndexEnd;
68 | public long TypeRecordBytes;
69 | public int HashStreamIndex;
70 | public int HashAuxStreamIndex;
71 | public long HashKeySize;
72 | public long NumHashBuckets;
73 | public long HashValueBufferOffset;
74 | public long HashValueBufferLength;
75 | public long IndexOffsetBufferOffset;
76 | public long IndexOffsetBufferLength;
77 | public long HashAdjBufferOffset;
78 | public long HashAdjBufferLength;
79 | public ArrayList typeRecords;
80 |
81 |
82 |
83 |
84 | HashMap structMap;
85 | HashMap classMap;
86 | HashMap unionMap;
87 |
88 |
89 | public TPIStream(byte[] data, TaskMonitor monitor) throws Exception
90 | {
91 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), true);
92 | Version = TPIVersion.getByValue(b.readUnsignedInt(0));
93 | if(Version == TPIVersion.V40)
94 | return;
95 | HeaderSize = b.readUnsignedInt(4);
96 | TypeIndexBegin = b.readUnsignedInt(8);
97 | TypeIndexEnd = b.readUnsignedInt(12);
98 | TypeRecordBytes = b.readUnsignedInt(16);
99 | HashStreamIndex = b.readUnsignedShort(20);
100 | HashAuxStreamIndex = b.readUnsignedShort(22);
101 | HashKeySize = b.readUnsignedInt(24);
102 | NumHashBuckets = b.readUnsignedInt(28);
103 | HashValueBufferOffset = b.readUnsignedInt(32);
104 | HashValueBufferLength = b.readUnsignedInt(36);
105 | IndexOffsetBufferOffset = b.readUnsignedInt(40);
106 | IndexOffsetBufferLength = b.readUnsignedInt(44);
107 | HashAdjBufferOffset = b.readUnsignedInt(48);
108 | HashAdjBufferLength = b.readUnsignedInt(52);
109 | typeRecords = new ArrayList();
110 | long pos = 56;
111 | long typeID = 0x1000;
112 | monitor.setProgress(0);
113 | monitor.setMaximum(TypeRecordBytes + 56);
114 | monitor.setMessage("Processing type records");
115 | while(pos - 56 < TypeRecordBytes)
116 | {
117 | if(monitor.isCancelled())
118 | return;
119 | monitor.setProgress(pos);
120 | int size = b.readUnsignedShort(pos) - 2;
121 | int kind = b.readUnsignedShort(pos + 2);
122 | byte[] record = b.readByteArray(pos + 4, size);
123 | typeRecords.add(new TypeRecord(typeID, kind, record));
124 | pos += size + 4;
125 | typeID++;
126 | }
127 | Log.info(String.format("XEX Loader: Processed %d type records", typeRecords.size()));
128 | }
129 |
130 | public class FieldMemberEntry
131 | {
132 | public long offset;
133 | public DataType type;
134 | public String name;
135 | public String comment;
136 | public boolean isBitField;
137 |
138 | public FieldMemberEntry(long o, DataType t, String n, String c, boolean isB)
139 | {
140 | offset = o;
141 | type = t;
142 | name = n;
143 | comment = c;
144 | isBitField = isB;
145 | }
146 | }
147 |
148 | public void ImportTypeRecords(Program program, TaskMonitor monitor) throws Exception
149 | {
150 | long countEnums = 0;
151 | long countStructures = 0;
152 | long countArrays = 0;
153 | long countUnions = 0;
154 | long countClasses = 0;
155 | long countModifiers = 0;
156 | DataTypeManager dtMan = program.getDataTypeManager();
157 | monitor.setMaximum(typeRecords.size());
158 | monitor.setMessage("Loading type records");
159 | long counter = 0;
160 | structMap = new HashMap();
161 | classMap = new HashMap();
162 | unionMap = new HashMap();
163 | for(TypeRecord rec : typeRecords)
164 | {
165 | if(monitor.isCancelled())
166 | return;
167 | monitor.setProgress(counter++);
168 | switch(rec.kind)
169 | {
170 | case LF_ENUM:
171 | if(AddEnumType((TypeRecord.LR_Enum)rec.record))
172 | countEnums++;
173 | break;
174 | case LF_STRUCTURE:
175 | if(AddStructureType((TypeRecord.LR_Structure)rec.record))
176 | countStructures++;
177 | break;
178 | case LF_ARRAY:
179 | if(AddArrayType((TypeRecord.LR_Array)rec.record))
180 | countArrays++;
181 | break;
182 | case LF_UNION:
183 | if(AddUnionType((TypeRecord.LR_Union)rec.record))
184 | countUnions++;
185 | break;
186 | case LF_CLASS:
187 | if(AddClassType((TypeRecord.LR_Class)rec.record))
188 | countClasses++;
189 | break;
190 | case LF_MODIFIER:
191 | if (AddModifierType((TypeRecord.LR_Modifier)rec.record))
192 | countModifiers++;
193 | break;
194 | default:
195 | break;
196 | }
197 | }
198 | for(TypeRecord rec : typeRecords)
199 | try
200 | {
201 | if(rec.record != null && rec.record.dataType != null)
202 | dtMan.addDataType(rec.record.dataType, DataTypeConflictHandler.DEFAULT_HANDLER);
203 | } catch (Exception ex) {
204 | Log.error("Failed to add " + rec.record.dataType.getName() + ":" + ex.getMessage());
205 | }
206 | Log.info(String.format("XEX Loader: Imported %d enums, %d structures, %d arrays, %d unions, %d classes, %d modifiers",
207 | countEnums,
208 | countStructures,
209 | countArrays,
210 | countUnions,
211 | countClasses,
212 | countModifiers));
213 | }
214 |
215 | private boolean AddClassType(TypeRecord.LR_Class clazz)
216 | {
217 | try
218 | {
219 | StructureDataType newClass;
220 | boolean existed = false;
221 | if(classMap.containsKey(clazz.name)) {
222 | newClass = classMap.get(clazz.name);
223 | existed = true;
224 | }
225 | else
226 | {
227 | newClass = new StructureDataType(clazz.name, 0);
228 | newClass.setPackingEnabled(true);
229 | classMap.put(clazz.name, newClass);
230 | }
231 | if(clazz.field != 0) {
232 | // Some PDBs have multiple definitions for datatypes ("UDT Mismatch" warning).
233 | // This makes sure to overwrite the datatype with this new one instead of appending to the previous one.
234 | if (existed) {
235 | newClass.deleteAll();
236 | }
237 | for(TypeRecord rec : typeRecords) {
238 | if(rec.typeID == clazz.field)
239 | {
240 | TypeRecord.LR_FieldList fieldList = (TypeRecord.LR_FieldList)rec.record;
241 | ArrayList entries = GetFieldListMembers(fieldList);
242 | if(entries == null)
243 | return false;
244 | for(FieldMemberEntry e : entries)
245 | if(!e.isBitField)
246 | newClass.add(e.type, e.name, e.comment);
247 | else
248 | newClass.addBitField(e.type, (int)e.offset, e.name, e.comment);
249 | break;
250 | }
251 | }
252 | }
253 | newClass.repack();
254 | clazz.dataType = newClass;
255 | return true;
256 | }
257 | catch (Exception e)
258 | {
259 | return false;
260 | }
261 | }
262 |
263 | private String GetModifierTypeName(TypeRecord.LR_Modifier modifier) {
264 | return modifier.attr.getName() + "__" + GetDataTypeNameByIndex(modifier.type);
265 | }
266 |
267 | private boolean AddModifierType(TypeRecord.LR_Modifier modifier) {
268 | try {
269 | String name = GetModifierTypeName(modifier);
270 | TypedefDataType dt = new TypedefDataType(name, GetDataTypeByIndex(modifier.type));
271 | modifier.dataType = dt;
272 | return true;
273 | }
274 | catch (Exception ex) {
275 | return false;
276 | }
277 | }
278 |
279 | private boolean AddUnionType(TypeRecord.LR_Union union)
280 | {
281 | try
282 | {
283 | UnionDataType newUnion;
284 | boolean existed = false;
285 | if(unionMap.containsKey(union.name)) {
286 | newUnion = unionMap.get(union.name);
287 | existed = true;
288 | }
289 | else
290 | {
291 | newUnion = new UnionDataType(union.name);
292 | newUnion.setPackingEnabled(true);
293 | unionMap.put(union.name, newUnion);
294 | }
295 | if(union.field != 0) {
296 | if (existed) {
297 | // unions don't have a deleteAll function for some reason
298 | for (int i = newUnion.getNumComponents() - 1; i >= 0; i--) {
299 | newUnion.delete(i);
300 | }
301 | }
302 | for(TypeRecord rec : typeRecords) {
303 | if(rec.typeID == union.field)
304 | {
305 | TypeRecord.LR_FieldList fieldList = (TypeRecord.LR_FieldList)rec.record;
306 | ArrayList entries = GetFieldListMembers(fieldList);
307 | if(entries == null)
308 | return false;
309 | for(FieldMemberEntry e : entries)
310 | if(!e.isBitField)
311 | newUnion.add(e.type, e.name, e.comment);
312 | else
313 | newUnion.addBitField(e.type, (int)e.offset, e.name, e.comment);
314 | break;
315 | }
316 | }
317 | }
318 | newUnion.repack();
319 | union.dataType = newUnion;
320 | return true;
321 | }
322 | catch(Exception ex)
323 | {
324 | return false;
325 | }
326 | }
327 |
328 | private boolean AddStructureType(TypeRecord.LR_Structure str)
329 | {
330 | try
331 | {
332 | StructureDataType newStruct;
333 | boolean existed = false;
334 | if(structMap.containsKey(str.name)) {
335 | newStruct = structMap.get(str.name);
336 | existed = true;
337 | }
338 | else
339 | {
340 | newStruct = new StructureDataType(str.name, 0);
341 | newStruct.setPackingEnabled(true);
342 | structMap.put(str.name, newStruct);
343 | }
344 | if(str.field != 0) {
345 | if (existed) {
346 | newStruct.deleteAll();
347 | }
348 | for(TypeRecord rec : typeRecords) {
349 | if(rec.typeID == str.field)
350 | {
351 | TypeRecord.LR_FieldList fieldList = (TypeRecord.LR_FieldList)rec.record;
352 | ArrayList entries = GetFieldListMembers(fieldList);
353 | if(entries == null)
354 | return false;
355 | for(FieldMemberEntry e : entries)
356 | if(!e.isBitField)
357 | newStruct.add(e.type, e.name, e.comment);
358 | else
359 | newStruct.addBitField(e.type, (int)e.offset, e.name, e.comment);
360 | break;
361 | }
362 | }
363 | }
364 | newStruct.repack();
365 | str.dataType = newStruct;
366 | return true;
367 | }
368 | catch (Exception e)
369 | {
370 | return false;
371 | }
372 | }
373 |
374 | private ArrayList GetFieldListMembers(TypeRecord.LR_FieldList fieldList)
375 | {
376 | try
377 | {
378 | ArrayList result = new ArrayList();
379 | for(TypeRecord.MemberRecord mr : fieldList.records)
380 | switch(mr.recordKind)
381 | {
382 | case LF_MEMBER:
383 | MR_Member member = (MR_Member)mr;
384 | long offset = member.offset.val_long;
385 | DataType dt = GetDataTypeByIndex(member.index);
386 | String name = GetDataTypeNameByIndex(member.index);
387 | LeafRecordKind kind = GetTypeKind(member.index);
388 | if(dt != null && name != null)
389 | result.add(new FieldMemberEntry(offset, dt, member.name, "//" + name, false));
390 | else if(kind != null)
391 | {
392 | switch(kind)
393 | {
394 | case LF_BITFIELD:
395 | LR_Bitfield bitfield = (LR_Bitfield)typeRecords.get((int)(member.index - 0x1000)).record;
396 | dt = GetDataTypeByIndex(bitfield.type);
397 | result.add(new FieldMemberEntry(bitfield.length, dt, member.name, "", true));
398 | break;
399 | case LF_UNION:
400 | if(name != null && unionMap.containsKey(name))
401 | {
402 | result.add(new FieldMemberEntry(offset, unionMap.get(name), member.name, "//" + name, false));
403 | break;
404 | }
405 | return null;
406 | default:
407 | return null;
408 | }
409 | }
410 | else
411 | return null;
412 | break;
413 | case LF_BCLASS:
414 | case LF_BINTERFACE:
415 | MR_BClass bclass = (MR_BClass)mr;
416 | offset = bclass.offset.val_long;
417 | dt = GetDataTypeByIndex(bclass.index);
418 | name = GetDataTypeNameByIndex(bclass.index);
419 | String memberName = "__inherit_" + offset;
420 | kind = GetTypeKind(bclass.index);
421 | if(dt != null)
422 | result.add(new FieldMemberEntry(offset, dt, memberName, "//" + name, false));
423 | else if(kind != null)
424 | {
425 | switch(kind)
426 | {
427 | case LF_BITFIELD:
428 | LR_Bitfield bitfield = (LR_Bitfield)typeRecords.get((int)(bclass.index - 0x1000)).record;
429 | dt = GetDataTypeByIndex(bitfield.type);
430 | result.add(new FieldMemberEntry(bitfield.length, dt, memberName, "", true));
431 | break;
432 | case LF_UNION:
433 | if(name != null && unionMap.containsKey(name))
434 | {
435 | result.add(new FieldMemberEntry(offset, unionMap.get(name), memberName, "//" + name, false));
436 | break;
437 | }
438 | return null;
439 | default:
440 | return null;
441 | }
442 | }
443 | else
444 | return null;
445 | break;
446 | case LF_VFUNCTAB:
447 | // Placeholder void* for now, might implement something more complex later
448 | MR_VFuncTab vfunctab = (MR_VFuncTab)mr;
449 | dt = GetDataTypeByIndex(vfunctab.index);
450 | result.add(new FieldMemberEntry(0, dt, MR_VFuncTab.name, "", false));
451 | break;
452 | default:
453 | return null;
454 | }
455 | return result;
456 | }
457 | catch (Exception e)
458 | {
459 | return null;
460 | }
461 | }
462 |
463 | private boolean AddArrayType(TypeRecord.LR_Array arr)
464 | {
465 | try
466 | {
467 | DataType dt = GetDataTypeByIndex(arr.elemtype);
468 | if(dt != null)
469 | {
470 | BinaryReader b = new BinaryReader(new ByteArrayProvider(arr.val.data), true);
471 | int len = b.readUnsignedShort(0);
472 | arr.dataType = new ArrayDataType(dt, len, 0);
473 | return true;
474 | }
475 | return false;
476 | }
477 | catch (Exception ex)
478 | {
479 | return false;
480 | }
481 | }
482 |
483 | private boolean AddEnumType(TypeRecord.LR_Enum en)
484 | {
485 | for(TypeRecord rec : typeRecords)
486 | if(rec.typeID == en.field)
487 | {
488 | TypeRecord.LR_FieldList fieldList = (TypeRecord.LR_FieldList)rec.record;
489 | EnumDataType newEnum = new EnumDataType(en.name, 8);
490 | for(TypeRecord.MemberRecord m : fieldList.records)
491 | {
492 | TypeRecord.MR_Enumerate entry = (TypeRecord.MR_Enumerate)m;
493 | newEnum.add(entry.name, entry.val.val_long);
494 | }
495 | en.dataType = newEnum;
496 | return true;
497 | }
498 | return false;
499 | }
500 |
501 | public LeafRecordKind GetTypeKind(long index)
502 | {
503 | index -= 0x1000;
504 | if(index > 0 && index < typeRecords.size())
505 | return typeRecords.get((int)index).kind;
506 | return null;
507 | }
508 |
509 | public DataType GetDataTypeByIndex(long index) throws Exception
510 | {
511 | if(index < 0x1000)
512 | return GetBasicType(BasicTypes.getByValue(index));
513 | index -= 0x1000;
514 | if(index > 0 && index < typeRecords.size())
515 | {
516 | TypeRecord rec = typeRecords.get((int)index);
517 | if(rec.record != null)
518 | switch(rec.kind)
519 | {
520 | case LF_POINTER:
521 | DataType dt = GetDataTypeByIndex(((LR_Pointer)rec.record).type);
522 | return new PointerDataType(dt);
523 | case LF_ARRAY:
524 | return((LR_Array)rec.record).dataType;
525 | case LF_STRUCTURE:
526 | return ((LR_Structure)rec.record).dataType;
527 | case LF_CLASS:
528 | return ((LR_Class)rec.record).dataType;
529 | case LF_ENUM:
530 | return ((LR_Enum)rec.record).dataType;
531 | case LF_MFUNCTION:
532 | return ((LR_MemberFunction)rec.record).dataType;
533 | case LF_MODIFIER:
534 | return ((LR_Modifier)rec.record).dataType;
535 | default:
536 | index++;
537 | break;
538 | }
539 | }
540 | return null;
541 | }
542 |
543 | public String GetDataTypeNameByIndex(long index)
544 | {
545 | if(index < 0x1000)
546 | return BasicTypes.getByValue(index).name();
547 | index -= 0x1000;
548 | if(index > 0 && index < typeRecords.size())
549 | {
550 | TypeRecord rec = typeRecords.get((int)index);
551 | if(rec.record != null)
552 | switch(rec.kind)
553 | {
554 | case LF_POINTER:
555 | return GetDataTypeNameByIndex(((LR_Pointer)rec.record).type) + "*";
556 | case LF_ARRAY:
557 | return((LR_Array)rec.record).name;
558 | case LF_STRUCTURE:
559 | return ((LR_Structure)rec.record).name;
560 | case LF_CLASS:
561 | return ((LR_Class)rec.record).name;
562 | case LF_ENUM:
563 | return ((LR_Enum)rec.record).name;
564 | case LF_UNION:
565 | return ((LR_Union)rec.record).name;
566 | case LF_MODIFIER:
567 | return GetModifierTypeName((LR_Modifier)rec.record);
568 | default:
569 | break;
570 | }
571 | }
572 | return null;
573 | }
574 |
575 | public DataType GetBasicType(BasicTypes bt) throws Exception
576 | {
577 | switch(bt)
578 | {
579 | case T_INT8:
580 | case T_UINT8:
581 | case T_CHAR:
582 | case T_UCHAR:
583 | case T_RCHAR:
584 | case T_BOOL08:
585 | return new ByteDataType();
586 | case T_SHORT:
587 | case T_USHORT:
588 | case T_WCHAR:
589 | return new ShortDataType();
590 | case T_INT4:
591 | case T_UINT4:
592 | case T_32PVOID:
593 | case T_LONG:
594 | case T_ULONG:
595 | case T_HRESULT:
596 | case T_32PHRESULT:
597 | case T_32PBOOL08:
598 | case T_32PCHAR:
599 | case T_32PUCHAR:
600 | case T_32PRCHAR:
601 | case T_32PWCHAR:
602 | case T_32PLONG:
603 | case T_32PULONG:
604 | case T_32PSHORT:
605 | case T_32PUSHORT:
606 | case T_32PREAL32:
607 | case T_32PREAL64:
608 | case T_32PINT4:
609 | case T_32PUINT4:
610 | case T_32PQUAD:
611 | case T_32PUQUAD:
612 | return new IntegerDataType();
613 | case T_QUAD:
614 | case T_UQUAD:
615 | return new LongDataType();
616 | case T_REAL32:
617 | return new FloatDataType();
618 | case T_REAL64:
619 | return new DoubleDataType();
620 | default:
621 | throw new Exception("missed basic datatype " + bt.getName());
622 | }
623 | }
624 | }
625 |
--------------------------------------------------------------------------------
/XEXLoaderWV/src/main/java/xexloaderwv/TypeRecord.java:
--------------------------------------------------------------------------------
1 | package xexloaderwv;
2 |
3 | import java.util.ArrayList;
4 |
5 | import ghidra.app.util.bin.BinaryReader;
6 | import ghidra.app.util.bin.ByteArrayProvider;
7 | import ghidra.program.model.data.DataType;
8 |
9 | public class TypeRecord {
10 |
11 | public enum LeafRecordKind
12 | {
13 | LF_VTSHAPE ("LF_VTSHAPE", 0x000a),
14 | LF_LABEL ("LF_LABEL",0x000e),
15 | LF_ENDPRECOMP ("LF_ENDPRECOMP",0x0014),
16 | LF_MODIFIER ("LF_MODIFIER",0x1001),
17 | LF_POINTER ("LF_POINTER", 0x1002),
18 | LF_PROCEDURE ("LF_PROCEDURE", 0x1008),
19 | LF_MFUNCTION ("LF_MFUNCTION", 0x1009),
20 | LF_ARGLIST ("LF_ARGLIST", 0x1201),
21 | LF_FIELDLIST ("LF_FIELDLIST", 0x1203),
22 | LF_BITFIELD ("LF_BITFIELD", 0x1205),
23 | LF_METHODLIST ("LF_METHODLIST", 0x1206),
24 | LF_ARRAY ("LF_ARRAY",0x1503),
25 | LF_CLASS ("LF_CLASS", 0x1504),
26 | LF_STRUCTURE ("LF_STRUCTURE", 0x1505),
27 | LF_UNION ("LF_UNION",0x1506),
28 | LF_ENUM ("LF_ENUM", 0x1507),
29 | LF_PRECOMP ("LF_PRECOMP", 0x1509),
30 | LF_TYPESERVER2 ("LF_TYPESERVER2",0x1515),
31 | LF_INTERFACE ("LF_INTERFACE",0x1519),
32 | LF_VFTABLE ("LF_VFTABLE", 0x151d),
33 | LF_FUNC_ID ("LF_FUNC_ID", 0x1601),
34 | LF_MFUNC_ID ("LF_MFUNC_ID", 0x1602),
35 | LF_BUILDINFO ("LF_BUILDINFO",0x1603),
36 | LF_SUBSTR_LIST ("LF_SUBSTR_LIST", 0x1604),
37 | LF_STRING_ID ("LF_STRING_ID",0x1605),
38 | LF_UDT_SRC_LINE ("LF_UDT_SRC_LINE",0x1606),
39 | LF_UDT_MOD_SRC_LINE ("LF_UDT_SRC_LINE",0x1607);
40 | private final String name;
41 | private final long value;
42 | private LeafRecordKind(String name, long value) { this.name = name; this.value = value; }
43 | public String getName() { return name; }
44 | public long getValue() { return value; }
45 | public static LeafRecordKind getByValue(long l)
46 | {
47 | for(LeafRecordKind lr : LeafRecordKind.values())
48 | if(lr.value == l)
49 | return lr;
50 | return null;
51 | }
52 | }
53 |
54 | public enum MemberRecordKind
55 | {
56 | LF_BCLASS ("LF_BCLASS" , 0x1400),
57 | LF_VBCLASS ("LF_VBCLASS" , 0x1401),
58 | LF_IVBCLASS ("LF_IVBCLASS" , 0x1402),
59 | LF_INDEX ("LF_INDEX" , 0x1404),
60 | LF_VFUNCTAB ("LF_VFUNCTAB" , 0x1409),
61 | LF_ENUMERATE ("LF_ENUMERATE" , 0x1502),
62 | LF_MEMBER ("LF_MEMBER" , 0x150d),
63 | LF_STMEMBER ("LF_STMEMBER" , 0x150e),
64 | LF_METHOD ("LF_METHOD" , 0x150f),
65 | LF_NESTTYPE ("LF_NESTTYPE" , 0x1510),
66 | LF_ONEMETHOD ("LF_ONEMETHOD" , 0x1511),
67 | LF_BINTERFACE ("LF_BINTERFACE" , 0x151a),;
68 | private final String name;
69 | private final long value;
70 | private MemberRecordKind(String name, long value) { this.name = name; this.value = value; }
71 | public String getName() { return name; }
72 | public long getValue() { return value; }
73 | public static MemberRecordKind getByValue(long l)
74 | {
75 | for(MemberRecordKind mr : MemberRecordKind.values())
76 | if(mr.value == l)
77 | return mr;
78 | return null;
79 | }
80 | }
81 |
82 | public enum ValueType
83 | {
84 | LF_CHAR ("LF_CHAR", 0x8000),
85 | LF_SHORT ("LF_SHORT", 0x8001),
86 | LF_USHORT ("LF_USHORT", 0x8002),
87 | LF_LONG ("LF_LONG", 0x8003),
88 | LF_ULONG ("LF_ULONG", 0x8004),
89 | LF_REAL32 ("LF_REAL32", 0x8005),
90 | LF_REAL64 ("LF_REAL64", 0x8006),
91 | LF_REAL80 ("LF_REAL80", 0x8007),
92 | LF_REAL128 ("LF_REAL128", 0x8008),
93 | LF_QUADWORD ("LF_QUADWORD", 0x8009),
94 | LF_UQUADWORD ("LF_UQUADWORD", 0x800a),
95 | LF_REAL48 ("LF_REAL48", 0x800b),
96 | LF_COMPLEX32 ("LF_COMPLEX32", 0x800c),
97 | LF_COMPLEX64 ("LF_COMPLEX64", 0x800d),
98 | LF_COMPLEX80 ("LF_COMPLEX80", 0x800e),
99 | LF_COMPLEX128 ("LF_COMPLEX128", 0x800f),
100 | LF_VARSTRING ("LF_VARSTRING", 0x8010),
101 | LF_OCTWORD ("LF_OCTWORD", 0x8017),
102 | LF_UOCTWORD ("LF_UOCTWORD", 0x8018),
103 | LF_DECIMAL ("LF_DECIMAL", 0x8019),
104 | LF_DATE ("LF_DATE", 0x801a),
105 | LF_UTF8STRING ("LF_UTF8STRING", 0x801b),
106 | LF_REAL16 ("LF_REAL16", 0x801c);
107 | private final String name;
108 | private final long value;
109 | private ValueType(String name, long value) { this.name = name; this.value = value; }
110 | public String getName() { return name; }
111 | public long getValue() { return value; }
112 | public static ValueType getByValue(long l)
113 | {
114 | for(ValueType t : ValueType.values())
115 | if(t.value == l)
116 | return t;
117 | return null;
118 | }
119 | }
120 |
121 | public enum MProp
122 | {
123 | MTvanilla ("MTvanilla", 0x00),
124 | MTvirtual ("MTvirtual", 0x01),
125 | MTstatic ("MTstatic", 0x02),
126 | MTfriend ("MTfriend", 0x03),
127 | MTintro ("MTintro", 0x04),
128 | MTpurevirt ("MTpurevirt", 0x05),
129 | MTpureintro ("MTpureintro", 0x06),
130 | error ("error", 0x07);
131 | private final String name;
132 | private final long value;
133 | private MProp(String name, long value) { this.name = name; this.value = value; }
134 | public String getName() { return name; }
135 | public long getValue() { return value; }
136 | public static MProp getByValue(long l)
137 | {
138 | for(MProp mp : MProp.values())
139 | if(mp.value == l)
140 | return mp;
141 | return null;
142 | }
143 | }
144 |
145 | public enum Access
146 | {
147 | _unknown ("_unknown", 0),
148 | _private ("_private", 1),
149 | _protected ("_protected", 2),
150 | _public ("_public", 3);
151 | private final String name;
152 | private final long value;
153 | private Access(String name, long value) { this.name = name; this.value = value; }
154 | public String getName() { return name; }
155 | public long getValue() { return value; }
156 | public static Access getByValue(long l)
157 | {
158 | for(Access a : Access.values())
159 | if(a.value == l)
160 | return a;
161 | return null;
162 | }
163 | }
164 |
165 | public enum PointerType
166 | {
167 | PTR_BASE_SEG ("PTR_BASE_SEG", 0x03),
168 | PTR_BASE_VAL ("PTR_BASE_VAL", 0x04),
169 | PTR_BASE_SEGVAL ("PTR_BASE_SEGVAL", 0x05),
170 | PTR_BASE_ADDR ("PTR_BASE_ADDR", 0x06),
171 | PTR_BASE_SEGADDR ("PTR_BASE_SEGADDR", 0x07),
172 | PTR_BASE_TYPE ("PTR_BASE_TYPE", 0x08),
173 | PTR_BASE_SELF ("PTR_BASE_SELF", 0x09),
174 | PTR_NEAR32 ("PTR_NEAR32", 0x0a),
175 | PTR_64 ("PTR_64", 0x0c),
176 | PTR_UNUSEDPTR ("PTR_UNUSEDPTR", 0x0d);
177 | private final String name;
178 | private final long value;
179 | private PointerType(String name, long value) { this.name = name; this.value = value; }
180 | public String getName() { return name; }
181 | public long getValue() { return value; }
182 | public static PointerType getByValue(long l)
183 | {
184 | for(PointerType p : PointerType.values())
185 | if(p.value == l)
186 | return p;
187 | return null;
188 | }
189 | }
190 |
191 | public enum PointerMode
192 | {
193 | PTR_MODE_PTR ("PTR_MODE_PTR", 0x00),
194 | PTR_MODE_REF ("PTR_MODE_REF", 0x01),
195 | PTR_MODE_PMEM ("PTR_MODE_PMEM", 0x02),
196 | PTR_MODE_PMFUNC ("PTR_MODE_PMFUNC", 0x03),
197 | PTR_MODE_RESERVED ("PTR_MODE_RESERVED", 0x04);
198 | private final String name;
199 | private final long value;
200 | private PointerMode(String name, long value) { this.name = name; this.value = value; }
201 | public String getName() { return name; }
202 | public long getValue() { return value; }
203 | public static PointerMode getByValue(long l)
204 | {
205 | for(PointerMode p : PointerMode.values())
206 | if(p.value == l)
207 | return p;
208 | return null;
209 | }
210 | }
211 |
212 | public enum BasicTypes
213 | {
214 | T_NOTYPE ("T_NOTYPE", 0x0000),
215 | T_ABS ("T_ABS", 0x0001),
216 | T_SEGMENT ("T_SEGMENT", 0x0002),
217 | T_VOID ("T_VOID", 0x0003),
218 | T_HRESULT ("T_HRESULT", 0x0008),
219 | T_32PHRESULT ("T_32PHRESULT", 0x0408),
220 | T_64PHRESULT ("T_64PHRESULT", 0x0608),
221 | T_PVOID ("T_PVOID", 0x0103),
222 | T_PFVOID ("T_PFVOID", 0x0203),
223 | T_PHVOID ("T_PHVOID", 0x0303),
224 | T_32PVOID ("T_32PVOID", 0x0403),
225 | T_32PFVOID ("T_32PFVOID", 0x0503),
226 | T_64PVOID ("T_64PVOID", 0x0603),
227 | T_CURRENCY ("T_CURRENCY", 0x0004),
228 | T_NBASICSTR ("T_NBASICSTR", 0x0005),
229 | T_FBASICSTR ("T_FBASICSTR", 0x0006),
230 | T_NOTTRANS ("T_NOTTRANS", 0x0007),
231 | T_BIT ("T_BIT", 0x0060),
232 | T_PASCHAR ("T_PASCHAR", 0x0061),
233 | T_BOOL32FF ("T_BOOL32FF", 0x0062),
234 | T_CHAR ("T_CHAR", 0x0010),
235 | T_PCHAR ("T_PCHAR", 0x0110),
236 | T_PFCHAR ("T_PFCHAR", 0x0210),
237 | T_PHCHAR ("T_PHCHAR", 0x0310),
238 | T_32PCHAR ("T_32PCHAR", 0x0410),
239 | T_32PFCHAR ("T_32PFCHAR", 0x0510),
240 | T_64PCHAR ("T_64PCHAR", 0x0610),
241 | T_UCHAR ("T_UCHAR", 0x0020),
242 | T_PUCHAR ("T_PUCHAR", 0x0120),
243 | T_PFUCHAR ("T_PFUCHAR", 0x0220),
244 | T_PHUCHAR ("T_PHUCHAR", 0x0320),
245 | T_32PUCHAR ("T_32PUCHAR", 0x0420),
246 | T_32PFUCHAR ("T_32PFUCHAR", 0x0520),
247 | T_64PUCHAR ("T_64PUCHAR", 0x0620),
248 | T_RCHAR ("T_RCHAR", 0x0070),
249 | T_PRCHAR ("T_PRCHAR", 0x0170),
250 | T_PFRCHAR ("T_PFRCHAR", 0x0270),
251 | T_PHRCHAR ("T_PHRCHAR", 0x0370),
252 | T_32PRCHAR ("T_32PRCHAR", 0x0470),
253 | T_32PFRCHAR ("T_32PFRCHAR", 0x0570),
254 | T_64PRCHAR ("T_64PRCHAR", 0x0670),
255 | T_WCHAR ("T_WCHAR", 0x0071),
256 | T_PWCHAR ("T_PWCHAR", 0x0171),
257 | T_PFWCHAR ("T_PFWCHAR", 0x0271),
258 | T_PHWCHAR ("T_PHWCHAR", 0x0371),
259 | T_32PWCHAR ("T_32PWCHAR", 0x0471),
260 | T_32PFWCHAR ("T_32PFWCHAR", 0x0571),
261 | T_64PWCHAR ("T_64PWCHAR", 0x0671),
262 | T_CHAR16 ("T_CHAR16", 0x007a),
263 | T_PCHAR16 ("T_PCHAR16", 0x017a),
264 | T_PFCHAR16 ("T_PFCHAR16", 0x027a),
265 | T_PHCHAR16 ("T_PHCHAR16", 0x037a),
266 | T_32PCHAR16 ("T_32PCHAR16", 0x047a),
267 | T_32PFCHAR16 ("T_32PFCHAR16", 0x057a),
268 | T_64PCHAR16 ("T_64PCHAR16", 0x067a),
269 | T_CHAR32 ("T_CHAR32", 0x007b),
270 | T_PCHAR32 ("T_PCHAR32", 0x017b),
271 | T_PFCHAR32 ("T_PFCHAR32", 0x027b),
272 | T_PHCHAR32 ("T_PHCHAR32", 0x037b),
273 | T_32PCHAR32 ("T_32PCHAR32", 0x047b),
274 | T_32PFCHAR32 ("T_32PFCHAR32", 0x057b),
275 | T_64PCHAR32 ("T_64PCHAR32", 0x067b),
276 | T_INT1 ("T_INT1", 0x0068),
277 | T_PINT1 ("T_PINT1", 0x0168),
278 | T_PFINT1 ("T_PFINT1", 0x0268),
279 | T_PHINT1 ("T_PHINT1", 0x0368),
280 | T_32PINT1 ("T_32PINT1", 0x0468),
281 | T_32PFINT1 ("T_32PFINT1", 0x0568),
282 | T_64PINT1 ("T_64PINT1", 0x0668),
283 | T_UINT1 ("T_UINT1", 0x0069),
284 | T_PUINT1 ("T_PUINT1", 0x0169),
285 | T_PFUINT1 ("T_PFUINT1", 0x0269),
286 | T_PHUINT1 ("T_PHUINT1", 0x0369),
287 | T_32PUINT1 ("T_32PUINT1", 0x0469),
288 | T_32PFUINT1 ("T_32PFUINT1", 0x0569),
289 | T_64PUINT1 ("T_64PUINT1", 0x0669),
290 | T_SHORT ("T_SHORT", 0x0011),
291 | T_PSHORT ("T_PSHORT", 0x0111),
292 | T_PFSHORT ("T_PFSHORT", 0x0211),
293 | T_PHSHORT ("T_PHSHORT", 0x0311),
294 | T_32PSHORT ("T_32PSHORT", 0x0411),
295 | T_32PFSHORT ("T_32PFSHORT", 0x0511),
296 | T_64PSHORT ("T_64PSHORT", 0x0611),
297 | T_USHORT ("T_USHORT", 0x0021),
298 | T_PUSHORT ("T_PUSHORT", 0x0121),
299 | T_PFUSHORT ("T_PFUSHORT", 0x0221),
300 | T_PHUSHORT ("T_PHUSHORT", 0x0321),
301 | T_32PUSHORT ("T_32PUSHORT", 0x0421),
302 | T_32PFUSHORT ("T_32PFUSHORT", 0x0521),
303 | T_64PUSHORT ("T_64PUSHORT", 0x0621),
304 | T_INT2 ("T_INT2", 0x0072),
305 | T_PINT2 ("T_PINT2", 0x0172),
306 | T_PFINT2 ("T_PFINT2", 0x0272),
307 | T_PHINT2 ("T_PHINT2", 0x0372),
308 | T_32PINT2 ("T_32PINT2", 0x0472),
309 | T_32PFINT2 ("T_32PFINT2", 0x0572),
310 | T_64PINT2 ("T_64PINT2", 0x0672),
311 | T_UINT2 ("T_UINT2", 0x0073),
312 | T_PUINT2 ("T_PUINT2", 0x0173),
313 | T_PFUINT2 ("T_PFUINT2", 0x0273),
314 | T_PHUINT2 ("T_PHUINT2", 0x0373),
315 | T_32PUINT2 ("T_32PUINT2", 0x0473),
316 | T_32PFUINT2 ("T_32PFUINT2", 0x0573),
317 | T_64PUINT2 ("T_64PUINT2", 0x0673),
318 | T_LONG ("T_LONG", 0x0012),
319 | T_ULONG ("T_ULONG", 0x0022),
320 | T_PLONG ("T_PLONG", 0x0112),
321 | T_PULONG ("T_PULONG", 0x0122),
322 | T_PFLONG ("T_PFLONG", 0x0212),
323 | T_PFULONG ("T_PFULONG", 0x0222),
324 | T_PHLONG ("T_PHLONG", 0x0312),
325 | T_PHULONG ("T_PHULONG", 0x0322),
326 | T_32PLONG ("T_32PLONG", 0x0412),
327 | T_32PULONG ("T_32PULONG", 0x0422),
328 | T_32PFLONG ("T_32PFLONG", 0x0512),
329 | T_32PFULONG ("T_32PFULONG", 0x0522),
330 | T_64PLONG ("T_64PLONG", 0x0612),
331 | T_64PULONG ("T_64PULONG", 0x0622),
332 | T_INT4 ("T_INT4", 0x0074),
333 | T_PINT4 ("T_PINT4", 0x0174),
334 | T_PFINT4 ("T_PFINT4", 0x0274),
335 | T_PHINT4 ("T_PHINT4", 0x0374),
336 | T_32PINT4 ("T_32PINT4", 0x0474),
337 | T_32PFINT4 ("T_32PFINT4", 0x0574),
338 | T_64PINT4 ("T_64PINT4", 0x0674),
339 | T_UINT4 ("T_UINT4", 0x0075),
340 | T_PUINT4 ("T_PUINT4", 0x0175),
341 | T_PFUINT4 ("T_PFUINT4", 0x0275),
342 | T_PHUINT4 ("T_PHUINT4", 0x0375),
343 | T_32PUINT4 ("T_32PUINT4", 0x0475),
344 | T_32PFUINT4 ("T_32PFUINT4", 0x0575),
345 | T_64PUINT4 ("T_64PUINT4", 0x0675),
346 | T_QUAD ("T_QUAD", 0x0013),
347 | T_PQUAD ("T_PQUAD", 0x0113),
348 | T_PFQUAD ("T_PFQUAD", 0x0213),
349 | T_PHQUAD ("T_PHQUAD", 0x0313),
350 | T_32PQUAD ("T_32PQUAD", 0x0413),
351 | T_32PFQUAD ("T_32PFQUAD", 0x0513),
352 | T_64PQUAD ("T_64PQUAD", 0x0613),
353 | T_UQUAD ("T_UQUAD", 0x0023),
354 | T_PUQUAD ("T_PUQUAD", 0x0123),
355 | T_PFUQUAD ("T_PFUQUAD", 0x0223),
356 | T_PHUQUAD ("T_PHUQUAD", 0x0323),
357 | T_32PUQUAD ("T_32PUQUAD", 0x0423),
358 | T_32PFUQUAD ("T_32PFUQUAD", 0x0523),
359 | T_64PUQUAD ("T_64PUQUAD", 0x0623),
360 | T_INT8 ("T_INT8", 0x0076),
361 | T_PINT8 ("T_PINT8", 0x0176),
362 | T_PFINT8 ("T_PFINT8", 0x0276),
363 | T_PHINT8 ("T_PHINT8", 0x0376),
364 | T_32PINT8 ("T_32PINT8", 0x0476),
365 | T_32PFINT8 ("T_32PFINT8", 0x0576),
366 | T_64PINT8 ("T_64PINT8", 0x0676),
367 | T_UINT8 ("T_UINT8", 0x0077),
368 | T_PUINT8 ("T_PUINT8", 0x0177),
369 | T_PFUINT8 ("T_PFUINT8", 0x0277),
370 | T_PHUINT8 ("T_PHUINT8", 0x0377),
371 | T_32PUINT8 ("T_32PUINT8", 0x0477),
372 | T_32PFUINT8 ("T_32PFUINT8", 0x0577),
373 | T_64PUINT8 ("T_64PUINT8", 0x0677),
374 | T_OCT ("T_OCT", 0x0014),
375 | T_POCT ("T_POCT", 0x0114),
376 | T_PFOCT ("T_PFOCT", 0x0214),
377 | T_PHOCT ("T_PHOCT", 0x0314),
378 | T_32POCT ("T_32POCT", 0x0414),
379 | T_32PFOCT ("T_32PFOCT", 0x0514),
380 | T_64POCT ("T_64POCT", 0x0614),
381 | T_UOCT ("T_UOCT", 0x0024),
382 | T_PUOCT ("T_PUOCT", 0x0124),
383 | T_PFUOCT ("T_PFUOCT", 0x0224),
384 | T_PHUOCT ("T_PHUOCT", 0x0324),
385 | T_32PUOCT ("T_32PUOCT", 0x0424),
386 | T_32PFUOCT ("T_32PFUOCT", 0x0524),
387 | T_64PUOCT ("T_64PUOCT", 0x0624),
388 | T_INT16 ("T_INT16", 0x0078),
389 | T_PINT16 ("T_PINT16", 0x0178),
390 | T_PFINT16 ("T_PFINT16", 0x0278),
391 | T_PHINT16 ("T_PHINT16", 0x0378),
392 | T_32PINT16 ("T_32PINT16", 0x0478),
393 | T_32PFINT16 ("T_32PFINT16", 0x0578),
394 | T_64PINT16 ("T_64PINT16", 0x0678),
395 | T_UINT16 ("T_UINT16", 0x0079),
396 | T_PUINT16 ("T_PUINT16", 0x0179),
397 | T_PFUINT16 ("T_PFUINT16", 0x0279),
398 | T_PHUINT16 ("T_PHUINT16", 0x0379),
399 | T_32PUINT16 ("T_32PUINT16", 0x0479),
400 | T_32PFUINT16 ("T_32PFUINT16", 0x0579),
401 | T_64PUINT16 ("T_64PUINT16", 0x0679),
402 | T_REAL16 ("T_REAL16", 0x0046),
403 | T_PREAL16 ("T_PREAL16", 0x0146),
404 | T_PFREAL16 ("T_PFREAL16", 0x0246),
405 | T_PHREAL16 ("T_PHREAL16", 0x0346),
406 | T_32PREAL16 ("T_32PREAL16", 0x0446),
407 | T_32PFREAL16 ("T_32PFREAL16", 0x0546),
408 | T_64PREAL16 ("T_64PREAL16", 0x0646),
409 | T_REAL32 ("T_REAL32", 0x0040),
410 | T_PREAL32 ("T_PREAL32", 0x0140),
411 | T_PFREAL32 ("T_PFREAL32", 0x0240),
412 | T_PHREAL32 ("T_PHREAL32", 0x0340),
413 | T_32PREAL32 ("T_32PREAL32", 0x0440),
414 | T_32PFREAL32 ("T_32PFREAL32", 0x0540),
415 | T_64PREAL32 ("T_64PREAL32", 0x0640),
416 | T_REAL32PP ("T_REAL32PP", 0x0045),
417 | T_PREAL32PP ("T_PREAL32PP", 0x0145),
418 | T_PFREAL32PP ("T_PFREAL32PP", 0x0245),
419 | T_PHREAL32PP ("T_PHREAL32PP", 0x0345),
420 | T_32PREAL32PP ("T_32PREAL32PP", 0x0445),
421 | T_32PFREAL32PP ("T_32PFREAL32PP", 0x0545),
422 | T_64PREAL32PP ("T_64PREAL32PP", 0x0645),
423 | T_REAL48 ("T_REAL48", 0x0044),
424 | T_PREAL48 ("T_PREAL48", 0x0144),
425 | T_PFREAL48 ("T_PFREAL48", 0x0244),
426 | T_PHREAL48 ("T_PHREAL48", 0x0344),
427 | T_32PREAL48 ("T_32PREAL48", 0x0444),
428 | T_32PFREAL48 ("T_32PFREAL48", 0x0544),
429 | T_64PREAL48 ("T_64PREAL48", 0x0644),
430 | T_REAL64 ("T_REAL64", 0x0041),
431 | T_PREAL64 ("T_PREAL64", 0x0141),
432 | T_PFREAL64 ("T_PFREAL64", 0x0241),
433 | T_PHREAL64 ("T_PHREAL64", 0x0341),
434 | T_32PREAL64 ("T_32PREAL64", 0x0441),
435 | T_32PFREAL64 ("T_32PFREAL64", 0x0541),
436 | T_64PREAL64 ("T_64PREAL64", 0x0641),
437 | T_REAL80 ("T_REAL80", 0x0042),
438 | T_PREAL80 ("T_PREAL80", 0x0142),
439 | T_PFREAL80 ("T_PFREAL80", 0x0242),
440 | T_PHREAL80 ("T_PHREAL80", 0x0342),
441 | T_32PREAL80 ("T_32PREAL80", 0x0442),
442 | T_32PFREAL80 ("T_32PFREAL80", 0x0542),
443 | T_64PREAL80 ("T_64PREAL80", 0x0642),
444 | T_REAL128 ("T_REAL128", 0x0043),
445 | T_PREAL128 ("T_PREAL128", 0x0143),
446 | T_PFREAL128 ("T_PFREAL128", 0x0243),
447 | T_PHREAL128 ("T_PHREAL128", 0x0343),
448 | T_32PREAL128 ("T_32PREAL128", 0x0443),
449 | T_32PFREAL128 ("T_32PFREAL128", 0x0543),
450 | T_64PREAL128 ("T_64PREAL128", 0x0643),
451 | T_CPLX32 ("T_CPLX32", 0x0050),
452 | T_PCPLX32 ("T_PCPLX32", 0x0150),
453 | T_PFCPLX32 ("T_PFCPLX32", 0x0250),
454 | T_PHCPLX32 ("T_PHCPLX32", 0x0350),
455 | T_32PCPLX32 ("T_32PCPLX32", 0x0450),
456 | T_32PFCPLX32 ("T_32PFCPLX32", 0x0550),
457 | T_64PCPLX32 ("T_64PCPLX32", 0x0650),
458 | T_CPLX64 ("T_CPLX64", 0x0051),
459 | T_PCPLX64 ("T_PCPLX64", 0x0151),
460 | T_PFCPLX64 ("T_PFCPLX64", 0x0251),
461 | T_PHCPLX64 ("T_PHCPLX64", 0x0351),
462 | T_32PCPLX64 ("T_32PCPLX64", 0x0451),
463 | T_32PFCPLX64 ("T_32PFCPLX64", 0x0551),
464 | T_64PCPLX64 ("T_64PCPLX64", 0x0651),
465 | T_CPLX80 ("T_CPLX80", 0x0052),
466 | T_PCPLX80 ("T_PCPLX80", 0x0152),
467 | T_PFCPLX80 ("T_PFCPLX80", 0x0252),
468 | T_PHCPLX80 ("T_PHCPLX80", 0x0352),
469 | T_32PCPLX80 ("T_32PCPLX80", 0x0452),
470 | T_32PFCPLX80 ("T_32PFCPLX80", 0x0552),
471 | T_64PCPLX80 ("T_64PCPLX80", 0x0652),
472 | T_CPLX128 ("T_CPLX128", 0x0053),
473 | T_PCPLX128 ("T_PCPLX128", 0x0153),
474 | T_PFCPLX128 ("T_PFCPLX128", 0x0253),
475 | T_PHCPLX128 ("T_PHCPLX128", 0x0353),
476 | T_32PCPLX128 ("T_32PCPLX128", 0x0453),
477 | T_32PFCPLX128 ("T_32PFCPLX128", 0x0553),
478 | T_64PCPLX128 ("T_64PCPLX128", 0x0653),
479 | T_BOOL08 ("T_BOOL08", 0x0030),
480 | T_PBOOL08 ("T_PBOOL08", 0x0130),
481 | T_PFBOOL08 ("T_PFBOOL08", 0x0230),
482 | T_PHBOOL08 ("T_PHBOOL08", 0x0330),
483 | T_32PBOOL08 ("T_32PBOOL08", 0x0430),
484 | T_32PFBOOL08 ("T_32PFBOOL08", 0x0530),
485 | T_64PBOOL08 ("T_64PBOOL08", 0x0630),
486 | T_BOOL16 ("T_BOOL16", 0x0031),
487 | T_PBOOL16 ("T_PBOOL16", 0x0131),
488 | T_PFBOOL16 ("T_PFBOOL16", 0x0231),
489 | T_PHBOOL16 ("T_PHBOOL16", 0x0331),
490 | T_32PBOOL16 ("T_32PBOOL16", 0x0431),
491 | T_32PFBOOL16 ("T_32PFBOOL16", 0x0531),
492 | T_64PBOOL16 ("T_64PBOOL16", 0x0631),
493 | T_BOOL32 ("T_BOOL32", 0x0032),
494 | T_PBOOL32 ("T_PBOOL32", 0x0132),
495 | T_PFBOOL32 ("T_PFBOOL32", 0x0232),
496 | T_PHBOOL32 ("T_PHBOOL32", 0x0332),
497 | T_32PBOOL32 ("T_32PBOOL32", 0x0432),
498 | T_32PFBOOL32 ("T_32PFBOOL32", 0x0532),
499 | T_64PBOOL32 ("T_64PBOOL32", 0x0632),
500 | T_BOOL64 ("T_BOOL64", 0x0033),
501 | T_PBOOL64 ("T_PBOOL64", 0x0133),
502 | T_PFBOOL64 ("T_PFBOOL64", 0x0233),
503 | T_PHBOOL64 ("T_PHBOOL64", 0x0333),
504 | T_32PBOOL64 ("T_32PBOOL64", 0x0433),
505 | T_32PFBOOL64 ("T_32PFBOOL64", 0x0533),
506 | T_64PBOOL64 ("T_64PBOOL64", 0x0633),
507 | T_NCVPTR ("T_NCVPTR", 0x01f0),
508 | T_FCVPTR ("T_FCVPTR", 0x02f0),
509 | T_HCVPTR ("T_HCVPTR", 0x03f0),
510 | T_32NCVPTR ("T_32NCVPTR", 0x04f0),
511 | T_32FCVPTR ("T_32FCVPTR", 0x05f0),
512 | T_64NCVPTR ("T_64NCVPTR", 0x06f0);
513 | private final String name;
514 | private final long value;
515 | private BasicTypes(String name, long value) { this.name = name; this.value = value; }
516 | public String getName() { return name; }
517 | public long getValue() { return value; }
518 | public static BasicTypes getByValue(long l)
519 | {
520 | for(BasicTypes bt : BasicTypes.values())
521 | if(bt.value == l)
522 | return bt;
523 | return null;
524 | }
525 | }
526 |
527 | public enum CallType
528 | {
529 | NEAR_C ("NEAR_C", 0x00000000),
530 | FAR_C ("FAR_C", 0x00000001),
531 | NEAR_PASCAL ("NEAR_PASCAL", 0x00000002),
532 | FAR_PASCAL ("FAR_PASCAL", 0x00000003),
533 | NEAR_FAST ("NEAR_FAST", 0x00000004),
534 | FAR_FAST ("FAR_FAST", 0x00000005),
535 | SKIPPED ("SKIPPED", 0x00000006),
536 | NEAR_STD ("NEAR_STD", 0x00000007),
537 | FAR_STD ("FAR_STD", 0x00000008),
538 | NEAR_SYS ("NEAR_SYS", 0x00000009),
539 | FAR_SYS ("FAR_SYS", 0x0000000A),
540 | THISCALL ("THISCALL", 0x0000000B),
541 | MIPSCALL ("MIPSCALL", 0x0000000C),
542 | GENERIC ("GENERIC", 0x0000000D),
543 | ALPHACALL ("ALPHACALL", 0x0000000E),
544 | PPCCALL ("PPCCALL", 0x0000000F),
545 | SHCALL ("SHCALL", 0x00000010),
546 | ARMCALL ("ARMCALL", 0x00000011),
547 | AM33CALL ("AM33CALL", 0x00000012),
548 | TRICALL ("TRICALL", 0x00000013),
549 | SH5CALL ("SH5CALL", 0x00000014),
550 | M32RCALL ("M32RCALL", 0x00000015),
551 | RESERVED ("RESERVED", 0x00000016);
552 | private final String name;
553 | private final long value;
554 | private CallType(String name, long value) { this.name = name; this.value = value; }
555 | public String getName() { return name; }
556 | public long getValue() { return value; }
557 | public static CallType getByValue(long l)
558 | {
559 | for(CallType ct : CallType.values())
560 | if(ct.value == l)
561 | return ct;
562 | return null;
563 | }
564 | }
565 |
566 | public enum ModAttr
567 | {
568 | MOD_const ("MOD_const", 0x00000001),
569 | MOD_volatile ("MOD_volatile", 0x00000002),
570 | MOD_unaligned ("MOD_unaligned", 0x00000004);
571 | private final String name;
572 | private final long value;
573 | private ModAttr(String name, long value) { this.name = name; this.value = value; }
574 | public String getName() { return name; }
575 | public long getValue() { return value; }
576 | public static ModAttr getByValue(long l)
577 | {
578 | for(ModAttr m : ModAttr.values())
579 | if(m.value == l)
580 | return m;
581 | return null;
582 | }
583 | }
584 |
585 | public enum Shape
586 | {
587 | near ("near", 0x00),
588 | far ("far", 0x01),
589 | thin ("thin", 0x02),
590 | outer ("outer", 0x03),
591 | meta ("meta", 0x04),
592 | near32 ("near32", 0x05),
593 | far32 ("far32", 0x06),
594 | unused ("unused", 0x07);
595 | private final String name;
596 | private final long value;
597 | private Shape(String name, long value) { this.name = name; this.value = value; }
598 | public String getName() { return name; }
599 | public long getValue() { return value; }
600 | public static Shape getByValue(long l)
601 | {
602 | for(Shape s : Shape.values())
603 | if(s.value == l)
604 | return s;
605 | return null;
606 | }
607 | }
608 |
609 | public enum MOCOM_UDT
610 | {
611 | CV_MOCOM_UDT_none ("CV_MOCOM_UDT_none", 0x00),
612 | CV_MOCOM_UDT_ref ("CV_MOCOM_UDT_ref", 0x01),
613 | CV_MOCOM_UDT_value ("CV_MOCOM_UDT_value", 0x02),
614 | CV_MOCOM_UDT_interface ("CV_MOCOM_UDT_interface", 0x03);
615 | private final String name;
616 | private final long value;
617 | private MOCOM_UDT(String name, long value) { this.name = name; this.value = value; }
618 | public String getName() { return name; }
619 | public long getValue() { return value; }
620 | public static MOCOM_UDT getByValue(long l)
621 | {
622 | for(MOCOM_UDT u : MOCOM_UDT.values())
623 | if(u.value == l)
624 | return u;
625 | return null;
626 | }
627 | }
628 |
629 | public abstract class LeafRecord
630 | {
631 | public DataType dataType = null;
632 | }
633 |
634 | public abstract class MemberRecord
635 | {
636 | public MemberRecordKind recordKind;
637 | public abstract long GetSize();
638 | }
639 |
640 | public class FieldAttribute
641 | {
642 | public boolean noconstruct;
643 | public boolean noinherit;
644 | public boolean pseudo;
645 | public MProp mprop;
646 | public Access access;
647 | public boolean compgenx;
648 | public int _raw;
649 | public FieldAttribute(int attr)
650 | {
651 | _raw = attr;
652 | access = Access.getByValue(Helper.GetBits(attr, 0, 2));
653 | mprop = MProp.getByValue(Helper.GetBits(attr, 2, 3));
654 | pseudo = Helper.GetBits(attr, 5, 1) != 0;
655 | noinherit = Helper.GetBits(attr, 6, 1) != 0;
656 | noconstruct = Helper.GetBits(attr, 7, 1) != 0;
657 | compgenx = Helper.GetBits(attr, 8, 1) != 0;
658 | }
659 | }
660 |
661 | public class Property
662 | {
663 | public boolean packed;
664 | public boolean ctor;
665 | public boolean ovlops;
666 | public boolean isnested;
667 | public boolean cnested;
668 | public boolean opassign;
669 | public boolean opcast;
670 | public boolean fwdref;
671 | public boolean scoped;
672 | public boolean hasuniquename;
673 | public boolean sealed;
674 | public boolean hfa;
675 | public boolean intrinsic;
676 | public MOCOM_UDT udt;
677 | public boolean reserved;
678 | public int _raw;
679 | public Property(int u)
680 | {
681 | _raw = u;
682 | packed = Helper.GetBits(u, 0, 1) != 0;
683 | ctor = Helper.GetBits(u, 1, 1) != 0;
684 | ovlops = Helper.GetBits(u, 2, 1) != 0;
685 | isnested = Helper.GetBits(u, 3, 1) != 0;
686 | cnested = Helper.GetBits(u, 4, 1) != 0;
687 | opassign = Helper.GetBits(u, 5, 1) != 0;
688 | opcast = Helper.GetBits(u, 6, 1) != 0;
689 | fwdref = Helper.GetBits(u, 7, 1) != 0;
690 | scoped = Helper.GetBits(u, 8, 1) != 0;
691 | hasuniquename = Helper.GetBits(u, 9, 1) != 0;
692 | sealed = Helper.GetBits(u, 10, 1) != 0;
693 | hfa = Helper.GetBits(u, 11, 1) != 0;
694 | intrinsic = Helper.GetBits(u, 12, 1) != 0;
695 | udt = MOCOM_UDT.getByValue(Helper.GetBits(u, 13, 2));
696 | reserved = Helper.GetBits(u, 15, 1) != 0;
697 | }
698 | }
699 |
700 | public class Value
701 | {
702 | public ValueType type;
703 | public byte[] data;
704 | public int _rawSize;
705 | public long val_long;
706 | private BinaryReader dataReader;
707 |
708 | private void SetData(byte[] d)
709 | {
710 | data = d;
711 | dataReader = new BinaryReader(new ByteArrayProvider(data), true);
712 | _rawSize += d.length;
713 | }
714 |
715 | public Value(BinaryReader b, long pos) throws Exception
716 | {
717 | int test = b.readUnsignedShort(pos);
718 | _rawSize = 2;
719 | if(test < 0x8000)
720 | {
721 | type = ValueType.LF_USHORT;
722 | data = b.readByteArray(pos, 2);
723 | dataReader = new BinaryReader(new ByteArrayProvider(data), true);
724 | val_long = dataReader.readUnsignedValue(0, 2);
725 | }
726 | else
727 | {
728 | type = ValueType.getByValue(test);
729 | switch(type)
730 | {
731 | case LF_CHAR:
732 | SetData(b.readByteArray(pos + 2, 1));
733 | val_long = dataReader.readUnsignedValue(0, 1);
734 | break;
735 | case LF_REAL16:
736 | case LF_SHORT:
737 | case LF_USHORT:
738 | SetData(b.readByteArray(pos + 2, 2));
739 | val_long = dataReader.readUnsignedValue(0, 2);
740 | break;
741 | case LF_LONG:
742 | case LF_ULONG:
743 | case LF_REAL32:
744 | SetData(b.readByteArray(pos + 2, 4));
745 | val_long = dataReader.readUnsignedValue(0, 4);
746 | break;
747 | case LF_REAL48:
748 | SetData(b.readByteArray(pos + 2, 6));
749 | break;
750 | case LF_DATE:
751 | case LF_COMPLEX32:
752 | case LF_REAL64:
753 | case LF_QUADWORD:
754 | case LF_UQUADWORD:
755 | SetData(b.readByteArray(pos + 2, 8));
756 | val_long = dataReader.readUnsignedValue(0, 8);
757 | break;
758 | case LF_REAL80:
759 | SetData(b.readByteArray(pos + 2, 10));
760 | break;
761 | case LF_DECIMAL:
762 | case LF_OCTWORD:
763 | case LF_UOCTWORD:
764 | case LF_COMPLEX64:
765 | case LF_REAL128:
766 | SetData(b.readByteArray(pos + 2, 16));
767 | break;
768 | case LF_COMPLEX80:
769 | SetData(b.readByteArray(pos + 2, 20));
770 | break;
771 | case LF_COMPLEX128:
772 | SetData(b.readByteArray(pos + 2, 32));
773 | break;
774 | case LF_UTF8STRING:
775 | case LF_VARSTRING:
776 | int count = b.readUnsignedShort(pos + 2);
777 | _rawSize += 2;
778 | SetData(b.readByteArray(pos + 4, count));
779 | break;
780 | }
781 | }
782 | }
783 | }
784 |
785 | public class LeafPointerAttr
786 | {
787 | public PointerType ptrtype;
788 | public PointerMode ptrmode;
789 | public boolean isflat32;
790 | public boolean isvolatile;
791 | public boolean isconst;
792 | public boolean isunaligned;
793 | public boolean isrestrict;
794 | public int _raw;
795 | public LeafPointerAttr(long attr)
796 | {
797 | ptrtype = PointerType.getByValue(Helper.GetBits(attr, 0, 5));
798 | ptrmode = PointerMode.getByValue(Helper.GetBits(attr, 5, 3));
799 | isflat32 = Helper.GetBits(attr, 8, 1) != 0;
800 | isvolatile = Helper.GetBits(attr, 9, 1) != 0;
801 | isconst = Helper.GetBits(attr, 10, 1) != 0;
802 | isunaligned = Helper.GetBits(attr, 11, 1) != 0;
803 | isrestrict = Helper.GetBits(attr, 12, 1) != 0;
804 | }
805 | }
806 |
807 | public class MR_Enumerate extends MemberRecord
808 | {
809 | public FieldAttribute attr;
810 | public Value val;
811 | public String name;
812 | public MR_Enumerate(BinaryReader b, long pos) throws Exception
813 | {
814 | recordKind = MemberRecordKind.LF_ENUMERATE;
815 | attr = new FieldAttribute(b.readUnsignedShort(pos));
816 | val = new Value(b, pos + 2);
817 | name = Helper.ReadCString(b, pos + 2 + val._rawSize);
818 | }
819 |
820 | @Override
821 | public long GetSize() {
822 | return 3 + val._rawSize + name.length();
823 | }
824 | }
825 |
826 | public class MR_Member extends MemberRecord
827 | {
828 | public FieldAttribute attr;
829 | public long index;
830 | public Value offset;
831 | public String name;
832 |
833 | public MR_Member(BinaryReader b, long pos) throws Exception
834 | {
835 | recordKind = MemberRecordKind.LF_MEMBER;
836 | attr = new FieldAttribute(b.readUnsignedShort(pos));
837 | index = b.readUnsignedInt(pos + 2);
838 | offset = new Value(b, pos + 6);
839 | name = Helper.ReadCString(b, pos + 6 + offset._rawSize);
840 | }
841 |
842 | @Override
843 | public long GetSize() {
844 | return 7 + offset._rawSize + name.length();
845 | }
846 | }
847 |
848 | public class MR_BClass extends MemberRecord
849 | {
850 | public FieldAttribute attr;
851 | public long index;
852 | public Value offset;
853 |
854 | public MR_BClass(BinaryReader b, long pos) throws Exception
855 | {
856 | recordKind = MemberRecordKind.LF_BCLASS;
857 | attr = new FieldAttribute(b.readUnsignedShort(pos));
858 | index = b.readUnsignedInt(pos + 2);
859 | offset = new Value(b, pos + 6);
860 | }
861 |
862 | @Override
863 | public long GetSize() {
864 | return 6 + offset._rawSize;
865 | }
866 | }
867 |
868 | public class MR_VFuncTab extends MemberRecord
869 | {
870 | public long index;
871 | public static String name = "__vt";
872 |
873 | public MR_VFuncTab(BinaryReader b, long pos) throws Exception
874 | {
875 | recordKind = MemberRecordKind.LF_VFUNCTAB;
876 | index = b.readUnsignedInt(pos + 2);
877 | }
878 |
879 | @Override
880 | public long GetSize() {
881 | return 2 + 4;
882 | }
883 | }
884 |
885 | public class LR_FieldList extends LeafRecord
886 | {
887 | public ArrayList records;
888 | public LR_FieldList(byte[] data) throws Exception
889 | {
890 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), true);
891 | long pos = 0;
892 | records = new ArrayList();
893 | boolean exit = false;
894 | while(pos < data.length && !exit)
895 | {
896 | MemberRecordKind k = MemberRecordKind.getByValue(b.readUnsignedShort(pos));
897 | if(k == null)
898 | return;
899 | pos += 2;
900 | switch(k)
901 | {
902 | case LF_ENUMERATE:
903 | MR_Enumerate mr_e = new MR_Enumerate(b, pos);
904 | pos += mr_e.GetSize();
905 | records.add(mr_e);
906 | break;
907 | case LF_MEMBER:
908 | MR_Member mr_m = new MR_Member(b, pos);
909 | pos += mr_m.GetSize();
910 | records.add(mr_m);
911 | break;
912 | case LF_BCLASS:
913 | case LF_BINTERFACE:
914 | MR_BClass mr_b = new MR_BClass(b, pos);
915 | pos += mr_b.GetSize();
916 | records.add(mr_b);
917 | break;
918 | case LF_VFUNCTAB:
919 | MR_VFuncTab mr_v = new MR_VFuncTab(b, pos);
920 | pos += mr_v.GetSize();
921 | records.add(mr_v);
922 | break;
923 | // Placeholders for now
924 | // TODO: Use ONEMETHOD leaves to autogen vtable datatypes
925 | case LF_ONEMETHOD:
926 | int attrs = b.readUnsignedShort(pos);
927 | pos += 2;
928 | pos += 4;
929 | if ((attrs & 0x10) == 0x10) {
930 | pos += 4;
931 | }
932 | pos += Helper.ReadCString(b, pos).length() + 1;
933 | break;
934 | case LF_METHOD:
935 | pos += 2 + 4 + Helper.ReadCString(b, pos+6).length() + 1;
936 | break;
937 | case LF_NESTTYPE:
938 | pos += 2 + 4 + Helper.ReadCString(b, pos+6).length() + 1;
939 | break;
940 | case LF_STMEMBER:
941 | pos += 2 + 4 + Helper.ReadCString(b, pos+6).length() + 1;
942 | break;
943 | default:
944 | exit = true;
945 | break;
946 | }
947 | while((pos % 4) != 0)
948 | pos++;
949 | }
950 | }
951 | }
952 |
953 | public class LR_Enum extends LeafRecord
954 | {
955 | public int count;
956 | public Property property;
957 | public long utype;
958 | public long field;
959 | public String name;
960 |
961 | public LR_Enum(byte[] data) throws Exception
962 | {
963 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), true);
964 | count = b.readUnsignedShort(0);
965 | property = new Property(b.readUnsignedShort(2));
966 | utype = b.readUnsignedInt(4);
967 | field = b.readUnsignedInt(8);
968 | name = Helper.ReadCString(b, 12);
969 | }
970 | }
971 |
972 | public class LR_Structure extends LeafRecord
973 | {
974 | public int count;
975 | public Property property;
976 | public long field;
977 | public long derived;
978 | public long vshape;
979 | public Value val;
980 | public String name;
981 | public String uniquename;
982 |
983 | public LR_Structure(byte[] data) throws Exception
984 | {
985 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), true);
986 | count = b.readUnsignedShort(0);
987 | property = new Property(b.readUnsignedShort(2));
988 | field = b.readUnsignedInt(4);
989 | derived = b.readUnsignedInt(8);
990 | vshape = b.readUnsignedInt(12);
991 | val = new Value(b, 16);
992 | name = Helper.ReadCString(b, 16 + val._rawSize);
993 | if(property.hasuniquename)
994 | uniquename = Helper.ReadCString(b, 17 + val._rawSize + name.length());
995 | }
996 | }
997 |
998 | public class LR_Pointer extends LeafRecord
999 | {
1000 | public long type;
1001 | public LeafPointerAttr attr;
1002 |
1003 | public LR_Pointer(byte[] data) throws Exception
1004 | {
1005 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), true);
1006 | type = b.readUnsignedInt(0);
1007 | attr = new LeafPointerAttr(b.readUnsignedInt(4));
1008 | }
1009 | }
1010 |
1011 | public class LR_Array extends LeafRecord
1012 | {
1013 | public long elemtype;
1014 | public long idxtype;
1015 | public Value val;
1016 | public String name;
1017 |
1018 | public LR_Array(byte[] data) throws Exception
1019 | {
1020 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), true);
1021 | elemtype = b.readUnsignedInt(0);
1022 | idxtype = b.readUnsignedInt(4);
1023 | val = new Value(b, 8);
1024 | name = Helper.ReadCString(b, 8 + val._rawSize);
1025 | }
1026 | }
1027 |
1028 | public class LR_Bitfield extends LeafRecord
1029 | {
1030 | public long type;
1031 | public int length;
1032 | public int position;
1033 |
1034 | public LR_Bitfield(byte[] data) throws Exception
1035 | {
1036 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), true);
1037 | type = b.readUnsignedInt(0);
1038 | length = b.readUnsignedByte(4);
1039 | position = b.readUnsignedByte(5);
1040 | }
1041 | }
1042 |
1043 | public class LR_Union extends LeafRecord
1044 | {
1045 | public int count;
1046 | public Property property;
1047 | public long field;
1048 | public Value val;
1049 | public String name;
1050 | public String uniquename;
1051 |
1052 | public LR_Union(byte[] data) throws Exception
1053 | {
1054 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), true);
1055 | count = b.readUnsignedShort(0);
1056 | property = new Property(b.readUnsignedShort(2));
1057 | field = b.readUnsignedInt(4);
1058 | val = new Value(b, 8);
1059 | name = Helper.ReadCString(b, 8 + val._rawSize);
1060 | if(property.hasuniquename)
1061 | uniquename = Helper.ReadCString(b, 9 + val._rawSize + name.length());
1062 | }
1063 | }
1064 |
1065 | public class LR_ArgList extends LeafRecord
1066 | {
1067 | public long count;
1068 | public long[] arg;
1069 |
1070 | public LR_ArgList(byte[] data) throws Exception
1071 | {
1072 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), true);
1073 | count = b.readUnsignedInt(0);
1074 | arg = new long[(int)count];
1075 | for(int i = 0; i < count; i++)
1076 | arg[i] = b.readUnsignedInt(i * 4 + 4);
1077 | }
1078 | }
1079 |
1080 | public class LR_Procedure extends LeafRecord
1081 | {
1082 | public long rvtype;
1083 | public int calltype;
1084 | public int reserved;
1085 | public int parmcount;
1086 | public long arglist;
1087 |
1088 | public LR_Procedure(byte[] data) throws Exception
1089 | {
1090 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), true);
1091 | rvtype = b.readUnsignedInt(0);
1092 | calltype = b.readUnsignedByte(4);
1093 | reserved = b.readUnsignedByte(5);
1094 | parmcount = b.readUnsignedShort(6);
1095 | arglist = b.readUnsignedInt(8);
1096 | }
1097 | }
1098 |
1099 | public class LR_MemberFunction extends LeafRecord
1100 | {
1101 | public long rvtype;
1102 | public long classtype;
1103 | public long thistype;
1104 | public CallType calltype;
1105 | public int reserved;
1106 | public int parmcount;
1107 | public long arglist;
1108 |
1109 | public LR_MemberFunction(byte[] data) throws Exception
1110 | {
1111 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), true);
1112 | rvtype = b.readUnsignedInt(0);
1113 | classtype = b.readUnsignedInt(4);
1114 | thistype = b.readUnsignedInt(8);
1115 | calltype = CallType.getByValue(b.readUnsignedByte(12));
1116 | reserved = b.readUnsignedByte(13);
1117 | parmcount = b.readUnsignedShort(14);
1118 | arglist = b.readUnsignedInt(16);
1119 | }
1120 | }
1121 |
1122 | public class LR_Modifier extends LeafRecord
1123 | {
1124 | public long type;
1125 | public ModAttr attr;
1126 |
1127 | public LR_Modifier(byte[] data) throws Exception
1128 | {
1129 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), true);
1130 | type = b.readUnsignedInt(0);
1131 | attr = ModAttr.getByValue(b.readUnsignedShort(4));
1132 | }
1133 | }
1134 |
1135 | public class LR_MethodList extends LeafRecord
1136 | {
1137 | public class Method
1138 | {
1139 | public FieldAttribute attr;
1140 | public long index;
1141 | public long vbaseoff;
1142 | public int _rawSize;
1143 | public Method(BinaryReader b, int pos) throws Exception
1144 | {
1145 | attr = new FieldAttribute(b.readUnsignedShort(pos));
1146 | index = b.readUnsignedInt(pos + 4);
1147 | _rawSize = 8;
1148 | if(attr.mprop == MProp.MTintro || attr.mprop == MProp.MTpureintro)
1149 | {
1150 | vbaseoff = b.readUnsignedInt(pos + 8);
1151 | _rawSize = 12;
1152 | }
1153 | }
1154 | }
1155 |
1156 | public ArrayList methods;
1157 |
1158 | public LR_MethodList(byte[] data) throws Exception
1159 | {
1160 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), true);
1161 | methods = new ArrayList();
1162 | int pos = 0;
1163 | while(pos < data.length)
1164 | {
1165 | Method m = new Method(b, pos);
1166 | pos += m._rawSize;
1167 | methods.add(m);
1168 | }
1169 | }
1170 | }
1171 |
1172 | public class LR_VTShape extends LeafRecord
1173 | {
1174 | public ArrayList shapes;
1175 |
1176 | public LR_VTShape(byte[] data) throws Exception
1177 | {
1178 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), true);
1179 | int count = b.readUnsignedShort(0);
1180 | int bcount = count / 2;
1181 | if((count % 2) != 0)
1182 | bcount++;
1183 | shapes = new ArrayList();
1184 | for(int i = 0; i < bcount; i++)
1185 | {
1186 | int d = b.readUnsignedByte(2 + i);
1187 | shapes.add(Shape.getByValue(d >> 4));
1188 | if(shapes.size() == count)
1189 | break;
1190 | shapes.add(Shape.getByValue(d & 0xf));
1191 | }
1192 | }
1193 | }
1194 |
1195 | public class LR_Class extends LeafRecord
1196 | {
1197 | public int count;
1198 | public Property property;
1199 | public long field;
1200 | public long derived;
1201 | public long vshape;
1202 | public Value val;
1203 | public String name;
1204 | public String uniquename;
1205 | public LR_Class(byte[] data) throws Exception
1206 | {
1207 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), true);
1208 | count = b.readUnsignedShort(0);
1209 | property = new Property(b.readUnsignedShort(2));
1210 | field = b.readUnsignedInt(4);
1211 | derived = b.readUnsignedInt(8);
1212 | vshape = b.readUnsignedInt(12);
1213 | val = new Value(b, 16);
1214 | name = Helper.ReadCString(b, 16 + val._rawSize);
1215 | if(property.hasuniquename)
1216 | uniquename = Helper.ReadCString(b, 17 + val._rawSize + name.length());
1217 | }
1218 | }
1219 |
1220 | public long typeID;
1221 | public LeafRecordKind kind;
1222 | public LeafRecord record;
1223 |
1224 | public TypeRecord(long ID, int k, byte[] data) throws Exception
1225 | {
1226 | typeID = ID;
1227 | kind = LeafRecordKind.getByValue(k);
1228 | if(kind != null)
1229 | switch(kind)
1230 | {
1231 | case LF_FIELDLIST:
1232 | record = new LR_FieldList(data);
1233 | break;
1234 | case LF_ENUM:
1235 | record = new LR_Enum(data);
1236 | break;
1237 | case LF_STRUCTURE:
1238 | record = new LR_Structure(data);
1239 | break;
1240 | case LF_POINTER:
1241 | record = new LR_Pointer(data);
1242 | break;
1243 | case LF_ARRAY:
1244 | record = new LR_Array(data);
1245 | break;
1246 | case LF_BITFIELD:
1247 | record = new LR_Bitfield(data);
1248 | break;
1249 | case LF_UNION:
1250 | record = new LR_Union(data);
1251 | break;
1252 | case LF_ARGLIST:
1253 | record = new LR_ArgList(data);
1254 | break;
1255 | case LF_PROCEDURE:
1256 | record = new LR_Procedure(data);
1257 | break;
1258 | case LF_MFUNCTION:
1259 | record = new LR_MemberFunction(data);
1260 | break;
1261 | case LF_MODIFIER:
1262 | record = new LR_Modifier(data);
1263 | break;
1264 | case LF_METHODLIST:
1265 | record = new LR_MethodList(data);
1266 | break;
1267 | case LF_VTSHAPE:
1268 | record = new LR_VTShape(data);
1269 | break;
1270 | case LF_CLASS:
1271 | record = new LR_Class(data);
1272 | break;
1273 | default:
1274 | record = null;
1275 | break;
1276 | }
1277 | }
1278 | }
1279 |
--------------------------------------------------------------------------------
/XEXLoaderWV/src/main/java/xexloaderwv/XEXDeltaPatch.java:
--------------------------------------------------------------------------------
1 | package xexloaderwv;
2 |
3 | import ghidra.app.util.bin.BinaryReader;
4 | import ghidra.app.util.bin.ByteArrayProvider;
5 |
6 | public class XEXDeltaPatch
7 | {
8 | public int old_addr;
9 | public int new_addr;
10 | public int uncompressed_len;
11 | public int compressed_len;
12 | public byte[] patch_data;
13 | public XEXDeltaPatch(byte[] data, int pos) throws Exception
14 | {
15 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), false);
16 | old_addr = b.readInt(pos);
17 | new_addr = b.readInt(pos + 4);
18 | uncompressed_len = Helper.forceU16(b.readShort(pos + 8));
19 | compressed_len = Helper.forceU16(b.readShort(pos + 10));
20 | patch_data = Helper.ReadArray(b, pos + 12, compressed_len);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/XEXLoaderWV/src/main/java/xexloaderwv/XEXHeader.java:
--------------------------------------------------------------------------------
1 | package xexloaderwv;
2 |
3 | import java.io.ByteArrayInputStream;
4 | import java.io.ByteArrayOutputStream;
5 | import java.io.InputStream;
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | import org.apache.commons.lang3.exception.ExceptionUtils;
10 | import org.python.jline.internal.Log;
11 |
12 | import ghidra.app.util.MemoryBlockUtils;
13 | import ghidra.app.util.Option;
14 | import ghidra.app.util.bin.BinaryReader;
15 | import ghidra.app.util.bin.ByteArrayProvider;
16 | import ghidra.app.util.importer.MessageLog;
17 | import ghidra.program.model.address.Address;
18 | import ghidra.program.model.data.DataUtilities;
19 | import ghidra.program.model.data.Structure;
20 | import ghidra.program.model.data.DataUtilities.ClearDataMode;
21 | import ghidra.program.model.listing.Program;
22 | import ghidra.program.model.mem.MemoryBlock;
23 | import ghidra.program.model.symbol.SourceType;
24 | import ghidra.program.model.symbol.SymbolUtilities;
25 | import ghidra.util.Msg;
26 | import ghidra.util.task.TaskMonitor;
27 | import xexloaderwv.PDBFile.SymbolRecord;
28 |
29 | public class XEXHeader {
30 | public int magic;
31 | public int flags;
32 | public int offsetPE;
33 | public int reserved;
34 | public int offsetSecuInfo;
35 | public int nOptHeader;
36 | public ArrayList optHeaders = new ArrayList();
37 | public BaseFileFormat baseFileFormat;
38 | public XEXLoaderInfo loaderInfo;
39 | public byte[] sessionKey;
40 | public ArrayList sections = new ArrayList();
41 | public byte[] peImage;
42 | public int imageBaseAddress;
43 | public int entryPointAddress;
44 | public ArrayList stringTable;
45 | public ArrayList importLibs;
46 | public ArrayList blocks = new ArrayList();
47 | public XEXPatchDescriptor patchDescriptor;
48 |
49 | public XEXHeader(byte[] data, List list, boolean isDevKit) throws Exception
50 | {
51 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), false);
52 | magic = b.readInt(0);
53 | flags = b.readInt(4);
54 | String[] flagNames = {"Title Module","Exports To Title","System Debugger","DLL Module","Module Patch","Patch Full","Patch Delta","User Mode"};
55 | ArrayList flagList = new ArrayList();
56 | for(int i = 0; i < 8; i++)
57 | if((flags & (1 << i)) != 0)
58 | flagList.add(flagNames[i]);
59 | for(String flag : flagList)
60 | Log.info("XEX Loader: Flag : " + flag);
61 | offsetPE = b.readInt(8);
62 | reserved = b.readInt(12);
63 | offsetSecuInfo = b.readInt(16);
64 | nOptHeader = b.readInt(20);
65 | Log.info("XEX Loader: Loading optional headers");
66 | int pos = 24;
67 | for(int i = 0; i < nOptHeader; i++)
68 | {
69 | optHeaders.add(new XEXOptionalHeader(data, pos));
70 | pos += 8;
71 | }
72 | for(int i = 0; i < nOptHeader; i++)
73 | {
74 | XEXOptionalHeader oh = optHeaders.get(i);
75 | int test = oh.id & 0xFF;
76 | if(test == 0xFF)
77 | {
78 | int len = b.readInt(oh.value);
79 | oh.data = b.readByteArray(oh.value, len);
80 | }
81 | else if (test < 2)
82 | oh.data = b.readByteArray(24 + i * 8 + 4, 4);
83 | else
84 | {
85 | int len = test * 4;
86 | oh.data = b.readByteArray(oh.value, len);
87 | }
88 | }
89 | ProcessOptionalHeaders();
90 | Log.info("XEX Loader: Loading loader info");
91 | loaderInfo = new XEXLoaderInfo(data, offsetSecuInfo);
92 | loaderInfo.isDevKit = isDevKit;
93 | DecryptFileKey();
94 | Log.info("XEX Loader: Loading section info");
95 | int sectionCount = b.readInt(offsetSecuInfo + 0x180);
96 | for(int i=0; i < sectionCount; i++)
97 | sections.add(new XEXSection(data, offsetSecuInfo + (i * 24) + 0x184));
98 | if(baseFileFormat.compression != 3)
99 | ReadPEImage(data);
100 | }
101 |
102 | public void DecryptFileKey() throws Exception
103 | {
104 | byte[] key;
105 | if(loaderInfo.isDevKit)
106 | key = new byte[16];
107 | else
108 | key = Helper.hexStringToByteArray("20B185A59D28FDC340583FBB0896BF91");
109 | String s = "";
110 | for(byte b : loaderInfo.fileKey)
111 | s += String.format("%02X ", b);
112 | Log.info("XEX Loader: File key = " + s);
113 | sessionKey = Helper.AESDecrypt(key, loaderInfo.fileKey);
114 | s = "";
115 | for(byte b : sessionKey)
116 | s += String.format("%02X ", b);
117 | Log.info("XEX Loader: Session key = " + s);
118 | }
119 |
120 | public void ProcessOptionalHeaders() throws Exception
121 | {
122 | Log.info("XEX Loader: Processing section info");
123 | for(XEXOptionalHeader sec : optHeaders)
124 | {
125 | String s = "";
126 | BinaryReader b = null;
127 | if(sec.data != null)
128 | b = new BinaryReader(new ByteArrayProvider(sec.data), false);
129 | switch(sec.id >> 8)
130 | {
131 | case 0x2:
132 | for(int i = 4; i < 12; i++)
133 | s += (char)b.readByte(i);
134 | Log.info("XEX Loader: Ressource Info = " + s);
135 | break;
136 | case 0x3:
137 | baseFileFormat = new BaseFileFormat(sec.data);
138 | break;
139 | case 0x5:
140 | patchDescriptor = new XEXPatchDescriptor(sec.data, 0);
141 | break;
142 | case 0x80:
143 | for(int i = 4; i < sec.data.length; i++)
144 | {
145 | int test = b.readByte(i);
146 | if(test == 0)
147 | break;
148 | s += (char)test;
149 | }
150 | Log.info("XEX Loader: Bounding Path = " + s);
151 | break;
152 | case 0x101:
153 | entryPointAddress = b.readInt(0);
154 | Log.info("XEX Loader: Entry point address = 0x" + String.format("%08X", entryPointAddress));
155 | break;
156 | case 0x102:
157 | imageBaseAddress = b.readInt(0);
158 | Log.info("XEX Loader: Imagebase address = 0x" + String.format("%08X", imageBaseAddress));
159 | break;
160 | case 0x103:
161 | ReadImportLibraries(sec.data);
162 | break;
163 |
164 | }
165 | }
166 | }
167 |
168 | public void ProcessAdditionalPDB(PDBFile pdb, Program program, TaskMonitor monitor, boolean loadTypes, boolean loadSymbols) throws Exception
169 | {
170 |
171 | if(loadTypes)
172 | pdb.tpi.ImportTypeRecords(program, monitor);
173 | if(loadSymbols)
174 | {
175 | DOSHeader dos = new DOSHeader(peImage);
176 | NTHeader nt = new NTHeader(peImage, dos.e_lfanew);
177 | int address = imageBaseAddress;
178 | for(NTHeader.SectionHeader sec : nt.secHeaders)
179 | if(sec.Name.equals(".text"))
180 | {
181 | address += sec.VirtualAddress;
182 | break;
183 | }
184 | int count = 0;
185 | monitor.setProgress(0);
186 | monitor.setMaximum(pdb.symbols.size());
187 | monitor.setMessage("Applying symbol records");
188 | for(int i = 0; i < pdb.symbols.size(); i++)
189 | {
190 | if(monitor.isCancelled())
191 | return;
192 | monitor.setProgress(i);
193 | SymbolRecord sym = pdb.symbols.get(i);
194 | if(sym.pubsymflags == 2 && sym.rectyp == 0x110e)
195 | {
196 | Address addr = MakeAddress((address + sym.off) & 0xFFFFFFFFL);
197 | if(addr != null)
198 | {
199 | int len = sym.name.length();
200 | String s = sym.name.substring(0, len < 2000 ? len : 2000);
201 | SymbolUtilities.createPreferredLabelOrFunctionSymbol(program, addr, null, s, SourceType.ANALYSIS);
202 | count++;
203 | }
204 | }
205 | }
206 | monitor.setProgress(0);
207 | Log.info("XEX Loader: Loaded " + count + " pdb function symbols");
208 | }
209 | }
210 |
211 | public void ProcessImportLibraries(Program program, TaskMonitor monitor) throws Exception
212 | {
213 | BinaryReader b = new BinaryReader(new ByteArrayProvider(peImage), false);
214 | for(ImportLibrary lib : importLibs)
215 | {
216 | for(int i = 0; i < lib.records.size(); i++)
217 | {
218 | int address = lib.records.get(i) - imageBaseAddress;
219 | int value = b.readInt(address);
220 | int ordinal = value & 0xFFFF;
221 | int type = value >> 24;
222 | ImportFunction ipf;
223 | switch(type)
224 | {
225 | case 0:
226 | ipf = new ImportFunction();
227 | ipf.address = lib.records.get(i);
228 | ipf.ordinal = ordinal;
229 | ipf.thunk = 0;
230 | lib.functions.add(ipf);
231 | break;
232 | case 1:
233 | ipf = lib.functions.get(lib.functions.size() - 1);
234 | ipf.thunk = lib.records.get(i);
235 | break;
236 | }
237 | }
238 | }
239 | int countImpl = 0;
240 | int countThunk = 0;
241 | for(ImportLibrary lib : importLibs)
242 | {
243 | for(ImportFunction fun : lib.functions)
244 | {
245 | Address addr = MakeAddress(fun.address & 0xFFFFFFFFL);
246 | if(addr != null)
247 | {
248 | SymbolUtilities.createPreferredLabelOrFunctionSymbol(program, addr, null, "__imp__" + ImportRenamer.Rename(lib.name, fun.ordinal) , SourceType.IMPORTED);
249 | countImpl++;
250 | }
251 | if(fun.thunk != 0)
252 | {
253 | int pos = fun.thunk - imageBaseAddress;
254 | peImage[pos] = 0x38;
255 | peImage[pos + 1] = 0x60;
256 | peImage[pos + 4] = 0x38;
257 | peImage[pos + 5] = (byte)0x80;
258 | addr = MakeAddress(fun.thunk & 0xFFFFFFFFL);
259 | if(addr != null)
260 | {
261 | SymbolUtilities.createPreferredLabelOrFunctionSymbol(program, addr, null, ImportRenamer.Rename(lib.name, fun.ordinal) , SourceType.ANALYSIS);
262 | countThunk++;
263 | }
264 | }
265 | }
266 | }
267 | Log.info("XEX Loader: Added import symbols(" + countImpl + " References, " + countThunk + " Thunks)");
268 | }
269 |
270 | public void ReadStringTable(byte[] data, int start, int len) throws Exception
271 | {
272 | stringTable = new ArrayList();
273 | int pos = start;
274 | String s = "";
275 | while(pos < start + len)
276 | {
277 | if(data[pos] != 0)
278 | s += (char)data[pos];
279 | else
280 | {
281 | while(data[pos + 1] == 0 && pos < start + len - 1)
282 | pos++;
283 | stringTable.add(s);
284 | s = "";
285 | }
286 | pos++;
287 | }
288 | }
289 |
290 | public void ReadImportLibraries(byte[] data) throws Exception
291 | {
292 | importLibs = new ArrayList();
293 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), false);
294 | int pos = 4;
295 | int stringSize = b.readInt(pos);
296 | int libCount = b.readInt(pos + 4);
297 | pos += 8;
298 | ReadStringTable(data, pos, stringSize);
299 | pos += stringSize;
300 | for(int i = 0; i < libCount; i++)
301 | {
302 | ImportLibrary lib = new ImportLibrary();
303 | pos += 0x24;
304 | short nameIdx = b.readShort(pos);
305 | short count = b.readShort(pos + 2);
306 | pos += 4;
307 | lib.name = stringTable.get(nameIdx);
308 | for(int j = 0; j < count; j++)
309 | lib.records.add(b.readInt(pos + j * 4));
310 | importLibs.add(lib);
311 | pos += count * 4;
312 | }
313 | }
314 |
315 | public void ReadPEImage(byte[] data) throws Exception
316 | {
317 | Log.info("XEX Loader: Loading PE Image");
318 | int len = data.length - offsetPE;
319 | byte[] compressed;
320 | compressed = new byte[len];
321 | for(int i = 0; i < len; i ++)
322 | compressed[i] = data[offsetPE + i];
323 | Log.info("XEX Loader: Encryption type = " + baseFileFormat.encryption);
324 | Log.info("XEX Loader: Compression type = " + baseFileFormat.compression);
325 | switch(baseFileFormat.encryption)
326 | {
327 | case 0:
328 | break;
329 | case 1:
330 | String s = "";
331 | for(byte b : sessionKey)
332 | s += String.format("%02X ", b);
333 | Log.info("XEX Loader: Decrypting using key = " + s);
334 | compressed = Helper.AESDecrypt(sessionKey, compressed);
335 | break;
336 | default:
337 | throw new Exception("Encryption type " + baseFileFormat.encryption + " not supported");
338 | }
339 | peImage = new byte[loaderInfo.imageSize];
340 | int posIn = 0, posOut = 0;
341 | switch(baseFileFormat.compression)
342 | {
343 | case 1:
344 | for(BaseFileFormat.BasicCompression bc : baseFileFormat.basic)
345 | {
346 | for(int i = 0; i < bc.dataSize && posIn + i < compressed.length; i++)
347 | peImage[i + posOut] = compressed[posIn + i];
348 | posOut += bc.dataSize + bc.zeroSize;
349 | posIn += bc.dataSize;
350 | }
351 | break;
352 | case 0:
353 | case 3:
354 | peImage = compressed;
355 | break;
356 | case 2:
357 | BaseFileFormat.NormalCompression nc = baseFileFormat.normal;
358 | byte[] buff = new byte[nc.blockSize];
359 | for(int i = 0; i < nc.blockSize; i++)
360 | buff[i] = compressed[posIn + i];
361 | posIn += nc.blockSize;
362 | ByteArrayOutputStream bop = new ByteArrayOutputStream();
363 | BinaryReader br = new BinaryReader(new ByteArrayProvider(buff), false);
364 | int nextSize;
365 | do
366 | {
367 | nextSize = br.readInt(0);
368 | for(int i = 24; i < buff.length;)
369 | {
370 | len = br.readUnsignedShort(i);
371 | if(len == 0)
372 | break;
373 | for(int j = 0; j < len; j++)
374 | bop.write(buff[i + j + 2]);
375 | i += 2 + len;
376 | }
377 | if(nextSize != 0)
378 | {
379 | buff = new byte[nextSize];
380 | for(int i = 0; i < nextSize; i++)
381 | buff[i] = compressed[posIn + i];
382 | posIn += nextSize;
383 | br = new BinaryReader(new ByteArrayProvider(buff), false);
384 | }
385 | }
386 | while(nextSize != 0);
387 | byte[] input = bop.toByteArray();
388 | byte[] output = new LzxDecompression().DecompressLZX(input);
389 | for(int i = 0; i < output.length; i++)
390 | peImage[i + posOut] = output[i];
391 | break;
392 | default:
393 | throw new Exception("Compression type " + baseFileFormat.compression + " not supported");
394 | }
395 | }
396 |
397 | public void ProcessPData(byte[] data, Program program, TaskMonitor monitor) throws Exception
398 | {
399 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), false);
400 | for(int i = 0; i < data.length; i += 8)
401 | {
402 | int address = b.readInt(i);
403 | Address addr = MakeAddress(address & 0xFFFFFFFFL);
404 | if(addr != null)
405 | SymbolUtilities.createPreferredLabelOrFunctionSymbol(program, addr, null, "Function_" + String.format("%08X", address), SourceType.ANALYSIS);
406 | }
407 | Log.info("XEX Loader: Loaded " + (data.length / 8) + " additional function symbols");
408 | }
409 |
410 | public void ProcessPEImage(Program program, TaskMonitor monitor, MessageLog log, boolean ProcessPData) throws Exception
411 | {
412 | Log.info("XEX Loader: Processing PE Image");
413 | DOSHeader dos = new DOSHeader(peImage);
414 | NTHeader nt = new NTHeader(peImage, dos.e_lfanew);
415 | byte[] pdata = null;
416 | for(NTHeader.SectionHeader sec : nt.secHeaders)
417 | {
418 | int address = sec.VirtualAddress;
419 | address += imageBaseAddress;
420 | int size = sec.PhysicalAddressOrVirtualSize;
421 | Log.info("XEX Loader: Loading section " + sec.Name + " at 0x" + String.format("%08X", address) + " size = 0x" + String.format("%08X", size));
422 | byte[] data = new byte[size];
423 | if( sec.VirtualAddress + size <= peImage.length)
424 | for(int i = 0; i < size; i++)
425 | data[i] = peImage[sec.VirtualAddress + i];
426 | InputStream ds = new ByteArrayInputStream(data);
427 | String perm = "";
428 | perm += ((sec.Characteristics & 0x40000000) != 0) ? "1" : "0";
429 | perm += ((sec.Characteristics & 0x80000000) != 0) ? "1" : "0";
430 | perm += ((sec.Characteristics & 0x20000000) != 0) ? "1" : "0";
431 | MakeBlock(program, sec.Name, sec.Name, address & 0xFFFFFFFFL, ds, data.length, perm, null, log, monitor);
432 | ds.close();
433 | if(sec.Name.equals(".pdata"))
434 | pdata = data;
435 | }
436 | if(pdata != null && ProcessPData)
437 | ProcessPData(pdata, program, monitor);
438 | Address addr = MakeAddress(entryPointAddress & 0xFFFFFFFFL);
439 | if(addr != null)
440 | {
441 | program.getSymbolTable().addExternalEntryPoint(addr);
442 | program.getSymbolTable().createLabel(addr, "entry", SourceType.ANALYSIS);
443 | }
444 | }
445 |
446 | public void MakeBlock(Program program, String name, String desc, long address, InputStream s, int size, String perm, Structure struc, MessageLog log, TaskMonitor monitor)
447 | {
448 | try
449 | {
450 | byte[] bf = perm.getBytes();
451 | Address addr = program.getAddressFactory().getDefaultAddressSpace().getAddress(address);
452 | MemoryBlock block = MemoryBlockUtils.createInitializedBlock(program, false, name, addr, s, size, desc, null, bf[0] == '1', bf[1] == '1', bf[2] == '1', log, monitor);
453 | blocks.add(block);
454 | if(struc != null)
455 | DataUtilities.createData(program, block.getStart(), struc, -1, false, ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA);
456 | }
457 | catch (Exception e) {
458 | Msg.error(this, ExceptionUtils.getStackTrace(e));
459 | }
460 | }
461 |
462 | public Address MakeAddress(long address)
463 | {
464 | for(MemoryBlock block : blocks)
465 | {
466 | if(address >= block.getStart().getAddressableWordOffset() &&
467 | address <= block.getEnd().getAddressableWordOffset())
468 | {
469 | Address addr = block.getStart();
470 | return addr.add(address - addr.getAddressableWordOffset());
471 | }
472 | }
473 | return null;
474 | }
475 | }
476 |
--------------------------------------------------------------------------------
/XEXLoaderWV/src/main/java/xexloaderwv/XEXLoaderInfo.java:
--------------------------------------------------------------------------------
1 | package xexloaderwv;
2 |
3 | import ghidra.app.util.bin.BinaryReader;
4 | import ghidra.app.util.bin.ByteArrayProvider;
5 |
6 | public class XEXLoaderInfo {
7 | public int headerSize;
8 | public int imageSize;
9 | public byte[] rsaSignature;
10 | public int _unknown1;
11 | public int imageFlags;
12 | public int loadAddress;
13 | public byte[] sectionDigest;
14 | public int importTableCount;
15 | public byte[] importTableDigest;
16 | public byte[] mediaId;
17 | public byte[] fileKey;
18 | public int exportTable;
19 | public byte[] headerDigest;
20 | public int gameRegions;
21 | public int mediaFlags;
22 | public boolean isDevKit;
23 |
24 | public XEXLoaderInfo(byte[] data, int pos)
25 | {
26 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), false);
27 | try
28 | {
29 | headerSize = b.readInt(pos);
30 | imageSize = b.readInt(pos + 4);
31 | pos += 8;
32 | rsaSignature = b.readByteArray(pos, 256);
33 | pos += 256;
34 | _unknown1 = b.readInt(pos);
35 | imageFlags = b.readInt(pos + 4);
36 | loadAddress = b.readInt(pos + 8);
37 | pos += 12;
38 | sectionDigest = b.readByteArray(pos, 20);
39 | pos += 20;
40 | importTableCount = b.readInt(pos);
41 | importTableDigest = b.readByteArray(pos + 4, 20);
42 | pos += 24;
43 | mediaId = b.readByteArray(pos, 16);
44 | pos += 16;
45 | fileKey = b.readByteArray(pos, 16);
46 | pos += 16;
47 | exportTable = b.readInt(pos);
48 | pos += 4;
49 | headerDigest = b.readByteArray(pos, 20);
50 | pos += 20;
51 | gameRegions = b.readInt(pos);
52 | mediaFlags = b.readInt(pos + 4);
53 |
54 | }catch (Exception e) { }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/XEXLoaderWV/src/main/java/xexloaderwv/XEXLoaderWVLoader.java:
--------------------------------------------------------------------------------
1 | package xexloaderwv;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.nio.file.Files;
6 | import java.nio.file.Path;
7 | import java.util.ArrayList;
8 | import java.util.Collection;
9 | import java.util.List;
10 |
11 | import javax.swing.SwingConstants;
12 |
13 | import org.python.jline.internal.Log;
14 |
15 | import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
16 | import ghidra.app.services.DataTypeManagerService;
17 | import ghidra.app.util.Option;
18 | import ghidra.app.util.bin.BinaryReader;
19 | import ghidra.app.util.bin.ByteArrayProvider;
20 | import ghidra.app.util.bin.ByteProvider;
21 | import ghidra.app.util.importer.MessageLog;
22 | import ghidra.app.util.opinion.AbstractLibrarySupportLoader;
23 | import ghidra.app.util.opinion.LoadSpec;
24 | import ghidra.framework.model.DomainObject;
25 | import ghidra.program.model.lang.LanguageCompilerSpecPair;
26 | import ghidra.program.model.listing.Program;
27 | import ghidra.util.exception.CancelledException;
28 | import ghidra.util.task.TaskBuilder;
29 | import ghidra.util.task.TaskLauncher;
30 | import ghidra.util.task.TaskMonitor;
31 | import pdb.symbolserver.ui.LoadPdbDialog;
32 | import pdb.symbolserver.ui.LoadPdbDialog.LoadPdbResults;
33 |
34 | public class XEXLoaderWVLoader extends AbstractLibrarySupportLoader {
35 |
36 | @Override
37 | public Collection findSupportedLoadSpecs(ByteProvider provider) throws IOException {
38 | List loadSpecs = new ArrayList<>();
39 | Log.info("XEX Loader: Checking Signature");
40 | BinaryReader br = new BinaryReader(provider, false);
41 | if (br.readInt(0) == 0x58455832)
42 | loadSpecs.add(
43 | new LoadSpec(this, 0, new LanguageCompilerSpecPair("PowerPC:BE:64:A2ALT-32addr", "default"), true));
44 | return loadSpecs;
45 | }
46 |
47 | @Override
48 | public String getName() {
49 | return "XEX Loader by Warranty Voider";
50 | }
51 |
52 | @Override
53 | protected void load(ByteProvider provider, LoadSpec loadSpec, List options, Program program,
54 | TaskMonitor monitor, MessageLog log) throws CancelledException, IOException {
55 | try {
56 | Log.info("XEX Loader: Trying to load as retail...");
57 | LoadXEX(provider, loadSpec, options, program, monitor, log, false);
58 | } catch (Exception e) {
59 | try {
60 | Log.info("XEX Loader: Trying to load as dev kit...");
61 | LoadXEX(provider, loadSpec, options, program, monitor, log, true);
62 | } catch (Exception e2) {
63 | Log.info("XEX Loader: Failed to load");
64 | throw new IOException();
65 | }
66 | }
67 | }
68 |
69 | public void LoadXEX(ByteProvider provider, LoadSpec loadSpec, List options, Program program,
70 | TaskMonitor monitor, MessageLog log, boolean isDevKit) throws Exception {
71 | byte[] buffROM = provider.getInputStream(0).readAllBytes();
72 | String patchPath = (String) options.get(3).getValue();
73 | if (!patchPath.equals(""))
74 | buffROM = ApplyPatch(buffROM, patchPath, options, isDevKit);
75 | ByteArrayProvider bapROM = new ByteArrayProvider(buffROM);
76 | Log.info("XEX Loader: Loading header");
77 | try {
78 | XEXHeader h = new XEXHeader(buffROM, options, isDevKit);
79 | boolean processPData = (boolean) options.get(0).getValue();
80 | h.ProcessPEImage(program, monitor, log, processPData);
81 | h.ProcessImportLibraries(program, monitor);
82 | if ((boolean) options.get(1).getValue())
83 | LoadPDB(program, monitor, (boolean) options.get(2).getValue(), h);
84 | } catch (Exception e) {
85 | bapROM.close();
86 | throw new Exception(e);
87 | }
88 | bapROM.close();
89 | }
90 |
91 | public void LoadPDB(Program program, TaskMonitor monitor, boolean useExperimental, XEXHeader h) throws Exception {
92 | LoadPdbResults loadPdbResults = LoadPdbDialog.choosePdbForProgram(program);
93 | if (loadPdbResults == null || loadPdbResults.pdbFile == null)
94 | return;
95 | File pdbFile = loadPdbResults.pdbFile;
96 | if (!useExperimental) {
97 | DataTypeManagerService dataTypeManagerService = AutoAnalysisManager.getAnalysisManager(program)
98 | .getDataTypeManagerService();
99 | LoadPdbTask loadPdbTask = new LoadPdbTask(program, pdbFile, loadPdbResults.useMsDiaParser,
100 | loadPdbResults.control, dataTypeManagerService);
101 | TaskBuilder.withTask(loadPdbTask).setStatusTextAlignment(SwingConstants.LEADING).setLaunchDelay(0);
102 | new TaskLauncher(loadPdbTask, null, 0);
103 | } else
104 | h.ProcessAdditionalPDB(new PDBFile(pdbFile.getPath(), monitor, program), program, monitor, true, true);
105 | }
106 |
107 | public byte[] ChangeBaseFileFormat(byte[] image) throws Exception {
108 | BinaryReader b = new BinaryReader(new ByteArrayProvider(image), false);
109 | int offsetBFF = -1;
110 | int nOptHeader = b.readInt(20);
111 | int pos = 24;
112 | for (int i = 0; i < nOptHeader; i++) {
113 | int id = b.readInt(pos);
114 | if (id >> 8 == 3)
115 | offsetBFF = b.readInt(pos + 4);
116 | pos += 8;
117 | }
118 | image[offsetBFF + 5] = 0;
119 | image[offsetBFF + 7] = 0;
120 | return image;
121 | }
122 |
123 | public byte[] ApplyPatch(byte[] buffROM, String patchPath, List options, boolean isDevKit)
124 | throws Exception {
125 | Log.info("XEX Loader: Applying patch");
126 | byte[] buffPatch = Files.readAllBytes(Path.of(patchPath));
127 | Log.info("XEX Loader: ### Loading Original XEX");
128 | XEXHeader orgHeader = new XEXHeader(buffROM, options, isDevKit);
129 | Log.info("XEX Loader: ### Loading Patch XEX");
130 | XEXHeader patchHeader = new XEXHeader(buffPatch, options, isDevKit);
131 | if (patchHeader.baseFileFormat.compression == 3) {
132 | XEXPatchDescriptor desc = patchHeader.patchDescriptor;
133 | byte[] sourceData = new byte[desc.delta_patch.uncompressed_len];
134 | for (int i = 0; i < desc.delta_patch.uncompressed_len; i++)
135 | sourceData[i] = buffROM[i + desc.delta_patch.old_addr];
136 | byte[] patchResult = new LzxDecompression().DecompressLZX(desc.delta_patch.patch_data, sourceData,
137 | desc.delta_patch.uncompressed_len);
138 | for (int i = 0; i < desc.delta_patch.uncompressed_len; i++)
139 | buffROM[i + desc.delta_patch.new_addr] = patchResult[i];
140 | int oldSize = orgHeader.peImage.length + orgHeader.offsetPE;
141 | int totalSize = orgHeader.offsetPE + patchHeader.loaderInfo.imageSize;
142 | if (oldSize > totalSize)
143 | totalSize = oldSize;
144 | byte[] temp = new byte[totalSize];
145 | int headerSize = orgHeader.offsetPE;
146 | for (int i = 0; i < headerSize; i++)
147 | temp[i] = buffROM[i];
148 | for (int i = 0; i < orgHeader.peImage.length; i++)
149 | temp[i + headerSize] = orgHeader.peImage[i];
150 | buffROM = temp;
151 | Log.info("XEX Loader: ### Loading XEX with patched header");
152 | XEXHeader newHeader = new XEXHeader(buffROM, options, isDevKit);
153 | byte[] newSessionKey = newHeader.sessionKey;
154 | patchHeader.sessionKey = Helper.AESDecrypt(newSessionKey, patchHeader.loaderInfo.fileKey);
155 | patchHeader.ReadPEImage(buffPatch);
156 | BinaryReader b = new BinaryReader(new ByteArrayProvider(patchHeader.peImage), false);
157 | int nextBlockSize = patchHeader.baseFileFormat.normal.blockSize;
158 | int pos = 0;
159 | while (nextBlockSize != 0) {
160 | int currentBlockSize = nextBlockSize;
161 | nextBlockSize = b.readInt(pos);
162 | int start = pos;
163 | pos += 24;
164 | while (pos < start + currentBlockSize) {
165 | XEXDeltaPatch delta_patch = new XEXDeltaPatch(patchHeader.peImage, pos);
166 | if (delta_patch.old_addr == 0 && delta_patch.new_addr == 0 && delta_patch.compressed_len == 0
167 | && delta_patch.uncompressed_len == 0)
168 | break;
169 | switch (delta_patch.compressed_len) {
170 | case 0:
171 | for (int i = 0; i < delta_patch.uncompressed_len; i++)
172 | buffROM[headerSize + delta_patch.new_addr + i] = 0;
173 | pos += 12;
174 | break;
175 | case 1:
176 | for (int i = 0; i < delta_patch.uncompressed_len; i++)
177 | buffROM[headerSize + delta_patch.new_addr + i] = buffROM[headerSize + delta_patch.old_addr
178 | + i];
179 | pos += 12;
180 | break;
181 | default:
182 | byte[] patchData = new byte[delta_patch.compressed_len];
183 | for (int i = 0; i < delta_patch.compressed_len; i++)
184 | patchData[i] = patchHeader.peImage[pos + i + 12];
185 | byte[] baseData = new byte[delta_patch.uncompressed_len];
186 | for (int i = 0; i < delta_patch.uncompressed_len; i++)
187 | baseData[i] = buffROM[i + delta_patch.old_addr + headerSize];
188 | patchResult = new LzxDecompression().DecompressLZX(patchData, baseData,
189 | delta_patch.uncompressed_len);
190 | for (int i = 0; i < delta_patch.uncompressed_len; i++)
191 | buffROM[i + delta_patch.new_addr + headerSize] = patchResult[i];
192 | pos += 12 + delta_patch.compressed_len;
193 | break;
194 | }
195 | }
196 | pos = start + currentBlockSize;
197 | }
198 | }
199 | return ChangeBaseFileFormat(buffROM);
200 | }
201 |
202 | @Override
203 | public List getDefaultOptions(ByteProvider provider, LoadSpec loadSpec, DomainObject domainObject,
204 | boolean loadIntoProgram) {
205 | List list = new ArrayList ();
206 | list.add(new Option("Process .pdata", true));
207 | list.add(new Option("Load PDB File", false));
208 | list.add(new Option("use experimental PDB loader", false));
209 | list.add(new Option("Path to xexp", ""));
210 | return list;
211 | }
212 | }
213 |
--------------------------------------------------------------------------------
/XEXLoaderWV/src/main/java/xexloaderwv/XEXOptionalHeader.java:
--------------------------------------------------------------------------------
1 | package xexloaderwv;
2 |
3 | import ghidra.app.util.bin.BinaryReader;
4 | import ghidra.app.util.bin.ByteArrayProvider;
5 |
6 | public class XEXOptionalHeader {
7 |
8 | public int id;
9 | public int value;
10 | public byte[] data;
11 |
12 | public XEXOptionalHeader(byte[] data, int pos)
13 | {
14 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), false);
15 | try
16 | {
17 | id = b.readInt(pos);
18 | value = b.readInt(pos + 4);
19 | }catch (Exception e) { }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/XEXLoaderWV/src/main/java/xexloaderwv/XEXPatchDescriptor.java:
--------------------------------------------------------------------------------
1 | package xexloaderwv;
2 |
3 | import ghidra.app.util.bin.BinaryReader;
4 | import ghidra.app.util.bin.ByteArrayProvider;
5 |
6 | public class XEXPatchDescriptor {
7 | public int size;
8 | public int target_version_value;
9 | public int source_version_value;
10 | public byte[] digest_source = new byte[0x14];
11 | public byte[] image_key_source = new byte[0x10];
12 | public int size_of_target_headers;
13 | public int delta_headers_source_offset;
14 | public int delta_headers_source_size;
15 | public int delta_headers_target_offset;
16 | public int delta_image_source_offset;
17 | public int delta_image_source_size;
18 | public int delta_image_target_offset;
19 | public XEXDeltaPatch delta_patch;
20 |
21 | public XEXPatchDescriptor(byte[] data, int pos)
22 | {
23 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), false);
24 | try
25 | {
26 | size = b.readInt(pos);
27 | target_version_value = b.readInt(pos + 4);
28 | source_version_value = b.readInt(pos + 8);
29 | pos += 12;
30 | digest_source = Helper.ReadArray(b, pos, 0x14);
31 | pos += 0x14;
32 | image_key_source = Helper.ReadArray(b, pos, 0x10);
33 | pos += 0x10;
34 | size_of_target_headers = b.readInt(pos);
35 | delta_headers_source_offset = b.readInt(pos + 4);
36 | delta_headers_source_size = b.readInt(pos + 8);
37 | delta_headers_target_offset = b.readInt(pos + 12);
38 | delta_image_source_offset = b.readInt(pos + 16);
39 | delta_image_source_size = b.readInt(pos + 20);
40 | delta_image_target_offset = b.readInt(pos + 24);
41 | pos += 28;
42 | delta_patch = new XEXDeltaPatch(data, pos);
43 | }catch (Exception e) { }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/XEXLoaderWV/src/main/java/xexloaderwv/XEXSection.java:
--------------------------------------------------------------------------------
1 | package xexloaderwv;
2 |
3 | import ghidra.app.util.bin.BinaryReader;
4 | import ghidra.app.util.bin.ByteArrayProvider;
5 |
6 | public class XEXSection {
7 | public byte type;
8 | public int pageCount;
9 | public byte[] digest;
10 | public XEXSection(byte[] data, int pos) throws Exception
11 | {
12 | BinaryReader b = new BinaryReader(new ByteArrayProvider(data), false);
13 | int temp = b.readInt(pos);
14 | type = (byte)(temp & 0xF);
15 | pageCount = temp >> 4;
16 | digest = b.readByteArray(pos + 4, 20);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/XEXLoaderWV/src/test/java/README.test.txt:
--------------------------------------------------------------------------------
1 | The "test" directory is intended to hold unit test cases. The package structure within
2 | this folder should correspond to that found in the "src" folder.
3 |
--------------------------------------------------------------------------------