Matriochka - Step 3

Description

Can you help me?

Recently, I found an executable binary.

As I'm a true newbie,

Certainly, to solve it, I will have difficulties.

Keep in mind, the first step is quite easy.

Maybe the last one will be quite tricky.

Emulating it could be a good idea.

You must solve steps 1 and 2 first.


Details

Points
300
Category
Crack Me
Validations
90

Attachments

This challenge has no attachment.

Step2で得たBase64エンコードデータ(aaa.txtとして保存)をデコードします。

$ cat aaa.txt | tr -d '\r\n' | base64 -d > bbb

デコードしたファイルのファイルタイプをfileコマンドで確認します。Linuxの64bitバイナリです。

$ file bbb
bbb: ELF 64-bit LSB  executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=2ea586c925bc94d07d2d3087837dac6ef32a180c, stripped

実行してみます。コマンドライン引数にパスワードの指定が必要であることが分かります。

$ ./bbb
Usage: ./bbb <pass>

ここで、逆アセンブルして動作を解析してみます。

$ objdump -s -D bbb > ccc.txt

以下の箇所で、シグナル処理関数の登録を行っています。これにより、11:メモリアクセス違反が発生した場合、アドレス0x4007fd番地の関数が呼び出されます。また、8:浮動小数点例外が発生した場合、アドレス0x401050番地の関数が呼び出されます。

  40114b:    be fd 07 40 00           mov    $0x4007fd,%esi        #関数のアドレス
  401150:    bf 0b 00 00 00           mov    $0xb,%edi                 #11:不正なメモリ参照
  401155:    e8 66 f5 ff ff           callq  4006c0 <signal@plt>     #シグナル登録
  40115a:    be 50 10 40 00           mov    $0x401050,%esi      #関数のアドレス
  40115f:    bf 08 00 00 00           mov    $0x8,%edi                  #8:浮動小数点例外
  401164:    e8 57 f5 ff ff           callq  4006c0 <signal@plt>     #シグナル登録

その後、以下の箇所で繰り返しkill関数を呼び出していますが、この部分でメモリアクセス違反が発生します。したがって、0x4007fd番地の関数へ処理が移ります。

  401172:    8b 45 fc                 mov    -0x4(%rbp),%eax   
  401175:    be 0b 00 00 00           mov    $0xb,%esi
  40117a:    89 c7                    mov    %eax,%edi
  40117c:    e8 5f f5 ff ff           callq  4006e0 <kill@plt>            #メモリアクセス違反
  401181:    83 45 f8 01              addl   $0x1,-0x8(%rbp)                #+1
  401185:    81 7d f8 ff 03 00 00     cmpl   $0x3ff,-0x8(%rbp)         #0x3ff=1023
  40118c:    7e e4                    jle    401172 <fwrite@plt+0xa72>   #小さいか等しい

0x4007fd番地の関数では、0文字目のチェックを行っています。

  400808:    0f b6 05 b1 38 20 00     movzbl 0x2038b1(%rip),%eax  # 6040c0 <stdout+0x20>引数の文字列
  40080f:    0f be c0                 movsbl %al,%eax                          #0文字目
  400812:    89 45 fc                 mov    %eax,-0x4(%rbp)
  400815:    8b 45 fc                 mov    -0x4(%rbp),%eax
  400818:    69 c8 e8 03 00 00        imul   $0x3e8,%eax,%ecx     #ecx=0文字目×1000
  40081e:    ba 79 78 78 78           mov    $0x78787879,%edx      #2021161081
  400823:    89 c8                    mov    %ecx,%eax
  400825:    f7 ea                    imul   %edx                                    #edx(上位4バイト),eax(下位4バイト)=eax×0x78787879
  400827:    c1 fa 05                 sar    $0x5,%edx                          #edx=edx/32
  40082a:    89 c8                    mov    %ecx,%eax                        #0文字目×1000
  40082c:    c1 f8 1f                 sar    $0x1f,%eax                          #31ビット右シフト(最上位ビット)
  40082f:    29 c2                    sub    %eax,%edx                          #edx=edx-eax
  400831:    89 d0                    mov    %edx,%eax                 
  400833:    89 45 fc                 mov    %eax,-0x4(%rbp)
  400836:    81 7d fc e7 03 00 00     cmpl   $0x3e7,-0x4(%rbp)    #999
  40083d:    7e 09                    jle    400848 <fwrite@plt+0x148> #小さいか等しい
  40083f:    81 7d fc e8 03 00 00     cmpl   $0x3e8,-0x4(%rbp)     #1000正解
  400846:    7e 02                    jle    40084a <fwrite@plt+0x14a> #小さいか等しい
  400848:    eb 10                    jmp    40085a <fwrite@plt+0x15a>

これを逆算して0文字目を求めるRubyプログラムが以下です。実行するとDが得られます。

#0moij
for i in 32..126 do
  ecx = i * 0x3e8
  tmp = ecx * (0x78787879)
  edx = tmp.to_s(16)[0..-9].to_i(16)
  eax = tmp.to_s(16)[-8, 8].to_i(16)
  edx = edx >> 5
  eax = ecx >> 0x1f
  edx = edx - eax
  if edx.to_s(16).start_with?("3e8") then
    print i.chr
    break
  end
end

0文字目のチェックがOKだと、以下の箇所で再度メモリアクセス違反が発生した場合のシグナルが登録されます。つまり、次にメモリアクセス違反が発生した場合は、0x40085c番地の関数が呼び出されます。

  40084a:    be 5c 08 40 00           mov    $0x40085c,%esi     #関数のアドレス
  40084f:    bf 0b 00 00 00           mov    $0xb,%edi                #11:不正なメモリ参照

  400854:    e8 67 fe ff ff           callq  4006c0 <signal@plt>   #シグナル登録

retで呼び出し元に戻り、kill関数が繰り返し呼び出されますので、再度、メモリアクセス違反が発生し、0x40085c番地の関数へ処理が移ります。ここでは1文字目のチェックが行われ、OKだった場合、再度シグナルが登録されます。

同様な処理が20回ほど行われ、最終的に以下の文字列を得ることが出来ます。

Did_you_like_signals?

実際にコマンドライン引数に指定して実行してみます。

$ ./bbb Did_you_like_signals?
Good good! Now let's play a game...
6ydQg8QCWEBQg+wCWMNQg8QCWEBAUIPsAljDUIPEAliDwARQg+wCWMPo1v9m6wJmLujO/8P76znr

(略)

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=

Goodと表示されました。

したがって、フラグは、

Did_you_like_signals?

です。






以下に、0文字目から各文字のチェックを逆算するRubyプログラムを載せておきます。

 

#0moij
for i in 32..126 do
  ecx = i * 0x3e8
  tmp = ecx * (0x78787879)
  edx = tmp.to_s(16)[0..-9].to_i(16)
  eax = tmp.to_s(16)[-8, 8].to_i(16)
  edx = edx >> 5
  eax = ecx >> 0x1f
  edx = edx - eax
  if edx.to_s(16).start_with?("3e8") then
    print i.chr
    break
  end
end
#1moji
for i in 32..126 do
  ecx = i * 0x3e8
  tmp = ecx * (0x9c09c09d - 0xffffffff - 1)
  edx = tmp.to_s(16)[0..-9].to_i(16)
  eax = tmp.to_s(16)[-8, 8].to_i(16)
  eax = ecx + edx
  edx = eax >> 6
  eax = ecx >> 0x1f
  edx = edx - eax
  if edx.to_s(16).start_with?("3e8") then
    print i.chr
    break
  end
end
#2moji
for i in 32..126 do
  ecx = i * 0x3e8
  tmp = ecx * (0x51eb851f)
  edx = tmp.to_s(16)[0..-9].to_i(16)
  eax = tmp.to_s(16)[-8, 8].to_i(16)
  edx = edx >> 5
  eax = ecx >> 0x1f
  edx = edx - eax
  if edx.to_s(16).start_with?("3e8") then
    print i.chr
    break
  end
