├── .gitattributes ├── .gitignore ├── README.md └── XEXLoaderWV ├── .antProperties.xml ├── .classpath ├── .project ├── .settings ├── org.eclipse.core.resources.prefs └── org.eclipse.jdt.core.prefs ├── Module.manifest ├── build.gradle ├── data ├── README.txt ├── build.xml ├── languages │ ├── skel.cspec │ ├── skel.ldefs │ ├── skel.opinion │ ├── skel.pspec │ ├── skel.sinc │ └── skel.slaspec └── sleighArgs.txt ├── extension.properties ├── ghidra_scripts └── README.txt ├── lib └── README.txt ├── os ├── linux64 │ └── README.txt ├── osx64 │ └── README.txt └── win64 │ └── README.txt └── src ├── main ├── help │ └── help │ │ ├── TOC_Source.xml │ │ ├── shared │ │ └── Frontpage.css │ │ └── topics │ │ └── xexloaderwv │ │ └── help.html └── java │ └── xexloaderwv │ ├── BaseFileFormat.java │ ├── DOSHeader.java │ ├── Helper.java │ ├── ImportFunction.java │ ├── ImportLibrary.java │ ├── ImportRenamer.java │ ├── LoadPdbTask.java │ ├── LzxDecompression.java │ ├── NTHeader.java │ ├── PDBFile.java │ ├── TPIStream.java │ ├── TypeRecord.java │ ├── XEXDeltaPatch.java │ ├── XEXHeader.java │ ├── XEXLoaderInfo.java │ ├── XEXLoaderWVLoader.java │ ├── XEXOptionalHeader.java │ ├── XEXPatchDescriptor.java │ └── XEXSection.java └── test └── java └── README.test.txt /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | XEXLoaderWV/src/main/help/help/xexloaderwv_TOC.xml 2 | XEXLoaderWV/src/main/help/help/xexloaderwv_map.xml 3 | XEXLoaderWV/src/main/help/help/xexloaderwv_HelpSet.hs 4 | XEXLoaderWV/src/main/help/help/topics/xexloaderwv/help.html 5 | XEXLoaderWV/src/main/help/help/topics/xexloaderwv/help.html 6 | XEXLoaderWV/.classpath 7 | XEXLoaderWV/.gradle/ 8 | XEXLoaderWV/.settings/ 9 | XEXLoaderWV/bin/ 10 | XEXLoaderWV/build/ 11 | XEXLoaderWV/dist/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # X360 XEX Loader for Ghidra by Warranty Voider 2 | 3 | this is a loader module for ghidra for XBox360 XEX files 4 | 5 | - supports PDB/XDB files 6 | - In loader import page, click Advanced. 7 | - Tick `Load PDB File` + `Use experimental PDB loader` and untick `Process .pdata` 8 | - Select `MSDIA` parser 9 | - supports XEXP delta patches 10 | 11 | requires min. JDK 17 12 | 13 | [![Alt text](https://img.youtube.com/vi/coGz0f7hHTM/0.jpg)](https://www.youtube.com/watch?v=coGz0f7hHTM) 14 | 15 | 16 | 17 | 18 | ## Build problem with gradle wrapper 19 | 20 | EDIT:2025.04.05 21 | 22 | it seems you have to update 23 | 24 | ```(Ghidra Install Dir)\Ghidra\application.properties``` 25 | 26 | and upgrade the gradle version like this 27 | 28 | ```application.gradle.min=8.10``` 29 | 30 | if you have problems with building from source in eclipse with the gradle wrapper. 31 | -------------------------------------------------------------------------------- /XEXLoaderWV/.antProperties.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /XEXLoaderWV/.classpath: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /XEXLoaderWV/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | XEXLoaderWV 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.buildship.core.gradleprojectbuilder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.buildship.core.gradleprojectnature 22 | 23 | 24 | 25 | Ghidra 26 | 2 27 | C:/Users/wv/Desktop/ghidra 28 | 29 | 30 | 31 | 32 | 1742916975364 33 | 34 | 30 35 | 36 | org.eclipse.core.resources.regexFilterMatcher 37 | node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /XEXLoaderWV/.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding/=UTF-8 3 | -------------------------------------------------------------------------------- /XEXLoaderWV/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=21 3 | org.eclipse.jdt.core.compiler.compliance=21 4 | org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=error 5 | org.eclipse.jdt.core.compiler.problem.autoboxing=ignore 6 | org.eclipse.jdt.core.compiler.problem.deprecation=warning 7 | org.eclipse.jdt.core.compiler.problem.discouragedReference=warning 8 | org.eclipse.jdt.core.compiler.problem.emptyStatement=warning 9 | org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore 10 | org.eclipse.jdt.core.compiler.problem.fieldHiding=warning 11 | org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning 12 | org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning 13 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=error 14 | org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=error 15 | org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=error 16 | org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning 17 | org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning 18 | org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning 19 | org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning 20 | org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore 21 | org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore 22 | org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore 23 | org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning 24 | org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore 25 | org.eclipse.jdt.core.compiler.problem.nullReference=warning 26 | org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning 27 | org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore 28 | org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning 29 | org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning 30 | org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning 31 | org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled 32 | org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore 33 | org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning 34 | org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning 35 | org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore 36 | org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning 37 | org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning 38 | org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning 39 | org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore 40 | org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning 41 | org.eclipse.jdt.core.compiler.problem.unusedImport=warning 42 | org.eclipse.jdt.core.compiler.problem.unusedLabel=warning 43 | org.eclipse.jdt.core.compiler.problem.unusedLocal=warning 44 | org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore 45 | org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning 46 | org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning 47 | org.eclipse.jdt.core.compiler.source=21 48 | -------------------------------------------------------------------------------- /XEXLoaderWV/Module.manifest: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeroKilo/XEXLoaderWV/7d1da43c50b350b49045c0c366fef77d986db86a/XEXLoaderWV/Module.manifest -------------------------------------------------------------------------------- /XEXLoaderWV/build.gradle: -------------------------------------------------------------------------------- 1 | // Builds a Ghidra Extension for a given Ghidra installation. 2 | // 3 | // An absolute path to the Ghidra installation directory must be supplied either by setting the 4 | // GHIDRA_INSTALL_DIR environment variable or Gradle project property: 5 | // 6 | // > export GHIDRA_INSTALL_DIR= 7 | // > gradle 8 | // 9 | // or 10 | // 11 | // > gradle -PGHIDRA_INSTALL_DIR= 12 | // 13 | // Gradle should be invoked from the directory of the project to build. Please see the 14 | // application.gradle.version property in /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