[1] view-source:https://www.freeslots.com/slot515.min.js?v=84
[1] view-source:https://www.freeslots.com/slot515.min.js?v=84
I'm not sure how many levels it was applied but my general strategy on it was the first obfuscation method seemed to be an IIFE that triggers eval on a big string that has had some transformations applied which then calls eval on the next level and so on so I would take the IIFE, turn it into a function definition stuck in a variable like "decodeFunction1" so I could just recursively call directly and change the ending to return the string instead of eval it directly. There is probably something that could be done with debugger breakpoints here but I don't know enough about how that plays out inside eval. Anyways if I were evil I'd make sure at some point in this chain there is a subtle change in what's happening that breaks this approach so I wouldn't be surprised if someone told me that was the case :).
It'd be interesting to see what some real JS devs could get to, both from a "how hard is it" perspective but also just to see what different obfuscations are used in the real world.
With it I get https://ghostbin.me/62d52999cc217 , from there it's decoding UTF-16 and at least one more decoding step (parts of decoded UTF-16 are mangled) to get the string j and the function o and resolving the original function with it.
Comment at the top also points to https://freeslots.com/libs/mersenne-twister.js
Using those two together to decode the RNG function, and searching around for some more local pointers (with some judicious renaming of functions for legibility, and some comments):
// polyfill for IE??
function trunc(a) {
return a < 0 ? Math.ceil(a) : Math.floor(a)
}
var genrand_res53 = function() {
var a = new MersenneTwister((new Date).getTime() + Math.floor(Math.random() * Math.pow(2, 32)));
return function() {
// Generate a random float by varying the 53-bit mantissa.
var b = genrand_int32(a) >>> 5,
c = genrand_int32(a) >>> 6;
// (b << 26 | c) / 2 ** 53
return (b * 67108864 + c) * 1.1102230246251565E-16
}
}();
function rand_int(a, b) {
var c = genrand_res53();
if (a === undefined) return c;
if (b === undefined) return trunc(c * a);
if (b > a) return a + trunc(c * (b - a));
return a;
}
function Kma() {
// credits is `Lma`; if you want to cheat, you can edit that variable directly
credits < 500 && (Ika = Ika - Ika % 1E6 + rand_int(890001) + 1E5)
}
So, we're generating a random integer from 0 to 890,000 (inclusive, with negligible chance of generating 890001) with each spin, and using that to update the state (seeded with current time; the top 1e6 of the value is determined via mixing of Date.now() and Math.random() and is fixed for a given session).There's then more to determine whether your state is a winner (based on the game mode), but I didn't feel like looking into that specifically.
I have had to deal with client that thought they could keep some bit of code secret on a browser before. I have had to explain many many times that anything the browser can do a human can do. So if a browser can run the code, at some point a human can too.
Meaning, effectively, it can be de-obfuscated into code with control flow that's readily understood by a human, even if it would take some patience and practice (and the right tools) to perform the de-obfuscation.
Re: the FreeSlots.com program, https://deobfuscate.io shows that most of the obfuscation is related to decoding characters per some algorithm of their devising and eventually eval'ing the string as a JS program. There are likely several tricky rounds of that technique (and others) used at layers within the obfuscated code.
If the FreeSlots devs are clever, then they likely have a scheme to randomly generate the code they want (producing their desired result in terms of odds), where the random part is w.r.t. how the obfuscation layers are composed. Done well, that could make it rather difficult to mechanically de-obfuscate their code changing over time, i.e. without a human intervening to help identify the distinct layers because... parsers are hard.
I gave it a quick shot with some spare time, was selfishly hoping someone else had done the work when I checked back :p.
I don't feel so incentivized at present, sorry if I'm letting you down.
Figuring out the odds generator...is a task I will leave to someone else :)