titanium-apk-recover 2.2.2 → 2.3.1
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/README.md +31 -11
- package/dist/{chunk-ML2DCRT6.js → chunk-LH747TFR.js} +106 -20
- package/dist/chunk-LH747TFR.js.map +1 -0
- package/dist/cli.cjs +100 -20
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +108 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +26 -6
- package/dist/index.d.ts +26 -6
- package/dist/index.js +7 -1
- package/package.json +1 -1
- package/dist/chunk-ML2DCRT6.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -35,14 +35,17 @@ __export(src_exports, {
|
|
|
35
35
|
buildInfo: () => buildInfo,
|
|
36
36
|
buildReconstruct: () => reconstruct,
|
|
37
37
|
buildTiappXml: () => buildTiappXml,
|
|
38
|
+
cloakKeyCandidates: () => cloakKeyCandidates,
|
|
38
39
|
decodeJavaInt: () => decodeJavaInt,
|
|
39
40
|
decryptCloakAsset: () => decryptCloakAsset,
|
|
40
41
|
decryptRange: () => decryptRange,
|
|
41
42
|
decryptRanges: () => decryptRanges,
|
|
42
43
|
deriveCloakKey: () => deriveCloakKey,
|
|
44
|
+
deriveKeyFromBlock: () => deriveKeyFromBlock,
|
|
43
45
|
detectAlloy: () => detectAlloy,
|
|
44
46
|
extractByteArrayFields: () => extractByteArrayFields,
|
|
45
47
|
extractCloakSalt: () => extractCloakSalt,
|
|
48
|
+
extractKeyBlock: () => extractKeyBlock,
|
|
46
49
|
extractRanges: () => extractRanges,
|
|
47
50
|
extractStringChunks: () => extractStringChunks,
|
|
48
51
|
instructionWidth: () => instructionWidth,
|
|
@@ -629,26 +632,109 @@ function readAssetCrypt(dexBuffers, packageHint) {
|
|
|
629
632
|
var import_node_crypto2 = require("crypto");
|
|
630
633
|
var import_node_zlib = require("zlib");
|
|
631
634
|
var KEY_LEN2 = 16;
|
|
632
|
-
var
|
|
633
|
-
|
|
634
|
-
|
|
635
|
+
var BLOCK_LEN = 64;
|
|
636
|
+
var FALLBACK_BLOCK_OFFSETS = [8200, 8196, 8208, 12292, 16388];
|
|
637
|
+
function extractKeyBlock(so) {
|
|
635
638
|
try {
|
|
636
|
-
if (so.length <
|
|
637
|
-
|
|
638
|
-
const
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
const
|
|
646
|
-
|
|
647
|
-
|
|
639
|
+
if (so.length < 64) return null;
|
|
640
|
+
if (so[0] !== 127 || so[1] !== 69 || so[2] !== 76 || so[3] !== 70) return null;
|
|
641
|
+
const is64 = so[4] === 2;
|
|
642
|
+
const le = so[5] !== 2;
|
|
643
|
+
const u16 = (o) => le ? so.readUInt16LE(o) : so.readUInt16BE(o);
|
|
644
|
+
const u32 = (o) => le ? so.readUInt32LE(o) : so.readUInt32BE(o);
|
|
645
|
+
const u64 = (o) => Number(le ? so.readBigUInt64LE(o) : so.readBigUInt64BE(o));
|
|
646
|
+
const shoff = is64 ? u64(40) : u32(32);
|
|
647
|
+
const shentsize = u16(is64 ? 58 : 46);
|
|
648
|
+
const shnum = u16(is64 ? 60 : 48);
|
|
649
|
+
if (shoff === 0 || shnum === 0 || shentsize === 0) return null;
|
|
650
|
+
const secs = [];
|
|
651
|
+
for (let i = 0; i < shnum; i++) {
|
|
652
|
+
const b = shoff + i * shentsize;
|
|
653
|
+
if (b + shentsize > so.length) return null;
|
|
654
|
+
secs.push(
|
|
655
|
+
is64 ? {
|
|
656
|
+
type: u32(b + 4),
|
|
657
|
+
addr: u64(b + 16),
|
|
658
|
+
offset: u64(b + 24),
|
|
659
|
+
size: u64(b + 32),
|
|
660
|
+
link: u32(b + 40),
|
|
661
|
+
entsize: u64(b + 56)
|
|
662
|
+
} : {
|
|
663
|
+
type: u32(b + 4),
|
|
664
|
+
addr: u32(b + 12),
|
|
665
|
+
offset: u32(b + 16),
|
|
666
|
+
size: u32(b + 20),
|
|
667
|
+
link: u32(b + 24),
|
|
668
|
+
entsize: u32(b + 36)
|
|
669
|
+
}
|
|
670
|
+
);
|
|
671
|
+
}
|
|
672
|
+
const SHT_SYMTAB = 2;
|
|
673
|
+
const SHT_DYNSYM = 11;
|
|
674
|
+
const symSec = secs.find((s) => s.type === SHT_DYNSYM) ?? secs.find((s) => s.type === SHT_SYMTAB);
|
|
675
|
+
const strSec = symSec ? secs[symSec.link] : void 0;
|
|
676
|
+
if (!symSec || !strSec) return null;
|
|
677
|
+
const symEnt = is64 ? 24 : 16;
|
|
678
|
+
const count = Math.floor(symSec.size / (symSec.entsize || symEnt));
|
|
679
|
+
for (let i = 0; i < count; i++) {
|
|
680
|
+
const s = symSec.offset + i * symEnt;
|
|
681
|
+
if (s + symEnt > so.length) break;
|
|
682
|
+
const nameOff = strSec.offset + u32(s);
|
|
683
|
+
if (nameOff <= 0 || nameOff >= so.length) continue;
|
|
684
|
+
let end = nameOff;
|
|
685
|
+
while (end < so.length && so[end] !== 0) end++;
|
|
686
|
+
if (so.toString("latin1", nameOff, end) !== "KEY_BLOCK") continue;
|
|
687
|
+
const value = is64 ? u64(s + 8) : u32(s + 4);
|
|
688
|
+
const shndx = u16(s + (is64 ? 6 : 14));
|
|
689
|
+
const host = secs[shndx]?.addr && value >= secs[shndx].addr && value < secs[shndx].addr + secs[shndx].size ? secs[shndx] : secs.find((x) => x.addr !== 0 && x.size > 0 && value >= x.addr && value < x.addr + x.size);
|
|
690
|
+
if (!host) return null;
|
|
691
|
+
const fileOff = value - host.addr + host.offset;
|
|
692
|
+
if (fileOff < 0 || fileOff + BLOCK_LEN > so.length) return null;
|
|
693
|
+
return so.subarray(fileOff, fileOff + BLOCK_LEN);
|
|
694
|
+
}
|
|
695
|
+
return null;
|
|
648
696
|
} catch {
|
|
649
697
|
return null;
|
|
650
698
|
}
|
|
651
699
|
}
|
|
700
|
+
function deriveKeyFromBlock(block, salt) {
|
|
701
|
+
if (salt.length !== KEY_LEN2 || block.length < BLOCK_LEN) return null;
|
|
702
|
+
const randomOffset = block.readUInt8(62);
|
|
703
|
+
if (randomOffset + 4 > BLOCK_LEN) return null;
|
|
704
|
+
const xor = Buffer.concat([
|
|
705
|
+
block.subarray(1, 5),
|
|
706
|
+
block.subarray(randomOffset, randomOffset + 4),
|
|
707
|
+
block.subarray(15, 15 + 4),
|
|
708
|
+
block.subarray(30, 30 + 4)
|
|
709
|
+
]);
|
|
710
|
+
if (xor.length < KEY_LEN2) return null;
|
|
711
|
+
const key = Buffer.alloc(KEY_LEN2);
|
|
712
|
+
for (let i = 0; i < KEY_LEN2; i++) key[i] = (salt[i] ?? 0) ^ (xor[i] ?? 0);
|
|
713
|
+
return key;
|
|
714
|
+
}
|
|
715
|
+
function cloakKeyCandidates(so, salt) {
|
|
716
|
+
if (salt.length !== KEY_LEN2) return [];
|
|
717
|
+
const blocks = [];
|
|
718
|
+
const elf = extractKeyBlock(so);
|
|
719
|
+
if (elf) blocks.push(elf);
|
|
720
|
+
for (const off of FALLBACK_BLOCK_OFFSETS) {
|
|
721
|
+
if (off + BLOCK_LEN <= so.length) blocks.push(so.subarray(off, off + BLOCK_LEN));
|
|
722
|
+
}
|
|
723
|
+
const keys = [];
|
|
724
|
+
const seen = /* @__PURE__ */ new Set();
|
|
725
|
+
for (const block of blocks) {
|
|
726
|
+
const key = deriveKeyFromBlock(block, salt);
|
|
727
|
+
if (!key) continue;
|
|
728
|
+
const hex = key.toString("hex");
|
|
729
|
+
if (seen.has(hex)) continue;
|
|
730
|
+
seen.add(hex);
|
|
731
|
+
keys.push(key);
|
|
732
|
+
}
|
|
733
|
+
return keys;
|
|
734
|
+
}
|
|
735
|
+
function deriveCloakKey(so, salt) {
|
|
736
|
+
return cloakKeyCandidates(so, salt)[0] ?? null;
|
|
737
|
+
}
|
|
652
738
|
function decryptCloakAsset(bin, key, salt) {
|
|
653
739
|
if (key.length !== KEY_LEN2 || salt.length !== KEY_LEN2) return null;
|
|
654
740
|
try {
|
|
@@ -678,10 +764,10 @@ function isProbablyText(buf) {
|
|
|
678
764
|
}
|
|
679
765
|
function pickCloakKey(cloakLibs, salt, sampleBin) {
|
|
680
766
|
for (const so of cloakLibs) {
|
|
681
|
-
const key
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
767
|
+
for (const key of cloakKeyCandidates(so, salt)) {
|
|
768
|
+
const decrypted = decryptCloakAsset(sampleBin, key, salt);
|
|
769
|
+
if (decrypted && isProbablyText(decrypted)) return key;
|
|
770
|
+
}
|
|
685
771
|
}
|
|
686
772
|
return null;
|
|
687
773
|
}
|
|
@@ -1103,14 +1189,17 @@ async function readSourceFiles(base) {
|
|
|
1103
1189
|
buildInfo,
|
|
1104
1190
|
buildReconstruct,
|
|
1105
1191
|
buildTiappXml,
|
|
1192
|
+
cloakKeyCandidates,
|
|
1106
1193
|
decodeJavaInt,
|
|
1107
1194
|
decryptCloakAsset,
|
|
1108
1195
|
decryptRange,
|
|
1109
1196
|
decryptRanges,
|
|
1110
1197
|
deriveCloakKey,
|
|
1198
|
+
deriveKeyFromBlock,
|
|
1111
1199
|
detectAlloy,
|
|
1112
1200
|
extractByteArrayFields,
|
|
1113
1201
|
extractCloakSalt,
|
|
1202
|
+
extractKeyBlock,
|
|
1114
1203
|
extractRanges,
|
|
1115
1204
|
extractStringChunks,
|
|
1116
1205
|
instructionWidth,
|