📜 ⬆️ ⬇️

Ways to "protect" flash-applications


Hello. I will try to talk about several ways to protect against code exploration, fraud and theft used in developing flash applications, as well as how to get around some of them.
It is worth noting that now there are many excellent presentations and works on this topic (see the links at the end of the article), however, I would like to describe some nuances in a little more detail, and combine a lot of information on the topic in one place. At least I will try to do it.

Everything described in this article should in no case be used for personal gain, copyright infringement, licensing agreements and any laws of any countries. There is no advertising, everything is written solely on the basis of their own preferences and experience. Code samples to the article - these are just examples, sketched in a hurry, remember this.


- introduction


In the world of flash (of course, it’s about the client) there is no guaranteed protection against intruders, you can only weed out the very hapless and complicate the work of those who decide to go to the end. It is worth striving to ensure that the cost and time of work of the ill-wisher were as high as possible, and your costs as low as possible. Ideally, try to make it easier, faster and cheaper for an attacker to buy or write from scratch than to bypass your obstacles.

The struggle between protection systems and bypass / unprotection systems is ongoing. This is due to the fact that anyone who wishes may have access to the specification of the SWF format and bytecode ( here , here and here again ), into which the ActionScript3 (further AS3) code is compiled. This allows you to freely write your own libraries and applications to parse SWF files into components (graphics, sounds, bytecode, etc.), and do anything with bytecode, for example:
In the field of protection there are different goals and means. Choose only what is suitable for your project, do not do too much work.
')

- content


We will look at several ways (they are different not only in their implementation, but also in their intended purpose) with examples of bypassing some of them, as well as a number of tools that can be used in the study of (your) code:
  1. URL-Lock (binding to one or more domains), protection from local launch
  2. Variables, resources and classes
  3. Watermarks (watermarks)
  4. SWF packaging
  5. Dynamic code generation and SWF editing
  6. Code obfuscation and data hiding
  7. Protection from saving SWF file from memory
  8. Flash explorer toolkit

- 1. URL-Lock, protection from local launch


The goal is to force the SWF file to work under certain conditions, for example, only under one or several domains, or to prohibit a local launch.
After determining the fact that the SWF is not started where it should be, you can program its behavior as you like. You can send objectionable domains \ URLs to the server (if this is not localhost) and log it in some kind of log.
It is better to keep the original domains (under which the SWF file should work) in encrypted form or not in the client at all (receive from the server also in encrypted form).
Consider several ways to bind to domains and define a local launch.

Linking to domains by retrieving the current URL \ domain


This is the most common way to bind to the domain. To get the current URL or domain, usually use:

a) loaderInfo :
The paths will not change if you embed SWF into an HTML page on a non-native domain without moving the SWF file itself.

b) LocalConnection : allows you to get the domain name under which the SWF file is currently running using LocalConnection.domain .
If the foreign SWF is in a domain other than your SWF's domain, and you have uploaded that SWF to the current security domain like this:
 var context:LoaderContext = new LoaderContext(true); context.securityDomain = SecurityDomain.currentDomain; loader.load(new URLRequest(url), context); 
or using Loader.loadBytes , the LocalConnection.domain loaded SWF will contain the domain of your SWF.
The paths will not change if you embed SWF into an HTML page on a non-native domain without moving the SWF file itself.

c) ExternalInterface : allows you to use JavaScript (hereinafter referred to as JS). For example, the path to the current page into which the SWF is embedded can be obtained using window.location.href . To call JS, use ExternalInterface.call . Because call as the first parameter takes the name of the method, and window.location.href is a property, then you should use toString ():
 var myHTMLUrl:String = ExternalInterface.call("window.location.href.toString"); 
By the way, the domain can also be obtained through ExternalInterface.call :
 var domain:String = ExternalInterface.call ("eval", "document.domain"); 

You can also use ExternalInterface to call your JS functions on the page where the SWF is located - both initially existing and created by you with eval:
 var customJavaScriptCode:String = "function customJS(){alert('Yes, this is a custom JS');}"; ExternalInterface.call("eval", customJavaScriptCode); ExternalInterface.call("customJS"); 
