連載 [第1回] :
  脆弱性診断の現場から

32ビットのARM環境のみで有効なディスアセンブルを妨害するテクニック

2024年7月19日(金)
小竹 泰一
第1回の今回は、ARM32のみで有効なアンチディスアセンブルのテクニックを紹介します。

はじめに

株式会社ステラセキュリティ 取締役CTOの小竹(@tkmru)です。

ディスアセンブルを妨害するアンチディスアセンブルという耐タンパ性を高めるための技術があります。本記事では、32ビットのARM環境(以下、ARM32)のみで有効なアンチディスアセンブルのテクニックを紹介します。

静的解析を妨害する
アンチディスアセンブル

リバースエンジニアリングの方法の1つに、バイナリをディスアセンブル(逆アセンブル)した結果を読み解く静的解析があります。ディスアセンブルというのは、バイナリを機械語からアセンブリ言語に変換することです。静的解析では、アセンブリ言語の命令を読み解くことで、プログラムの挙動を明らかにします。

アンチディスアセンブル(Anti-Disassembly)は、静的解析を妨害するために、ディスアセンブルを正常に行えなくする技術です。解析を逃れるために、攻撃者がマルウェアに用いることもあれば、チートを防ぐためにゲームに用いられることや、不正なコピー防止のためにソフトウェア製品に用いられることもあります。

ARMでのアンチディスアセンブルは
x86/x64に比べ困難

x86/x64では、アセンブリ言語の命令は可変長です。x86/x64の場合、命令が可変長であることを利用し、命令の途中のバイトを分岐先として解釈させるなどして、命令間の境界をディスアセンブラに誤認させることで、比較的容易にアンチディスアセンブルを実現できます。

しかし、ARMの命令は固定長です。ARM32では、命令の長さは32ビット(4バイト)で固定です。例外として、16ビット(2バイト)のThumb命令セットがあります。これは、プログラムのサイズを削減し、消費電力を低減するために設計された命令セットです。Thumb命令を使用するには、動作モードを切り替える必要があります。ARMでは、このようにほとんどの命令が固定長であるため、命令間の境界を誤認させることが難しく、アンチディスアセンブルを実現するのが難しくなります。

PLD命令を活用した
アンチディスアセンブル

PLD(PreLoad Data)命令は、メインメモリからL1/L2キャッシュにデータを読み込む命令です。メモリアクセスの高速化のために用意されています。公式リファレンスには、次のシンタックスで利用できると記載されています。レジスタで指定されたアドレスにオフセットを加算して、そのアドレスにあるデータを読み込みます。

PLD [レジスタ, オフセット]

PLD命令に指定されたアドレスを、IDA Proなどのリバースエンジニアリングツールは、データとして解釈します。そのため、PLD命令にコードが存在するアドレスを指定すると、そのアドレスにある命令はディスアセンブルされません。このように、PLD命令を活用して、アンチディスアセンブルを実現できます。L1/L2キャッシュを前後で使用していなければ、PLD命令を挿入してもプログラムの動作に影響はありません。PLD命令に指定できるアドレスにはアライメントの制限がない点、変なアドレスを読み込んでしまっても例外を発生させない点も良い点です。

PLD命令を挿入する

シンプルなHello, world!という文字列を出力するだけのプログラムにPLD命令を挿入し、IDA Pro、Ghidraでディスアセンブルしてみます。PLD命令のオペランドには、次に実行する命令を指すPCレジスタを指定します。

#include <stdio.h>

int main() {
    __asm__ volatile(
        "pld [pc]\n"
    );
    puts("Hello, world!\n");
    return 0;
}

コンパイルと実行

x64のUbuntu 22.04でARM32のクロスコンパイル環境を構築し、QEMUというエミュレータを使ってコンパイルしたプログラムを実行してみます。実行したいプログラムのアーキテクチャとPCのアーキテクチャが異なる場合は、QEMUのようなエミュレータを使わないと実行できません。

まず、aptコマンドを使って、コンパイラとQEMUをインストールします。

$ sudo apt install -y gcc-arm-linux-gnueabihf qemu-user-static

インストールが完了したら、次のコマンドでプログラムをコンパイルします。先ほどのプログラムはinsert-pld.cというファイルに保存してあるとします。

$ arm-linux-gnueabihf-gcc -marm insert-pld.c -o insert-pld

