Adobe-Runtime-Support icon indicating copy to clipboard operation
Adobe-Runtime-Support copied to clipboard

[Feature Request] Code Obfuscation in AIR sdk

Open Shaunmax opened this issue 3 years ago • 37 comments

Problem Description

With the use of decompilers, our SWF's from android apks are exposing precious code and game design/business logics to our competitors and amateur developers. We need a solid code obfuscation feature in AIR sdk, which should make it extremely harder for hackers to read the code and should make the decompilers to crash.

There were 3rd party developers like kindi providing support for code obfuscation, along with optimisation and asset compression but unfortunately their softwares seems to be outdate and they are no longer providing any support.

As it's extremely risky to release builds in Google Play Store with no code obfuscation. I request @ajwfrost & the harman team to look at this issue at the highest priority and provide us a valuable solution as soon as possible.

I sincerely request other developers to vote for this feature and share their valuable feedbacks.

Appreciate your support.

Shaunmax avatar Oct 13 '20 16:10 Shaunmax

Or as an alternative, maybe compile AS3 to native code for Android and Windows, as it happens already on iOS?

htmiel avatar Oct 13 '20 20:10 htmiel

This is one I had always wondered about (having done my fair share of decompiling of SWFs - though of course mostly this was to solve our customers' bugs!). The SWF and AS3 specifications are open so anyone can create a decompiler..

AOT compiling is a major piece of work and I suspect third-party or shared SWF libraries may still be needed with non-native code, so I would more be thinking of a way that the SWF files could be encrypted and then for AIR to decrypt them as it loads (like right now it compresses them - again, using open standards) - maybe we could compress them with built-in encryption.

The challenge then is authorising the decryption. We can try to add some obfuscated mechanism within AIR (we'd need to make sure it's not clear to anyone who's trying to work out how we're doing the decryption by looking at the assembler code of the AIR library..)... let me talk to some of our folk internally; we'd welcome other comments/suggestions on this though!

thanks

ajwfrost avatar Oct 13 '20 21:10 ajwfrost

+1 for code obfuscation support. our codes is part of our intellectual property

blackjyn avatar Oct 14 '20 04:10 blackjyn

I have for a while thought there should an option to strip the text which decompilers use. I can see why it's there. Flash in particular lets you dynamically load content such as other Flash/SWF apps, access their symbols and methods by name. This was used extensively for advertising/publisher preloaders and to embed adverts in webgames.

But no-one is making webgames any more. We are instead making standalone apps. Dynamically loading code is generally poor practice if not explicitly disallowed. Apps are distributed independently not via preloaders on websites. Adverts are supplied by native code in ANEs.

So it makes sense to strip out code from the SWF, or at least replace it with symbols. At least make it an option for developers who know they are making a final, standalone app. Get it out there quickly and developers can try it and see if there are any issues.

JohnBlackburne avatar Oct 14 '20 05:10 JohnBlackburne

Maybe there is a way to integrate Proguard or even better on top of Proguard, make Android compile like iOS apps do, so it will be even harder to decompile.

leossmith avatar Oct 14 '20 08:10 leossmith

This is one I had always wondered about (having done my fair share of decompiling of SWFs - though of course mostly this was to solve our customers' bugs!). The SWF and AS3 specifications are open so anyone can create a decompiler..

I also would like to see this added.. but....what ever ends up being added to the SDK, please do not change the default actions of the build process and make add ons like this optional via command line vars. Thanks.

dmunsie avatar Oct 14 '20 10:10 dmunsie

Is it possible for Harman to work along with Kindi or acquire them? they have been out of business for a long time. Their obfuscation software is pretty impressive, if that can be included in AIR sdk that would be a great boost for our fraework.

Shaunmax avatar Sep 05 '21 07:09 Shaunmax

I could actually imagine that when there was proper code obfuscation more developers would out themselves using as3/flash/AIR. I would think that since its easy to decompile swf a bunch of devs would prefet to not tell anyone about it in order to keep their "secrets" and prevent others from "stealing" their sources/assets

2jfw avatar Sep 06 '21 12:09 2jfw

I couldn't see any way of contacting folk from Kindi, wondering if anyone has a contact there?

To gauge the idea of some priorities though: are people looking mostly to encrypt their assets (images, sound files etc), or to prevent decompilers from showing off the ActionScript source code?

The one thing I wonder is that - if you're using a Windows app at least - it's possible to do a memory dump of a process and then inspect that, which someone could use to get at a decrypted copy of the contents. So I'm not sure whether it's possible to do something completely secure. If we just encrypted the SWF contents and then decrypted them at runtime, it should prevent casual folk from getting at stuff, but anyone with access to the process memory could see the decrypted stuff.

ajwfrost avatar Sep 06 '21 14:09 ajwfrost

@ajwfrost I would think that Mobile iOS and Android are more important and a target to decompilation than Windows/Mac are since these (mostly) mobile games are likely lightweight in their codebase and assets are more likely to get stripped out and used in other games - e.g. see

  • https://www.reddit.com/r/commandandconquer/comments/lvm7vc/yet_another_shameless_mobile_game_using_stolen/

  • https://www.reddit.com/r/Steam/comments/glvre9/mobile_game_state_of_survival_using_stolen_asset/

  • https://www.gamerevolution.com/news/567887-pokemon-mobile-game-stolen-assets

"Chinese companies also frequently copy U.S. games, creating unauthorized “clones,” or steal U.S. IP assets. ": https://www.uscc.gov/sites/default/files/Research/China's%20Digital%20Game%20Sector.pdf

It is more common than you might think. I would think that both, securing codebase and assets, is nearly equally important, whereas assets are more likely to be stolen. Personally, I would be more afraid that my codebase gets stolen and reused maybe multiple times as engine rather than them using any assets because I feel the code (/engine) is more precious.

2jfw avatar Sep 06 '21 14:09 2jfw

The only contact I have from them from back in 2012, when I bought their SecureSWF application is:

Kindi Software, LLC 10 Yajouz Str POBox 2684 Amman 11941 Jordan

Phone:+962 6 533 5152 (ext 36) Fax: +962 6 533 5031

[email protected]

2jfw avatar Sep 06 '21 14:09 2jfw

Thanks @2jfw I'll drop them a mail in case they're still around..

In terms of protecting things: https://stackoverflow.com/questions/18151308/how-to-secure-the-assets-stored-in-android-apk and presumably the same sort of thing from an IPA file..

Essentially it would always need the ability to decrypt - keys etc - to be present in the app and/or runtime. So it would make it harder, but I don't know whether it would dissuade any "professional" thieves...

ajwfrost avatar Sep 06 '21 14:09 ajwfrost

"Or as an alternative, maybe compile AS3 to native code for Android and Windows, as it happens already on iOS?" I support the idea, but I'd like to see this ^^^ happen first before spending time/resources on obfuscation.

dmunsie avatar Sep 06 '21 14:09 dmunsie

Is it possible for Harman to work along with Kindi or acquire them? they have been out of business for a long time. Their obfuscation software is pretty impressive, if that can be included in AIR sdk that would be a great boost for our fraework.

Oh yeah, it is/was - I had made very good experience with their software and obfuscating capabilities. I did decompile my obfuscated AIR mobile app at that time and found that it was not readable. The app used some ANEs and SWCs too, so the obfuscator was able to handle that all (though it may not have obfuscated them).

2jfw avatar Sep 06 '21 14:09 2jfw

I couldn't see any way of contacting folk from Kindi, wondering if anyone has a contact there?

I just checked in LinkedIn and found this contact : - https://www.linkedin.com/in/hosam-abu-alam-b4b6524/

To gauge the idea of some priorities though: are people looking mostly to encrypt their assets (images, sound files etc), or to prevent decompilers from showing off the ActionScript source code?

As an independent developer, I dont care much about my code getting exposed, but its difficult to convince our clients who are very much worried about both.

Shaunmax avatar Sep 06 '21 16:09 Shaunmax

Just as an update, we will be including a utility to encrypt a SWF file into a forthcoming version of the AIR SDK. Limitations will be:

  1. you will need to have the application packaged with the captive runtime in order to work (well, it would also work with a shared runtime, as long as the shared runtime version also is the same version used by the SDK, or later...)
  2. you won't be able to use the LoaderInfo.bytes property to see the decrypted data - which means you can't use an encrypted SWF as both the primordial worker and a background worker..

As mentioned earlier, it's stand-alone encryption so not completely impervious to cracking by someone who's very dedicated, but it should be at least as good as the Kindi approach..

ajwfrost avatar Dec 15 '21 13:12 ajwfrost

Just as an update, we will be including a utility to encrypt a SWF file into a forthcoming version of the AIR SDK. Limitations will be:

  1. you will need to have the application packaged with the captive runtime in order to work (well, it would also work with a shared runtime, as long as the shared runtime version also is the same version used by the SDK, or later...)
  2. you won't be able to use the LoaderInfo.bytes property to see the decrypted data - which means you can't use an encrypted SWF as both the primordial worker and a background worker..

As mentioned earlier, it's stand-alone encryption so not completely impervious to cracking by someone who's very dedicated, but it should be at least as good as the Kindi approach..

This is amazing news! Thanks a lot for taking care on this, Andrew! This is another point, which can be taken well for advertising AIR SDK: "Comes with build-in obfuscation! Do not worry about others easily decompiling your app and stealing your assets and code!"

Just curious, was there any contact/communication with Kindi?

2jfw avatar Dec 15 '21 13:12 2jfw

Great news! I would also add to @2jfw question, are Strings obfuscated too and how strong?

MalacTheLittle avatar Dec 15 '21 13:12 MalacTheLittle

Just curious, was there any contact/communication with Kindi?

I'd sent a mail to the support email address but didn't hear .. but from earlier info it looked like they weren't supporting the product now anyway.

are Strings obfuscated too and how strong

It's just encrypting the SWF as a whole - so basically a bit like when you compress a SWF, there is an 8-byte header but then the rest of the content can be uncompressed, zlib-compressed or LZMA-compressed; we've just added a further option for this to be encrypted. So you wouldn't be able to read strings... the file is then decrypted upon loading (in the same location as the decompression) so everything is protected up to the point you've loaded in the SWF file to memory.

Which does mean that if someone were to load in the application and then do a memory-dump of the whole process, they could search the memory to find the decrypted SWF. Hmm... so, maybe we (also?) need to provide a utility class for the encryption of individual assets...

ajwfrost avatar Dec 15 '21 13:12 ajwfrost

Which does mean that if someone were to load in the application and then do a memory-dump of the whole process, they could search the memory to find the decrypted SWF. Hmm... so, maybe we (also?) need to provide a utility class for the encryption of individual assets...

I think asset protection is an important part since they are actually getting stolen (see https://github.com/airsdk/Adobe-Runtime-Support/issues/494#issuecomment-913697653)

2jfw avatar Dec 15 '21 14:12 2jfw

So I've just been looking through the features that Kindi has and I really am not sure how they do some of that without being able to update the runtime, unless they're having everything accessed via some kind of library and are recompiling all of the ActionScript (which is very possible given the amount of obfuscation and optimization they're able to do...)

So we have a slight advantage by being able to update the runtime itself, but are also perhaps not able to offer the levels of code obfuscation etc that they've put in place! But in terms of asset protection:

  • it should be possible for us to create new SWF 'tags' that replace image data with encrypted versions of images, and then when the render is asking for them, it will decrypt on the fly. As ever, if you took a memory snapshot, then the image would be visible in memory after it was expanded to a bitmap (which would be the same as with Kindi..)

  • we can probably do the same with the constant pool within ActionScript byte code, particularly for string data, but this would need to be expanded into memory when it's used i.e. when a function that references a string constant is first accessed. But we'd need to check a little more how this works in the VM...

Let me know of any other priorities...

thanks

ajwfrost avatar Dec 15 '21 16:12 ajwfrost

ActionScript-wise, as far as I remember, Kindi have renamed all variables and method names by something like "_loc1", "_loc2" etc.. so it will be hard for anyone who decompiles the code to read and understand it. They did not obfuscate Strings. Regadring assets/images, I am actually not sure but I would think they were not obfuscated.

So I am wondering, when someone now makes a memory dump form the SWF, will they see the variable and method names I used @ajwfrost ?

2jfw avatar Dec 16 '21 12:12 2jfw

@2jfw I'm not sure if this is called obfuscation, but Kindi did made Strings unreadable converting them to kind of functions. Here you can see levels of String encription/obfuscation:

image

Key can be chosen from 32-bit to 288-bit.

I made small example: in Animate I just wrote code var privateKey:String = "ABCDEFGHIJKLMNOPQRSTUVXYZ";. Result of decompiling unprotected .swf (decompiled with online decompiler) is single .as file:

package test_fla {
   import flash.display.MovieClip;
   
   public dynamic class MainTimeline extends MovieClip { 
      public var privateKey:String;
      
      public function MainTimeline() {
         super();
         addFrameScript(0,this.frame1);
      }
      
      function frame1() : * {
         this.privateKey = "ABCDEFGHIJKLMNOPQRSTUVXYZ";
      }
   }
}

And here's result of Kindi procesing it in RC4 mode with 96-bit key (decompiled it with online decompiler):

package test_fla {
   import flash.display.MovieClip;
   
   public dynamic class MainTimeline extends MovieClip {
      public var privateKey:String;
      
      public function MainTimeline() {
         super();
         addFrameScript(0,this.frame1);
      }
      
      function frame1() : * {
         this.privateKey = §_a_-_---§.§_a_--_--§(-1820302793);
      }
   }
}

with bunch of other .as files: image

Here's both decompiled files for analysis: test_decompiled.zip test_secure_decompiled.zip

I find obfuscation of Strings most important so you can store private keys in the app for encryption and decryption of other assets. That way you can make your own encryption algorithm.

MalacTheLittle avatar Dec 16 '21 15:12 MalacTheLittle

Thanks for the insight!

this.privateKey = §_a_-_---§.§_a_--_--§(-1820302793); what magic is this? So there will be another occurence of it somewhere as function? Wouldn't have imagined that this works...

2jfw avatar Dec 16 '21 15:12 2jfw

@MalacTheLittle is it possible to get hold of that 'protected' SWF file itself? I'd be interested by the ABC instructions (rather than by the "decompiled to human-readable" output...)

Normally, a string literal would be stored into the constant pool and then retrieve by the ActionScript via a "pushstring" command and then e.g. "setproperty". So it would need to change the "pushstring" instruction to turn it into a function call, not quite sure what bytecode would make the decompiler look like that though...

Interestingly though, in the avmplus it looks like a string retrieved in this manner is kept in memory i.e. string literals are not then subject to garbage collection. Whereas for things like this, you would want to have a string that's just instantiated and then cleaned up when not in use (and see the new System.poisonStrings property) - so, this may then involve them changing the functionality so that it creates the string dynamically from some other (encrypted) memory block.

If so .. this would be simplest to do via a separate function call ... so you could have this.privateKey = Library.encryptedStrings(MY_PRIVATE_KEY_INDEX);

Interesting stuff :-)

thanks

ajwfrost avatar Dec 16 '21 16:12 ajwfrost

Just realised:

this.privateKey = §_a_-_---§.§_a_--_--§(-1820302793); what magic is this?

It's a function called §_a_-_---§.§_a_--_--§() with a parameter -1820302793 So, similar to a function Library.encryptedStrings() with parameter defined via an enumeration...

Rather than risk playing around with existing AS3 bytecode, it would be easier for us to provide a separate tool for you to create a block of encrypted strings, and a library to use them (or we build that decryption into the runtime, more likely.. which then gets a little more secure..)

Let us have a bit of a play with that...

ajwfrost avatar Dec 16 '21 16:12 ajwfrost

How about:

  1. you create a set of strings in a 'properties' file format in a utf-8 text file e.g.
MY_PRIVATE_KEY=something_here
ANOTHER_STRING=something_else
  1. we provide a tool to turn this into an encrypted blob

  2. you then embed the blob into the SWF file via the 'embed' instruction in your AS3 code

                [Embed( source = "encrypedStrings.bin", mimeType="application/octet-stream")]
                private const EncStrings:Class;
  1. you access a string via var privateKey : String = System.encryptedString(EncStrings, "MY_PRIVATE_KEY");

It may even be possible for us to do something like:

                [Embed( source = "stringsToEncrypt.txt", mimeType="text/plain", encrypted="true")]
                private const EncStrings:Class;

to skip step 2... (and actually, adding that tag to 'embed' would be useful for other types too e.g. images!....)

ajwfrost avatar Dec 16 '21 16:12 ajwfrost

This is the one I used to use. You may want to contact them and see if it's something you can work with.

https://www.ambiera.com/irrfuscator/index.html

dmunsie avatar Dec 16 '21 17:12 dmunsie

@MalacTheLittle is it possible to get hold of that 'protected' SWF file itself? I'd be interested by the ABC instructions (rather than by the "decompiled to human-readable" output...)

Sure thing, sorry I missed to attach that one too :) test_swfs.zip

MalacTheLittle avatar Dec 16 '21 18:12 MalacTheLittle

Thanks ... so yes:

       6    getlocal0     	
       7    getlex        	_e_-----_ //nameIndex = 10
       9    pushint       	-1820302793	// 0x-6c7f9dc9
       11   callproperty  	_e_-_-__- (1) //nameIndex = 14
       14   coerce_s      	
       15   initproperty  	privateKey //nameIndex = 2

and later we have:

class _e_-----_ extends flash.display::Sprite
     static function _e_-_-__-(int):String	/* disp_id=6 method_id=7 nameIndex = 145 */
...

Well, I can see why decompilers wouldn't like it! But after this class has been loaded, the strings would be decrypted (from what I can make out!) so yes it's similar to what we're looking at.

@dmunsie thanks for that link, will take a look..

cheers

ajwfrost avatar Dec 16 '21 18:12 ajwfrost