フラッシュアプ​​リケーションを「保護」する方法


こんにちは。 フラッシュアプ​​リケーションの開発で使用されるコード調査、詐欺、盗難から保護するためのいくつかの方法と、それらのいくつかを回避する方法についてお話します。
現在、このトピックに関する多くの優れたプレゼンテーションと作品があります(記事の最後のリンクを参照)が、いくつかのニュアンスをより詳細に説明し、トピックに関する多くの情報を1か所にまとめたいと思います。 少なくとも私はそれをしようとします。

個人的な利益、著作権侵害、ライセンス契約、およびあらゆる国の法律を取得するために、この記事に記載されているすべてのものを決して使用しないでください。 広告はありません。すべては個人的な好みと経験に基づいて書かれています。 この記事のコード例は簡単な例です。これを覚えておいてください。


-はじめに


フラッシュの世界(スピーチ、もちろんクライアントについて)では、侵入者に対する保護は保証されていません。不幸なものだけを除外し、最後まで行くことに決めた人の作業を複雑にすることができます。 悪者の費用と時間を可能な限り高くし、費用をできるだけ低くするように努力することは価値があります。 理想的には、攻撃者が障害物を回避するよりも、ゼロから購入または書き込みを簡単、高速、安価にできるようにしてください。

保護システムとバイパス/保護解除システムの間の闘争は進行中です。 これは、ActionScript3(以降AS3)コードがコンパイルされるSWF形式とバイトコード( ここここここでも)の仕様にアクセスできる人が誰でもアクセスできるという事実によるものです。 これにより、SWFファイルをコンポーネント(グラフィック、サウンド、バイトコードなど)に解析するための独自のライブラリとアプリケーションを自由に記述でき、バイトコードを使用して何でもできます。次に例を示します。
保護の分野では、さまざまな目標と手段があります。 プロジェクトに適したものだけを選択し、不要な作業は行わないでください。


-コンテンツ


いくつかの方法(実装だけでなく、意図した目的も異なる)のいくつかを回避する例と、コードを調べるときに使用できるいくつかのツールを検討します。
  1. URLロック(1つまたは複数のドメインにバインド)、ローカル起動に対する保護
  2. 変数、リソース、およびクラス
  3. 透かし
  4. SWFパッキング
  5. 動的なコード生成とSWF編集
  6. コードの難読化とデータの隠蔽
  7. メモリからのSWFファイルの保存に対する保護
  8. Flash Explorerツールキット

-1. URLロック、ローカル起動に対する保護


目標は、SWFファイルを特定の条件下、たとえば1つ以上のドメインでのみ機能させること、またはローカルでの起動を禁止することです。
必要な場所にSWFが起動されていないことを確認した後、必要に応じてその動作をプログラムできます。 不要なドメイン\ URLをサーバーに送信して(localhostでない場合)、それらを何らかのログに入力できます。
元のドメイン(SWFファイルが機能する)を暗号化された形式で保持するか、クライアントにまったく保持しない(サーバーからも暗号化された形式で受け入れる)ことをお勧めします。
ドメインにバインドしてローカルスタートアップを決定するいくつかの方法を見てみましょう。

現在のURL \ドメインを取得してドメインにバインドする


これは、ドメインにバインドする最も一般的な方法です。 現在のURLまたはドメインを取得するには、通常次を使用します。

a) loaderInfo
SWFファイル自体を移動せずに非ネイティブドメインのHTMLページにSWFを埋め込んだ場合、パスは変更されません。

b) LocalConnectionLocalConnection.domainを使用して、SWFファイルが現在実行されているドメインの名前を取得できます。
外部SWFがSWFのドメイン以外のドメインにあり、次のように現在のセキュリティドメインにそのSWFをアップロードした場合:
 var context:LoaderContext = new LoaderContext(true); context.securityDomain = SecurityDomain.currentDomain; loader.load(new URLRequest(url), context); 
またはLoader.loadBytesを使用するLocalConnection.domainロードされたSWFのLocalConnection.domain SWFのドメインが含まれます。
SWFファイル自体を移動せずに非ネイティブドメインのHTMLページにSWFを埋め込んだ場合、パスは変更されません。