And do not forget that this method requires the implementation of JS, which is not always possible.
If you try to work around by embedding in an HTML page on a "non-native" domain without moving the SWF file itself, executing ExternalInterface.call will generate a SecurityError.

d) FlashVars : sometimes, when placing SWF in an HTML page or when loading from another SWF, the path to the domain and / or other data is transmitted via FlashVars (which is really bad, because it is an obvious “hole” to unlink from domains):

FlashVars can be passed as a parameter:

 <object ...> <param name="FlashVars" value="var1=value1&var2=value2" /> </object> 
or through the file name:
 <object ...> <param name="movie" value="somecoolmovie.swf? var1=value1&var2=value2" /> </object> 
You can reach FlashVars like this:
- in AS3 - root.loaderInfo.parameters.var1
- in AS2 - _root.var1

Linking to domains without getting the current URL or domain


This method is based on cross-domain security policy. Binding SWF at launch tries to load a "special" dummy file from a specific host with a crossdomain.xml file on a direct path, with permission to load resources only from trusted domains, one of which must have a SWF. Accordingly, if the “stolen” SWF file will access the “special” file from a domain not specified in crossdomain.xml, a sandbox security violation will occur and the “special” file will not load. It also generates an exception and triggers the SecurityErrorEvent.SECURITY_ERROR event on an instance of the LoaderInfo class ( Loader.contentLoaderInfo ). This will determine if the SWF is not where it should be.
The "special" file should be accessed in a direct way to prevent its substitution.

Local Launch Definition


The local launch of SWF can be determined by obtaining a reference to SWF or HTML and checking it for the presence of the substring "file: //".
If the SWF is running outside of HTML, then the ExternalInterface.call method will return null.
You can also check the type of FP in which the SWF is running, using Capabilities.playerType :
Another way is by comparing Security.sandboxType with Security.REMOTE .

All of these techniques have their advantages and disadvantages - some do not require a server, but require recompilation of the SWF file when changing the domains to which the binding should be performed, and some - vice versa.
In the codes for the article (a link to the archive is at the end of the article), in the folder "1-URL Lock", you will find an example with the implementation of some of the methods described and a couple of examples of patches for one of the methods.
Attention! Most URL Lock tricks can be bypassed by working from under a local server, such as Denwer or XAMPP.


- 2. Variables, resources and classes


Usually variables and resources are taken care of when writing games. Of course, it is better to keep important logic, data and variables outside the client, but, alas, this is not always possible, therefore, sometimes you need to think about how to reduce the number of loopholes for scam.
Substituting resources and classes are not used as often as editing variables, but they are still used, so I will try to tell you how they do it and how it can be prevented (it is impossible to defend against it).

Variable protection


Variables should be hidden and protected from changes. The easiest way to hide - writing your "wrappers" around the base classes.
For example, CryptInt, CryptString, etc. In the classes themselves, you can write methods to get and give the value by encrypting or decrypting it, which will hide the variable in memory. Take a look at the implementation of the CryptInt and CryptString classes in the codes for the article, in the folder "2-Memory & Domain \ MemoryExample".
Also, to hide the values ​​of variables, you can break them into components, mix, shift, etc. You can even try to write a kind of pipeline that will move the hidden value from one variable to another, freeing the used variables for the GC (Garbage Collector). As "temporary storage" for such processed variables, you can use ByteArray, possibly with the involvement of "Alchemy" (fastmem from Azoth , Memory from Apparat ).
And so that the variables could not be changed, even if they are found, then you can use, for example, comparing the value of a variable with a standard. Moreover, the comparison can be made when changing a variable or accessing it, and at specified intervals.

Substitution of resources


You can replace the SWF entirely, or load external files in the browser cache. In a fake SWF file, or in a substituted resource, any changes to the graphics (size, transparency, shift, frame rate, etc.) and code (which does what you least want) can be made.
To complicate the task of the ill-wisher (it is impossible to protect against substitution), you should verify the authenticity of the downloaded data and yourself - for example, you can store MD5 and compare it when loading, while MD5 should be stored somewhere far away and in encrypted form.
If the SWF communicates with the server — perform hidden checks — send the downloaded resources to the MD5 server, for example.

