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
|
/* eslint-disable no-extend-native */
/* eslint-disable @typescript-eslint/ban-types */
/**
* make hooked methods "native"
*/
export const makeNative = (() => {
const l = new Map<Function, Function>();
hookNative(
Function.prototype,
"toString",
(_toString) => {
return function () {
if (l.has(this)) {
const _fn = l.get(this) || parseInt; // "function () {\n [native code]\n}"
if (l.has(_fn)) {
// nested
return _fn.toString();
} else {
return _toString.call(_fn) as string;
}
}
return _toString.call(this) as string;
};
},
true
);
return (fn: Function, original: Function) => {
l.set(fn, original);
};
})();
export function hookNative<T extends object, M extends keyof T>(
target: T,
method: M,
hook: (originalFn: T[M], detach: () => void) => T[M],
async = false
): void {
// reserve for future hook update
const _fn = target[method];
const detach = () => {
target[method] = _fn; // detach
};
// This script can run before anything on the page,
// so setting this function to be non-configurable and non-writable is no use.
const hookedFn = hook(_fn, detach);
target[method] = hookedFn;
if (!async) {
makeNative(hookedFn as any, _fn as any);
} else {
setTimeout(() => {
makeNative(hookedFn as any, _fn as any);
});
}
}
|