@futpib/parser 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +24 -0
- package/.github/workflows/main.yml +1 -0
- package/build/androidPackageParser.js +30 -32
- package/build/arbitraryDalvikBytecode.d.ts +3 -3
- package/build/arbitraryDalvikBytecode.js +33 -27
- package/build/arbitraryDalvikExecutable.js +55 -17
- package/build/arbitraryJava.d.ts +31 -0
- package/build/arbitraryJava.js +532 -0
- package/build/arbitraryJavaScript.d.ts +3 -0
- package/build/arbitraryJavaScript.js +263 -0
- package/build/arbitraryJavascript.d.ts +3 -0
- package/build/arbitraryJavascript.js +263 -0
- package/build/arbitraryZig.d.ts +3 -0
- package/build/arbitraryZig.js +240 -0
- package/build/arbitraryZipStream.d.ts +1 -1
- package/build/arrayParser.js +72 -13
- package/build/backsmali.d.ts +4 -3
- package/build/backsmali.js +26 -6
- package/build/bash.d.ts +6 -1
- package/build/bashParser.js +131 -90
- package/build/bashParser.test.js +162 -0
- package/build/bashParserEdgeCases.test.d.ts +1 -0
- package/build/bashParserEdgeCases.test.js +117 -0
- package/build/dalvikBytecodeParser/addressConversion.d.ts +110 -0
- package/build/dalvikBytecodeParser/addressConversion.js +334 -0
- package/build/dalvikBytecodeParser/formatParsers.d.ts +7 -6
- package/build/dalvikBytecodeParser/formatParsers.js +13 -14
- package/build/dalvikBytecodeParser.d.ts +60 -31
- package/build/dalvikBytecodeParser.js +92 -35
- package/build/dalvikBytecodeParser.test-d.d.ts +1 -0
- package/build/dalvikBytecodeParser.test-d.js +268 -0
- package/build/dalvikBytecodeUnparser/formatUnparsers.d.ts +9 -8
- package/build/dalvikBytecodeUnparser/formatUnparsers.js +13 -12
- package/build/dalvikBytecodeUnparser.d.ts +2 -2
- package/build/dalvikBytecodeUnparser.js +23 -23
- package/build/dalvikBytecodeUnparser.test.js +7 -7
- package/build/dalvikExecutable.d.ts +3 -3
- package/build/dalvikExecutable.test-d.d.ts +1 -0
- package/build/dalvikExecutable.test-d.js +59 -0
- package/build/dalvikExecutableParser/typedNumbers.d.ts +18 -0
- package/build/dalvikExecutableParser/typedNumbers.js +3 -0
- package/build/dalvikExecutableParser.d.ts +2 -1
- package/build/dalvikExecutableParser.js +96 -77
- package/build/dalvikExecutableParser.test.js +24 -3
- package/build/dalvikExecutableParserAgainstSmaliParser.test.js +3 -0
- package/build/dalvikExecutableUnparser/poolScanners.d.ts +2 -2
- package/build/dalvikExecutableUnparser/sectionUnparsers.d.ts +3 -3
- package/build/dalvikExecutableUnparser/sectionUnparsers.js +26 -11
- package/build/dalvikExecutableUnparser.d.ts +2 -2
- package/build/dalvikExecutableUnparser.test.js +2 -1
- package/build/disjunctionParser.d.ts +5 -3
- package/build/disjunctionParser.js +79 -17
- package/build/disjunctionParser.test-d.d.ts +1 -0
- package/build/disjunctionParser.test-d.js +72 -0
- package/build/elementSwitchParser.d.ts +4 -0
- package/build/{exactElementSwitchParser.js → elementSwitchParser.js} +3 -4
- package/build/elementSwitchParser.test-d.d.ts +1 -0
- package/build/elementSwitchParser.test-d.js +44 -0
- package/build/exactSequenceParser.d.ts +4 -2
- package/build/exactSequenceParser.test-d.d.ts +1 -0
- package/build/exactSequenceParser.test-d.js +36 -0
- package/build/fetchCid.js +2 -66
- package/build/index.d.ts +3 -2
- package/build/index.js +2 -1
- package/build/index.test.js +16 -1
- package/build/inputReader.d.ts +10 -0
- package/build/inputReader.js +36 -0
- package/build/java.d.ts +502 -0
- package/build/java.js +2 -0
- package/build/javaKeyStoreParser.js +14 -17
- package/build/javaParser.d.ts +51 -0
- package/build/javaParser.js +1538 -0
- package/build/javaParser.test.d.ts +1 -0
- package/build/javaParser.test.js +1287 -0
- package/build/javaScript.d.ts +35 -0
- package/build/javaScript.js +1 -0
- package/build/javaScriptParser.d.ts +9 -0
- package/build/javaScriptParser.js +34 -0
- package/build/javaScriptUnparser.d.ts +3 -0
- package/build/javaScriptUnparser.js +4 -0
- package/build/javaScriptUnparser.test.d.ts +1 -0
- package/build/javaScriptUnparser.test.js +24 -0
- package/build/javaUnparser.d.ts +2 -0
- package/build/javaUnparser.js +519 -0
- package/build/javaUnparser.test.d.ts +1 -0
- package/build/javaUnparser.test.js +24 -0
- package/build/javascript.d.ts +35 -0
- package/build/javascript.js +1 -0
- package/build/javascriptParser.d.ts +9 -0
- package/build/javascriptParser.js +34 -0
- package/build/javascriptUnparser.d.ts +3 -0
- package/build/javascriptUnparser.js +4 -0
- package/build/javascriptUnparser.test.d.ts +1 -0
- package/build/javascriptUnparser.test.js +24 -0
- package/build/jsonParser.js +2 -12
- package/build/lazyMessageError.d.ts +3 -0
- package/build/lookaheadParser.js +60 -3
- package/build/negativeLookaheadParser.js +70 -11
- package/build/nonEmptyArrayParser.js +72 -13
- package/build/objectParser.d.ts +12 -0
- package/build/objectParser.js +31 -0
- package/build/objectParser.test-d.d.ts +1 -0
- package/build/objectParser.test-d.js +112 -0
- package/build/objectParser.test.d.ts +1 -0
- package/build/objectParser.test.js +55 -0
- package/build/optionalParser.js +69 -10
- package/build/parser.d.ts +4 -0
- package/build/parser.js +3 -1
- package/build/parser.test.js +114 -1
- package/build/parserConsumedSequenceParser.js +66 -7
- package/build/parserContext.d.ts +6 -0
- package/build/parserContext.js +20 -11
- package/build/parserError.d.ts +119 -27
- package/build/parserError.js +16 -8
- package/build/regexpParser.js +33 -3
- package/build/regexpParser.test.js +31 -0
- package/build/regularExpressionParser.js +35 -15
- package/build/separatedArrayParser.js +73 -14
- package/build/separatedNonEmptyArrayParser.js +73 -14
- package/build/sliceBoundedParser.js +62 -5
- package/build/smaliParser.d.ts +7 -7
- package/build/smaliParser.js +185 -268
- package/build/smaliParser.test.js +58 -0
- package/build/stringEscapes.d.ts +5 -0
- package/build/stringEscapes.js +244 -0
- package/build/symbolicExpression.d.ts +29 -0
- package/build/symbolicExpression.js +1 -0
- package/build/symbolicExpressionParser.d.ts +4 -0
- package/build/symbolicExpressionParser.js +123 -0
- package/build/symbolicExpressionParser.test.d.ts +1 -0
- package/build/symbolicExpressionParser.test.js +289 -0
- package/build/terminatedArrayParser.js +113 -38
- package/build/terminatedArrayParser.test.js +4 -2
- package/build/tupleParser.d.ts +7 -15
- package/build/tupleParser.js +1 -0
- package/build/unionParser.d.ts +5 -3
- package/build/unionParser.js +7 -2
- package/build/unionParser.test-d.d.ts +1 -0
- package/build/unionParser.test-d.js +72 -0
- package/build/unionParser.test.js +10 -11
- package/build/zig.d.ts +280 -0
- package/build/zig.js +2 -0
- package/build/zigParser.d.ts +3 -0
- package/build/zigParser.js +1119 -0
- package/build/zigParser.test.d.ts +1 -0
- package/build/zigParser.test.js +1590 -0
- package/build/zigUnparser.d.ts +2 -0
- package/build/zigUnparser.js +460 -0
- package/build/zigUnparser.test.d.ts +1 -0
- package/build/zigUnparser.test.js +24 -0
- package/build/zipParser.js +19 -32
- package/build/zipUnparser.js +19 -7
- package/build/zipUnparser.test.js +1 -1
- package/node_modules-@types/s-expression/index.d.ts +5 -0
- package/package.json +24 -6
- package/src/androidPackageParser.ts +33 -60
- package/src/arbitraryDalvikBytecode.ts +39 -31
- package/src/arbitraryDalvikExecutable.ts +65 -20
- package/src/arbitraryJava.ts +804 -0
- package/src/arbitraryJavaScript.ts +410 -0
- package/src/arbitraryZig.ts +380 -0
- package/src/arrayParser.ts +1 -3
- package/src/backsmali.ts +35 -4
- package/src/bash.ts +8 -1
- package/src/bashParser.test.ts +258 -0
- package/src/bashParser.ts +180 -143
- package/src/dalvikBytecodeParser/addressConversion.ts +496 -0
- package/src/dalvikBytecodeParser/formatParsers.ts +19 -29
- package/src/dalvikBytecodeParser.test-d.ts +310 -0
- package/src/dalvikBytecodeParser.ts +194 -69
- package/src/dalvikBytecodeUnparser/formatUnparsers.ts +27 -26
- package/src/dalvikBytecodeUnparser.test.ts +7 -7
- package/src/dalvikBytecodeUnparser.ts +31 -30
- package/src/dalvikExecutable.test-d.ts +132 -0
- package/src/dalvikExecutable.ts +3 -3
- package/src/dalvikExecutableParser/typedNumbers.ts +11 -0
- package/src/dalvikExecutableParser.test.ts +37 -3
- package/src/dalvikExecutableParser.test.ts.md +163 -2
- package/src/dalvikExecutableParser.test.ts.snap +0 -0
- package/src/dalvikExecutableParser.ts +121 -139
- package/src/dalvikExecutableParserAgainstSmaliParser.test.ts +4 -0
- package/src/dalvikExecutableUnparser/poolScanners.ts +6 -6
- package/src/dalvikExecutableUnparser/sectionUnparsers.ts +38 -14
- package/src/dalvikExecutableUnparser.test.ts +3 -2
- package/src/dalvikExecutableUnparser.ts +4 -4
- package/src/disjunctionParser.test-d.ts +105 -0
- package/src/disjunctionParser.ts +18 -15
- package/src/elementSwitchParser.test-d.ts +74 -0
- package/src/elementSwitchParser.ts +51 -0
- package/src/exactSequenceParser.test-d.ts +43 -0
- package/src/exactSequenceParser.ts +13 -8
- package/src/fetchCid.ts +2 -76
- package/src/index.test.ts +22 -1
- package/src/index.ts +7 -1
- package/src/inputReader.ts +53 -0
- package/src/java.ts +708 -0
- package/src/javaKeyStoreParser.ts +18 -32
- package/src/javaParser.test.ts +1592 -0
- package/src/javaParser.ts +2640 -0
- package/src/javaScript.ts +36 -0
- package/src/javaScriptParser.ts +57 -0
- package/src/javaScriptUnparser.test.ts +37 -0
- package/src/javaScriptUnparser.ts +7 -0
- package/src/javaUnparser.test.ts +37 -0
- package/src/javaUnparser.ts +640 -0
- package/src/jsonParser.ts +6 -27
- package/src/lookaheadParser.ts +2 -6
- package/src/negativeLookaheadParser.ts +1 -3
- package/src/nonEmptyArrayParser.ts +1 -3
- package/src/objectParser.test-d.ts +152 -0
- package/src/objectParser.test.ts +71 -0
- package/src/objectParser.ts +69 -0
- package/src/optionalParser.ts +1 -3
- package/src/parser.test.ts +151 -4
- package/src/parser.ts +11 -1
- package/src/parserConsumedSequenceParser.ts +2 -4
- package/src/parserContext.ts +26 -11
- package/src/parserError.ts +17 -3
- package/src/regexpParser.test.ts +78 -0
- package/src/regexpParser.ts +35 -3
- package/src/regularExpressionParser.ts +36 -37
- package/src/separatedArrayParser.ts +1 -3
- package/src/separatedNonEmptyArrayParser.ts +1 -3
- package/src/sliceBoundedParser.test.ts +2 -2
- package/src/sliceBoundedParser.ts +15 -19
- package/src/smaliParser.test.ts +64 -0
- package/src/smaliParser.test.ts.md +12 -12
- package/src/smaliParser.test.ts.snap +0 -0
- package/src/smaliParser.ts +246 -534
- package/src/stringEscapes.ts +253 -0
- package/src/symbolicExpression.ts +17 -0
- package/src/symbolicExpressionParser.test.ts +466 -0
- package/src/symbolicExpressionParser.ts +190 -0
- package/src/terminatedArrayParser.test.ts +9 -6
- package/src/terminatedArrayParser.ts +25 -29
- package/src/tupleParser.ts +21 -18
- package/src/unionParser.test-d.ts +105 -0
- package/src/unionParser.test.ts +18 -17
- package/src/unionParser.ts +28 -16
- package/src/zig.ts +411 -0
- package/src/zigParser.test.ts +1693 -0
- package/src/zigParser.ts +1745 -0
- package/src/zigUnparser.test.ts +37 -0
- package/src/zigUnparser.ts +615 -0
- package/src/zipParser.ts +20 -56
- package/src/zipUnparser.test.ts +1 -1
- package/src/zipUnparser.ts +22 -7
- package/tsconfig.json +2 -2
- package/build/exactElementSwitchParser.d.ts +0 -3
- package/src/exactElementSwitchParser.ts +0 -41
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type Unparser } from '../unparser.js';
|
|
2
|
+
import { type CodeUnit, isoCodeUnit } from '../dalvikExecutableParser/typedNumbers.js';
|
|
2
3
|
|
|
3
4
|
// Basic type unparsers
|
|
4
5
|
export const ubyteUnparser: Unparser<number, Uint8Array> = async function * (input) {
|
|
@@ -55,13 +56,13 @@ export const nibblesUnparser: Unparser<[ number, number ], Uint8Array> = async f
|
|
|
55
56
|
yield * ubyteUnparser(byte, unparserContext);
|
|
56
57
|
};
|
|
57
58
|
|
|
58
|
-
// Format 10t:
|
|
59
|
+
// Format 10t: branchOffsetCodeUnit (1 byte signed)
|
|
59
60
|
type DalvikBytecodeFormat10t = {
|
|
60
|
-
|
|
61
|
+
branchOffsetCodeUnit: CodeUnit;
|
|
61
62
|
};
|
|
62
63
|
|
|
63
64
|
export const dalvikBytecodeFormat10tUnparser: Unparser<DalvikBytecodeFormat10t, Uint8Array> = async function * (input, unparserContext) {
|
|
64
|
-
yield * byteUnparser(input.
|
|
65
|
+
yield * byteUnparser(isoCodeUnit.unwrap(input.branchOffsetCodeUnit), unparserContext);
|
|
65
66
|
};
|
|
66
67
|
|
|
67
68
|
// Format 10x: no data
|
|
@@ -104,14 +105,14 @@ export const dalvikBytecodeFormat12xReversedUnparser: Unparser<DalvikBytecodeFor
|
|
|
104
105
|
yield * nibblesUnparser([ input.registers[1], input.registers[0] ], unparserContext);
|
|
105
106
|
};
|
|
106
107
|
|
|
107
|
-
// Format 20t: zero byte +
|
|
108
|
+
// Format 20t: zero byte + branchOffsetCodeUnit (2 bytes signed)
|
|
108
109
|
type DalvikBytecodeFormat20t = {
|
|
109
|
-
|
|
110
|
+
branchOffsetCodeUnit: CodeUnit;
|
|
110
111
|
};
|
|
111
112
|
|
|
112
113
|
export const dalvikBytecodeFormat20tUnparser: Unparser<DalvikBytecodeFormat20t, Uint8Array> = async function * (input, unparserContext) {
|
|
113
114
|
yield * ubyteUnparser(0, unparserContext);
|
|
114
|
-
yield * shortUnparser(input.
|
|
115
|
+
yield * shortUnparser(isoCodeUnit.unwrap(input.branchOffsetCodeUnit), unparserContext);
|
|
115
116
|
};
|
|
116
117
|
|
|
117
118
|
// Format 21c: register + index (2 bytes)
|
|
@@ -136,15 +137,15 @@ export const dalvikBytecodeFormat21hUnparser: Unparser<DalvikBytecodeFormat21h,
|
|
|
136
137
|
yield * ushortUnparser(input.value, unparserContext);
|
|
137
138
|
};
|
|
138
139
|
|
|
139
|
-
// Format 21t: register +
|
|
140
|
+
// Format 21t: register + branchOffsetCodeUnit (2 bytes signed)
|
|
140
141
|
type DalvikBytecodeFormat21t = {
|
|
141
|
-
|
|
142
|
+
branchOffsetCodeUnit: CodeUnit;
|
|
142
143
|
registers: number[];
|
|
143
144
|
};
|
|
144
145
|
|
|
145
146
|
export const dalvikBytecodeFormat21tUnparser: Unparser<DalvikBytecodeFormat21t, Uint8Array> = async function * (input, unparserContext) {
|
|
146
147
|
yield * ubyteUnparser(input.registers[0], unparserContext);
|
|
147
|
-
yield * shortUnparser(input.
|
|
148
|
+
yield * shortUnparser(isoCodeUnit.unwrap(input.branchOffsetCodeUnit), unparserContext);
|
|
148
149
|
};
|
|
149
150
|
|
|
150
151
|
// Format 21s: register + value (2 bytes signed)
|
|
@@ -192,22 +193,22 @@ export const dalvikBytecodeFormat22sUnparser: Unparser<DalvikBytecodeFormat22s,
|
|
|
192
193
|
yield * shortUnparser(input.value, unparserContext);
|
|
193
194
|
};
|
|
194
195
|
|
|
195
|
-
// Format 22t: two registers in nibbles +
|
|
196
|
+
// Format 22t: two registers in nibbles + branchOffsetCodeUnit (2 bytes signed)
|
|
196
197
|
type DalvikBytecodeFormat22t = {
|
|
197
|
-
|
|
198
|
+
branchOffsetCodeUnit: CodeUnit;
|
|
198
199
|
registers: number[];
|
|
199
200
|
};
|
|
200
201
|
|
|
201
202
|
export const dalvikBytecodeFormat22tUnparser: Unparser<DalvikBytecodeFormat22t, Uint8Array> = async function * (input, unparserContext) {
|
|
202
203
|
yield * nibblesUnparser([ input.registers[1], input.registers[0] ], unparserContext);
|
|
203
|
-
yield * shortUnparser(input.
|
|
204
|
+
yield * shortUnparser(isoCodeUnit.unwrap(input.branchOffsetCodeUnit), unparserContext);
|
|
204
205
|
};
|
|
205
206
|
|
|
206
207
|
// Format 22t for commutative operations (if-eq, if-ne): registers are already in sorted/canonical order
|
|
207
208
|
// so we don't reverse them
|
|
208
209
|
export const dalvikBytecodeFormat22tCommutativeUnparser: Unparser<DalvikBytecodeFormat22t, Uint8Array> = async function * (input, unparserContext) {
|
|
209
210
|
yield * nibblesUnparser([ input.registers[0], input.registers[1] ], unparserContext);
|
|
210
|
-
yield * shortUnparser(input.
|
|
211
|
+
yield * shortUnparser(isoCodeUnit.unwrap(input.branchOffsetCodeUnit), unparserContext);
|
|
211
212
|
};
|
|
212
213
|
|
|
213
214
|
// Format 22x: register + register (2 bytes)
|
|
@@ -231,13 +232,13 @@ export const dalvikBytecodeFormat23xUnparser: Unparser<DalvikBytecodeFormat23x,
|
|
|
231
232
|
yield * ubyteUnparser(input.registers[2], unparserContext);
|
|
232
233
|
};
|
|
233
234
|
|
|
234
|
-
// Format 30t: zero byte +
|
|
235
|
+
// Format 30t: zero byte + branchOffsetCodeUnit (4 bytes signed)
|
|
235
236
|
type DalvikBytecodeFormat30t = {
|
|
236
|
-
|
|
237
|
+
branchOffsetCodeUnit: CodeUnit;
|
|
237
238
|
};
|
|
238
239
|
|
|
239
240
|
export const dalvikBytecodeFormat30tUnparser: Unparser<DalvikBytecodeFormat30t, Uint8Array> = async function * (input, unparserContext) {
|
|
240
|
-
yield * intUnparser(input.
|
|
241
|
+
yield * intUnparser(isoCodeUnit.unwrap(input.branchOffsetCodeUnit), unparserContext);
|
|
241
242
|
};
|
|
242
243
|
|
|
243
244
|
// Format 31i: register + value (4 bytes signed)
|
|
@@ -262,15 +263,15 @@ export const dalvikBytecodeFormat31cUnparser: Unparser<DalvikBytecodeFormat31c,
|
|
|
262
263
|
yield * uintUnparser(input.index, unparserContext);
|
|
263
264
|
};
|
|
264
265
|
|
|
265
|
-
// Format 31t: register +
|
|
266
|
+
// Format 31t: register + branchOffsetCodeUnit (4 bytes signed)
|
|
266
267
|
type DalvikBytecodeFormat31t = {
|
|
267
|
-
|
|
268
|
+
branchOffsetCodeUnit: CodeUnit;
|
|
268
269
|
registers: number[];
|
|
269
270
|
};
|
|
270
271
|
|
|
271
272
|
export const dalvikBytecodeFormat31tUnparser: Unparser<DalvikBytecodeFormat31t, Uint8Array> = async function * (input, unparserContext) {
|
|
272
273
|
yield * ubyteUnparser(input.registers[0], unparserContext);
|
|
273
|
-
yield * intUnparser(input.
|
|
274
|
+
yield * intUnparser(isoCodeUnit.unwrap(input.branchOffsetCodeUnit), unparserContext);
|
|
274
275
|
};
|
|
275
276
|
|
|
276
277
|
// Format 32x: two registers (2 bytes each)
|
|
@@ -374,19 +375,19 @@ export const dalvikBytecodeFormat4rccUnparser: Unparser<DalvikBytecodeFormat4rcc
|
|
|
374
375
|
type DalvikBytecodeOperationPackedSwitchPayload = {
|
|
375
376
|
operation: 'packed-switch-payload';
|
|
376
377
|
value: number;
|
|
377
|
-
|
|
378
|
+
branchOffsetsCodeUnit: CodeUnit[];
|
|
378
379
|
};
|
|
379
380
|
|
|
380
381
|
export const dalvikBytecodeOperationPackedSwitchPayloadUnparser: Unparser<DalvikBytecodeOperationPackedSwitchPayload, Uint8Array> = async function * (input, unparserContext) {
|
|
381
382
|
// Ident (0x0100) - little-endian
|
|
382
383
|
yield * ushortUnparser(0x01_00, unparserContext);
|
|
383
384
|
// Size
|
|
384
|
-
yield * ushortUnparser(input.
|
|
385
|
+
yield * ushortUnparser(input.branchOffsetsCodeUnit.length, unparserContext);
|
|
385
386
|
// First key value
|
|
386
387
|
yield * intUnparser(input.value, unparserContext);
|
|
387
388
|
// Branch offsets
|
|
388
|
-
for (const offset of input.
|
|
389
|
-
yield * intUnparser(offset, unparserContext);
|
|
389
|
+
for (const offset of input.branchOffsetsCodeUnit) {
|
|
390
|
+
yield * intUnparser(isoCodeUnit.unwrap(offset), unparserContext);
|
|
390
391
|
}
|
|
391
392
|
};
|
|
392
393
|
|
|
@@ -394,7 +395,7 @@ export const dalvikBytecodeOperationPackedSwitchPayloadUnparser: Unparser<Dalvik
|
|
|
394
395
|
type DalvikBytecodeOperationSparseSwitchPayload = {
|
|
395
396
|
operation: 'sparse-switch-payload';
|
|
396
397
|
keys: number[];
|
|
397
|
-
|
|
398
|
+
branchOffsetsCodeUnit: CodeUnit[];
|
|
398
399
|
};
|
|
399
400
|
|
|
400
401
|
export const dalvikBytecodeOperationSparseSwitchPayloadUnparser: Unparser<DalvikBytecodeOperationSparseSwitchPayload, Uint8Array> = async function * (input, unparserContext) {
|
|
@@ -407,8 +408,8 @@ export const dalvikBytecodeOperationSparseSwitchPayloadUnparser: Unparser<Dalvik
|
|
|
407
408
|
yield * intUnparser(key, unparserContext);
|
|
408
409
|
}
|
|
409
410
|
// Branch offsets
|
|
410
|
-
for (const offset of input.
|
|
411
|
-
yield * intUnparser(offset, unparserContext);
|
|
411
|
+
for (const offset of input.branchOffsetsCodeUnit) {
|
|
412
|
+
yield * intUnparser(isoCodeUnit.unwrap(offset), unparserContext);
|
|
412
413
|
}
|
|
413
414
|
};
|
|
414
415
|
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import { testProp } from '@fast-check/ava';
|
|
2
2
|
import { runUnparser } from './unparser.js';
|
|
3
|
-
import {
|
|
3
|
+
import { rawDalvikBytecodeUnparser } from './dalvikBytecodeUnparser.js';
|
|
4
4
|
import { uint8ArrayUnparserOutputCompanion } from './unparserOutputCompanion.js';
|
|
5
5
|
import { runParser } from './parser.js';
|
|
6
|
-
import {
|
|
6
|
+
import { createRawDalvikBytecodeParser } from './dalvikBytecodeParser.js';
|
|
7
7
|
import { uint8ArrayParserInputCompanion } from './parserInputCompanion.js';
|
|
8
|
-
import {
|
|
8
|
+
import { arbitraryRawDalvikBytecode } from './arbitraryDalvikBytecode.js';
|
|
9
9
|
import { uint8ArrayAsyncIterableToUint8Array } from './uint8Array.js';
|
|
10
10
|
|
|
11
11
|
const seed = process.env.SEED ? Number(process.env.SEED) : undefined;
|
|
12
12
|
|
|
13
13
|
testProp(
|
|
14
14
|
'dalvik bytecode roundtrip',
|
|
15
|
-
[
|
|
15
|
+
[arbitraryRawDalvikBytecode],
|
|
16
16
|
async (t, bytecode) => {
|
|
17
17
|
// Unparse the bytecode to bytes
|
|
18
18
|
const unparsedStreamIterable = runUnparser(
|
|
19
|
-
|
|
19
|
+
rawDalvikBytecodeUnparser,
|
|
20
20
|
bytecode,
|
|
21
21
|
uint8ArrayUnparserOutputCompanion
|
|
22
22
|
);
|
|
@@ -25,11 +25,11 @@ testProp(
|
|
|
25
25
|
const unparsedStream = await uint8ArrayAsyncIterableToUint8Array(unparsedStreamIterable);
|
|
26
26
|
|
|
27
27
|
// Create parser with the correct size
|
|
28
|
-
const
|
|
28
|
+
const rawDalvikBytecodeParser = createRawDalvikBytecodeParser(unparsedStream.length);
|
|
29
29
|
|
|
30
30
|
// Re-parse the unparsed bytes
|
|
31
31
|
const actual = await runParser(
|
|
32
|
-
|
|
32
|
+
rawDalvikBytecodeParser,
|
|
33
33
|
unparsedStream,
|
|
34
34
|
uint8ArrayParserInputCompanion
|
|
35
35
|
);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { type Unparser, type UnparserResult } from './unparser.js';
|
|
2
2
|
import { type UnparserContext } from './unparserContext.js';
|
|
3
|
-
import { type
|
|
3
|
+
import { type RawDalvikBytecode, type RawDalvikBytecodeOperation } from './dalvikBytecodeParser.js';
|
|
4
4
|
import {
|
|
5
|
+
type CodeUnit,
|
|
5
6
|
isoIndexIntoStringIds,
|
|
6
7
|
isoIndexIntoTypeIds,
|
|
7
8
|
isoIndexIntoMethodIds,
|
|
@@ -312,26 +313,26 @@ const operationToOpcodeMap: Map<string, number> = new Map([
|
|
|
312
313
|
// They use multi-byte identifiers: 0x0100, 0x0200, 0x0300
|
|
313
314
|
]);
|
|
314
315
|
|
|
315
|
-
export const
|
|
316
|
+
export const rawDalvikBytecodeUnparser: Unparser<RawDalvikBytecode, Uint8Array> = async function * (input, unparserContext) {
|
|
316
317
|
for (const operation of input) {
|
|
317
|
-
yield *
|
|
318
|
+
yield * rawDalvikBytecodeOperationUnparser(operation, unparserContext);
|
|
318
319
|
}
|
|
319
320
|
};
|
|
320
321
|
|
|
321
322
|
// Type guards for payload operations
|
|
322
|
-
function isPackedSwitchPayload(op:
|
|
323
|
+
function isPackedSwitchPayload(op: RawDalvikBytecodeOperation): op is RawDalvikBytecodeOperation & { operation: 'packed-switch-payload' } {
|
|
323
324
|
return typeof op === 'object' && op !== null && 'operation' in op && op.operation === 'packed-switch-payload';
|
|
324
325
|
}
|
|
325
326
|
|
|
326
|
-
function isSparseSwitchPayload(op:
|
|
327
|
+
function isSparseSwitchPayload(op: RawDalvikBytecodeOperation): op is RawDalvikBytecodeOperation & { operation: 'sparse-switch-payload' } {
|
|
327
328
|
return typeof op === 'object' && op !== null && 'operation' in op && op.operation === 'sparse-switch-payload';
|
|
328
329
|
}
|
|
329
330
|
|
|
330
|
-
function isFillArrayDataPayload(op:
|
|
331
|
+
function isFillArrayDataPayload(op: RawDalvikBytecodeOperation): op is RawDalvikBytecodeOperation & { operation: 'fill-array-data-payload' } {
|
|
331
332
|
return typeof op === 'object' && op !== null && 'operation' in op && op.operation === 'fill-array-data-payload';
|
|
332
333
|
}
|
|
333
334
|
|
|
334
|
-
const
|
|
335
|
+
const rawDalvikBytecodeOperationUnparser: Unparser<RawDalvikBytecodeOperation, Uint8Array> = async function * (operation, unparserContext) {
|
|
335
336
|
if (!operation || typeof operation !== 'object' || !('operation' in operation)) {
|
|
336
337
|
throw new Error('Invalid operation');
|
|
337
338
|
}
|
|
@@ -374,19 +375,19 @@ const dalvikBytecodeOperationUnparser: Unparser<DalvikBytecodeOperation, Uint8Ar
|
|
|
374
375
|
};
|
|
375
376
|
|
|
376
377
|
// Helper to check if operation has specific fields
|
|
377
|
-
function hasRegisters(op:
|
|
378
|
+
function hasRegisters(op: RawDalvikBytecodeOperation): op is RawDalvikBytecodeOperation & { registers: number[] } {
|
|
378
379
|
return 'registers' in op;
|
|
379
380
|
}
|
|
380
381
|
|
|
381
|
-
function hasValue(op:
|
|
382
|
+
function hasValue(op: RawDalvikBytecodeOperation): op is RawDalvikBytecodeOperation & { value: number | bigint } {
|
|
382
383
|
return 'value' in op;
|
|
383
384
|
}
|
|
384
385
|
|
|
385
|
-
function
|
|
386
|
-
return '
|
|
386
|
+
function hasBranchOffsetCodeUnit(op: RawDalvikBytecodeOperation): op is RawDalvikBytecodeOperation & { branchOffsetCodeUnit: CodeUnit } {
|
|
387
|
+
return 'branchOffsetCodeUnit' in op;
|
|
387
388
|
}
|
|
388
389
|
|
|
389
|
-
async function * unparseOperationData(operation:
|
|
390
|
+
async function * unparseOperationData(operation: RawDalvikBytecodeOperation, unparserContext: UnparserContext<Uint8Array, number>): UnparserResult<Uint8Array, number> {
|
|
390
391
|
if (!('operation' in operation)) {
|
|
391
392
|
throw new Error('Invalid operation structure');
|
|
392
393
|
}
|
|
@@ -601,59 +602,59 @@ async function * unparseOperationData(operation: DalvikBytecodeOperation, unpars
|
|
|
601
602
|
|
|
602
603
|
// Format 10t (goto)
|
|
603
604
|
if (operationName === 'goto') {
|
|
604
|
-
if (!
|
|
605
|
-
throw new Error(`Operation ${operationName} missing
|
|
605
|
+
if (!hasBranchOffsetCodeUnit(operation)) {
|
|
606
|
+
throw new Error(`Operation ${operationName} missing branchOffsetCodeUnit field`);
|
|
606
607
|
}
|
|
607
|
-
yield * dalvikBytecodeFormat10tUnparser({
|
|
608
|
+
yield * dalvikBytecodeFormat10tUnparser({ branchOffsetCodeUnit: operation.branchOffsetCodeUnit }, unparserContext);
|
|
608
609
|
return;
|
|
609
610
|
}
|
|
610
611
|
|
|
611
612
|
// Format 20t (goto/16)
|
|
612
613
|
if (operationName === 'goto/16') {
|
|
613
|
-
if (!
|
|
614
|
-
throw new Error(`Operation ${operationName} missing
|
|
614
|
+
if (!hasBranchOffsetCodeUnit(operation)) {
|
|
615
|
+
throw new Error(`Operation ${operationName} missing branchOffsetCodeUnit field`);
|
|
615
616
|
}
|
|
616
|
-
yield * dalvikBytecodeFormat20tUnparser({
|
|
617
|
+
yield * dalvikBytecodeFormat20tUnparser({ branchOffsetCodeUnit: operation.branchOffsetCodeUnit }, unparserContext);
|
|
617
618
|
return;
|
|
618
619
|
}
|
|
619
620
|
|
|
620
621
|
// Format 30t (goto/32)
|
|
621
622
|
if (operationName === 'goto/32') {
|
|
622
|
-
if (!
|
|
623
|
-
throw new Error(`Operation ${operationName} missing
|
|
623
|
+
if (!hasBranchOffsetCodeUnit(operation)) {
|
|
624
|
+
throw new Error(`Operation ${operationName} missing branchOffsetCodeUnit field`);
|
|
624
625
|
}
|
|
625
|
-
yield * dalvikBytecodeFormat30tUnparser({
|
|
626
|
+
yield * dalvikBytecodeFormat30tUnparser({ branchOffsetCodeUnit: operation.branchOffsetCodeUnit }, unparserContext);
|
|
626
627
|
return;
|
|
627
628
|
}
|
|
628
629
|
|
|
629
630
|
// Format 22t (if-* operations)
|
|
630
631
|
if (operationName.startsWith('if-') && !operationName.endsWith('z')) {
|
|
631
|
-
if (!
|
|
632
|
-
throw new Error(`Operation ${operationName} missing
|
|
632
|
+
if (!hasBranchOffsetCodeUnit(operation) || !hasRegisters(operation)) {
|
|
633
|
+
throw new Error(`Operation ${operationName} missing branchOffsetCodeUnit or registers field`);
|
|
633
634
|
}
|
|
634
635
|
// Commutative operations (if-eq, if-ne) have sorted registers, so don't reverse
|
|
635
636
|
const isCommutative = operationName === 'if-eq' || operationName === 'if-ne';
|
|
636
637
|
const unparser = isCommutative ? dalvikBytecodeFormat22tCommutativeUnparser : dalvikBytecodeFormat22tUnparser;
|
|
637
|
-
yield * unparser({
|
|
638
|
+
yield * unparser({ branchOffsetCodeUnit: operation.branchOffsetCodeUnit, registers: operation.registers }, unparserContext);
|
|
638
639
|
return;
|
|
639
640
|
}
|
|
640
641
|
|
|
641
642
|
// Format 21t (if-*z operations)
|
|
642
643
|
if (operationName.startsWith('if-') && operationName.endsWith('z')) {
|
|
643
|
-
if (!
|
|
644
|
-
throw new Error(`Operation ${operationName} missing
|
|
644
|
+
if (!hasBranchOffsetCodeUnit(operation) || !hasRegisters(operation)) {
|
|
645
|
+
throw new Error(`Operation ${operationName} missing branchOffsetCodeUnit or registers field`);
|
|
645
646
|
}
|
|
646
|
-
yield * dalvikBytecodeFormat21tUnparser({
|
|
647
|
+
yield * dalvikBytecodeFormat21tUnparser({ branchOffsetCodeUnit: operation.branchOffsetCodeUnit, registers: operation.registers }, unparserContext);
|
|
647
648
|
return;
|
|
648
649
|
}
|
|
649
650
|
|
|
650
651
|
// Format 31t (packed-switch, sparse-switch, fill-array-data)
|
|
651
652
|
if (operationName === 'packed-switch' || operationName === 'sparse-switch' ||
|
|
652
653
|
operationName === 'fill-array-data') {
|
|
653
|
-
if (!
|
|
654
|
-
throw new Error(`Operation ${operationName} missing
|
|
654
|
+
if (!hasBranchOffsetCodeUnit(operation) || !hasRegisters(operation)) {
|
|
655
|
+
throw new Error(`Operation ${operationName} missing branchOffsetCodeUnit or registers field`);
|
|
655
656
|
}
|
|
656
|
-
yield * dalvikBytecodeFormat31tUnparser({
|
|
657
|
+
yield * dalvikBytecodeFormat31tUnparser({ branchOffsetCodeUnit: operation.branchOffsetCodeUnit, registers: operation.registers }, unparserContext);
|
|
657
658
|
return;
|
|
658
659
|
}
|
|
659
660
|
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { expectType } from 'tsd';
|
|
2
|
+
import { type ParserOutput } from './parser.js';
|
|
3
|
+
import { dalvikExecutableParser } from './dalvikExecutableParser.js';
|
|
4
|
+
|
|
5
|
+
// Test that DalvikExecutable instruction index fields use plain number types
|
|
6
|
+
// This ensures typed numbers (CodeUnit, InstructionIndex) do not leak into the public API
|
|
7
|
+
|
|
8
|
+
// Derive types from the actual parser output
|
|
9
|
+
type ParsedDalvikExecutable = ParserOutput<typeof dalvikExecutableParser>;
|
|
10
|
+
type ParsedClassDefinition = ParsedDalvikExecutable['classDefinitions'][number];
|
|
11
|
+
type ParsedClassData = NonNullable<ParsedClassDefinition['classData']>;
|
|
12
|
+
type ParsedMethod = ParsedClassData['directMethods'][number];
|
|
13
|
+
type ParsedCode = NonNullable<ParsedMethod['code']>;
|
|
14
|
+
type ParsedInstructions = ParsedCode['instructions'];
|
|
15
|
+
type ParsedOperation = ParsedInstructions[number];
|
|
16
|
+
|
|
17
|
+
// Test try/catch block types
|
|
18
|
+
declare const dex: ParsedDalvikExecutable;
|
|
19
|
+
const classDef = dex.classDefinitions[0];
|
|
20
|
+
const classData = classDef.classData!;
|
|
21
|
+
const method = classData.directMethods[0];
|
|
22
|
+
const code = method.code!;
|
|
23
|
+
|
|
24
|
+
// Try block field types
|
|
25
|
+
const tryBlock = code.tries[0];
|
|
26
|
+
expectType<number>(tryBlock.startInstructionIndex);
|
|
27
|
+
expectType<number>(tryBlock.instructionCount);
|
|
28
|
+
|
|
29
|
+
// Handler field types
|
|
30
|
+
const handler = tryBlock.handler;
|
|
31
|
+
expectType<number | undefined>(handler.catchAllInstructionIndex);
|
|
32
|
+
|
|
33
|
+
// Type-address pair field types
|
|
34
|
+
const typeAddressPair = handler.handlers[0];
|
|
35
|
+
expectType<number>(typeAddressPair.handlerInstructionIndex);
|
|
36
|
+
|
|
37
|
+
// Test bytecode operation types - branch offsets should be plain numbers
|
|
38
|
+
type GotoOperation = Extract<ParsedOperation, { operation: 'goto' }>;
|
|
39
|
+
declare const gotoOp: GotoOperation;
|
|
40
|
+
expectType<number>(gotoOp.targetInstructionIndex);
|
|
41
|
+
|
|
42
|
+
type Goto16Operation = Extract<ParsedOperation, { operation: 'goto/16' }>;
|
|
43
|
+
declare const goto16Op: Goto16Operation;
|
|
44
|
+
expectType<number>(goto16Op.targetInstructionIndex);
|
|
45
|
+
|
|
46
|
+
type Goto32Operation = Extract<ParsedOperation, { operation: 'goto/32' }>;
|
|
47
|
+
declare const goto32Op: Goto32Operation;
|
|
48
|
+
expectType<number>(goto32Op.targetInstructionIndex);
|
|
49
|
+
|
|
50
|
+
type PackedSwitchOperation = Extract<ParsedOperation, { operation: 'packed-switch' }>;
|
|
51
|
+
declare const packedSwitchOp: PackedSwitchOperation;
|
|
52
|
+
expectType<number>(packedSwitchOp.targetInstructionIndex);
|
|
53
|
+
|
|
54
|
+
type SparseSwitchOperation = Extract<ParsedOperation, { operation: 'sparse-switch' }>;
|
|
55
|
+
declare const sparseSwitchOp: SparseSwitchOperation;
|
|
56
|
+
expectType<number>(sparseSwitchOp.targetInstructionIndex);
|
|
57
|
+
|
|
58
|
+
type PackedSwitchPayloadOperation = Extract<ParsedOperation, { operation: 'packed-switch-payload' }>;
|
|
59
|
+
declare const packedSwitchPayloadOp: PackedSwitchPayloadOperation;
|
|
60
|
+
expectType<number[]>(packedSwitchPayloadOp.targetInstructionIndices);
|
|
61
|
+
|
|
62
|
+
type SparseSwitchPayloadOperation = Extract<ParsedOperation, { operation: 'sparse-switch-payload' }>;
|
|
63
|
+
declare const sparseSwitchPayloadOp: SparseSwitchPayloadOperation;
|
|
64
|
+
expectType<number[]>(sparseSwitchPayloadOp.targetInstructionIndices);
|
|
65
|
+
|
|
66
|
+
type FillArrayDataOperation = Extract<ParsedOperation, { operation: 'fill-array-data' }>;
|
|
67
|
+
declare const fillArrayDataOp: FillArrayDataOperation;
|
|
68
|
+
expectType<number>(fillArrayDataOp.targetInstructionIndex);
|
|
69
|
+
|
|
70
|
+
type IfEqOperation = Extract<ParsedOperation, { operation: 'if-eq' }>;
|
|
71
|
+
declare const ifEqOp: IfEqOperation;
|
|
72
|
+
expectType<number>(ifEqOp.targetInstructionIndex);
|
|
73
|
+
|
|
74
|
+
type IfEqzOperation = Extract<ParsedOperation, { operation: 'if-eqz' }>;
|
|
75
|
+
declare const ifEqzOp: IfEqzOperation;
|
|
76
|
+
expectType<number>(ifEqzOp.targetInstructionIndex);
|
|
77
|
+
|
|
78
|
+
// Test that index fields are resolved to their actual types (not raw indices)
|
|
79
|
+
// Operations with methodIndex should have method: DalvikExecutableMethod
|
|
80
|
+
type InvokeVirtualOperation = Extract<ParsedOperation, { operation: 'invoke-virtual' }>;
|
|
81
|
+
declare const invokeVirtualOp: InvokeVirtualOperation;
|
|
82
|
+
expectType<{ class: string; prototype: { shorty: string; returnType: string; parameters: string[] }; name: string }>(invokeVirtualOp.method);
|
|
83
|
+
|
|
84
|
+
// Operations with fieldIndex should have field: DalvikExecutableField
|
|
85
|
+
type IgetOperation = Extract<ParsedOperation, { operation: 'iget' }>;
|
|
86
|
+
declare const igetOp: IgetOperation;
|
|
87
|
+
expectType<{ class: string; type: string; name: string }>(igetOp.field);
|
|
88
|
+
|
|
89
|
+
// Operations with typeIndex should have type: string
|
|
90
|
+
type CheckCastOperation = Extract<ParsedOperation, { operation: 'check-cast' }>;
|
|
91
|
+
declare const checkCastOp: CheckCastOperation;
|
|
92
|
+
expectType<string>(checkCastOp.type);
|
|
93
|
+
|
|
94
|
+
// Operations with stringIndex should have string: string
|
|
95
|
+
type ConstStringOperation = Extract<ParsedOperation, { operation: 'const-string' }>;
|
|
96
|
+
declare const constStringOp: ConstStringOperation;
|
|
97
|
+
expectType<string>(constStringOp.string);
|
|
98
|
+
|
|
99
|
+
// Test that raw index fields do NOT exist on resolved types
|
|
100
|
+
// @ts-expect-error - methodIndex should not exist, use method instead
|
|
101
|
+
invokeVirtualOp.methodIndex;
|
|
102
|
+
// @ts-expect-error - fieldIndex should not exist, use field instead
|
|
103
|
+
igetOp.fieldIndex;
|
|
104
|
+
// @ts-expect-error - typeIndex should not exist, use type instead
|
|
105
|
+
checkCastOp.typeIndex;
|
|
106
|
+
// @ts-expect-error - stringIndex should not exist, use string instead
|
|
107
|
+
constStringOp.stringIndex;
|
|
108
|
+
|
|
109
|
+
// Test that values can be constructed with resolved fields
|
|
110
|
+
const _invokeVirtual: InvokeVirtualOperation = {
|
|
111
|
+
operation: 'invoke-virtual',
|
|
112
|
+
registers: [0],
|
|
113
|
+
method: { class: 'Lfoo/Bar;', prototype: { shorty: 'V', returnType: 'V', parameters: [] }, name: 'baz' },
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const _iget: IgetOperation = {
|
|
117
|
+
operation: 'iget',
|
|
118
|
+
registers: [0, 1],
|
|
119
|
+
field: { class: 'Lfoo/Bar;', type: 'I', name: 'x' },
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const _checkCast: CheckCastOperation = {
|
|
123
|
+
operation: 'check-cast',
|
|
124
|
+
registers: [0],
|
|
125
|
+
type: 'Lfoo/Bar;',
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const _constString: ConstStringOperation = {
|
|
129
|
+
operation: 'const-string',
|
|
130
|
+
registers: [0],
|
|
131
|
+
string: 'hello',
|
|
132
|
+
};
|
package/src/dalvikExecutable.ts
CHANGED
|
@@ -67,19 +67,19 @@ export type DalvikExecutableEncodedValue =
|
|
|
67
67
|
| { type: 'boolean'; value: boolean };
|
|
68
68
|
|
|
69
69
|
type DalvikExecutableTry = {
|
|
70
|
-
|
|
70
|
+
startInstructionIndex: number;
|
|
71
71
|
instructionCount: number;
|
|
72
72
|
handler: DalvikExecutableEncodedCatchHandler;
|
|
73
73
|
};
|
|
74
74
|
|
|
75
75
|
type DalvikExecutableEncodedTypeAddressPair = {
|
|
76
76
|
type: string;
|
|
77
|
-
|
|
77
|
+
handlerInstructionIndex: number;
|
|
78
78
|
};
|
|
79
79
|
|
|
80
80
|
type DalvikExecutableEncodedCatchHandler = {
|
|
81
81
|
handlers: DalvikExecutableEncodedTypeAddressPair[];
|
|
82
|
-
|
|
82
|
+
catchAllInstructionIndex: undefined | number;
|
|
83
83
|
};
|
|
84
84
|
|
|
85
85
|
export type DalvikExecutableCode<Instructions> = {
|
|
@@ -15,6 +15,17 @@ export const isoIndexIntoFieldIds = iso<IndexIntoFieldIds>();
|
|
|
15
15
|
export type IndexIntoMethodIds = {} & Newtype<{ readonly IndexIntoMethodIds: unique symbol }, number>;
|
|
16
16
|
export const isoIndexIntoMethodIds = iso<IndexIntoMethodIds>();
|
|
17
17
|
|
|
18
|
+
export type IndexIntoCallSiteIds = {} & Newtype<{ readonly IndexIntoCallSiteIds: unique symbol }, number>;
|
|
19
|
+
export const isoIndexIntoCallSiteIds = iso<IndexIntoCallSiteIds>();
|
|
20
|
+
|
|
21
|
+
// Code unit addresses/offsets (raw DEX format, 16-bit code units)
|
|
22
|
+
export type CodeUnit = {} & Newtype<{ readonly CodeUnit: unique symbol }, number>;
|
|
23
|
+
export const isoCodeUnit = iso<CodeUnit>();
|
|
24
|
+
|
|
25
|
+
// Instruction index addresses/offsets (converted format, instruction-relative)
|
|
26
|
+
export type InstructionIndex = {} & Newtype<{ readonly InstructionIndex: unique symbol }, number>;
|
|
27
|
+
export const isoInstructionIndex = iso<InstructionIndex>();
|
|
28
|
+
|
|
18
29
|
export type OffsetToStringDataItem = {} & Newtype<{ readonly OffsetToStringDataItem: unique symbol }, number>;
|
|
19
30
|
export const isoOffsetToStringDataItem = iso<OffsetToStringDataItem>();
|
|
20
31
|
|
|
@@ -70,8 +70,10 @@ const dexWithParsedInstructionsMacro = test.macro({
|
|
|
70
70
|
return;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
t.false(key.endsWith('Offset')
|
|
74
|
-
|
|
73
|
+
t.false(key.endsWith('Offset'), 'All offsets should be resolved: ' + path.join('.'));
|
|
74
|
+
// InstructionIndex fields are expected in Tier 3
|
|
75
|
+
const allowedIndexFields = ['targetInstructionIndex', 'targetInstructionIndices', 'startInstructionIndex', 'handlerInstructionIndex', 'catchAllInstructionIndex'];
|
|
76
|
+
t.false(key.endsWith('Index') && !allowedIndexFields.includes(key) && key !== 'targetInstructionIndices', 'All indexes should be resolved: ' + path.join('.'));
|
|
75
77
|
});
|
|
76
78
|
|
|
77
79
|
if (shouldSnapshot) {
|
|
@@ -83,7 +85,39 @@ const dexWithParsedInstructionsMacro = test.macro({
|
|
|
83
85
|
},
|
|
84
86
|
});
|
|
85
87
|
|
|
86
|
-
test.serial
|
|
88
|
+
test.serial(dexWithParsedInstructionsMacro, 'bafkreibb4gsprc3fvmnyqx6obswvm7e7wngnfj64gz65ey72r7xgyzymt4', true);
|
|
87
89
|
test.serial.skip(dexWithParsedInstructionsMacro, 'bafybeiebe27ylo53trgitu6fqfbmba43c4ivxj3nt4kumsilkucpbdxtqq', false);
|
|
88
90
|
test.serial.skip(dexWithParsedInstructionsMacro, 'bafybeibbupm7uzhuq4pa674rb2amxsenbdaoijigmaf4onaodaql4mh7yy', false);
|
|
89
91
|
test.serial.skip(dexWithParsedInstructionsMacro, 'bafybeicb3qajmwy6li7hche2nkucvytaxcyxhwhphmi73tgydjzmyoqoda', false);
|
|
92
|
+
|
|
93
|
+
const methodMacro = test.macro({
|
|
94
|
+
title: (providedTitle, dexCid: string, className: string, methodName: string) =>
|
|
95
|
+
providedTitle ?? `method ${className}.${methodName} from ${dexCid}`,
|
|
96
|
+
async exec(t, dexCid: string, className: string, methodName: string) {
|
|
97
|
+
const dexStream = await fetchCid(dexCid);
|
|
98
|
+
|
|
99
|
+
const dex = await runParser(dalvikExecutableParser, dexStream, uint8ArrayParserInputCompanion, {
|
|
100
|
+
errorJoinMode: 'all',
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
const classDef = dex.classDefinitions.find(c => c.class === className);
|
|
104
|
+
t.truthy(classDef, `Class ${className} not found`);
|
|
105
|
+
|
|
106
|
+
const allMethods = [
|
|
107
|
+
...(classDef!.classData?.directMethods ?? []),
|
|
108
|
+
...(classDef!.classData?.virtualMethods ?? []),
|
|
109
|
+
];
|
|
110
|
+
|
|
111
|
+
const method = allMethods.find(m => m.method.name === methodName);
|
|
112
|
+
t.truthy(method, `Method ${methodName} not found in ${className}`);
|
|
113
|
+
|
|
114
|
+
t.snapshot(method);
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test.serial(
|
|
119
|
+
methodMacro,
|
|
120
|
+
'bafkreifycfnx4xf3nlml4qavlyxr6bes66nxsow3iaqjghewfsozoj2h3q',
|
|
121
|
+
'Lpl/czak/minimal/MainActivity;',
|
|
122
|
+
'getPackedSwitchResult',
|
|
123
|
+
);
|