2020-10-21 14:58:24 +00:00
|
|
|
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
|
|
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
|
|
|
|
2020-11-09 19:07:57 +00:00
|
|
|
import { hookNative } from './anti-detection'
|
2020-11-26 02:06:35 +00:00
|
|
|
import { console, getUnsafeWindow } from './utils'
|
2020-11-09 19:07:57 +00:00
|
|
|
|
2020-11-13 23:27:28 +00:00
|
|
|
const CHUNK_PUSH_FN = /^function [^r]\(\w\){/
|
2020-11-09 19:48:57 +00:00
|
|
|
|
2020-10-21 14:58:24 +00:00
|
|
|
interface Module {
|
|
|
|
(module, exports, __webpack_require__): void;
|
|
|
|
}
|
|
|
|
|
2020-11-18 18:57:56 +00:00
|
|
|
type WebpackJson = [(number | string)[], { [id: string]: Module }, any[]?][]
|
2020-10-21 14:58:24 +00:00
|
|
|
|
|
|
|
const moduleLookup = (id: string, globalWebpackJson: WebpackJson) => {
|
|
|
|
const pack = globalWebpackJson.find(x => x[1][id])!
|
|
|
|
return pack[1][id]
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve (webpack_require) a module from the page's webpack package
|
|
|
|
*
|
|
|
|
* I know this is super hacky.
|
|
|
|
*/
|
|
|
|
export const webpackHook = (moduleId: string, moduleOverrides: { [id: string]: Module } = {}, globalWebpackJson: WebpackJson = window['webpackJsonpmusescore']) => {
|
|
|
|
const t = Object.assign((id: string, override = true) => {
|
|
|
|
const r: any = {}
|
|
|
|
const m: Module = (override && moduleOverrides[id])
|
|
|
|
? moduleOverrides[id]
|
|
|
|
: moduleLookup(id, globalWebpackJson)
|
|
|
|
m(r, r, t)
|
|
|
|
if (r.exports) return r.exports
|
|
|
|
return r
|
|
|
|
}, {
|
|
|
|
d (exp, name, fn) {
|
|
|
|
return Object.prototype.hasOwnProperty.call(exp, name) ||
|
|
|
|
Object.defineProperty(exp, name, { enumerable: true, get: fn })
|
|
|
|
},
|
|
|
|
n (e) {
|
2020-10-22 19:30:31 +00:00
|
|
|
const m = e.__esModule ? () => e.default : () => e
|
|
|
|
t.d(m, 'a', m)
|
|
|
|
return m
|
2020-10-21 14:58:24 +00:00
|
|
|
},
|
|
|
|
r (r) {
|
|
|
|
Object.defineProperty(r, '__esModule', { value: true })
|
|
|
|
},
|
|
|
|
e () {
|
|
|
|
return Promise.resolve()
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
return t(moduleId)
|
|
|
|
}
|
|
|
|
|
2020-11-12 18:28:40 +00:00
|
|
|
export const ALL = '*'
|
|
|
|
|
2020-11-17 17:00:41 +00:00
|
|
|
export const [webpackGlobalOverride, onPackLoad] = (() => {
|
|
|
|
type OnPackLoadFn = (pack: WebpackJson[0]) => any
|
|
|
|
|
2020-11-09 19:07:57 +00:00
|
|
|
const moduleOverrides: { [id: string]: Module } = {}
|
2020-11-17 17:00:41 +00:00
|
|
|
const onPackLoadFns: OnPackLoadFn[] = []
|
2020-11-09 19:07:57 +00:00
|
|
|
|
|
|
|
function applyOverride (pack: WebpackJson[0]) {
|
2020-11-12 18:28:40 +00:00
|
|
|
let entries = Object.entries(moduleOverrides)
|
|
|
|
// apply to all
|
|
|
|
const all = moduleOverrides[ALL]
|
|
|
|
if (all) {
|
|
|
|
entries = Object.keys(pack[1]).map(id => [id, all])
|
|
|
|
}
|
|
|
|
|
|
|
|
entries.forEach(([id, override]) => {
|
2020-11-09 19:07:57 +00:00
|
|
|
const mod = pack[1][id]
|
|
|
|
if (mod) {
|
|
|
|
pack[1][id] = function (n, r, t) {
|
|
|
|
// make exports configurable
|
|
|
|
t = Object.assign(t, {
|
|
|
|
d (exp, name, fn) {
|
|
|
|
return Object.defineProperty(exp, name, { enumerable: true, get: fn, configurable: true })
|
|
|
|
},
|
|
|
|
})
|
|
|
|
mod(n, r, t)
|
|
|
|
override(n, r, t)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// hook `webpackJsonpmusescore.push` as soon as `webpackJsonpmusescore` is available
|
2020-11-26 02:06:35 +00:00
|
|
|
const _w = getUnsafeWindow()
|
|
|
|
let jsonp = _w['webpackJsonpmusescore']
|
2020-11-09 19:48:57 +00:00
|
|
|
let hooked = false
|
2020-11-26 02:06:35 +00:00
|
|
|
Object.defineProperty(_w, 'webpackJsonpmusescore', {
|
2020-11-09 19:07:57 +00:00
|
|
|
get () { return jsonp },
|
|
|
|
set (v: WebpackJson) {
|
|
|
|
jsonp = v
|
2020-11-13 23:27:28 +00:00
|
|
|
if (!hooked && v.push.toString().match(CHUNK_PUSH_FN)) {
|
2020-11-09 19:48:57 +00:00
|
|
|
hooked = true
|
|
|
|
hookNative(v, 'push', (_fn) => {
|
|
|
|
return function (pack) {
|
2020-11-17 17:00:41 +00:00
|
|
|
onPackLoadFns.forEach(fn => fn(pack))
|
2020-11-09 19:48:57 +00:00
|
|
|
applyOverride(pack)
|
|
|
|
return _fn.call(this, pack)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2020-11-09 19:07:57 +00:00
|
|
|
},
|
|
|
|
})
|
|
|
|
|
2020-11-17 17:00:41 +00:00
|
|
|
return [
|
|
|
|
// set overrides
|
|
|
|
(moduleId: string, override: Module) => {
|
|
|
|
moduleOverrides[moduleId] = override
|
|
|
|
},
|
|
|
|
// set onPackLoad listeners
|
|
|
|
(fn: OnPackLoadFn) => {
|
|
|
|
onPackLoadFns.push(fn)
|
|
|
|
},
|
|
|
|
] as const
|
2020-11-09 19:07:57 +00:00
|
|
|
})()
|
|
|
|
|
2020-11-17 17:09:23 +00:00
|
|
|
export const webpackContext = new Promise<any>((resolve) => {
|
|
|
|
webpackGlobalOverride(ALL, (n, r, t) => {
|
|
|
|
resolve(t)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2020-11-19 05:51:09 +00:00
|
|
|
const PACK_ID_REG = /\+(\{.*?"\})\[\w\]\+/
|
|
|
|
|
|
|
|
export const loadAllPacks = () => {
|
|
|
|
return webpackContext.then((ctx) => {
|
|
|
|
try {
|
|
|
|
const fn = ctx.e.toString()
|
|
|
|
const packsData = fn.match(PACK_ID_REG)[1] as string
|
|
|
|
// eslint-disable-next-line no-new-func, @typescript-eslint/no-implied-eval
|
|
|
|
const packs = Function(`return (${packsData})`)() as { [id: string]: string }
|
|
|
|
|
|
|
|
Object.keys(packs).forEach((id) => {
|
|
|
|
ctx.e(id)
|
|
|
|
})
|
|
|
|
} catch (err) {
|
|
|
|
console.error(err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-11-19 22:54:25 +00:00
|
|
|
const OBF_FN_REG = /\w\(".{4}"\),(\w)=(\[".+?\]);\w=\1,\w=(\d+).+?\);var (\w=.+?,\w\})/
|
|
|
|
export const OBFUSCATED_REG = /(\w)\((\d+),"(.{4})"\)/g
|
|
|
|
|
|
|
|
export const getObfuscationCtx = (mod: Module): (n: number, s: string) => string => {
|
|
|
|
const str = mod.toString()
|
|
|
|
const m = str.match(OBF_FN_REG)
|
|
|
|
if (!m) return () => ''
|
|
|
|
|
|
|
|
try {
|
|
|
|
const arrVar = m[1]
|
|
|
|
const arr = JSON.parse(m[2])
|
|
|
|
|
|
|
|
let n = +m[3] + 1
|
|
|
|
for (; --n;) arr.push(arr.shift())
|
|
|
|
|
|
|
|
const fnStr = m[4]
|
|
|
|
const ctxStr = `var ${arrVar}=${JSON.stringify(arr)};return (${fnStr})`
|
|
|
|
// eslint-disable-next-line no-new-func, @typescript-eslint/no-implied-eval
|
|
|
|
const fn = new Function(ctxStr)()
|
|
|
|
|
|
|
|
return fn
|
|
|
|
} catch (err) {
|
|
|
|
console.error(err)
|
|
|
|
return () => ''
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-21 14:58:24 +00:00
|
|
|
export default webpackHook
|