Skip to content

Scripts & expressions ​

Overview ​

An LmBox Bridge feature built for Adobe After Effects: compress, obfuscate and decrypt scripts and expressions. It helps you protect your code from unauthorized access and changes, and lets authors open and edit their own scripts and expressions when needed.

Interface ​

Obfuscating, encrypting and decrypting Ae expression scripts

In this article we use a common elastic expression from Ae as the example.

Click to see the original expression code
js
/**
 * Function: test block comment
 * Author: KernelKun
 * Email: [email protected]
 * Date: 2024-06-14 09:01:00
 * Version: v1.0
 */
 // Elastic expression parameters
 var freq = 2; // frequency
 var decay = 3; // decay
var test="这是一段没有作用的字符串"
 var n = 0;
if (numKeys > 0) {
    n = nearestKey(time).index;
    if (key(n).time > time) {
        n--;
    }
}

if (n == 0) {
    value;
} else {
  var t = time - key(n).time;
  // compute the elastic amplitude
  var  amp = (key(n).value - key(Math.max(1, n-1)).value) * 0.5; 
  var w = freq * Math.PI * 2; // compute the elastic frequency
  // apply the elastic effect
  value + amp * Math.sin(w * t) / Math.exp(decay * t); 
}

Expression compression ​

js
var e=2;var a=3;var v="\u8fd9\u662f\u4e00\u6bb5\u6ca1\u6709\u4f5c\u7528\u7684\u5b57\u7b26\u4e32";var i=0;if(numKeys>0){i=nearestKey(time).index;if(key(i).time>time){i--}}if(i==0){value}else{var t=time-key(i).time;var r=(key(i).value-key(Math.max(1,i-1)).value)*.5;var m=e*Math.PI*2;value+r*Math.sin(m*t)/Math.exp(a*t)}
js
var freq = 2;
var decay = 3;
var test = "\u8fd9\u662f\u4e00\u6bb5\u6ca1\u6709\u4f5c\u7528\u7684\u5b57\u7b26\u4e32";
var n = 0;
if (numKeys > 0) {
    n = nearestKey(time).index;
    if (key(n).time > time) {
        n--;
    }
}
if (n == 0) {
    value;
} else {
    var t = time - key(n).time;
    var amp = (key(n).value - key(Math.max(1, n - 1)).value) * .5;
    var w = freq * Math.PI * 2;
    value + amp * Math.sin(w * t) / Math.exp(decay * t);
}
ts
var freq = 2;
var decay = 3;
var test = "这是一段没有作用的字符串";
var n = 0;
if (numKeys > 0) {
    n = nearestKey(time).index;
    if (key(n).time > time) {
        n--;
    }
}
if (n == 0) {
    value;
} else {
    var t = time - key(n).time;
    var amp = (key(n).value - key(Math.max(1, n - 1)).value) * .5;
    var w = freq * Math.PI * 2;
    value + amp * Math.sin(w * t) / Math.exp(decay * t);
}
ts
var e = 2;
var a = 3;
var v = "这是一段没有作用的字符串";
var i = 0;
if (numKeys > 0) {
    i = nearestKey(time).index;
    if (key(i).time > time) {
        i--;
    }
}
if (i == 0) {
    value;
} else {
    var t = time - key(i).time;
    var r = (key(i).value - key(Math.max(1, i - 1)).value) * .5;
    var m = e * Math.PI * 2;
    value + r * Math.sin(m * t) / Math.exp(a * t);
}
ts
/**
 * Function: test block comment
 * Author: KernelKun
 * Email: [email protected]
 * Date: 2024-06-14 09:01:00
 * Version: v1.0
 */
// Elastic expression parameters
var freq=2;// frequency
var decay=3;// decay
var test="这是一段没有作用的字符串";var n=0;if(numKeys>0){n=nearestKey(time).index;if(key(n).time>time){n--}}if(n==0){value}else{var t=time-key(n).time;
// compute the elastic amplitude
var amp=(key(n).value-key(Math.max(1,n-1)).value)*.5;var w=freq*Math.PI*2;// compute the elastic frequency
// apply the elastic effect
value+amp*Math.sin(w*t)/Math.exp(decay*t)}

INFO

We found that compression is a tool that reduces code size and lightens the calculation load of Ae expressions. The run time of a piece of js code is tiny, but this runs inside Ae. For example, why is time a variable that keeps changing? Because it is calculated on every frame. So in an Ae expression the code lives in a loop and runs on every frame that plays, which differs from front-end js that only needs to run once.

Expression obfuscation ​