c) ExternalInterface :JavaScript(以降JS)を使用できます。 たとえば、SWFが埋め込まれている現在のページへのパスは、 window.location.hrefを使用して取得できます。 JSを呼び出すには、 ExternalInterface.call使用します。 なぜなら 最初のパラメーターがメソッドの名前を取り、 window.location.hrefがプロパティである場合は、toString()を使用する必要があります。
 var myHTMLUrl:String = ExternalInterface.call("window.location.href.toString"); 
ちなみに、ドメインはExternalInterface.callからも取得できます。
 var domain:String = ExternalInterface.call ("eval", "document.domain"); 

ExternalInterfaceを使用して、SWFが配置されているページでJS関数を呼び出すこともできます-既存のものとevalを使用して自分で作成したものの両方:
 var customJavaScriptCode:String = "function customJS(){alert('Yes, this is a custom JS');}"; ExternalInterface.call("eval", customJavaScriptCode); ExternalInterface.call("customJS"); 
また、この方法にはJSが必要であることを忘れないでください。これは常に可能ではありません。
SWFファイル自体を移動せずに、非ネイティブドメインのHTMLページへの埋め込みをバイパスしようとすると、 ExternalInterface.callの実行によりSecurityErrorが生成されます。

d) FlashVars :HTMLページにSWFを配置するとき、または別のSWFから読み込むときに、FlashVarsを介してドメインや他のデータへのパスを転送する場合があります(これは、ドメイン):

FlashVarsはパラメーターとして渡すことができます。

 <object ...> <param name="FlashVars" value="var1=value1&var2=value2" /> </object> 
またはファイル名で:
 <object ...> <param name="movie" value="somecoolmovie.swf? var1=value1&var2=value2" /> </object> 
次のようにFlashVarsにアクセスできます。
root.loaderInfo.parameters.var1
_root.var1

現在のURLまたはドメインを取得せずにドメインにバインドする


この方法は、クロスドメインセキュリティポリシーに基づいています。 起動時にバインドされたSWFは、crossdomain.xmlファイルが存在する特定のホストから「特別な」ダミーファイルをダウンロードしようとします。その際、SWFの1つにある信頼できるドメインからのみリソースをダウンロードできます。 したがって、「盗まれた」SWFファイルがcrossdomain.xmlで指定されていないドメインの「特別な」ファイルにアクセスすると、サンドボックスセキュリティ違反が発生し、「特別な」ファイルはロードされません。 さらに、例外がスローされ、LoaderInfoクラス( Loader.contentLoaderInfo )のインスタンスに対してSecurityErrorEvent.SECURITY_ERRORイベントが発生Loader.contentLoaderInfoます。 これにより、SWFが本来あるべき場所にないことがわかります。
「特別な」ファイルは、置換を防ぐために直接アクセスする必要があります。

ローカルトリガー定義


SWFのローカル起動は、SWFまたはHTMLへのリンクを取得し、サブストリング「file://」の存在を確認することで判断できます。
SWFがHTMLの外部で実行される場合、 ExternalInterface.callメソッドはnullを返します。
Capabilities.playerTypeを使用して、SWFが実行されるFPのタイプを確認することもできます。
別の方法は、 Security.sandboxTypeSecurity.REMOTE比較することです。

これらのすべての方法には長所と短所があります。サーバーを必要としないものもありますが、バインディングを行うドメインを変更する際にSWFファイルを再コンパイルする必要があるものもあります。
記事のコード(アーカイブへのリンクは記事の最後にあります)の「1-URL Lock」フォルダーに、説明されているいくつかのメソッドの実装の例と、メソッドの1つに対するパッチのいくつかの例があります。
注意! ほとんどのURLロックトリックは、DenwerやXAMPPなどのローカルサーバーで作業することで回避できます。


-2.変数、リソース、およびクラス


通常、変数とリソースはゲームを作成するときに処理されます。 もちろん、重要なロジック、データ、変数をクライアントの外部に置く方が良いのですが、残念ながら、これは常に可能とは限りません。そのため、詐欺の抜け穴の数を減らす方法を考える必要があります。
変数の編集ほど頻繁にリソースとクラスの置換を使用しませんが、それでも使用します。そのため、それらをどのように使用し、どのように防止できるかを説明します(これから自分を保護することは不可能です)。

可変保護


