MichaelXF / js-confuser

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

feat: block-level calculator/dispatcher #100

Open Le0Developer opened 1 year ago

Le0Developer commented 1 year ago

Is your feature request related to a problem? Please describe.

In addition to the global calculator function, local/block-level calculator functions are very annoying to deal with.

This is an example from a script obfuscated by Cloudflare's proprietary solution:

  function hl(d, e) {
    e = {
      IODHZ: strLookup(1495),
      ZaiCw: function (f, g, h) {
        return f(g, h);
      }
    };
    e[strLookup(801)](hh, d, function (f) {
      f[strLookup(1846)][strLookup(1875)] = strLookup(347);
      f[strLookup(1846)].visibility = e.IODHZ;
    });
  }

As you can see, the e object contains a block-level dispatcher and variable, but it can also include calculators and even the same one multiple times:


      f = {
        VmRPf: function (j, k) {
          return k === j;
        },
        jzNUF: "complete",
        InfVk: function (j, k) {
          return k | j;
        },
        XFOiM: function (j, k) {
          return j << k;
        },
        EpYUF: function (j, k) {
          return k ^ j;
        },
        TGnJl: function (j, k) {
          return j - k;
        },
        ihSaf: function (j, k) {
          return k ^ j;
        },
        netJL: function (j, k) {
          return j & k;
        },
        ftAEZ: function (j, k) {
          return j - k;
        },
        KqEBC: function (j, k) {
          return j ^ k;
        },
        ZKdga: function (j, k) {
          return j < k;
        },
        WxnhP: function (j, k) {
          return k ^ j;
        },
        buCzB: function (j, k) {
          return k ^ j;
        },
        ANDzz: function (j, k) {
          return j + k;
        },
        yGbbD: function (j, k) {
          return j + k;
        },
        xUDZY: function (j, k) {
          return k ^ j;
        },
        sZhYi: function (j, k) {
          return j ^ k;
        },
        OOYGk: function (j, k) {
          return j & k;
        },
        APBrv: function (j, k) {
          return j ^ k;
        },
        UNIAH: function (j, k) {
          return k ^ j;
        },
        nXtSj: function (j, k) {
          return j ^ k;
        },
        xlBks: function (j, k) {
          return j - k;
        },
        PetUx: function (j, k) {
          return j ^ k;
        },
        AnGxH: function (j, k) {
          return j ^ k;
        },
        RbfOG: function (j, k) {
          return k === j;
        },
        fzjxF: function (j, k) {
          return k === j;
        },
        oNtLY: strLookup(1018),
        mlhOQ: strLookup(522),
        ehmzL: function (j, k) {
          return j(k);
        },
        KexZm: strLookup(1471),
        Iajza: strLookup(1762),
        oHdAV: strLookup(1217),
        IrhEi: strLookup(1560),
        ecuWj: function (j, k) {
          return j === k;
        },
        mQGaA: function (j, k) {
          return j !== k;
        },
        BLreP: strLookup(567)
      };

Sometimes in deeply nested functions, a block-level dispatcher/calculator also calls another higher-up one:


f = {
  Hcgyw: strLookup(1027),
  kZhQS: function (l, m) {
    return l + m;
  },
  njgAA: function (l) {
    return l();
  },
  vSaUg: function (l, m) {
    return m === l;
  },
  GddGi: function (l, m) {
    return l < m;
  },
  gTouW: strLookup(347),
  bxzGp: strLookup(1349),
  cCbfw: strLookup(1072),
  TDQGI: strLookup(729),
  UtfmT: function (l, m) {
    return m === l;
  },
  BCvmI: strLookup(447),
  BeEUo: function (l, m) {
    return m === l;
  },
  QxEvm: strLookup(984),
  kcjNA: function (l, m) {
    return l === m;
  },
  YaqZh: strLookup(1329),
  EQVuX: strLookup(1876),
  wRfVC: strLookup(459),
  awDrx: function (l) {
    return l();
  },
  AvtlX: function (l, m) {
    return l(m);
  },
  SPHDi: strLookup(1316),
  SCEKk: function (l, m) {
    return l(m);
  },
  gxpYE: function (l) {
    return l();
  },
  IUoch: strLookup(1707),
  jMlyM: strLookup(1328),
  cVtpB: strLookup(1140),
  WcJaN: strLookup(1464),
  BRVga: function (l, m) {
    return l + m;
  }
};

/* later */

  l = {
    phzoe: function (B, C) {
      return f[strLookup(1910)](B, C); // higher-up
    },
    eFbES: strLookup(1103),
    aocNW: function (B, C) {
      return f[strLookup(661)](B, C); // higher-up
    },
    CzTgP: strLookup(493),
    PyEZj: "error code: 1020",
    YyLwb: f[strLookup(634)], // higher-up
    RjTgN: strLookup(1560)
  };
MichaelXF commented 1 year ago

Yes that could added to calculator. What I notice is the e object contains strings and other types of functions on it. This could also be implemented in JS-Confuser. What do you think should change?

Le0Developer commented 1 year ago

I am not too familiar with the entire codebase, so you should do the call where best to implement this.

Just a few more notes:

// example, after undoing string concealment
// only one string (ignoring "log") and a lot more confusing imo than an extra random string
var e  = {
  "hello world": function(a, b) {
    return a(b)
  }
}
e["hello world"](console.log, "hello world")
MichaelXF commented 1 year ago

1) Specialized dispatchers, yes! 2) Removing var and putting it a function parameter is a very cool idea. 3) transformObjectKeys is neat but it's weak obfuscation.

I think going about this would be to buff up dispatcher. It will probably not be exactly like cf's obfuscation but I'll see what ideas could be implemented when I have the time. The var idea is also nice and would possibly be added to movedDeclarations as it's appropriate transformation.