アイジア

CTF, 情報セキュリティの学んだことメモ

Reversing.kr easy keygen

Reversing.Kr第二回。

実行

ファイルを解凍してeasy keygen.exeを実行してみる。

f:id:favoritte15:20180502195418p:plain

添付されていたテキストファイルによると、シリアルが「5B134977135E7D13」のユーザ名を見つけなければいけないとのこと。

IDAで開く

easy keygen.exeをIDAで開きmain関数の逆アセンブル結果を見る。

f:id:favoritte15:20180501192047p:plain

・main関数。call sub 4011B9となっているのはsprintf関数。

main関数内部に変数として

[esp+0x10] = 0x10 [esp+0x11] = 0x20 [esp+0x12] = 0x30が代入されている。

(sprintfの呼出し後

add esb,4

によってスタックが補正されているので

[esp+0x10] → [esp+0xC] = 0x10

[esp+0x20] → [esp+0x1C] = 0x20

[esp+0x30]→ [esp+0x2C] = 0x30

になる。

このように関数を呼び出した側(ここではmain関数)でスタックの補正を行う方式を_cdeclという。呼び出した関数内でスタック補正を行う方式を__stdcallという。)

 

f:id:favoritte15:20180501192153p:plain

・その後scanfを呼び出してユーザネームの入力を求める。入力文字列は[esp+0x10]に格納されるようだ。

 

f:id:favoritte15:20180501193832p:plain

次。繰り返し処理っぽい。

 

movsx ecx,  byte ptr [esp+esi+0x0C]

movsx edx, byte ptr [esp+ebp+0x10]

一回目は

ecxに0x10(16)

edxに入力文字列1文字のアスキーコード

を入れてこれをXORしている。

その結果はecxに上書きされる。

 sprintfでこのecxを格納先のアドレスへ書き込む。

(格納先アドレスは[esp+0x74])

 

その後、esiとebpをインクリメントしてこれを繰り返し。

 

1文字目は0x10(16)、2文字目は0x20(32)、3文字目は0x30(48)でXORされ

esiは3以上になったら0に戻されるので

4文字目にまた0x10でXOR...という感じで処理されている。

 

f:id:favoritte15:20180502184324p:plain

Input Nameを加工したら、次はscanfでシリアルの入力を求める。

シリアルは[esp+0x10]に格納される。

 

f:id:favoritte15:20180502184606p:plain

その後、esiに[esp+0x74]のアドレスを格納している。[esp+0x74]には先ほどXORされたInput Nameが格納されているはずだ。

これをシリアルと比べて同じであれば正解処理に進んでいる。

 

Write up

このことからシリアルキーはInput Nameの各文字のアスキーコードを16,32,48でXORしたものであることが分かった。XOR演算にはもう一度XORをすると元に戻るという性質がある。つまり

InputName (XOR) 16 = Serial ならば Serial (XOR) 16 = InputName

が成り立つため、これを利用してSerialからInputNameを逆算できる。

 

コードを書いてユーザネームをゲットした。