変数は非表示にし、変更から保護する必要があります。 非表示にする最も簡単な方法は、基本クラスの周りに独自のラッパーを作成することです。
たとえば、CryptInt、CryptStringなど。 クラス自体には、値を受け取って返す、暗号化または復号化するメソッドを記述できます。これにより、メモリ内の変数が非表示になります。 「2-Memory&Domain \ MemoryExample」フォルダー内の記事のコードにあるCryptIntおよびCryptStringクラスの実装を見てください。
また、変数の値を非表示にするために、変数をコンポーネントに分解し、混合、シフトなどすることができます。 隠された値をある変数から別の変数に移動し、GC(ガベージコレクター)に使用された変数を解放するようなパイプラインを作成することもできます。 ByteArrayは、おそらく「Alchemy」( Azothの fastmem、 Apparatの Memory)を使用して、そのようなリサイクル可能な変数の「一時ストレージ」として使用できます。
そして、変数が見つかっても変更できないように、たとえば、変数の値を参照と比較することができます。 さらに、変数の変更時または変数へのアクセス時、および指定された間隔の両方で比較を行うことができます。

リソース交換


SWF全体を置き換えるか、ブラウザキャッシュに外部ファイルをロードできます。 偽のSWFファイルまたはスプーフィングされたリソースでは、グラフィックス(サイズ、透明度、シフト、フレームレートなど)およびコード(これは何でもしたくない)に変更を加えることができます。
悪者のタスクを複雑にする(なりすましから身を守ることは不可能です)ために、ダウンロードしたデータと自分の信authentic性を検証する必要があります-たとえば、MD5を保存して起動時に比較し、MD5を暗号化された形でどこかに保存する必要があります。
SWFがサーバーと通信する場合-非表示のチェックを実行する-たとえば、ダウンロードしたリソースをMD5サーバーに送信します。

可能であれば、スプーフィングを防ぐために、外部SWFおよびその他のリソースをメインSWFの本体に暗号化された形式で保存し、自分から削除した後にLoader.loadBytesでロードできます。 Loader.loadBytesは、ダウンロードしたデータをブラウザーのキャッシュに保存しませんが、同時にメインSWFはキャッシュされます。 このような場合のLoader.loadBytes使用に関する詳細は、記事の次のセクションのいずれかに記載されています。
暗号化された形式のリソースやその他のSWFファイルをサーバーに要求し、それらを復号化してLoader.loadBytes介してダウンロードすることもできます。

クラスのオーバーライド


これから自分を守ることも不可能だとすぐに言います。
ApplicationDomainローダーにターゲットSWFをロードすることにより、クラスを置き換えることができます。 これを行うには、置き換えられるクラスと同じ名前のクラスを含むブートローダーを作成し、SWFをドメインにロードします。
 var appDomain:ApplicationDomain = ApplicationDomain.currentDomain; var swfLoader:Loader = new Loader(); swfLoader.load(new URLRequest('original.swf'), new LoaderContext(false, appDomain)); 
したがって、ロードされたSWFは、ローダーからクラスと「通信」することを強制されます。 実装例は、「2-Memory&Domain \ applicationDomain」フォルダーにある記事のコードで確認できます。 子およびドメインへのアップロードを使用したクラス置換の例があります。 「犠牲者」には、輻輳をチェックするためのいくつかのオプションがあります(それらが含まれるクラスの置換がかかります)。
これを防ぐには、独自のローダーを介してメインSWFを新しいApplicationDomainにロードします。
 var appDomain:ApplicationDomain = new ApplicationDomain(null); var swfLoader:Loader = new Loader(); swfLoader.load(new URLRequest('original.swf'), new LoaderContext(false, appDomain)); 
ブートローダーとメインSWFの間に強力な接続を確立して、それらを「分離」することは非常に困難です。 ただし、ブートローダを置き換えて、この接続を維持できた場合、これらの努力は無駄になります。

本当に重要な変数とデータのみを保護し、メソッドを組み合わせます。
可能であれば、サーバーの重要な変数を操作するロジックを使用し、リソースのサブスクライブと変更の確認を行います。


-3.透かし


これらは、コピー防止、違法使用、および広告目的に使用できます。

