MichaelXF / js-confuser

JS-Confuser is a JavaScript obfuscation tool to make your programs *impossible* to read.
https://js-confuser.com
MIT License
236 stars 35 forks source link

SAFE Functions for integrity checks and for encryption #153

Open doctor8296 opened 3 days ago

doctor8296 commented 3 days ago

I collected/writed safe functions (based on literals), which are unpatchable and non-redefinable, and can safely be used for integrety checks or for "easy" encryption.

The only problem with those methods is that they have to use String.fromCharCode and String.prototype.charCodeAt (which are patchable). It can be solved by predefined literal dictionaries with symbols and charcodes. But it is not convenient to have whole unicode dictionary in code, because it is very large. However as far as we know all the characters used in code (and it is very unlikely that it will have all the characters, I'd say even more than 2% of it). Or we can use limited predefined set, like only ASCII chars.

const charCodeAt = (string, index) => {
  /** NO SAFE IMPLEMENTATION EXCEPT PREDEFINED DICTIONARIES */

  return string.charCodeAt(index);  
};

const fromCharCode = (code) => {
  /** NO SAFE IMPLEMENTATION EXCEPT PREDEFINED DICTIONARIES */

  return String.fromCharCode(code);
};

// safe Math.imul polyfill
const imul = (a, b) => {
  return (
    ((a & 0xffff) * (b & 0xffff) +
      ((((a >>> 16) * (b & 0xffff) + (a & 0xffff) * (b >>> 16)) << 16) >>> 0)) |
    0
  );
};

// hash function
const cyrb53 = (key, seed = 0) => {
  const A = 2654435761;
  const B = 1597334677;
  const C = 2246822507;
  const D = 3266489909;
  const E = 4294967296;
  const F = 2097151;

  let h1 = 0xdeadbeef ^ seed;
  let h2 = 0x41c6ce57 ^ seed;

  for (let index = 0, char; index < key.length; index++) {
    char = charCodeAt(key, index);

    h1 = imul(h1 ^ char, A);
    h2 = imul(h2 ^ char, B);
  }

  h1 = imul(h1 ^ (h1 >>> 16), C) ^ imul(h2 ^ (h2 >>> 13), D);
  h2 = imul(h2 ^ (h2 >>> 16), C) ^ imul(h1 ^ (h1 >>> 13), D);

  return E * (F & h2) + (h1 >>> 0);
};

// seeded random
const splitmix32 = (a) => {
  return () => {
    a |= 0;
    a = (a + 0x9e3779b9) | 0;
    let t = a ^ (a >>> 16);
    t = imul(t, 0x21f0aaad);
    t = t ^ (t >>> 15);
    t = imul(t, 0x735a2d97);
    return ((t = t ^ (t >>> 15)) >>> 0) / 4294967296;
  };
};

const ENCRYPTION_SEED = 90837146782

// symmetrical encryption
const easyEncrypt = (input, password) => {
  const random = splitmix32(cyrb53(password, ENCRYPTION_SEED));
  let output = "";
  for (let i = 0; i < input.length; i++) {
    output += fromCharCode(
      charCodeAt(input[i], 0) ^
        charCodeAt(password, i % input.length) ^
        charCodeAt(password, (input.length * random()) | 0) ^
        ((65536 * random()) | 0)
    );
  }
  return output;
};

image

MichaelXF commented 2 days ago

Nice. Are people actually patching the String.fromCharCode and String.prototype.charCodeAt and bypassing Integrity?

doctor8296 commented 2 days ago

Are people actually patching the String.fromCharCode and String.prototype.charCodeAt and bypassing Integrity

They absolutely capabel of it. By hooking onto String.fromCharCode they can have clear view on what gets decrypted / what password is etc etc.

Screenshot 2024-11-12 at 10 22 29

I even can imagine how it is possible to bypass integrity check (basically it is already possible by redefining Function.prototype.toString. And as you learn pattern of checks (order functions get checked) you can bypass it, since the behaviour of the protection is static. Or you can read stack and replace only when you need it).

And not only that! They can just crash the script with that, which is very dangerous in some cases.

The model should be consistent and independent (isolated) from any other external factors.

Talking of determined code behaviour, I very like the idea about randomized behaviour of it in someway, so some redefinitions that expect static checks will break. But unfortunately there is no possible way to get random values, "pure" random function, that cannot be redefined. But if you know how to get just random strings based only sole on literals or some other techniques, it will be helpful.