AWSのアクセスキーをハードコードする

ソースコードを公開するわけじゃないしAWSの認証キーはハードコードしても良いよね。
という事で色々と調べました。

ビルドした実行ファイルは第三者に渡す可能性があるかも、というシチュエーション。


<!--
https://qiita.com/sator_imaging/items/1d5d2282cfa3716f26e9
-->

## 結果

##### ベタでハードコードした場合

- 中間言語だろうがネイティブコードだろうが即バレ
    - 当然ですね。
    - ただ、バイナリから抽出した文字列一覧から「コレ、AWSの認証情報だな？？」と感じ取るセンスは必要。


##### 難読化して .NET（C#） 中間言語にコンパイルした場合

- 難読化したところで実行ファイルからソースコードを復元出来る可能性が高いので、ちょっとした時間稼ぎ程度。
- とは言え、ソースコードを読む根気と「このアプリ、難読化された認証情報がハードコードされてそうだな」と感じ取るセンスが必要。


##### 難読化してC++等ネイティブコードにコンパイルした場合

- ベタ書きだと実行ファイル内の文字列を抽出すればすぐに見つかる（要根気）
- 難読化しておけばプログラミングちょっと分かる、程度だと解析方法が分からないのでほぼ防げるんじゃ？
    - （とりあえず自分には無理だった）


##### ハードコードを避けて認証キーを `.json` ファイル等から読み込む場合

- そういう公式サンプルがあったりするけど、それはそれで難読化やハードコードを行うよりも認証キーが簡単に見つけられる。
    - 外部と共有する際はファイルがどう扱われるか分からないので気を付けたい。
- 内々での利用、共有相手ごとに切り替え、またはAWSアカウントは自前で用意してね、を想定したものか。



仮想通貨マイニング用にAWSのアクセスキーを探しまわってるような人らは GitHub を周回しているだろうから、難読化してネイティブコードにしておけば自動化された攻撃の対象になることは回避できそう。