If possible, in order to prevent spoofing, external SWFs and other resources can be stored in the body of the main SWF in encrypted form and loaded with Loader.loadBytes , before removing them from themselves. Loader.loadBytes does not save downloaded data to the browser cache, but at the same time, your main SWF will be cached. More information about using Loader.loadBytes in such cases is written in one of the following sections of the article.
You can also request resources and other SWF files from the server, which are in encrypted form, then decrypt them and download them through Loader.loadBytes .

Class overrides


I will say right away that it is also impossible to defend oneself against this.
You can substitute classes by loading the target SWF in the ApplicationDomain loader. To do this, you can write a bootloader containing a class with the same name as the one being replaced, and load the SWF into your domain:
 var appDomain:ApplicationDomain = ApplicationDomain.currentDomain; var swfLoader:Loader = new Loader(); swfLoader.load(new URLRequest('original.swf'), new LoaderContext(false, appDomain)); 
Thus, the loaded SWF will be forced to "communicate" with the class from its loader. You can see examples of implementation in the codes for the article, in the folder "2-Memory & Domain \ applicationDomain". You will find there examples of class substitution by loading into a child and into your domain. In the "victim" you can find several options for checking for workload (which cost replacing the class in which they are contained).
You can try to prevent this by loading the main SWF through your own bootloader into the new ApplicationDomain:
 var appDomain:ApplicationDomain = new ApplicationDomain(null); var swfLoader:Loader = new Loader(); swfLoader.load(new URLRequest('original.swf'), new LoaderContext(false, appDomain)); 
and establishing a strong link between the loader and the main SWF so that it is very difficult to “separate” them. However, if you change the bootloader and manage to keep this connection, then these efforts will be in vain.

Protect only really important variables and data, combine methods.
If possible, make the logic of working with important variables on the server, and sign and check resources for changes.


- 3. Watermarks (watermarks)


Can be used for protection against copying, illegal use, as well as for advertising purposes.

Here are some of their types:

  1. Well visible elements: text, logo, image, etc.
    If the label is “soldered” (refers both to images as well as to graphics in SWF), then it will have to be removed manually by editing the data that have been applied to the label, which can be very difficult or even impossible task.
    If the label lies separately (or is added programmatically), for example, on the topmost “layer” in the SWF, then the chances of it being neatly removed are much higher.
  2. Hidden items. They can be anywhere. It is often impossible to get rid of such watermarks, because no one except their creators will know where to look. Such labels must be unique in order to be able to prove in court that these are really labels and that they cannot be repeated.
This item turned out to be very flawed, however, there is nothing more to say here, just do not forget that such remedies also exist.


- 4. "Packaging" SWF


It’s impossible to hide SWFs completely, but there is at least one very well-known method that can make it harder for hapless intruders to find the desired SWF a little.

You can add SWF to your flex or flash project using the Embed tag, for example:
 [Embed(source = "./dummy.swf", mimeType = "application/octet-stream")] private var _content:Class; 
A file added this way (it can be any binary file or several files if there are several Embed tags) is placed in the DefineBinaryData tag.
Then you can load the file "packed" in this way using Loader.loadBytes like this:
 var someFile:ByteArray = new _content(); loader.loadBytes(someFile); 
There are a lot of tools for parsing SWF files and tag manipulation, thanks to which it is possible to replace or add the DefineBinaryData tag.
Knowing all this, you can jot down your simple "packer" to automate the process. Before wrapping, SWF can be transformed somehow, for example, by processing simple and fast symmetric xor, and in the loader (which will contain "packed" SWF) to write code that will decrypt the SWF stored in it, and then load it. A simple "encryption" with xor is needed only to protect against automatic processing by decompilers, so that the SWF file is not located in the "clean" form within the loader; more complex encryption is meaningless.
It happens that files are "embedded" in other ways, for example, in the form of BitmapData, and also create several levels of nesting.

An example of the implementation of the simplest packer can be found in the codes for the article, in the folder "3-SWFPacker". Also there are two files: orig.swf and packed.swf - you can try to decompile and compare them.
This method is done in at least two ways:
- research of the decryptor algorithm in the loader and writing your own decryptor (laborious, especially if the loader is very nested)
- preservation of the part of the memory in which the SWF file already unpacked and loaded into the FP is located (simply and quickly, especially if protection from saving from memory described below is not used)


