読者です 読者をやめる 読者になる 読者になる

Log.i53

Themidaのアンパックを目指すブログ改め使い物になるえんじにゃを目指すブログ

参照文字列の隠蔽

C x86 難読化

静的解析において目的の処理を見つける時の一般的なアプローチの1つに参照文字列(Referenced Text String)の利用があります。IDA ProやOllyDbgなどのデバッガにはプログラム内で利用されている文字列を抽出して一覧表示する機能が備わっています。このようなデバッガによる参照文字列の索引から逃れる方法がいくつか存在しますが、よく見かけるのが文字列をバイト単位に分解して利用する難読化手法です。参照文字列をバイト単位に分解して保持し、後で加工して利用することでデバッガに文字列として認識させないようにすることができます。

通常の例

#include <stdio.h>

int main() {
    char* array = "Hello World!";
    printf("%s\n", array);
    return 0;
}

上記のプログラムをOllyDbg上で実行して、CPUウインドウで右クリックして【Search for】【All referenced text strings】を選択します。すると"Hello World!"の文字列が参照文字列一覧に表示されていることが確認できます。

f:id:i53:20150423180824p:plain
コンパイラや最適化によってバイナリは異なります。

int配列で分解する例

では、ソースコードを以下のように変更してみます。"Hello World!"の文字列をそれぞれASCIIコードでint型配列にバイト単位で格納してからchar配列に格納して標準出力するものです。

#include <stdio.h>
#include <stdlib.h>

int main() {
    int int_array[] = {0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0};
    int size = sizeof(int_array) / sizeof(int); 
    char *char_array = (char*)malloc(sizeof(char) * size);
    for (int i = 0; i < size; i++) {
        char_array[i] = (char)int_array[i];
    }
    printf("%s\n", char_array);
    free(char_array);
    return 0;
}

先ほどと同様にOllyDbgで参照文字列の検索を行っても当該文字列がヒットしないことが分かります。
f:id:i53:20150423181554p:plain
コンパイラや最適化によってバイナリは異なります。

バイト配列で分解する例

さらに、マルウェアやプロテクタなどでは次のようなタイプの難読化もよく見かけます。コンパイルすると"MOV BYTE PTR, [array], IMM8"に置き換わるものです。

#include <stdio.h>

int main() {
    char array[13];
    array[0] = 0x48;
    array[1] = 0x65;
    array[2] = 0x6C;
    array[3] = 0x6C;
    array[4] = 0x6F;
    array[5] = 0x20;
    array[6] = 0x57;
    array[7] = 0x6F;
    array[8] = 0x72;
    array[9] = 0x6C;
    array[10] = 0x64;
    array[11] = 0x21;
    array[12] = 0;
	
    printf("%s\n", array);
    return 0;
}

OllyDbgで確認すると以下のようになります。
f:id:i53:20150423191238p:plain
コンパイラや最適化によってバイナリは異なります。

変数単位で分解する例

上記の例を少し分かりにくくする手法です。

#include <stdio.h>

int main() {
    char H = 0x48;
    char e = 0x65;
    char l = 0x6C;
    char o = 0x6F;
    char _ = 0x20;
    char W = 0x57;
    char r = 0x72;
    char d = 0x64;
    char ex = 0x21;

    char array[13];
    array[0] = H;
    array[1] = e;
    array[2] = l;
    array[3] = l;
    array[4] = o;
    array[5] = _;
    array[6] = W;
    array[7] = o;
    array[8] = r;
    array[9] = l;
    array[10] = d;
    array[11] = ex;
    array[12] = 0;
	
    printf("%s\n", array);
    return 0;
}

OllyDbgで確認すると以下のようになります。
f:id:i53:20150423181746p:plain
コンパイラや最適化によってバイナリは異なります。

備考

コンパイラBorland C++ Compiler 5.5
デバッガ:OllyDbg v1.10