Reversing.kr easy keygen
Reversing.Kr第二回。
実行
ファイルを解凍してeasy keygen.exeを実行してみる。
添付されていたテキストファイルによると、シリアルが「5B134977135E7D13」のユーザ名を見つけなければいけないとのこと。
IDAで開く
easy keygen.exeをIDAで開きmain関数の逆アセンブル結果を見る。
・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という。)
・その後scanfを呼び出してユーザネームの入力を求める。入力文字列は[esp+0x10]に格納されるようだ。
次。繰り返し処理っぽい。
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...という感じで処理されている。
Input Nameを加工したら、次はscanfでシリアルの入力を求める。
シリアルは[esp+0x10]に格納される。
その後、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を逆算できる。
コードを書いてユーザネームをゲットした。