- [GitHub に AWS キーペアを上げると抜かれるってほんと？？？試してみよー！ - Qiita](https://qiita.com/saitotak/items/813ac6c2057ac64d5fef)
- [AWSで不正利用され80000ドルの請求が来た話 - Qiita](https://qiita.com/koyama9876/items/add70cba3cccdb7fa995)
- [AWSが不正利用され300万円の請求が届いてから免除までの一部始終 - Qiita](https://qiita.com/AkiyoshiOkano/items/72002409e3be9215ae7e)





<!--
何も対策しないよりは良い（かも）、一方で「は？？？ これで良いと思ってる？？？」というヘイトを買う可能性。上手くバランスしていきましょう。


※ ハードコードしないのが一番だと分かっちゃいるけどやめられない


-->



## 🧪 テスト内容


- [難読化](#難読化)
- [ネイティブコード（C++）](#ネイティブコードc)
    - [Unity+IL2CPP で C# をネイティブコード化](#unityil2cpp-で-c-をネイティブコード化)
- [中間言語（.NET/C#）](#中間言語netc)
    - [文字列抽出](#文字列抽出)
    - [ソースコードの復元](#ソースコードの復元)
        - [復元結果： C#コンソールアプリ](#復元結果-cコンソールアプリ)
        - [復元結果： C#コンソールアプリ（自己完結・単一ファイル）](#復元結果-cコンソールアプリ自己完結単一ファイル)
        - [復元結果： Unity+Monoバックエンド](#復元結果-unitymonoバックエンド)



# 難読化


`THE-KEY-MUST-BE-KEPT-IN-SECRET` を以下のツールで難読化。

https://www.sator-imaging.com/p/secret-key-obfuscator.html#title


こんな感じに 👇


```cpp
#include <iostream>

int main()
{
    std::string akqrsysg = "BKB4K0VO2O4oG3USFiHHcvPT-WV0E1";
    std::string jelgafbu = "Hewg4Gu3IjgEBmX519rBuw+jZWJRMf";
    std::string bbbdnvpg = "5rgmQbimSdy8+THE-kXTYOHcU5Ni7K";
    std::string tpyftwhx = "3ooi-bC8mIUHKU9OP9EoIauizbT-V5";
    std::string givmqxcq = "5IN-SECR7TFniNjtGDaapzw3ZGPxzW";
    std::string bvrsavpv = "kd+lnf7YW-kfyRYc4ww2sH1oc+wEW1";
    std::string orrhbnql = "uETqhaxpkMlm4905WDXHaq1PHVI2pi";
    std::string mxknirgr = "Pg3crnvKXlcpHdW8Eab8AW7dibqQrF";
    std::string pru_kdeu = "AZj12VKEY-MUShtCGfbOjLUPDAlgRE";
    std::string mzhpjgcl = "JKEOtV0UxiuRpg4bXvvO-4GYV9uXgh";
    std::string xkj_rnuw = "T-BE-KEnez382LWwZfbYELZ93n8on3";
    std::string wwjkdzfr = "erxOrO6b-DpZ5fu0rhZPwxqOZrvyoY";

    std::string secret = bbbdnvpg.substr(13, 4) + pru_kdeu.substr(6, 7) + xkj_rnuw.substr(0, 7) + akqrsysg.substr(22, 3) + givmqxcq.substr(1, 7) + orrhbnql.substr(1, 2);


    std::cout << "Secret Key: " << secret << "\n";
}
```


# ネイティブコード（C++）



ビルドした `.exe` から難読化した文字列は見つかる。それぞれ単体では意味を成さないので使い道はない。

これらがどこでどのように使われているのかを `.exe` から解析できればアクセスキーは復元されてしまう。


<img src="https://dl.dropbox.com/s/s7if4yl14yo7w29/Strings-on-Cpp.png" />



## Unity+IL2CPP で C# をネイティブコード化

ゲームエンジンの Unity には C# を C++ に変換してビルドする IL2CPP という機能がある。

<img src="https://dl.dropbox.com/s/fhpqujbmrckyer3/Unity-Test.png" />


そちらを使った場合は、、、👇

<img src="https://dl.dropbox.com/s/5ctu4ocalv3ik70/Strings-on-IL2CPP.png" />


コチラも文字列自体は見つかる。

IL2CPPによって Minified（？）されているので、C++の場合より見つけるのが難しい。というか探すべき対象を正確に知らないと見つけられない状態になっている。木を隠すなら森の中。



# 中間言語（.NET/C#）


<!--
使用したソースコードは以下の通り。

```csharp
using System;

namespace ObfuscationTest
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var akqrsysg = "BKB4K0VO2O4oG3USFiHHcvPT-WV0E1";
            var jelgafbu = "Hewg4Gu3IjgEBmX519rBuw+jZWJRMf";
            var bbbdnvpg = "5rgmQbimSdy8+THE-kXTYOHcU5Ni7K";
            var tpyftwhx = "3ooi-bC8mIUHKU9OP9EoIauizbT-V5";
            var givmqxcq = "5IN-SECR7TFniNjtGDaapzw3ZGPxzW";
            var bvrsavpv = "kd+lnf7YW-kfyRYc4ww2sH1oc+wEW1";
            var orrhbnql = "uETqhaxpkMlm4905WDXHaq1PHVI2pi";
            var mxknirgr = "Pg3crnvKXlcpHdW8Eab8AW7dibqQrF";
            var pru_kdeu = "AZj12VKEY-MUShtCGfbOjLUPDAlgRE";
            var mzhpjgcl = "JKEOtV0UxiuRpg4bXvvO-4GYV9uXgh";
            var xkj_rnuw = "T-BE-KEnez382LWwZfbYELZ93n8on3";
            var wwjkdzfr = "erxOrO6b-DpZ5fu0rhZPwxqOZrvyoY";

            var secret = bbbdnvpg.Substring(13, 4) + pru_kdeu.Substring(6, 7) + xkj_rnuw.Substring(0, 7) + akqrsysg.Substring(22, 3) + givmqxcq.Substring(1, 7) + orrhbnql.Substring(1, 2);

            Console.WriteLine($"Secret Key: {secret}");

        }

    }
}
```
-->


## 文字列抽出


ネイティブコードにコンパイルした場合と同様バイナリデータから文字列を抽出できる。

※ リリースビルドなので未使用のものは消滅している

<img src="https://dl.dropbox.com/s/79o0kqlyzjidu0e/Strings-on-ReleaseBuild.png" />


## ソースコードの復元

難読化したところで所詮は中間言語（IL）、ビルドした実行ファイルからソースコードへの復元は容易い。

### 復元結果： C#コンソールアプリ

<img src="https://dl.dropbox.com/s/m2dcimku3mxcz4d/Decompile-CSharpConsole.png" />


### 復元結果： C#コンソールアプリ（自己完結・単一ファイル）

自己完結（Self-Contained）かつ単一ファイルとしてビルドすれば復元は難しい？ と思ったのも束の間、調べたらすぐ復元方法が分かった。

<img src="https://dl.dropbox.com/s/97i57qhh1gz5jjt/Decompile-SelfContained.png" />


### 復元結果： Unity+Monoバックエンド

Unity+Mono でのビルドも特に問題なく復元可能。それはそう。

<img src="https://dl.dropbox.com/s/g8wvkhyrshfyzrx/Decompile-UnityMono.png" />



--


データもそうですが、金額的被害があるのが怖いですねー。


以上です。お疲れ様でした。