js
var _0x317aa1=_0x59df,_0x117dc0=0x1c9*-0x3+-0x1321+-0x11d*-0x16,_0x44f3c2=-0x591+-0x26*-0xf9+-0x3*0xa76,_0x362779=_0x317aa1(0x199)+'\u7b26\u4e32',_0x4d45fa=-0x1527+-0x11d5+0x26fc;function _0x59df(_0x1b4294,_0x4d0afe){var _0x20d73b=_0x1237();return _0x59df=function(_0x5582a8,_0x2fd644){_0x5582a8=_0x5582a8-(-0x11c1*0x1+-0x232*0xb+0x2b80);var _0x5e460c=_0x20d73b[_0x5582a8];return _0x5e460c;},_0x59df(_0x1b4294,_0x4d0afe);}function _0x1237(){var _0x25e9db=['\u8fd9\u662f\u4e00\u6bb5\u6ca1\u6709\u4f5c\u7528\u7684\u5b57','\x69\x6e\x64\x65\x78','\x74\x69\x6d\x65','\x76\x61\x6c\x75\x65','\x6d\x61\x78','\x65\x78\x70'];_0x1237=function(){return _0x25e9db;};return _0x1237();}numKeys>-0x1*0x13c1+0x54d*-0x2+-0x1*-0x1e5b&&(_0x4d45fa=nearestKey(time)[_0x317aa1(0x19a)],key(_0x4d45fa)[_0x317aa1(0x19b)]>time&&_0x4d45fa--);if(_0x4d45fa==-0x1*-0x170f+0x2d3+-0x19e2)value;else{var _0x449cd1=time-key(_0x4d45fa)['\x74\x69\x6d\x65'],_0x26a18b=(key(_0x4d45fa)[_0x317aa1(0x19c)]-key(Math[_0x317aa1(0x19d)](-0xa0*-0x18+-0x10c0+0x1c1,_0x4d45fa-(0x13*0x33+-0x1dd1+0x9b*0x2b)))[_0x317aa1(0x19c)])*(0x24d*0x10+-0x52e+-0x1fa2+0.5),_0x3dc523=_0x117dc0*Math['\x50\x49']*(-0x193+0x1*0x1cf6+-0x1b61);value+_0x26a18b*Math['\x73\x69\x6e'](_0x3dc523*_0x449cd1)/Math[_0x317aa1(0x19e)](_0x44f3c2*_0x449cd1);}
js
function _0x3ab2(_0xd38729,_0x2bf060){var _0x3eb3c7=_0x1cb8();_0x3ab2=function(_0x4b4a27,_0x5147f3){_0x4b4a27=_0x4b4a27-(0x10f1*-0x1+-0x2*0x7c5+-0x11*-0x1fd);var _0x5e3915=_0x3eb3c7[_0x4b4a27];return _0x5e3915;};return _0x3ab2(_0xd38729,_0x2bf060);}var _0x596680=_0x3ab2;var e=0x106*-0x3+0x1*0xc4d+0x313*-0x3;var a=0x2595*0x1+-0x12b*0xe+0x1c*-0xc2;var v=_0x596680(0x152);var i=0x71+-0x1ad2+0x1a61*0x1;if(numKeys>-0x1f*-0xa6+0x79f+-0x1bb9){i=nearestKey(time)[_0x596680(0x153)];if(key(i)['time']>time){i--;}}function _0x1cb8(){var _0x3dc93a=['这是一段没有作用的字符串','index','time','value','sin','exp'];_0x1cb8=function(){return _0x3dc93a;};return _0x1cb8();}if(i==-0x5*0x240+-0x1f7a+0x2aba){value;}else{var t=time-key(i)[_0x596680(0x154)];var r=(key(i)[_0x596680(0x155)]-key(Math['max'](0x1*0x16e4+0x1*0x1a6b+-0x314e,i-(0x4*0x732+-0x14*-0x53+-0x2343)))['value'])*(0x6f9*-0x5+-0xffe+0x32db+0.5);var m=e*Math['PI']*(0x1a96+-0x1892+-0x101*0x2);value+r*Math[_0x596680(0x156)](m*t)/Math[_0x596680(0x157)](a*t);}
ts
var _0x819ce4 = _0x470d;
var e = -0x12ac + 0x13ea + -0x4f * 0x4;
var a = -0x1 * 0xb8d + 0x1 * 0x89 + 0x3ad * 0x3;
var v = _0x819ce4(0x16d);
function _0x470d(_0x26aa94, _0x289abe) {
    var _0x42086e = _0x5ad4();
    _0x470d = function (_0x41cc04, _0x1c0a2b) {
        _0x41cc04 = _0x41cc04 - (-0x1 * -0x67 + 0x2358 + 0x1 * -0x2252);
        var _0xb64c98 = _0x42086e[_0x41cc04];
        return _0xb64c98;
    };
    return _0x470d(_0x26aa94, _0x289abe);
}
var i = -0x18e * 0x1 + 0x255a + -0x23cc;
if (numKeys > -0x33b + 0x695 * 0x5 + -0xed7 * 0x2) {
    i = nearestKey(time)[_0x819ce4(0x16e)];
    if (key(i)[_0x819ce4(0x16f)] > time) {
        i--;
    }
}
function _0x5ad4() {
    var _0x1d6223 = [
        '这是一段没有作用的字符串',
        'index',
        'time',
        'value',
        'sin',
        'exp'
    ];
    _0x5ad4 = function () {
        return _0x1d6223;
    };
    return _0x5ad4();
}
if (i == 0x1c92 + -0x10b6 + -0xbdc) {
    value;
} else {
    var t = time - key(i)['time'];
    var r = (key(i)[_0x819ce4(0x170)] - key(Math['max'](-0xdab + -0x1b9d + -0x3 * -0xdc3, i - (-0x867 + 0x5 * -0x488 + 0x1f10)))[_0x819ce4(0x170)]) * (-0x108f + -0x34c * 0xb + 0x34d3 + 0.5);
    var m = e * Math['PI'] * (0xc95 * -0x1 + -0x10c6 + 0x1d5d);
    value + r * Math[_0x819ce4(0x171)](m * t) / Math[_0x819ce4(0x172)](a * t);
}
ts
var _0x3700bd = _0x16af;
function _0x4a5e() {
    var _0x49ff00 = [
        'index',
        'time',
        'value',
        'max'
    ];
    _0x4a5e = function () {
        return _0x49ff00;
    };
    return _0x4a5e();
}
var e = -0x1caf + -0x85 + 0x1d36;
var a = -0x7 * -0xca + -0x1 * -0x469 + 0x1fc * -0x5;
function _0x16af(_0x444f33, _0xe00e7e) {
    var _0xcae48c = _0x4a5e();
    _0x16af = function (_0x2f0e66, _0xca4a58) {
        _0x2f0e66 = _0x2f0e66 - (-0x18fb + 0x4 * 0x577 + 0x5 * 0xee);
        var _0x2d11ee = _0xcae48c[_0x2f0e66];
        return _0x2d11ee;
    };
    return _0x16af(_0x444f33, _0xe00e7e);
}
var v = '这是一段没有作用的字' + '符串';
var i = -0x4d4 + -0x116 + 0x5ea;
if (numKeys > 0x48 + -0x5c3 + 0x57b) {
    i = nearestKey(time)[_0x3700bd(0x187)];
    if (key(i)[_0x3700bd(0x188)] > time) {
        i--;
    }
}
if (i == -0x23 * 0x43 + -0x4 * 0x617 + 0x2185) {
    value;
} else {
    var t = time - key(i)['time'];
    var r = (key(i)[_0x3700bd(0x189)] - key(Math[_0x3700bd(0x18a)](-0xec * -0x1d + 0x1 * -0x1e0d + 0x5 * 0xaa, i - (0x1c1f * 0x1 + -0x1803 + -0x41b * 0x1)))['value']) * (0x701 * -0x1 + -0x22cd + 0x29ce + 0.5);
    var m = e * Math['PI'] * (0x19 * -0xcc + -0xd0f + 0x5 * 0x699);
    value + r * Math['sin'](m * t) / Math['exp'](a * t);
}
ts
var _0x4d01b5 = _0x5021;
var e = -0xeb + 0xd * -0x2a1 + -0x2 * -0x118d;
function _0x5021(_0x97497, _0x2e915a) {
    var _0x5fa204 = _0x2338();
    _0x5021 = function (_0x228406, _0x322633) {
        _0x228406 = _0x228406 - (-0x523 * -0x5 + 0x1 * -0xa37 + 0x709 * -0x2);
        var _0x43baa8 = _0x5fa204[_0x228406];
        return _0x43baa8;
    };
    return _0x5021(_0x97497, _0x2e915a);
}
var a = 0xe35 * 0x2 + -0x1863 + -0x404;
var v = _0x4d01b5(0x166);
var i = 0x641 + -0x295 * -0x2 + -0xb6b;
if (numKeys > -0x1652 + 0xb0b + 0xb47) {
    i = nearestKey(time)['\x69\x6e\x64\x65\x78'];
    if (key(i)[_0x4d01b5(0x167)] > time) {
        i--;
    }
}
if (i == -0x1f * -0xd6 + 0xb8e * -0x2 + -0x2ce) {
    value;
} else {
    var t = time - key(i)[_0x4d01b5(0x167)];
    var r = (key(i)[_0x4d01b5(0x168)] - key(Math[_0x4d01b5(0x169)](-0x2214 + 0x2e9 + 0x1f2c, i - (0x4f * -0x37 + -0x2071 * -0x1 + -0xf77)))['\x76\x61\x6c\x75\x65']) * (-0x1be3 + -0xa6d + 0x2650 + 0.5);
    var m = e * Math['\x50\x49'] * (-0x1c37 + 0xa6 * -0x1c + 0x1 * 0x2e61);
    value + r * Math[_0x4d01b5(0x16a)](m * t) / Math[_0x4d01b5(0x16b)](a * t);
}
function _0x2338() {
    var _0x4fd33e = [
        '\u8fd9\u662f\u4e00\u6bb5\u6ca1\u6709\u4f5c\u7528\u7684\u5b57\u7b26\u4e32',
        '\x74\x69\x6d\x65',
        '\x76\x61\x6c\x75\x65',
        '\x6d\x61\x78',
        '\x73\x69\x6e',
        '\x65\x78\x70'
    ];
    _0x2338 = function () {
        return _0x4fd33e;
    };
    return _0x2338();
}
ts
var _0x4d7a90 = _0x3b18;
var _0x1357d7 = 0x6 * -0x31b + -0x2519 + 0x2ef * 0x13;
function _0x3b18(_0x2c0204, _0x8506e9) {
    var _0x18f21c = _0x5dc8();
    _0x3b18 = function (_0x268c67, _0x4218cc) {
        _0x268c67 = _0x268c67 - (0x1 * -0x67a + 0x25c4 + 0x2 * -0xeb1);
        var _0x389b3d = _0x18f21c[_0x268c67];
        return _0x389b3d;
    };
    return _0x3b18(_0x2c0204, _0x8506e9);
}
var _0x5cd828 = -0xf2b + -0x200a + 0x2f38;
var _0x54732f = _0x4d7a90(0x1e8);
var _0x12f2f6 = 0x1029 + 0x1853 + -0x287c;
if (numKeys > -0x1e20 + 0x1915 + 0x1 * 0x50b) {
    _0x12f2f6 = nearestKey(time)['index'];
    if (key(_0x12f2f6)[_0x4d7a90(0x1e9)] > time) {
        _0x12f2f6--;
    }
}
if (_0x12f2f6 == -0x47 * 0x1f + 0x1 * -0xbb7 + 0x1450) {
    value;
} else {
    var _0xa7eed3 = time - key(_0x12f2f6)[_0x4d7a90(0x1e9)];
    var _0xf9f20d = (key(_0x12f2f6)[_0x4d7a90(0x1ea)] - key(Math[_0x4d7a90(0x1eb)](0x135 * -0x4 + 0x1deb + -0x1916, _0x12f2f6 - (0xce * -0x1c + -0x1a * 0x10 + -0x4d5 * -0x5)))['value']) * (0x57 * 0x50 + -0x1884 * -0x1 + -0x33b4 * 0x1 + 0.5);
    var _0x3e936f = _0x1357d7 * Math['PI'] * (0x190 + -0x267c * -0x1 + -0x280a);
    value + _0xf9f20d * Math[_0x4d7a90(0x1ec)](_0x3e936f * _0xa7eed3) / Math[_0x4d7a90(0x1ed)](_0x5cd828 * _0xa7eed3);
}
function _0x5dc8() {
    var _0x52117e = [
        '这是一段没有作用的字符串',
        'time',
        'value',
        'max',
        'sin',
        'exp'
    ];
    _0x5dc8 = function () {
        return _0x52117e;
    };
    return _0x5dc8();
}

INFO

We found that obfuscation increases the amount of calculation, and the complexity grows exponentially when you stack obfuscation repeatedly. This complexity is what protects the original code from being tampered with, to a degree.

Expression encryption ​

sonng

Not available yet. Stay tuned

Expression decryption ​

  • Decrypt Ae expression decrypts the expression of the selected Ae layer. The target is an expression encrypted as jsxBin binary. This is a reverse process, for example an expression in the format below will be decrypted
js
eval("@JSXBIN@ES@(2.0)@MyBbyBnByB")

Script decryption ​

  • Decrypt script text decrypts a script file encrypted as 'jsxbin' that you pick. Success is not guaranteed, and it is for learning only.

Comment tool ​

Add or replace comment fields in Ae expressions in batch.

Video tutorial ​

Video coming soon