[逆向學習] BUUOJ 第二彈
1.Java逆向解密
工具:jd-gui
拖入jd-gui得到加密函式 public static void Encrypt(char[] arr)
易得出是將使用者輸入加上‘@’^0x20的值再與KEY比較是否相等。
0x20為16進位制,異或時要轉換為10進位制即32
可寫出指令碼:
key=[180, 136, 137, 147, 191, 137, 147, 191, 148, 136, 133, 191, 134, 140, 129, 135, 191, 65]
a=''
for i in key:
a += chr(i - ord('@')^32)
print (a)
解得 This_is_the_flag_!
2.[BJDCTF2020]BJD hamburger competition
工具:dnSpy,C#線上ide
下載開啟壓縮包,發現是以unity為框架的小遊戲,直接搜尋Assembly-CSharp.dll檔案,拖入dnspy進行反編譯,找到關鍵類函式 ButtonSpawnFruit .發現關鍵程式碼
找個網站解密雜湊值得:
接著就是進行MD5加密,跟進函式。
一開始看不太懂,直接就用c#線上ide把這段程式碼搬上去。
後來查到是呼叫系統md5加密函式後將字母全部轉換為大寫,再取前20個字元作為結果返回.得到md5加密後的結果,注意是用flag{}包上,而不是BJDCTF{} 。
3.[HDCTF2019]Maze
工具:Exeinfo pe,upx,IDA
拖入Exeinfo pe,發現是一個加了upx殼的32位程式,走個流程脫殼。
拖入IDA中尋找start函式,跟進main。
發現main沒有被ida識別成函式,看樣子是被加花指令了。
注意到_mian中有個jnz跳轉,前面有個cmp,且跳轉地址和與指令相鄰的下一地址相同,所以相當於沒跳轉,把他nop掉。
因為下面call另一個不是地址的地址,所以將反編譯程式碼轉換成機器碼來看看。
其中
E8
對應指令為 call
58
對應指令為 pop
當ida把E8
識別為call時,58 C7 45 EC
便會被看作地址,此地址不存在便會無法反彙編,因此真正的指令應該是pop,所以把db 0E8h
接著按p將_mian轉換為函式再進行反彙編。跟進 dword_408078和 dword_40807C檢視到初始狀態:dword_408078=7 dword_40807C=0,然後經過14次移動後要使 dword_408078=5 dword_40807C=-4才能解出答案。
結合程式碼和題目名字Maze可得是一道迷宮題,但是程式好像沒有判斷迷宮。只要滿足兩個a和四個s就可以得到Congratulations!
用ida搜尋一下字串,處理一下得到資料
整理一下
*******+**
******* **
**** **
** *****
** **F****
** ****
**********
因為dword_408078=7 dword_40807C=0,所以是+為起點,F為中點,且ad控制左右,ws控制上下。又因為
a --dword_408078
d ++dword_408078
s --dword_40807C
w ++dword_40807C
所以s是上,w是下,a是右,d是左。
若迷宮為正向,則行走路徑為wwdddwddwwaaas;若迷宮為反向,則行走路徑為ssaaasaassdddw。
先驗證一下.
排除正向迷宮,提交一下:flag{ssaaasaassdddw}
4.[GKCTF2020]BabyDriver
工具:IDA
根據題目描述,拖入IDA64中。看來看去沒有頭緒,搜下字串,估計是個迷宮題
跟進字串,發現一共有224個字元,猜測是16*
14 或 14*
16,寫個指令碼驗證一下
list = '****************o.*..*......*..**.**...**.*.*.***.****.**.*.*.***...**....*.*.*****..***.**.*..**.**.***.**.**.**.**.******.**.**.**....***.**.**.*****.***....**...***.**********..***......#****.***************************** '
a = 0
for i in range(len(list)):
a = a + 1
print(list[i], end='')
if a % 16 == 0:
print('\n', end='')
得到
****************
o.*..*......*..*
*.**...**.*.*.**
*.****.**.*.*.**
*...**....*.*.**
***..***.**.*..*
*.**.***.**.**.*
*.**.******.**.*
*.**....***.**.*
*.*****.***....*
*...***.********
**..***......#**
**.*************
****************
跟進a0,並檢視交叉引用列表。
跟進sub_140001380進行反編譯。得到關鍵程式碼,先分析好分析。
v9 = aO[v5];
if ( v9 == '*' )
{
v10 = "failed!\n";
}
else
{
if ( v9 != '#' )
{
LABEL_27:
aO[v5] = 'o'; //更新位置
goto LABEL_28;
}
v10 = "success! flag is flag{md5(input)}\n";
}
dword_1400030E4 = 16;
DbgPrint(v10);
v5 = dword_1400030E4;
goto LABEL_27;
}
}
可知當碰到*時結束。碰到#時,你所輸入的值md5加密後就是flag。
再來分析輸入判斷。由於是驅動檔案,所以輸入比較的是16進位制的鍵盤碼
LABEL_28:
v6 += 6;
if ( !--v7 )
goto LABEL_29;
}
aO[v5] = 46;
v8 = *v6;
if ( *v6 == 0x17 ) // I
{
if ( v5 & 0xFFFFFFF0 ) // 當V5>16,條件成立,因為是向上。所以不用考慮208這倒數第二層的邊界
{
v5 -= 16; //上移
goto LABEL_21;
}
v5 += 208; // 當V5<16也就是在第一層,強制碰到最後一層牆壁結束
dword_1400030E4 = v5;
}
if ( v8 == 0x25 ) // K
{
if ( (v5 & 0xFFFFFFF0) != 208 ) // 當V5>16且不等於208,條件成立,因為是向下。所以要考慮208這倒數第二層的邊界
{
v5 += 16; //下移
goto LABEL_21;
}
v5 -= 208; // 當v5=208,強制碰到第一層牆壁結束
dword_1400030E4 = v5;
}
if ( v8 == 0x24 ) // J
{
if ( v5 & 15 ) //當v5不等於16的倍數時,即不在每一層的左邊界,條件成立
{
--v5; //左移
goto LABEL_21;
}
v5 += 15; //當v5等於16的倍數時,即在某一層的左邊界 ,向右移15位,即移動到這一層的右邊界
dword_1400030E4 = v5;
}
if ( v8 != 0x26 ) // L
goto LABEL_22;
if ( (v5 & 15) == 15 ) //當v5等於16的倍數-1時,即在某一層的右邊界,條件成立
v5 -= 15; //向左移15位,即移動到這一層的左邊界
else
++v5; //右移
LABEL_21:
dword_1400030E4 = v5;
所以,根據上面的迷宮和程式碼的分析:
若為正向迷宮,則行走路徑為 LKKKLLKLKKKLLLKKKLLLLLL;
若為反向迷宮,則行走路徑為 JIIIJJIJIIIJJJIIIJJJJJJ。
然後進行md5 32位小寫加密,進行驗證,可得到只有正向才是對的,即flag{403950a6f64f7fc4b655dea696997851} 。