If you are looking for the decompiler itself, visit https://github.com/jindrapetrik/jpexs-decompiler
NEW : We have got a new blog where we post some interesting SWF internals info.

#1145 consecutive NOT(!)s are being merged, altering the code behavior at times
Author:
ilufang

Date created:
Type: bug
Visibility: Everybody
Assigned to:
Labels: Decompilation
State: closed 

> What steps will reproduce the problem? What is the expected output? What do you see
instead?
Create an swf containing code like this
trace(!!"Hello"); // Evaluates to true
Decompile that with ffdec, it becomes something like
trace("Hello"); // Evaluates to "Hello"
Basically the double-NOTs are automatically removed in the decompiled actionscript. (They
are still present in pcode though) In cases like above when logical-NOTs are not used
against boolean values, simply removing them can cause the code to behave differently.
> What version of the product are you using? Is it "nightly build"? Which operating system
do you have?
I guess this is platform independent and the issue appears in all recent versions. Just in
case, I am running MacOS 10.11.2, JavaSE 64 bit build 1.8.0_71-b15 and FFDec 7.1.2 Release
and FFDec 7.1.2 Nightly 1243.
> Please provide any additional information below.
Here's the case for me (a bit irrelevant): Although using !! is illogical and redundant,
the scenario actually happened in a block of manually obfuscated actionscript. The
developer used the implicit toString to hide code, eg, /./(!!{}) for the letter "t". Of
course this is hardly deobfuscatable through a general approach, but can you fix this so
that the decompiled code can still produce the same results, making further analysis
possible? Anyway, thank you very much for this wonderful project!
Ad "this is hardly deobfuscatable through a general approach"
Challenge accepted!
I already seen a swf with this kind of things but not realized that
it's actual obfuscation. Thanks for the idea. Will definitely try to get past this in the
decompiler :-)
Haha, here is the swf containing the obfuscated code. It's located in
scene.sally.__abcde__. For __abcde__ object foo, calling foo._(foo.o) gets the "protected"
value (for verification), which is typically an integer between 1 and 99.
Good luck! XD

uhh, this one looks pretty harder that ones I have seen earlier,
something tells me that you were a bit right with the statement "hadly deobfuscatable"
:-D
But thanks for the sample SWF file, maybe I will figure out something with it, chances are
low, but it is definitely challenging :-).
I will surely fix the !! problem.
Do you have an idea which tool (obfuscator?) produces such code?
You said it's "manually obfuscated". I don't think anybody will do this manually, it's a
lot of work. Or could you provide some related links? Google is not helpful with this or I
do not provide useful search keywords.
I have seen one other SWF with similar obsfuscation so I wonder how can someone use it in
his own SWF.
I'm sorry I am not related to any part of the creation of that swf. It is a part of the
online game Kantai Collection. I also have no idea about how these crazy stuff came out. I
also tried a lot of web search and got no clues : (
Here's why I think it is manually obfuscated: throughout all swf components of the game,
only 7 methods are obfuscated in that way. These methods just produce meaningless
parameters used in sending HTTP API requests to prevent automated bot requests. All other
code is perfectly readable, without even hiding a method name. Moreover, the techniques
themselves varied a lot and are so complicated in structure that I think it might just not
apply to any generic function easily. The principle of its obfuscation is basically "leave
NO character of the source code as-is". It also became more and more complicated as the
developer updated the game. That is why I guess those developers obfuscated only these key
functions by hand.
In case you might need, here are the 7 main methods:
mainD2.swf: mainD2.___(bytesIn, bytesOut, key) decodes Core.swf as binary data for
Loader.loadBytes
Core_decoded.swf: common.util.Util.$$ (display as method_61 in source code by a bug?)
generate one parameter
Core_decoded.swf: common.util.Util.f generate one filename
Core_decoded.swf: common.util.Util.s (not yet found)
Core_decoded.swf: connection.api_port.PortAPI.__ generate one parameter
DutyMain.swf: scene.duty.utils.__ generate one parameter
SallyMain.swf: scene.sally.__abcde__ generate one parameter (the previous one)
They might call one or two supporting functions, but not these are obfuscated (or
partially obfuscated)
Thanks.
It looks like the other similar file I was talking about is from #792 and it's probably
the Core_decoded, or a past version of it.
So it is unique to this game, you're right.
It is amazing since it looks like actual obfuscation, not like one of these "just insert
if 56==4 to make decompiler crash" tools.
I'll try to improve our deobfuscator-simplifier,
but probably won't get anything super readable.
Thanks a lot. I tried the latest nightly and it works just right. The code is much shorter
and more readable now!
However, as I tried to analyze these functions, I pasted the code into Flash Builder and
the script did not work exactly as the SWF did. I looked into the code and found a few
bugs that you might also want to fix:
1. (P-Code->AS decompilation, no deobfuscation) Missing parenthesis when doing rshift and
urshift
Compile something like a>>(b>>>c), the decompiler will generate a>>b>>>c, giving wrong
results
2. (P-Code->AS decompilation, no deobfuscation) P-Code casting instruction like convert_s
is ignored
`String(this).length` should return 15 because `this` becomes `"[object Object]"`. But the
casting is missing in the decompiled script, giving `this.length`, causing an error to
generate as this.length is not defined.
3. (AS deobfuscation, P-Code to AS OK) values inside square brackets are probably assumed
to be numbers, therefore using string indexes against objects results in a NaN in the
deobfuscated code.
/./(/.. /({})) + /.$/(/../({})) + /./(/./([])) + /./(/..$/(!{})) + /.../(!!{}) + /../(/..
/({})) + /.$/(/../({})) + /.$/(/../(!!{})) evaluates to "constructor", thus
1[/./(/.. /({})) + /.$/(/../({})) + /./(/./([])) + /./(/..$/(!{})) + /.../(!!{}) +
/../(/.. /({})) + /.$/(/../({})) + /.$/(/../(!!{}))] evaluates to [class Number]
Without deobfuscation the code works exactly as intended when pasted, but after
auto-deobfuscation, it becomes
1["NaN"] which gives an error.
In the attached file please find the three specific scenarios above.
Also for the deobfuscation part, I am just guessing, is it possible to evaluate constant
expressions to simplify the code?
Thank you!

Hi, I'll try to implement fix for the points 1,2,3.
Ad "evaluate constant expressions to simplify the code".,
I already implemented something like this (forgot to tell), you can enable it as
experimental feature in Advanced settings / Other / (Internal) _simplifyExpressions.
It makes your code a bit more readable. Only exception is when there is function argument
involved.
Now there are a lot of unnecessary parentheses in the following format:
if (a && (b && (c && d))
and
a * (b * (c * d))
earlier it was:
if (a && b && c && d)
and
a * b * c * d
I know that it is correct now, but it causes a lot of differences with the previous
decompilations, so hard to compare the result and find the real differences. Could you
please fix it?
Forgot to add examples.
100000.swf\scripts\__Packages\JSON.as
current:
if(this.next() == "r" && (this.next() == "u" && this.next() == "e"))
before:
if(this.next() == "r" && this.next() == "u" && this.next() == "e")
2.swf (71401 bytes)\scripts\DefineSprite_27\frame_1\DoAction.as
current:
_loc5_ = 100 * (_loc2_ * _loc8_) / _loc9_;
before:
_loc5_ = 100 * _loc2_ * _loc8_ / _loc9_;
I am afraid it is not a bug, it is feature :-).
The decompiled parentheses show exactly how the code will be executed - order of
execution.
Order of execution sometimes matter. It does not matter for numbers or local registers,
but it is important for calling methods.
If you compile following code, the decompiler will detect where the parentheses are and
correctly displays them.
Previous version of decompiler ignored order of operations in many cases which can lead to
incorrectly decompiled code.
public function main()
{
if(this.tst("a") && this.tst("b") && this.tst("c"))
{
trace("first");
}
if(this.tst("a") && (this.tst("b") && this.tst("c")))
{
trace("second");
}
var a:* = 5;
var b:* = 6;
var c:* = 2;
var d1:* = 100 * (a * b) / c;
var d2:* = 100 * a * b / c;
}
public function tst(k:String) : Boolean
{
return true;
}
ilufang: the three scenarios should be fixed in 8.0.1 (but better try nightly build).
Just check "Simplify expressions" in settings.
The third one results in trace(1["constructor"]),
because 1["constructor"] cannot be simplified more - you cannot create Number constructor
manually, but...
If you convert it some way to string, like
var a:String = 1["constructor"]
or String(1["constructor"]), then it will be simplified correctly I guess.
State: new→upgraded
Thanks for the explanation, I'd like to investigate it a little bit more, because for me
it seems that the original code was (without parenthesis), and i don't think that any
programmer puts parenthesis in this case:)
if (this.next() == 'r' && this.next() == 'u' && this.next() == 'e') {
https://github.com/earth911/search-api-sample-code-as2/blob/master/JSON.as line 319
Maybe it is different for AS2. But it is not important for now, thanks.
State: upgraded→new
Sorry it was accidentally set to new again.... probably because i wrote the comment in the
same time as you...
State: new→upgraded
State: upgraded→closed