テキスト文字列:組み込みソフトウェアに潜む脆弱性
長年にわたり、デスクトップコンピュータのセキュリティは懸念事項でした。一度インターネットに接続されると、本質的に何らかの攻撃を受ける可能性があります。このような侵入は、データの窃取、システムの破壊、動作の変更などを目的とする場合があります。保護手段はよく知られ、広く適用されています。一方、組み込みシステムはネットワークに接続されることが稀で、コードが通常ROMに格納されていたため、このような問題から免疫があるように見えていました。しかし、状況は変わりました。現代のシステムの大部分がインターネットに接続されており、コードをRAMにコピーしてそこから実行することが一般的になっています。これは、セキュリティが組み込みソフトウェア設計において重要な考慮事項になったことを意味します。
英語は優れたコミュニケーションツールです。非常に表現力豊かな言語であり、高い精度と微妙なニュアンスでコミュニケーションを可能にします。しかし、日常会話では、私たちの多くは怠惰で、単語を100%正確に使わないことがよくあります。ここで例に挙げたいのは、safety(安全性)とsecurity(セキュリティ)が、あたかも同義語であるかのようにほぼ互換的に使われている点です。私が聞いた中で最も良い定義は、次のようなものです:安全性とは、デバイスから世界を守るプロセスであり、セキュリティとは、世界からデバイスを守ることです。今日はセキュリティについて話します。
システムが完全に防弾仕様である必要がある場合、産業グレードの暗号化が必要です。これは通常、特定のハードウェアサポートを必要としますが、これが容易に入手可能であっても、そのような高度なセキュリティが必要ないアプリケーションではオーバーキルと見なされる可能性があります。そのような場合には他の選択肢があり、それを探っていきます。
ハッカーがデバイスのメモリ内容にアクセスできれば、それが何をし、どのように動作するかを解明し始めることができます。これが動作変更の第一段階です。コードは逆アセンブルされ、ロジックが露見する可能性があります。暗号化がなければ、これを防ぐ手立てはほとんどありません。次にハッカーが行う可能性があるのは、データの16進/ASCIIダンプを見て、意味のあるものを見つけようとすることです。彼らはパターンや認識可能な構造を探しています。ここでいくつかの予防措置を講じることができます。暗号化が選択肢にない場合でも、難読化は可能です。
データ難読化の目的は、データをそれが何であるか認識しにくくすることで、ハッカーを遅らせたり阻止したりすることです。メモリダンプをスキャンすると、容易に見つかるものの一つがテキスト文字列です。そこで、ここに焦点を当てます。
C/C++コードでは、テキスト文字列は通常、ASCIIコードを含むバイト列で、ヌルバイトで終端されます。これは非常に見つけやすいため、変更します。まず、ヌル終端子の代わりに、各文字列の最初のバイトを長さ指定子とします。文字列の文字は、データをわずかにスクランブルして、見慣れない外観にします。具体的には、各バイトの上位ニブルと下位ニブルを入れ替えます。プレーンテキスト文字列を入力として、適切な初期化を持つ配列宣言を生成するユーティリティプログラムが必要です。以下はそのユーティリティの中核となる関数です:
void scramble(int index, unsigned char *input) { unsigned char *charpointer, character; printf("unsigned char string%d[%d] = {0x%02x,", index, strlen(input)+1, strlen(input)); charpointer = input; while(*charpointer) { character = *charpointer++; character = ((character & 0x0f) << 4) | ((character & 0xf0) >> 4); printf("0x%02x", character); if (*charpointer) printf(","); } printf("}; // \"%s\"\n", input); }
この関数にインデックス4と文字列「Hello world」(オリジナルですね?)を渡すと、出力は次のようになります:
unsigned char string4[12] = {0x0b, 0x84, 0x56, 0xc6, 0xc6, 0xf6, 0x02, 0x77, 0xf6, 0x27, 0xc6, 0x46}; // "Hello world"
これをコードにコピー&ペーストし、表示時にテキストをアンスクランブルする関数を書くだけです。各文字列にインデックス番号を与える代わりに、indexパラメータを文字列に置き換えて任意の名前を付けることもできます。生成されたコードはコメントに読みやすい形式で文字列を示しているため、ある程度自己文書化されていますが、これはソースコードにのみ現れます。ハッカーがソースコードにアクセスできているなら、あなたはすでに十分なトラブルに見舞われており、私はこれ以上助けられません!
以下はアンスクランブル処理を示すコードです:
void main() { unsigned char temp, buffer[50]; int count = string4[0], index=0; while(count--) { temp = string4[index+1]; temp = ((temp & 0x0f) << 4) | ((temp & 0xf0) >> 4); buffer[index] = temp; index++; } buffer[index] = 0; printf("-%s-\n", buffer); }
各バイトのニブルを入れ替えるのは、スクランブルを行う多くの方法の一つに過ぎません。もう一つの可能性は、例えば各文字を3ビット左ローテートすることです。それを行うコードは以下の通りです:
unsigned char leftrotate3(unsigned char c) { c = (c << 3) | (c >> 5); return c; }
ここで概説した難読化技術は、文字単位で文字列をスクランブルします。文字列全体に対して処理を行うことも可能です。例えば、文字列を長いビット列として扱い、任意の数だけ左にローテートさせることができます。このアルゴリズムのコーディングは、より熱心な読者の課題として残しておきます。
すべてのテキスト文字列を一箇所に集約することの副次的効果として、他の言語向けのソフトウェアバージョンを作成するのが非常に簡単になることも注目に値します。
繰り返し強調しますが、データ難読化は防弾仕様から程遠く、よくて真剣なハッカーを遅らせる程度です。アンスクランブルコードが逆アセンブルされる可能性があるからです。この技術のコツは、難読化を追跡困難な痕跡にすることです。真に高いセキュリティが必要なら、完全な暗号化を検討しなければなりません。
埋め込み
- ピアノ:古代のルーツから現代の極みへ
- 3Dプリント・ワークフロー・ソフトウェアに必須の10機能
- 3Dプリントとソフトウェアが製造業のデジタル変革をどう推進するか
- ロボットが工場を変える:知っておくべきこと
- 組み込みソフトウェアがハードウェアサプライチェーンを再構築し、より高い俊敏性を実現
- ソフトウェア相互接続がスマートファクトリーにもたらす主なメリット
- 施設管理ソフトウェアが宗教施設にもたらすメリット
- 組み込みシステムが牽引する現代自動車のイノベーション
- 組み込みシステムの基礎と実世界での応用
- SOAFEE:ソフトウェア定義自動車プラットフォームを強化するクラウドネイティブアーキテクチャ
- DevOpsで組み込みソフトウェア開発の課題を克服する