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

アセンブラ命令とマシン語で相互変換したい。

 OllyDbgの作者が(おそらくOllyDbg内で使っていると思われる)80x86 32-bit Disassembler and Assemblerソースコード含めて公開しています。サイズも小さく、勉強にはもってこいなのでここで紹介したいと思います。

 ソースコード一式は上記サイトからダウンロードできるのですが、そのままだとVisual C++ 2010 Express版ではビルドが通りませんので、少し修正する必要があります。ソースファイルは以下の5つです。

 これらを適当にプロジェクトに追加してビルドすると、pow10l、strupr、trlwr、strnicmp、memicmpあたりの関数がない(とかdeprecatedだとか)と言われて警告なりエラーなりが出ます。またdir.hがないとも言われると思います。

 とりあえず足りない関数はこんな感じで自前で実装してあげます。dir.hはコメントアウト、string.hもコメントアウトでOKです(以下の関数を追加すれば)。

long double pow10l(long double x)
{
    return powl(10, x);
}
char *strupr(char *s)
{
    char *p = s;
    while (*s){
        *s = toupper(*s);
        ++s;
    }
    return p;
}
char *strlwr(char *s)
{
    char *p = s;
    
    while (*s){
        *s = tolower(*s);
        ++s;
    }
    return p;
}
int strnicmp(const char *s1, const char *s2, size_t len)
{
    unsigned char c1, c2;
    
    if (!len)
        return 0;
    
    do {
        c1 = *s1++;
        c2 = *s2++;
        
        if (!c1 || !c2)
            break;
        
        if (c1 == c2)
            continue;
        
        c1 = tolower(c1);
        c2 = tolower(c2);
        if (c1 != c2)
            break;
    } while (--len);
    
    return (int)c1 - (int)c2;
}
int memicmp(const void *s1, const void *s2, size_t n)
{
    int dif;
    unsigned char *b1 = (unsigned char *)s1;
    unsigned char *b2 = (unsigned char *)s2;

    for (; n-- >0; b1++, b2++ ){
        dif = toupper(*b1) - toupper(*b2);
        if (dif != 0)
            return(dif);
    }

    return 0;
}

 またセキュリティがどうのこうのとも警告されるので、気になるようならすべての.cファイルで_CRT_SECURE_NO_WARNINGSをdefineしてください。

#define _CRT_SECURE_NO_WARNINGS

 以上を適用したものをGitHubに公開しています。

 実行するとテストプログラム(main.c)の結果が表示されますが、自前で書くとこんな感じになります。

int main()
{
    t_disasm da;
    t_asmmodel am;
    char errtext[1024];
    char pasm[] = "mov ecx,esp";
    unsigned char hex[] = { 0x8b, 0xcc };
    int len, i;

    // mov ecx,esp
    Disasm((char *)hex, sizeof(hex), 0x400000, &da, DISASM_CODE);
    printf("8b cc = %s\n", da.result);
    
    // 8b cc
    len = Assemble(pasm, 0x400000, &am, 0, 0, errtext);
    printf("mov ecx,esp = ");
    for(i=0; i < len; i++)
        printf("%02x ", am.code[i] & 0xff);
    printf("\n");
    return 0;
}
C:\>asmdisas.exe
8b cc = MOV ECX,ESP
mov ecx,esp = 8b cc

 それぞれ相互変換できています。全ソースコードも3000行ちょっとと読みやすい感じになっていますのでアセンブラの勉強に役立つかもしれません。