コンパイルが完了したら、QEMUを使って実行します。環境変数QEMU_LD_PREFIXを使って、プログラムが使う共有ライブラリのパスを指定する必要があることに注意してください。指定しないと、/ld-linux-armhf.so.3が見つからないというエラーが発生します。次のように問題なく実行できることを確認できるはずです。

$ export QEMU_LD_PREFIX='/usr/arm-linux-gnueabihf/'
$ qemu-arm-static insert-pld
Hello, world!

ディスアセンブル結果の確認

IDA Proでディスアセンブルした結果を確認してみましょう。狙い通り、アンチディスアセンブルが成功しています。PLD命令のオペランドに指定されたアドレスをデータとして解釈しているため、そのアドレスにある命令はディスアセンブルされていません。

ディスアセンブル結果を確認できないだけでなく、Graph viewを表示できないことも確認できます。

Ghidraでもディスアセンブル結果を確認してみましょう。意外なことに、Ghidraではアンチディスアセンブルが成功していません。これは、PLD命令のオペランドに指定されたアドレスを解釈していないからです。IDA Proほど気が利かない多機能でないことが良い方向に作用していると言えるでしょう。

オフセットを調整し、
任意のアドレスの命令にアンチディスアセンブルを施す

PLD命令ではレジスタで指定したベースアドレスに対するオフセットを指定できます。これを用いて任意のアドレスのコードにアンチディスアセンブルを施すことができます。アドレスを調整して、PLD命令があるアドレスの直後にある命令に対してアンチディスアセンブルを施してみましょう。

#include <stdio.h>

int main() {
    __asm__ volatile(
        "pld [pc, #-4]\n"
    );
    puts("Hello, world!\n");
    return 0;
}

今回のプログラムも先ほどのプログラムと同様の手順でコンパイル、実行できます。IDA Proでディスアセンブルした結果を確認すると先ほどとはアンチディスアセンブルの対象が異なっていることが分かります。

まとめ

この記事では、ARM32のみで有効なアンチディスアセンブルのテクニックを紹介しました。PLD命令を活用することで、ディスアセンブルを妨害することができます。この記事で紹介したテクニックを応用し、NOP Sledを組み合わせたり、PLD命令とディスアセンブラが解釈できないよう一部のバイトを壊したりすることで、解析をより困難にすることもできます。応用例についても機会があれば紹介したいと思います。

また、今回紹介したテクニックは、Ghidraには全く効かず、GhidraはIDA Proよりも優位でした。しかし、リバースエンジニアリングを行っていると反対にIDA Proの方がディスアセンブルの精度が高いことの方が多いです。耐タンパ性を高める取り組みをする際は、複数のリバースエンジニアリングツールで検証することが重要です。

【参考文献】

※本記事は、株式会社ステラセキュリティが配信しているコンテンツ「Sterra Security Tech Blog」からの転載です。
元記事についてはこちらをご覧ください。

株式会社ステラセキュリティ 取締役副社長 CTO
大学卒業後、株式会社ディー・エヌ・エーに入社し、セキュリティエンジニアとして活躍。その後、株式会社アカツキに1人目のセキュリティエンジニアとして入社し、脆弱性診断内製化、セキュリティチーム組成に尽力。 著書に『ポートスキャナ自作ではじめるペネトレーションテスト』『マスタリングGhidra』(いずれもオライリー・ジャパン)、『リバースエンジニアリングツールGhidra実践ガイド』(マイナビ出版)

連載バックナンバー

セキュリティ技術解説
第5回

32ビット/64ビットの両方のARM環境で有効なディスアセンブルを妨害するテクニック

2024/11/22
第5回の今回は、ドキュメントが少ない32ビット/64ビットのARM環境におけるアンチディスアセンブル技術の使い方を解説します。
働き方技術解説
第4回

アップロード機能の検証のためのファイルを作成するツール「dummy」を作った話

2024/10/18
第4回の今回は、脆弱性診断やQAに役立つ静的ファイルを作成するコマンドラインツール「dummy」の使い方を解説します。
セキュリティ技術解説
第3回

VRヘッドセットからの通信をプロキシツールで確認する方法

2024/10/4
第3回の今回は、ByteDances社製のPICO 4というVRヘッドセットでMITMを行う方法を解説します。

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています