觀察:
1.首先在IDA中找到main函數:
首先輸入字符串s,接着把字符串s作爲隨機數的種子。
調用sub_400796函數和sub_400937函數。
由於s未知,所以需要猜測s的哪部分作爲隨機數的種子。
2.觀察sub_400796函數:
該函數主要分爲兩部分,第一部分是對byte_6010C0進行賦值:
第二部分是利用byte_6010C0和byte_601070以及a1原來的值,求得a1第一次加密後的值:
所以,如果要求解a1原來的值,需要已知:
byte_6010C0(已知)、byte_601070(已知)、a1第一次加密後的值(未知,需要解密下一個函數才能得到)。
3.觀察sub_400937函數:
_ctype_b_loc
這裏爲判斷是否爲小寫字母。分析上一個函數,可以看出a1中所有的字母都滿足*__ctype_b_loc())[v4] & 0x200
該條件。
所以src與a1相比,只是將字母的順序進行了調換。
另外,由於a1的長度最小爲v8*v9 - v8,而src的長度爲v8*v9。所以a1中長度不夠的部分需要隨機生成。
4.總結:
本題的求解順序爲:
1.猜測隨機數的種子。
2.根據題目中給出的字符串,對sub_400937函數中的加密過程進行解密。
3.將解密的結果代入sub_400796函數中,求得s的值。
求解:
1.猜測隨機數的種子:
猜測s的前四位爲”flag”,由於小端問題,轉換爲16進制後應該爲:
0x67616C66
。
2.sub_400937解密:
由於src的長度正好等於v8*v9.所以在編寫解密程序時,v9不用再加1了。
解密程序的主要工作就是行列的調換。
char a[] = "vfnlhthn__bneptls}xlragp{__vejblxpkfygz_wsktsgnv";
srand(0x67616C66);
int v7 = 0;
int v8 = rand() % 7 + 2;
int v9 = strlen(a) / v8;
for (int i = 0; i < v9; i++) {
for (int j = 0; j < v8; j++) {
printf("%c", a[j*v9 + i]);
}
}
最後得到輸出爲:
vhex{bykfnpl_lgtn_tr_xzsl_lavp_ghbsgekwntn}pjfsv
不考慮後面幾位隨機生成的數字,可以得到a1爲:
vhex{bykfnpl_lgtn_tr_xzsl_lavp_ghbsgekwntn}
3.sub_400796解密:
首先編程求解出byte_6010C0,並找到byte_601070的值。
然後編程求解a1,主要方法就是窮搜。
char a[] = "qwertyuiopasdfghjklzxcvbnm";
char b[] = "abcdefghijklmnopqrstuvwxyzbcdefghijklmnopqrstuvwxyzacdefghijklmnopqrstuvwxyzabdefghijklmnopqrstuvwxyzabcefghijklmnopqrstuvwxyzabcdfghijklmnopqrstuvwxyzabcdeghijklmnopqrstuvwxyzabcdefhijklmnopqrstuvwxyzabcdefgijklmnopqrstuvwxyzabcdefghjklmnopqrstuvwxyzabcdefghiklmnopqrstuvwxyzabcdefghijlmnopqrstuvwxyzabcdefghijkmnopqrstuvwxyzabcdefghijklnopqrstuvwxyzabcdefghijklmopqrstuvwxyzabcdefghijklmnpqrstuvwxyzabcdefghijklmnoqrstuvwxyzabcdefghijklmnoprstuvwxyzabcdefghijklmnopqstuvwxyzabcdefghijklmnopqrtuvwxyzabcdefghijklmnopqrsuvwxyzabcdefghijklmnopqrstvwxyzabcdefghijklmnopqrstuwxyzabcdefghijklmnopqrstuvxyzabcdefghijklmnopqrstuvwyzabcdefghijklmnopqrstuvwxzabcdefghijklmnopqrstuvwxy";
char c[] = "vhex{bykfnpl_lgtn_tr_xzsl_lavp_ghbsgekwntn}";
int k = 0;
while (k < strlen(c)) {
if(c[k]>96&&c[k]<123){
for (int i = 97; i < 123; i++) {
if (c[k] == b[26 * ((i - 97) % 26) + (a[k % 26] - 97) % 26]) {
printf("%c", i);
break;
}
}
}
else printf("%c", c[k]);
k++;
}
運行程序得到flag:
flag{decrypt_game_is_very_very_interesting}
反思:
本題主要卡在兩個地方:
1.猜測隨機數的種子。
2.猜測&0x200的意義。