それらのタイプの一部を次に示します。

  1. 視認性の高い要素:テキスト、ロゴ、画像など
    ラベルが「はんだ付け」されている場合(SWFの画像とグラフィックの両方に適用されます)、ラベルに適用されたデータを編集して手動で削除する必要があります。これは非常に困難または完全に不可能な作業です。
    たとえば、SWFの最上位の「レイヤー」にラベルが個別に配置されている(またはプログラムで追加されている)場合、ラベルが慎重に削除される可能性ははるかに高くなります。
  2. 隠しアイテム。 彼らはどこにでもいることができます。 そのような透かしを取り除くことはしばしば不可能です、なぜなら 作成者以外は誰もどこを見るべきかわからないでしょう。 これらのマークは、これらが実際にマークであり、それらを繰り返すことが不可能であることを法廷で証明できるようにするために一意でなければなりません。
この項目は非常に欠陥があることが判明しましたが、ここで言うことはありません。そのような救済策も存在することを忘れないでください。


-4. SWFの「パッケージ化」


SWFを完全に隠すことはできませんが、不運な攻撃者による目的のSWFの検索を複雑にする可能性のある非常によく知られた方法が少なくとも1つあります。

Embedタグを使用して、たとえば次のように、SWFをflexまたはflashプロジェクトに追加できます。
 [Embed(source = "./dummy.swf", mimeType = "application/octet-stream")] private var _content:Class; 
この方法で追加されたファイル(複数のEmbedタグがある場合、任意のバイナリファイルまたは複数のファイル)がDefineBinaryDataタグに配置されます。
次に、次のようにLoader.loadBytesを使用して、この方法で「パック」されたファイルをロードできます。
 var someFile:ByteArray = new _content(); loader.loadBytes(someFile); 
SWFファイルの解析とタグの操作には多くのツールがあり、DefineBinaryDataタグを置き換えたり追加したりすることができます。
これらすべてを知っていれば、プロセスを自動化するために単純な「パッカー」をスケッチできます。 ラップする前に、SWFを何らかの方法で変換することができます。たとえば、単純で高速な対称xorで処理し、ブートローダー(「パックされた」SWFを含む)でSWFを復号化してロードするコードを記述します。 xorを使用した単純な「暗号化」は、デコンパイラによる自動処理から保護するためにのみ必要であるため、SWFファイルは「純粋な形式」でローダーに含まれず、より複雑な暗号化は無意味です。
BitmapDataの形式など、他の方法でファイルが「埋め込まれ」、複数レベルのネストが作成されることもあります。

最も単純なパッカーの実装例は、記事のコードの「3-SWFPacker」フォルダーにあります。 また、orig.swfとpacked.swfの2つのファイルがあります。これらを逆コンパイルして比較することができます。
このメソッドは、少なくとも2つの方法で行います。
-ブートローダーでのデコーダーアルゴリズムの研究と独自のデコーダーの作成(特に大規模なネストローダーでは時間がかかる)
-既に解凍されてFPにロードされたSWFファイルが存在するメモリ部分を保存します(特に、以下で説明するメモリからの保護に対する保護手段が使用されていない場合は、簡単かつ迅速に)


-5.動的なコード生成とSWF編集


すでに繰り返し尋ねられています-リアルタイムフラッシュでコードを生成したり、他のSWFファイルを作成および編集することは可能ですか? 答えはイエスです、可能です!
コードについては、 AS3Commons ByteCodeを試してください。 このプロジェクトでは、リアルタイムのバイトコードを収集して実行できます。
さまざまなメソッドとプロパティを持つクラスを最初から作成したり、他のクラスから継承したりできます。 たとえば、メソッド本体は、バイトコードを直線的に使用して記述することができますmethodBuilder.addOpcode(Opcode.getlocal_0)またはすぐにブロックで:
 var source:String = (<![CDATA[ getlocal_0 pushscope ... getlocal_1 returnvalue]]>).toString(); methodBuilder.addAsmSource(source); 
abcBuilder.buildAndLoad()を使用して、生成されたコードをAVMにロードできます。
また、バイトコードを操作するためにas3abcを試すことができます。これは、著者によれば、悪名高いJoa EbertによるすばらしいApparatフレームワークの部分的な移植版です。
バイトコードではなくスクリプトの動的な実行を夢見ているなら、 as3scriptinglibを見てください 。 このプロジェクトを使用すると、JavaScriptを含むActionScript 3 / ECMAScriptスクリプトをリアルタイムでコンパイルおよび実行できます。 これがflexデモアプリケーションでどのように機能するかを確認できます 。 残念ながら、プロジェクトは長い間更新されていません。

SWFファイル自体とその構造を試すには、 as3swfまたはswfassistを試してください。