end
#3moji
for i in 32..126 do
  ecx = i * 0x3e8
  tmp = ecx * (0xac769185 - 0xffffffff - 1)
  edx = tmp.to_s(16)[0..-9].to_i(16)
  eax = tmp.to_s(16)[-8, 8].to_i(16)
  eax = ecx + edx
  edx = eax >> 6
  eax = ecx >> 0x1f
  edx = edx - eax
  if edx.to_s(16).start_with?("3e8") then
    print i.chr
    break
  end
end
#4moji
for i in 32..126 do
  ecx = i * 0x3e8
  tmp = ecx * (0x43b3d5b)
  edx = tmp.to_s(16)[0..-9].to_i(16)
  eax = tmp.to_s(16)[-8, 8].to_i(16)
  edx = edx >> 1
  eax = ecx >> 0x1f
  edx = edx - eax
  if edx.to_s(16).start_with?("3e8") then
    print i.chr
    break
  end
end
#5moji
for i in 32..126 do
  ecx = i * 0x3e8
  tmp = ecx * (0x939a85c5 - 0xffffffff - 1)
  edx = tmp.to_s(16)[0..-9].to_i(16)
  eax = tmp.to_s(16)[-8, 8].to_i(16)
  eax = ecx + edx
  edx = eax >> 6
  eax = ecx >> 0x1f
  edx = edx - eax
  if edx.to_s(16).start_with?("3e8") then
    print i.chr
    break
  end
end
#6moji
for i in 32..126 do
  ecx = i * 0x3e8
  tmp = ecx * (0x8c08c08d - 0xffffffff - 1)
  edx = tmp.to_s(16)[0..-9].to_i(16)
  eax = tmp.to_s(16)[-8, 8].to_i(16)
  eax = ecx + edx
  edx = eax >> 6
  eax = ecx >> 0x1f
  edx = edx - eax
  if edx.to_s(16).start_with?("3e8") then
    print i.chr
    break
  end
end
#7moji
for i in 32..126 do
  ecx = i * 0x3e8
  tmp = ecx * (0xac769185 - 0xffffffff - 1)
  edx = tmp.to_s(16)[0..-9].to_i(16)
  eax = tmp.to_s(16)[-8, 8].to_i(16)
  eax = ecx + edx
  edx = eax >> 6
  eax = ecx >> 0x1f
  edx = edx - eax
  if edx.to_s(16).start_with?("3e8") then
    print i.chr
    break
  end
end
#8moji
for i in 32..126 do
  ecx = i * 0x3e8
  tmp = ecx * (0x4bda12f7)
  edx = tmp.to_s(16)[0..-9].to_i(16)
  eax = tmp.to_s(16)[-8, 8].to_i(16)
  edx = edx >> 5
  eax = ecx >> 0x1f
  edx = edx - eax
  if edx.to_s(16).start_with?("3e8") then
    print i.chr
    break
  end
end
#9moji
for i in 32..126 do
  ecx = i * 0x3e8
  tmp = ecx * (0x9c09c09d - 0xffffffff - 1)
  edx = tmp.to_s(16)[0..-9].to_i(16)
  eax = tmp.to_s(16)[-8, 8].to_i(16)
  eax = ecx + edx
  edx = eax >> 6
  eax = ecx >> 0x1f
  edx = edx - eax
  if edx.to_s(16).start_with?("3e8") then
    print i.chr
    break
  end
end
#10moji
for i in 32..126 do
  ecx = i * 0x3e8
  tmp = ecx * (0x4c8f8d29)
  edx = tmp.to_s(16)[0..-9].to_i(16)
  eax = tmp.to_s(16)[-8, 8].to_i(16)
  edx = edx >> 5
  eax = ecx >> 0x1f
  edx = edx - eax
  if edx.to_s(16).start_with?("3e8") then
    print i.chr
    break
  end
end
#11moji
for i in 32..126 do
  ecx = i * 0x3e8
  tmp = ecx * (0x288df0cb)
  edx = tmp.to_s(16)[0..-9].to_i(16)
  eax = tmp.to_s(16)[-8, 8].to_i(16)
  edx = edx >> 4
  eax = ecx >> 0x1f
  edx = edx - eax
  if edx.to_s(16).start_with?("3e8") then
    print i.chr
    break
  end
