EXE/DLL -> com変換ツール

はじめに

PE勉強会#2の資料を見ていて、もう一つツールを作りたくなったので作ってみました。

DLLの作り方も学んだので、DLLを使ったものも作ってみました。

EXE/DLL -> com変換ツール

編集箇所

PE勉強会#2の資料より。EXE/DLL(PE形式)からCOM形式に変更するために。

  • 0000 - 003Fを削除
    • DOS EXEのヘッダ
  • 0044を00 -> 01に
    • COMはアドレス0100から始まるので、そのための調整?
ソースコード
#include <stdio.h>

/* convert.c
 *
 * this program converts exe/dll file to com file.
 */

void usage( char **argv ) {

  printf( "usage : %s <input binary file> <output binary file>\n", argv[ 0 ] ) ;
  return ;

}


int main( int argc, char **argv ) {

  FILE *fin, *fout ;
  int c ;
  unsigned int i = 0 ;

  if( argc != 3 ) {
    usage( argv ) ;
    return -1 ;
  }

  if( ! ( fin = fopen( argv[ 1 ], "rb" ) ) ) {
    printf( "failed to open input file.\n" ) ;
    return -1 ;
  }

  if( ! ( fout = fopen( argv[ 2 ], "wb" ) ) ) {
    printf( "failed to open output file.\n" ) ;
    fclose( fin ) ;
    return -1 ;
  }

  while( ( c = getc( fin ) ) != EOF ) {
    if( i > 63 ) {
      if( i == 68 )
        putc( 1, fout ) ;
      else
        putc( c, fout ) ;
    }
    i++ ;
  }

  fclose( fin ) ;
  fclose( fout ) ;

  return 0 ;

}
実行例
% gcc -o convert.exe convert.c
% ./convert.exe ./dump.exe ./dump.com
% debug dump.com
-g
This program cannot be run in DOS mode.
プログラムは正常に終了しました.

DLLを使用したもの

前回のエントリではPE形式かを判定するツールを作りました。このツールを組み込んで、入力ファイルがPE形式でない場合処理を中断するように変更しました。

PE判定ツール(judge.c)はDLLにしてみました。

ソースコード

PE判定DLLのソース。

#include <stdio.h>

/*  judge2.c
 *  
 *  this program is made from judge.c with some tune.
 *
 *  return  1 : file is PE.
 *          0 : file is not PE.
 *         -1 : error.
 */

int judge( char *filename ) {

  FILE *fp ;
  int c ;
  unsigned int i = 0, head_addr = 0, valid = 0 ;

 
  if( ! ( fp = fopen( filename, "rb" ) ) ) {
    printf( "failed to open file.\n" ) ;
    return -1 ;
  }

  while( ( c = getc( fp ) ) != EOF ) {

    if( i == 0 ) {
      if( c != 77 )
        break ;
    } else if( i == 1 ) {
      if( c != 90 )
        break ;
    } else if( i >= 60 && i <= 63 ) {
      head_addr += ( c << ( ( i - 60 ) * 8 ) ) ;
    } else if( head_addr ) {
      if( i == head_addr ) {
        if( c != 80 )
          break ;
      } else if( i == head_addr + 1 ) {
        if( c != 69 )
          break ;
      } else if( i == head_addr + 2 ) {
        if( c != 0 )
          break ;
      } else if( i == head_addr + 3 ) {
        if( c == 0 )
          valid = 1 ;
        break ;
      } else if( i > head_addr + 3 ) {
        break ;
      }
    }

    i++ ;

  }

  fclose( fp ) ;

  return valid ;

}

本体のソース。

#include <stdio.h>

/* convert2.c
 *
 * this program is made from convert.c with some tune.
 */

void usage( char **argv ) {

  printf( "usage : %s <input binary file> <output binary file>\n", argv[ 0 ] ) ;
  return ;

}


int main( int argc, char **argv ) {

  FILE *fin, *fout ;
  int c ;
  unsigned int i = 0 ;

  if( argc != 3 ) {
    usage( argv ) ;
    return -1 ;
  }

  if( ! judge( argv[ 1 ] ) ) {
    printf( "input file is not EXE/DLL file.\n" ) ;
    return -1 ;
  }

  if( ! ( fin = fopen( argv[ 1 ], "rb" ) ) ) {
    printf( "failed to open input file.\n" ) ;
    return -1 ;
  }

  if( ! ( fout = fopen( argv[ 2 ], "wb" ) ) ) {
    printf( "failed to open output file.\n" ) ;
    fclose( fin ) ;
    return -1 ;
  }

  while( ( c = getc( fin ) ) != EOF ) {
    if( i > 63 ) {
      if( i == 68 )
        putc( 1, fout ) ;
      else
        putc( c, fout ) ;
    }
    i++ ;
  }

  fclose( fin ) ;
  fclose( fout ) ;

  return 0 ;

}
実行例
% gcc -shared -o ./judge.dll ./judge2.c
% gcc -o ./convert2.exe ./convert2.c ./judge.dll
% ./convert2.exe ./dump.exe ./dump.com
% debug dump.com
-g
This program cannot be run in DOS mode.
プログラムは正常に終了しました.

終わりに

COMへの変換ツールと言っていますが、DOSスタブのDOS EXEヘッダを削っているだけです。タイトルで期待してしまった人すみません。

あと、putc(ファイル出力)がやりたかっただけです、はい。

ここまで来たら逆アセンブルツールとか作ってみようかと思ったんですが、色々調べないといけないのでまた今度。