LoginSignup
0
0

More than 1 year has passed since last update.

簡単な実行ファイルをリバースエンジニアリングしてみた

Last updated at Posted at 2022-11-09

背景

ツールの使い方の備忘録として残したかった

Ghidraのインストール

ここから落とす

Javaのランタイムが必要なので入れてなかったら入れる

Ghidraでの解析

ghidraRun.batで起動できる

起動したらドラゴンくんを選択する

image.png

importFileで解析したいバイナリをインポート

image.png

いろいろ出るがとりあえずそのままOK押してくと解析してくれる

解析が終わると、ウィンドウ左のSymbolTreeのFunctionsを見てみる。

image.png

これがバイナリ内部の関数だ。
それらしい関数名はないので、main関数を選択する

image.png

真ん中のウィンドウはアセンブリなので今回は見ない。
右のDecompileウィンドウを見てみると、アセンブリをc言語に(機械的に)戻したものが表示される。
あくまでアセンブリになったものを無理くりcにしているので、変数名は適当なものが入る。

before

void main(void)

{
  size_t sVar1;
  char local_58 [23];
  char local_41;
  int local_2c;
  FILE *local_28;
  FILE *local_20;
  uint local_14;
  int local_10;
  char local_9;
  
  local_20 = fopen("flag.txt","r");
  local_28 = fopen("rev_this","a");
  if (local_20 == (FILE *)0x0) {
    puts("No flag found, please make sure this is run on the server");
  }
  if (local_28 == (FILE *)0x0) {
    puts("please run this on the server");
  }
  sVar1 = fread(local_58,0x18,1,local_20);
  local_2c = (int)sVar1;
  if ((int)sVar1 < 1) {
                    /* WARNING: Subroutine does not return */
    exit(0);
  }
  for (local_10 = 0; local_10 < 8; local_10 = local_10 + 1) {
    local_9 = local_58[local_10];
    fputc((int)local_9,local_28);
  }
  for (local_14 = 8; (int)local_14 < 0x17; local_14 = local_14 + 1) {
    if ((local_14 & 1) == 0) {
      local_9 = local_58[(int)local_14] + '\x05';
    }
    else {
      local_9 = local_58[(int)local_14] + -2;
    }
    fputc((int)local_9,local_28);
  }
  local_9 = local_41;
  fputc((int)local_41,local_28);
  fclose(local_28);
  fclose(local_20);
  return;
}

ここまでがGhidraでの操作。

解析したソースからフラグを推定する

ここからが本当のリバースエンジニアリング作業。
このままでは見づらいので、テキストエディタで変数名などを整形する。
たとえば、

local_20 = fopen("flag.txt","r");
local_28 = fopen("rev_this","a");

なんかはfopenしているので入出力ファイルだとわかる。

sVar1 = fread(local_58,0x18,1,local_20);

freadしているので、local_58は入力ファイルの文字列が入ると推測できる。

そんなこんなで整形した結果が以下。

after
void main(void)

{
  size_t sVar1;
  char input_char_array [23];
  char local_41;
  int local_2c;
  FILE *output_file;
  FILE *input_file;
  uint j;
  int i;
  char enc_char;
  
  input_file = fopen("flag.txt","r");
  output_file = fopen("rev_this","a");
  if (input_file == (FILE *)0x0) {
    puts("No flag found, please make sure this is run on the server");
  }
  if (output_file == (FILE *)0x0) {
    puts("please run this on the server");
  }
  sVar1 = fread(input_char_array,0x18,1,input_file);
  local_2c = (int)sVar1;

  // 読み込んだ文字がないとき
  if ((int)sVar1 < 1) {
                    /* WARNING: Subroutine does not return */
    exit(0);
  }

// 暗号化処理
  for (i = 0; i < 8; i = i + 1) { // 8回ループ
  // 1文字目~8文字目まで
    enc_char = input_char_array[i];
    fputc((int)enc_char,output_file);
  }
  for (j = 8; (int)j < 0x17; j = j + 1) {
    // 8文字目~23文字目まで
    if ((j & 1) == 0) { // 下位1ビット以外をマスクして0のとき=偶数インデックスのとき
    // 奇数文字目
      enc_char = input_char_array[(int)j] + '\x05';
    }
    else { // 奇数インデックス
    // 偶数文字目
      enc_char = input_char_array[(int)j] + -2;
    }
    fputc((int)enc_char,output_file);
  }
  enc_char = local_41;
  fputc((int)local_41,output_file);
  fclose(output_file);
  fclose(input_file);
  return;

1~8文字目はprefixなのでそのまま。

このプログラムの暗号化アルゴリズムは

  • 奇数文字目:文字コードを+5する
  • 偶数文字目:文字コードを-2する

ということが分かったので、

アウトプットのファイルrev_thisの文字列を、

  • 奇数文字目:文字コードを-5する
  • 偶数文字目:文字コードを+2する

してあげればいい。

以上。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0