end
#12moji
for i in 32..126 do
  ecx = i * 0x3e8
  tmp = ecx * (0xac769185 - 0xffffffff - 1)
  edx = tmp.to_s(16)[0..-9].to_i(16)
  eax = tmp.to_s(16)[-8, 8].to_i(16)
  eax = ecx + edx
  edx = eax >> 6
  eax = ecx >> 0x1f
  edx = edx - eax
  if edx.to_s(16).start_with?("3e8") then
    print i.chr
    break
  end
end
#13moji
for i in 32..126 do
  ecx = i * 0x3e8
  tmp = ecx * (0x473c1ab7)
  edx = tmp.to_s(16)[0..-9].to_i(16)
  eax = tmp.to_s(16)[-8, 8].to_i(16)
  edx = edx >> 5
  eax = ecx >> 0x1f
  edx = edx - eax
  if edx.to_s(16).start_with?("3e8") then
    print i.chr
    break
  end
end
#14moji
for i in 32..126 do
  ecx = i * 0x3e8
  tmp = ecx * (0x9c09c09d - 0xffffffff - 1)
  edx = tmp.to_s(16)[0..-9].to_i(16)
  eax = tmp.to_s(16)[-8, 8].to_i(16)
  eax = ecx + edx
  edx = eax >> 6
  eax = ecx >> 0x1f
  edx = edx - eax
  if edx.to_s(16).start_with?("3e8") then
    print i.chr
    break
  end
end
#15moji
for i in 32..126 do
  ecx = i * 0x3e8
  tmp = ecx * (0x13e22cbd)
  edx = tmp.to_s(16)[0..-9].to_i(16)
  eax = tmp.to_s(16)[-8, 8].to_i(16)
  edx = edx >> 3
  eax = ecx >> 0x1f
  edx = edx - eax
  if edx.to_s(16).start_with?("3e8") then
    print i.chr
    break
  end
end
#16moji
for i in 32..126 do
  ecx = i * 0x3e8
  tmp = ecx * (0x94f2095 - 0xffffffff - 1)
  edx = tmp.to_s(16)[0..-9].to_i(16)
  eax = tmp.to_s(16)[-8, 8].to_i(16)
  edx = edx >> 2
  eax = ecx >> 0x1f
  edx = edx - eax
  if edx.to_s(16).start_with?("3e8") then
    print i.chr
    break
  end
end
#17moji
for i in 32..126 do
  ecx = i * 0x3e8
  tmp = ecx * (0x151d07eb)
  edx = tmp.to_s(16)[0..-9].to_i(16)
  eax = tmp.to_s(16)[-8, 8].to_i(16)
  edx = edx >> 3
  eax = ecx >> 0x1f
  edx = edx - eax
  if edx.to_s(16).start_with?("3e8") then
    print i.chr
    break
  end
end
#18moji
for i in 32..126 do
  ecx = i * 0x3e8
  tmp = ecx * (0x4bda12f7)
  edx = tmp.to_s(16)[0..-9].to_i(16)
  eax = tmp.to_s(16)[-8, 8].to_i(16)
  edx = edx >> 5
  eax = ecx >> 0x1f
  edx = edx - eax
  if edx.to_s(16).start_with?("3e8") then
    print i.chr
    break
  end
end
#19moji
for i in 32..126 do
  ecx = i * 0x3e8
  tmp = ecx * (0x473c1ab7)
  edx = tmp.to_s(16)[0..-9].to_i(16)
  eax = tmp.to_s(16)[-8, 8].to_i(16)
  edx = edx >> 5
  eax = ecx >> 0x1f
  edx = edx - eax
  if edx.to_s(16).start_with?("3e8") then
    print i.chr
    break
  end
end
#20moji
for i in 32..126 do
  ecx = i * 0x3e8
  tmp = ecx * (0x82082083 - 0xffffffff - 1)
  edx = tmp.to_s(16)[0..-9].to_i(16)
  eax = tmp.to_s(16)[-8, 8].to_i(16)
  eax = ecx + edx
  edx = eax >> 5
  eax = ecx >> 0x1f
  edx = edx - eax
  if edx.to_s(16).start_with?("3e8") then
    print i.chr
    break
  end
end