MENU閉じる

LAB

その他プログラムTIPS

研究室プログラムTIPSその他2011.8.31

ドングル3

ドングルシリーズ最後となります。
もはやドングルそのものとは関係の薄い内容となっておりますが、
そもそもドングルとはプログラムの実行制限により、プログラムライセンス保持者を守るものです。

どんなに頑張ってハードウェアキーを使って全にライセンスキーをやり取りしても、
実際に実行するプログラム側を攻撃されてしまうこともあるのです。

今回はこの実行するプログラムを守る方法の一つをご紹介します。
実行コードを隠すです。
簡単なサンプルコードを以下に掲載します。
Windows7(Intel Core i7CPU) VisualStudio2010にて動作確認しています。

#include
#include

// ただの加算関数
int funcAdd(int a, int b)
{
    return a + b;
}
 
// 上の関数のx86バイナリコード
unsigned char codeAdd[] =
{
    // _a$ = 8
    // _b$ = 12
    0x55,                               //  push    ebp
    0x8b, 0xec,                         //  mov     ebp,    esp
    0x81, 0xec, 0xc0,0x00, 0x00, 0x00,  //  sub     esp,    192
    0x53,                               //  push    ebx
    0x56,                               //  push    esi
    0x57,                               //  push    edi
    0x8d, 0xbd, 0x40, 0xff, 0xff, 0xff, //  lea     edi,    [ebp - 192]
    0xb9, 0x30, 0x00, 0x00, 0x00,       //  mov     ecx,    48
    0xb8, 0xcc, 0xcc, 0xcc, 0xcc,       //  mov     eax,    -858993460
    0xf3, 0xab,                         //  rep     stosd
    0x8b, 0x45, 0x08,                   //  mov     eax,    _a$[ebp]
    0x03, 0x45, 0x0c,                   //  add     eax,    _b$[ebp]
    0x5f,                               //  pop     edi
    0x5e,                               //  pop     esi
    0x5b,                               //  pop     ebx
    0x8b, 0xe5,                         //  mov     esp,    edp
    0x5d,                               //  pop     edp
    0xc3                                //  ret     0
};
 
typedef int(*funcType)(int a, int b);
int main()
{
    // 通常関数のコール結果
    printf("func %d\n", funcAdd(5, 10));
 
    // 少し前のwindowsから実行属性の無い領域を実行させられないプロテクトが入っている為
    // 実行属性付の領域を確保する
    void* code = VirtualAlloc( NULL, sizeof(codeAdd), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if(code != NULL){
        memcpy(code, codeAdd, sizeof(codeAdd));
        DWORD oldProteted;
        VirtualProtect( code, sizeof(codeAdd), PAGE_EXECUTE, &oldProteted );
        // このような感じでデータ領域のコードを実行属性の領域に移してきて実行させる事が出来る
        funcType func = (funcType)code;
        printf("code %d\n", func(5, 10));
    }
    return 0;
}

uncAddという関数はプログラムコードを逆アセンブラした際に、
プログラム領域に配置されますが、
codeAddというデータはデータ領域に配置されます。
ある程度の規模のプログラムになるとちょっと見ただけでは、
このcodeAdd部分を探すのは難しくなります。
さらにこれを応用すると実行コードを暗号化したり
別ファイルからリソースの如く読み込んだり出来ます。
より目につきにくく読みにくくすることが出来るようになります。

ちなみにx86バイナリコードは
構成プロパティのC/C++の出力ファイルから
アセンブリの出力で
”アセンブリコードとコンピュータ語コード(/FAc)”を選択するとビルド後に出力されるものを利用しています。

とは言えこのあたりの防衛はいつかは破られると言われているものです。
頻繁にバージョンアップを行って、最新版を生み出し続ける事が最大の対策かもしれないですね。

RECRUIT

大阪・東京共にスタッフを募集しています。
特にキャリア採用のプログラマー・アーティストに興味がある方は下のボタンをクリックしてください

RECRUIT SITE