aboutsummaryrefslogtreecommitdiff
path: root/src/anti-detection.ts
blob: c3bd14bc8cbcfe95fe9a8426e7845d5de9501319 (plain) (blame)
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);
        });
    }
}