オンザフライでコードを生成する機能、およびリアルタイムでSWFを編集および作成する機能により、さまざまな複雑なスクリプトやトリックを作成して、攻撃者を混乱させ、コードを隠すことができます。 ここで、たとえば、私の頭に浮かんだ最初の3つのトリック:
  1. サーバー側の部分でクライアント側でcode \ bytecodeを生成および実行し、コード全体から元のSWFに悪意のあるユーザーを残します。ただし、それらを残してもかまいません(無料のライブラリ、ボタンなどのコード)+デコーダーのコード「ビルダー」はすでに最終コードです。
  2. コードのトリックと同様に、クライアント側でSWFを部分的に収集します。タグで収集したり、サーバーから受信したり、ブートローダーにパックされた暗号化データから1つずつアンパックしたりできます。
  3. 実行プロセス中に自己修正コードを作成します。たとえば、特定のルールまたはパターンに従って異なる方法で同じメソッドを生成します。 たとえば、i ++はi + = 1として実装できます(FP 10.1では少なくとも異なるバイトコードになります)。また、ループはさまざまな方法で実装できます。
    生成されたコードがそれを生成したメソッドを変更するような方法で工夫することが可能かもしれません。 たとえば、実行の次の反復で他のクラスとメソッドが生成されるため、コードが大幅に複雑化および混乱するため、攻撃者が取得した場合、攻撃者はこの「混乱」をすべて解析するためにできるだけ多くの時間を費やす必要がありました。
    これはかなり複雑な(またはフラッシュでは不可能な)トリックだと思います。 フラッシュ上でこのアイデアの実際に機能する実装にまだ会っていません。 あなたが会ったなら、どこを見るべきか教えてください、私は勉強するのがうれしいです。

-6.コードの難読化とデータの隠蔽


まず難読化について。 ソースコードとバイトコードでコンパイルされたコードの両方を公開できます。 ソースコードの難読化はそれほど便利で効果的ではありません。バイトコードの難読化はより魅力的に見えます。 ソースコードはコンパイラの要件を満たさなければなりません。コンパイラの要件は、バイトコードについては言えません。さらに、想像力と創意工夫の現れの範囲がはるかに広くなっています。
バイトコードの難読化には、アンチデコンパイラトリックの使用、コードの非表示および「ポイ捨て」など、要素の名前をコンパイラにとって意味のない許容できない名前に変更することが含まれる場合があります。

名前の変更は、おそらく、少なくとも何かをフラッシュに隠すための唯一の不可逆的かつ100%の作業方法です。 メソッドの本質は、メソッド、プロパティ、パッケージ、およびコンパイル後に保存されるがコードの実行時には使用されない名前の他の要素を変更することです。 元の名前を自動的に復元することは不可能です。コードの調査中に意味を推測しながら、これを手動で行う必要があります。 難読化後、新しい名前には無効な文字または予約語が含まれる場合があり、逆コンパイル後に取得したコードを簡単に再コンパイルして使用することはできません。

バイトコードを難読化すると、逆コンパイラがコードを複雑な方法でブロック単位で分析するという事実に基づいて、逆コンパイラに「トラップ」が設定される場合があります。
さらに、コードは単純に「ごみ」になる可能性があり、ボリュームが増加し、可読性が低下します。これはパフォーマンスに悪影響を与える可能性があります。

データはさまざまな方法で非表示にできます。たとえば、次のとおりです。
.

, , , SWF . — SWF , .
SWF, "", , , , . "" , .


— 7. SWF


. , , – SWF- ( SWF ), SWF . SWF , = SWF .
, ByteArray. , :
 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; } 
, swfBytes – "" "" "" , "" .


— 8. flash


, ( 2010 ):

:
( ):
\:
, Amayeta SWF Encrypt, DComSoft SWF Protector, Mochi Encryption – , "" ( ), .
, , , , makc3d .

\ ..:
その他:
, , , , .



, , , , . , SWF , , , , , . – , .
— SWF , .. , .

, . , - . , , .

():
  1. Claus Wahlers "Hacking SWF" 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 – , flash ( , ..).
  10. flash senocular "Security Domains, Application Domains, and More in ActionScript 3.0".
  11. Adobe flash.
  12. Adobe FP 10 (White Paper).
, .

: codestage.ru/files/flash_defend_files.7z

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


All Articles