- 5. Dynamic code generation and SWF editing


I was repeatedly asked whether it is possible to generate code in flash in real time or create and edit other SWF files? The answer is yes, it is possible!
As for the code, try AS3Commons ByteCode . This project will allow you to collect and perform real-time bytecode.
You can create classes with different methods and properties from scratch, or by inheriting from other classes. The bodies of methods, for example, can be described using linear bytecode - methodBuilder.addOpcode(Opcode.getlocal_0) , or immediately in blocks:
 var source:String = (<![CDATA[ getlocal_0 pushscope ... getlocal_1 returnvalue]]>).toString(); methodBuilder.addAsmSource(source); 
You can load the generated code into AVM using abcBuilder.buildAndLoad() .
Also for manipulations with bytecode, you can try as3abc , which, according to the author, is a partial port of the wonderful Apparat framework from the notorious Joa Ebert.
If you are dreaming about the dynamic execution of the script, and not bytecode, then look at as3scriptinglib . Using this project, you can compile and execute ActionScript 3 / ECMAScript scripts, including JavaScript, in real time. Look at how this works in the flex demo application . Unfortunately, the project has not been updated for a long time.

To experiment with the SWF file itself and its structure, try as3swf or swfassist .

The ability to generate code on the fly, as well as the ability to edit and create SWF in real time, allow you to create various complex scenarios and techniques for enticing an attacker and hiding your code. Here, for example, the first 3 techniques that came to my mind:
  1. Generate and execute code / bytecode on the client side in parts coming from the server, leaving ill-wishers in the original SWF of the entire code, only that you do not mind leaving (code of free libraries, buttons, etc.) + decrypter code and The "builder" is already the final code.
  2. Collect SWF in parts on the client side, similar to the code trick - you can collect by tags, getting them from the server, or unpacking one by one from the encrypted data packaged in the loader.
  3. Create a code that is self-modifying during the execution process, which, for example, will generate the same methods according to certain rules or patterns in different ways. For example, i ++ can be implemented as i + = 1 (and it will be different bytecode, at least it is different now, in FP 10.1), also the cycles can be implemented differently, etc.
    It may be possible to trick it so that the generated code changes the methods that generated it. For example, in the next iteration of their execution, other classes and methods are already generated, thereby significantly complicating and confusing the code, so that if an attacker obtains it, the latter would have to spend as much time as possible on the analysis of this whole mess.
    I guess this is a rather complicated (or even impossible flash) trick. I haven’t yet met a really working implementation of this idea on flash. If you met - then tell me where to look, I will be glad to learn.

- 6. Code obfuscation and data hiding


First about obfuscation. Both the source code and the bytecode compiled code can be exposed to it. Obfuscation of the source code is not so convenient and effective, bypasscode entanglement looks much more attractive, since the source code must meet the requirements of the compiler, which cannot be said about baytkod, in which, moreover, there is much more room for the manifestation of imagination and ingenuity.
Bytecode obfuscation may include renaming elements into meaningless and unacceptable names for the compiler, using some anti-decompiler tricks, hiding and trash the code, etc.

Renaming is probably the only irreversible and 100% working way to hide at least something in flash. The essence of the method is to change the methods, properties, packages and other elements of names that are preserved after compilation, but are not used when executing code. It is impossible to automatically restore the original names, you have to do it manually, guessing about them within the meaning of the code exploration. After obfuscation, new names may contain invalid characters or reserved words, which will not allow to easily recompile and use the code obtained after decompilation.

Sometimes when obfuscating bytecode, they set up "traps" for decompilers, based on the fact that decompilers analyze the code in complex, in blocks, unlike FP, which executes it linearly, for example:
In addition, the code can simply be "littered", increasing it in volume and reducing its readability. This can adversely affect performance.

Data hiding can be done in different ways, for example:
Some decompilers and disassemblers make it easy to find and explore custom tags and metadata.

