xhacker-zzz
2 years ago
10 changed files with 94 additions and 11 deletions
@ -0,0 +1,71 @@ |
|||
import { Decrypt as RawDecrypt } from './raw'; |
|||
import { GetArrayBuffer } from '@/decrypt/utils'; |
|||
import { DecryptResult } from '@/decrypt/entity'; |
|||
|
|||
const segmentSize = 0x20; |
|||
|
|||
function isPrintableAsciiChar(ch: number) { |
|||
return ch >= 0x20 && ch <= 0x7E; |
|||
} |
|||
|
|||
function isUpperHexChar(ch: number) { |
|||
return (ch >= 0x30 && ch <= 0x39) || (ch >= 0x41 && ch <= 0x46); |
|||
} |
|||
|
|||
/** |
|||
* @param {Buffer} data |
|||
* @param {Buffer} key |
|||
* @param {boolean} copy |
|||
* @returns Buffer |
|||
*/ |
|||
function decryptSegment(data: Uint8Array, key: Uint8Array) { |
|||
for (let i = 0; i < data.byteLength; i++) { |
|||
data[i] -= key[i % segmentSize]; |
|||
} |
|||
return Buffer.from(data); |
|||
} |
|||
|
|||
export async function Decrypt(file: File, raw_filename: string): Promise<DecryptResult> { |
|||
const buf = new Uint8Array(await GetArrayBuffer(file)); |
|||
|
|||
// 咪咕编码的 WAV 文件有很多“空洞”内容,尝试密钥。
|
|||
const header = buf.slice(0, 0x100); |
|||
const bytesRIFF = Buffer.from('RIFF', 'ascii'); |
|||
const bytesWaveFormat = Buffer.from('WAVEfmt ', 'ascii'); |
|||
const possibleKeys = []; |
|||
|
|||
for (let i = segmentSize; i < segmentSize * 20; i += segmentSize) { |
|||
const possibleKey = buf.slice(i, i + segmentSize); |
|||
if (!possibleKey.every(isUpperHexChar)) continue; |
|||
|
|||
const tempHeader = decryptSegment(header, possibleKey); |
|||
if (tempHeader.slice(0, 4).compare(bytesRIFF)) continue; |
|||
if (tempHeader.slice(8, 16).compare(bytesWaveFormat)) continue; |
|||
|
|||
// fmt chunk 大小可以是 16 / 18 / 40。
|
|||
const fmtChunkSize = tempHeader.readUInt32LE(0x10); |
|||
if (![16, 18, 40].includes(fmtChunkSize)) continue; |
|||
|
|||
// 下一个 chunk
|
|||
const firstDataChunkOffset = 0x14 + fmtChunkSize; |
|||
const chunkName = tempHeader.slice(firstDataChunkOffset, firstDataChunkOffset + 4); |
|||
if (!chunkName.every(isPrintableAsciiChar)) continue; |
|||
|
|||
const secondDataChunkOffset = firstDataChunkOffset + 8 + tempHeader.readUInt32LE(firstDataChunkOffset + 4); |
|||
if (secondDataChunkOffset <= header.byteLength) { |
|||
const secondChunkName = tempHeader.slice(secondDataChunkOffset, secondDataChunkOffset + 4); |
|||
if (!secondChunkName.every(isPrintableAsciiChar)) continue; |
|||
} |
|||
|
|||
possibleKeys.push(Buffer.from(possibleKey).toString('ascii')); |
|||
} |
|||
|
|||
if (possibleKeys.length <= 0) { |
|||
throw new Error(`ERROR: no suitable key discovered`); |
|||
} |
|||
|
|||
const decryptionKey = Buffer.from(possibleKeys[0], 'ascii'); |
|||
decryptSegment(buf, decryptionKey); |
|||
const musicData = new Blob([buf], { type: 'audio/x-wav' }); |
|||
return await RawDecrypt(musicData, raw_filename, 'wav', false); |
|||
} |
Loading…
Reference in new issue