昨天線下賽的復盤
這次最大的感受:Re做題的時候不要啥都沒分析出來就去寫代碼,不要覺得自己寫著寫著就能看懂,不可能的,不如先分析好,即使是先猜一下呢,還有就是測試數據不要寫0,會和本身就是空的數據混了
Re1
分最少的一題,附件很大而且F12全是Py開頭的

斷定是python逆向:
pyinstxtractor拆exe程序:

一般情況下,需要找和附件同名的pyc文件進行反編譯,但是沒找到,比較可疑的是src這個
用pycdc進行反編譯:
# Source Generated with Decompyle++
# File: src.pyc (Python 3.10)
import hashlib
def get_user_input():
user_input = input('請輸入: ').strip()
if len(user_input) != 9:
print('你的輸入存在錯誤!')
continue
if not user_input.isdigit():
print('你的輸入存在錯誤!')
continue
return user_input
def check_md5_match(user_input, target_hash):
input_md5 = hashlib.md5(user_input.encode()).hexdigest()
if input_md5 == target_hash:
return True
def main():
TARGET_HASH = 'b4bb721a74f07177a6dbc3e113c327e3'
user_input = get_user_input()
is_match = check_md5_match(user_input, TARGET_HASH)
if is_match:
flag = "flag{md5(user_input + 'SDnisc')}"
print('驗證成功!')
print(f'''Flag: {flag}''')
return None
None('驗證失敗!')
if __name__ == '__main__':
main()
return None
可以看出,首先會對input的內容去除回車和空格/制表符那種
if not user_input.isdigit():其次,不能存在字母,長度為9,進行md5值計算,然后和給出的md5進行比較
所以,結論很明確了,我們只需要進行9位純數字的md5爆破就可以。
我們當然可以用python寫個腳本。但事實證明特別慢,不如用hashcat掩碼爆破
hashcat -a 3 b4bb721a74f07177a6dbc3e113c327e3 ?d?d?d?d?d?d?d?d?d -m 0
這里就不進行爆破了,直接給了

然后直接后面加上SDisc,進行md5就是flag
Re2
比較繞,但是比賽還是可以做的(雖然我最后卡死在這上面了)

大體看一下,去關注569D那個函數,這是主要的加密函數
但在那之前,我先寫一下數據加載的函數

你會發現,所有數據都是在src后76位上開始向后延申數據的,srca是在src的最后,也就是116位以后的160個字節空間內

這個函數傳入了兩個值,一個是enc,也就是加密好的flag,另一個是寫進去的flag
首先是判斷長度,這里就不詳細看了

我感覺這里是最能誤導人的點,它把寫入的flag的值賦給了加密好的flag?但是實質上,enc的前76位是空的,所以寫這個完全沒有問題
然后是逐字節加密,每個字節加密40次,第一次加密的時候,傳入第一個值的地點是4*28+4=116,很熟悉的位置吧?

剩下的就是很亂的加密過程了,這里不詳細贅述

這里說一下,誤導我的點:

還是太菜了,被位運算卡住了,這里其實畫個圖會比較清晰,這里相當于左移n2位,然后將溢出的n2位移動到最后,所以我們寫逆向代碼的時候就要反過來(其實只需要把輸入的鍵反過來就行)
這里貼一下手寫的腳本,感覺要比ai給的清晰一點
# 本腳本是鵬云杯逆向第三個題,相當于第二個簡單的題吧(一共就仨)
# 嘗試手寫python腳本
key = [0x3, 0x5, 0x1, 0x6, 0x2, 0x4, 0x5, 0x6, 0x3, 0x1, 0x2, 0x5, 0x4, 0x6, 0x1, 0x3, 0x2, 0x5, 0x4, 0x6, 0x1, 0x3, 0x2, 0x5, 0x4, 0x6, 0x1, 0x3, 0x5, 0x2, 0x4, 0x6, 0x1, 0x3, 0x2, 0x5, 0x4, 0x6, 0x1, 0x3]
enc = [0xB4, 0xB6, 0x9F, 0xA1, 0xC5, 0xAD, 0x7A, 0x68, 0x77, 0xAD, 0x7B, 0x70, 0x1D, 0x68, 0x70, 0x7B, 0x76, 0x70, 0xA0, 0x7C, 0x1D, 0xAE, 0x7B, 0x77, 0xB4, 0x7C, 0xAE, 0xB4, 0x68, 0xA0, 0x68, 0xF9, 0x76, 0xB3, 0x70, 0x77, 0x9F, 0xBA]
def switchEnc(en , key):
match key:
case 1:
en = (en ^ 5) & 0xFF
case 2:
en = (en - 1) & 0xFF
case 3:
en = (en + 1 )& 0xFF
case 4:
en = case4(en)
case 5:
en = case5(en, 1)
case _:
en = case6(en ,1)
return en
def case4(en1):
# en2 = case5(en1 + 3, 2)
# return (case6(en2 - 2, 2) - 1) & 0xFF
en2 = (case6((en1 + 1) & 0xFF ,2) + 2) & 0xFF
return (case5(en2, 2) - 3) & 0xFF
def case5(en1 ,n2):
n2 &= 7
en1 = en1 >> (n2 % 8) | en1 <<(8 - n2 % 8)
return en1 & 0xFF
def case6(en1 ,n2):
n2 &= 7
en1 = en1 << (n2 % 8) | en1 >>(8 - n2 % 8)
return en1 & 0xFF
print(len(enc))
for i in range(len(enc)):
for j in key[::-1]:
enc[i] = switchEnc(enc[i] , j)
print(chr(enc[i]),end="")
對于溢出問題:我的建議是把所有加法后面都加上防止溢出的&FF

浙公網安備 33010602011771號