In order to learn how to create quality interference to decompilers, you will have to study how decompilers explore bytecode and SWF in general. But remember - the developers of decompilers are constantly developing their products and if your SWF with cunning tricks gets to them, then soon these tricks may stop working.
There are SWF protection utilities that use only tricks against decompilers or “packaging” methods, without obfuscating names, which allows getting almost original source code using high-quality public or own decompilers that is compiled without errors and is well read. Below I will talk about the "right" tools that you should pay attention to.


- 7. Protection against saving SWF file from memory


Guaranteed to protect against dump memory can not be. However, there is a simple technique that can complicate the process - you can create a lot of fake SWF headers (it is for them that SWF files are usually searched in memory) that will help the original SWF to get lost among them. So that your SWF file does not stand out from the others, you can create a mass of fake headers with dimensions = the size of your SWF file.
To make the headers visible in memory, just write them in ByteArray. Here is an example of the implementation of this method, pulled out of the bootloader of one of the protectors:
 private function spamMemory(swfBytes:ByteArray):void { var allLen:uint = swfBytes.readUnsignedInt(); var swfLen:uint = swfBytes.readUnsignedInt(); var spamMemorySWFLen:uint = swfBytes.readUnsignedInt(); var spamMemorySWFBytes:ByteArray = new ByteArray(); spamMemorySWFBytes.endian = Endian.LITTLE_ENDIAN; swfBytes.readBytes(spamMemorySWFBytes, 0, spamMemorySWFLen); var allBytes:ByteArray = new ByteArray(); while (allBytes.length < allLen) { spamMemorySWFBytes.position = 4; spamMemorySWFBytes.writeUnsignedInt((((swfLen * 3) / 4) + ((Math.random() * swfLen) / 2))); allBytes.writeBytes(spamMemorySWFBytes); }; Sprite.prototype["__spam_"] = allBytes; } 
As you might have guessed, swfBytes is an array of bytes with the beginning of the "template" header and the "settings" for creating "fake" headers, and in the loop the length of the "template" headers is filled with a random value in the specified range.


- 8. Tools of the researcher flash


Based on my own experience, I would recommend these tools (prices listed at the end of 2010):

Decompilers:
( ):
\:
Also, please note that Amayeta SWF Encrypt, DComSoft SWF Protector, Mochi Encryption - this is not what you would have to "protect" your projects (for now), you will spend your money on useless protection.
Moreover, you can independently implement the simplest obfuscation, as, for example, this is done in the example from makc3d .

Deprotectors \ decryptors, etc .:
Miscellanea:
If you know other tools that really deserve attention, and are ready to talk about them, then tell us in the comments or write in person, I will be glad to get to know them.


- epilogue


Summarizing, we can say that, skillfully using the available tools to protect your projects, you will be able to weed out a certain audience of intruders. However, if a professional takes up the study of your SWF file, then he probably will not stop at the obstacles and bring the matter to the end, especially if he is motivated by an interesting task or a sufficient monetary reward.Therefore, always sensibly assess your contribution to the protection of your projects - do not spend too much time and money on it if it is not worth it.
And yet - do not compile SWF with debug information, since it contains many useful data hackers, not to mention performance degradation.

Thank you for reading this difficult to read material. I hope you found something new for yourself. Any suggestions, comments and constructive suggestions you can leave in the comments, I will be very grateful to you.

Materials for study and sources of information for this article (randomly):
  1. Presentation of Claus Wahlers "Hacking SWF" with FITC Amsterdam 2010.
  2. ( valyard ) " " FlashGAMM 2010
  3. , - , .
  4. romamik " ".
  5. Nautilus " ".
  6. puzzlesea "Robolander, 25 days later. , ".
  7. flashco ": €1500".
  8. Alexis' SWF Reference — , SWF .
  9. OWASP is a kind of security wiki related to flash (links to articles, tools, etc.).
  10. A very impressive article on the security model in flash from senocular titled "Security Domains, Application Domains, and More in ActionScript 3.0".
  11. Adobe articles on security in flash.
  12. Adobe official article on security in FP 10 (White Paper).
Also in this article and the codes for it can be used a variety of materials from sources not mentioned here, which I did not recall.

Files for the article: codestage.ru/files/flash_defend_files.7z

Source: https://habr.com/ru/post/110686/


All Articles