Reversing.Kr 100pts Windows問 Writeup

当たり前ですが、常設なのでFlagは書きません。解き方のみ。

Easy Crack

基本的に入力を一文字ずつ比較しているだけ。(3,4文字目だけは二文字まとめて strncmp 関数で比較している)
静的解析でも解けるが、 x64dbg などのデバッガーを使うことで、より簡単に解くことができる。

Flag: **********

Easy Keygen

生成されるキーが 5B134977135E7D13 の時の使用者の名前を求めれば良いらしい。デコンパイルしたコード(特に sprintf 関数を使ってキーを生成していると思われる場所)を読んで、名前を逆算するようなスクリプトを書けば解けます。

name = ''
serial = '5B134977135E7D13'
xor_key = [0x10, 0x20, 0x30]

c = 0
for i in range(0, len(serial), 2):
    if 2 < c: c = 0
    name += chr(int(serial[i:i+2], 16) ^ xor_key[c])
    c += 1

print(name)

Flag: **********

Easy Unpack

最後の方の逆アセンブル結果を読めば問題で問われているOEPはわかりますが、折角なのでアンパックまでやっていきたいと思います。

entry関数のデコンパイル結果を読むと、何らかのデータをデコードしていると思われるfor文の存在を確認することができます。

f:id:m0pisec:20210908142611p:plain

一連の処理をGhidra Script上で実装してみます。

xor_key = [0x10, 0x20, 0x30, 0x40, 0x50]
b1_enc = getBytes(toAddr(0x409000), 1262)

def decode_xor(enc_data):
    c = 0
    res = ''
    for pch in enc_data:
        if 4 < c: c = 0
        res += chr((pch & 0xff) ^ xor_key[c])
        c += 1
    return res

b1 = decode_xor(b1_enc)
print('[+] 1st Block Decoded: ' + b1)

デコードされたデータをバイナリエディタで表示してみましょう。

f:id:m0pisec:20210908143255p:plain

可読な文字列が多いことから、正しくデコードできていることがわかります。他にも似たような処理をしている部分が確認できるので、それらをデコードする処理、デコードしたデータを繋ぎ合わせてペイロードとして出力する処理を追加してスクリプトを完成させましょう。

import os

xor_key = [0x10, 0x20, 0x30, 0x40, 0x50]
b1_enc = getBytes(toAddr(0x401000), 0x4000)
b2_enc = getBytes(toAddr(0x405000), 0x1000)
b3_enc = getBytes(toAddr(0x406000), 0x3000)
b4_enc = getBytes(toAddr(0x409000), 0x4ee)

output_dir = askDirectory("Select Output Folder", "Select Output Folder")

def decode_xor(enc_data):
    c = 0
    res = ''
    for pch in enc_data:
        if 4 < c: c = 0
        res += chr((pch & 0xff) ^ xor_key[c])
        c += 1
    return res

def b2r(data):
    res = ''
    for pch in data:
        res += chr(pch & 0xff)
    return res

b1 = decode_xor(b1_enc)
b2 = b2r(b2_enc)
b3 = decode_xor(b3_enc)
b4 = decode_xor(b4_enc)

output_path = os.path.join(str(output_dir), 'payload.bin')
open(output_path, 'wb').write(b1+b2+b3+b4)
print("[+] Extracted payload to {}".format(output_path))

出力されたファイルをGhidraでロードしてみると、正常にデコンパイルできている為、アンパックが成功していることがわかります。