日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

REVERSE-COMPETITION-HGAME2022-Week4

發布時間:2023/12/10 编程问答 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 REVERSE-COMPETITION-HGAME2022-Week4 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

REVERSE-COMPETITION-HGAME2022-Week4

    • ( WOW )
    • server
    • ezvm
    • hardasm

( WOW )

32位exe,ida打開
觀察偽代碼邏輯,上面的紅框中,輸入經過加密,密文放入Buf2中,然后Buf2和已知的密文res比較
比較完,打印"win"或者"error"
發現下面還有一部分對Buf2處理的代碼邏輯,而且幾乎和上面對輸入加密的結構是一樣的
于是猜測下面的紅框中就是解密邏輯

起調試,隨便構造一個長度為32的輸入
在調用memcmp前下斷,將內存中Buf2的數據patch成已知的密文res
進行下面對Buf2的解密,解密后的input即為flag

server

64位exe,用ida7.7打開
(52pojie上有最新的全插件綠色版ida7.7可供下載)
從main函數中知道監聽本地的9090端口
回調函數為main_HttpHandleFunc,調試發現,輸入經過main_encrypt處理后,與已知的res比較

進入main_encrypt函數,偽代碼看不出什么,玄機在匯編指令
可以發現main_encrypt的前半部分實際上是個RSA加密,并且已知p,q,e

輸入經rsa加密后,將十進制密文的每一個數字轉成字符存入rsa_cipher中
然后進行后半部分的兩輪異或運算,異或后的結果與已知的res比較

這里舉一個例子來理解后半部分的兩輪異或運算,以便能夠更好地逆向

# -*- coding:utf-8 -*- import gmpy2 num1=92582184765240663364795767694262273105045150785272129481762171937885924776597#p num2=107310528658039985708896636559112400334262005367649176746429531274300859498993#q num1_mul_num2=num1*num2#n num3=950501#e my_in_s="hgame{abcdefghijklmnopqrstuvwxy}"#構造的輸入 my_in=0x6867616d657b6162636465666768696a6b6c6d6e6f707172737475767778797d my_in_cipher=gmpy2.powmod(my_in,num3,num1_mul_num2)#rsa加密 my_in_cipher_s=str(my_in_cipher) print("RSA加密后的十進制密文:") print(my_in_cipher_s) print("RSA加密后的十進制密文長度:") print(len(my_in_cipher_s)) #模擬main_encrypt中后半部分的兩輪異或運算 res=[] for i in range(len(my_in_cipher_s)-1):res.append(ord(my_in_cipher_s[i])) print("十進制密文的每一個數字轉成字符:") print(res) v22=102 index=0 while index<153:tmp=res[index]res[index]^=v22v22=tmpindex+=1 print("第一輪異或運算結果:") print(res) index=0 while index<153:tmp=res[index]res[index]^=v22v22=tmpindex+=1 print("第二輪異或運算結果:") print(res) # RSA加密后的十進制密文: # 2315576653393559402200063691755666172531457200527539170715551199511112051176056764826673635703056993058028383465485142593456001504496707046294726739445446 # RSA加密后的十進制密文長度: # 154 # 十進制密文的每一個數字轉成字符:(后面用cipher表示) # [50, 51, 49, 53, 53, 55, 54, 54, 53, 51, 51, 57, 51, 53, 53, 57, 52, 48, 50, 50, 48, 48, 48, 54, 51, 54, 57, 49, 55, 53, 53, 54, 54, 54, 49, 55, 50, 53, 51, 49, 52, 53, 55, 50, 48, 48, 53, 50, 55, 53, 51, 57, 49, 55, 48, 55, 49, 53, 53, 53, 49, 49, 57, 57, 53, 49, 49, 49, 49, 50, 48, 53, 49, 49, 55, 54, 48, 53, 54, 55, 54, 52, 56, 50, 54, 54, 55, 51, 54, 51, 53, 55, 48, 51, 48, 53, 54, 57, 57, 51, 48, 53, 56, 48, 50, 56, 51, 56, 51, 52, 54, 53, 52, 56, 53, 49, 52, 50, 53, 57, 51, 52, 53, 54, 48, 48, 49, 53, 48, 52, 52, 57, 54, 55, 48, 55, 48, 52, 54, 50, 57, 52, 55, 50, 54, 55, 51, 57, 52, 52, 53, 52, 52] # 第一輪異或運算結果:(后面用round_1表示) # [84, 1, 2, 4, 0, 2, 1, 0, 3, 6, 0, 10, 10, 6, 0, 12, 13, 4, 2, 0, 2, 0, 0, 6, 5, 5, 15, 8, 6, 2, 0, 3, 0, 0, 7, 6, 5, 7, 6, 2, 5, 1, 2, 5, 2, 0, 5, 7, 5, 2, 6, 10, 8, 6, 7, 7, 6, 4, 0, 0, 4, 0, 8, 0, 12, 4, 0, 0, 0, 3, 2, 5, 4, 0, 6, 1, 6, 5, 3, 1, 1, 2, 12, 10, 4, 0, 1, 4, 5, 5, 6, 2, 7, 3, 3, 5, 3, 15, 0, 10, 3, 5, 13, 8, 2, 10, 11, 11, 11, 7, 2, 3, 1, 12, 13, 4, 5, 6, 7, 12, 10, 7, 1, 3, 6, 0, 1, 4, 5, 4, 0, 13, 15, 1, 7, 7, 7, 4, 2, 4, 11, 13, 3, 5, 4, 1, 4, 10, 13, 0, 1, 1, 0] # 第二輪異或運算結果:(后面用round_2表示) # [96, 85, 3, 6, 4, 2, 3, 1, 3, 5, 6, 10, 0, 12, 6, 12, 1, 9, 6, 2, 2, 2, 0, 6, 3, 0, 10, 7, 14, 4, 2, 3, 3, 0, 7, 1, 3, 2, 1, 4, 7, 4, 3, 7, 7, 2, 5, 2, 2, 7, 4, 12, 2, 14, 1, 0, 1, 2, 4, 0, 4, 4, 8, 8, 12, 8, 4, 0, 0, 3, 1, 7, 1, 4, 6, 7, 7, 3, 6, 2, 0, 3, 14, 6, 14, 4, 1, 5, 1, 0, 3, 4, 5, 4, 0, 6, 6, 12, 15, 10, 9, 6, 8, 5, 10, 8, 1, 0, 0, 12, 5, 1, 2, 13, 1, 9, 1, 3, 1, 11, 6, 13, 6, 2, 5, 6, 1, 5, 1, 1, 4, 13, 2, 14, 6, 0, 0, 3, 6, 6, 15, 6, 14, 6, 1, 5, 5, 14, 7, 13, 1, 0, 1]

我們可以發現
round_1[0]=102 xor cipher[0],round_1[1]=cipher[0] xor cipher[1],依次類推(這里的102是已知的
round_2[0]=52 xor round_1[0],round_2[1]=round_1[0] xor round_1[1],依次類推
這里的52實際上等于cipher[len(cipher)-1],也就是cipher的最后一個值
但是由于cipher是RSA加密后的密文,所以其實cipher[len(cipher)-1]是未知的
想要逆向兩輪異或運算從而得到正確的RSA密文
需要爆破cipher[len(cipher)-1],范圍是十進制數字字符

# -*- coding:utf-8 -*- import gmpy2 from Crypto.Util.number import long_to_bytes # res 相當于 round_2 res=[0x63,0x55,0x4,0x3,0x5,0x5,0x5,0x3,0x7,0x7,0x2,0x8,0x8,0xb,0x1,0x2,0xa,0x4,0x2,0xd,0x8,0x9,0xc,0x9,0x4,0xd,0x8,0x0,0xe,0x0,0xf,0xd,0xe,0xa,0x2,0x2,0x1,0x7,0x3,0x5,0x6,0x4,0x6,0x7,0x6,0x2,0x2,0x5,0x3,0x3,0x9,0x6,0x0,0xb,0xd,0xb,0x0,0x2,0x3,0x8,0x3,0xb,0x7,0x1,0xb,0x5,0xe,0x5,0x0,0xa,0xe,0xf,0xd,0x7,0xd,0x7,0xe,0x1,0xf,0x1,0xb,0x5,0x6,0x2,0xc,0x6,0xa,0x4,0x1,0x7,0x4,0x2,0x6,0x3,0x6,0xc,0x5,0xc,0x3,0xc,0x6,0x0,0x4,0xf,0x2,0xe,0x7,0x0,0xe,0xe,0xc,0x4,0x3,0x4,0x2,0x0,0x0,0x2,0x6,0x2,0x3,0x6,0x4,0x4,0x4,0x7,0x1,0x2,0x3,0x9,0x2,0xc,0x8,0x1,0xc,0x3,0xc,0x2,0x0,0x3,0xe,0x3,0xe,0xc,0x9,0x1,0x7,0xf,0x5,0x7,0x2,0x2,0x4] p=92582184765240663364795767694262273105045150785272129481762171937885924776597 q=107310528658039985708896636559112400334262005367649176746429531274300859498993 n=p*q e=950501 phin=(p-1)*(q-1) d=gmpy2.invert(e,phin) # i 相當于 cipher[len(cipher)-1],爆破的目標 for i in range(0x30,0x3a):tmp1=[res[0]^i] # tmp1 相當于 round_1for j in range(1,len(res)):tmp1.append(res[j]^tmp1[j-1])tmp2=[tmp1[0]^102]# tmp2 相當于 cipherfor j in range(1,len(tmp1)):tmp2.append(tmp1[j]^tmp2[j-1])wrong=0for m in tmp2: # cipher 中每個元素都必須是十進制數字字符if m<0x30 or m>0x39:wrong=1breakif wrong:continueif i==tmp2[len(tmp2)-1]:# 驗證爆破的目標和還原出來的cipher[len(cipher)-1]是否相同cipher=""for k in tmp2:cipher+=chr(k)cipher_num=int(cipher)m=gmpy2.powmod(cipher_num,d,n)# RSA解密print(long_to_bytes(m)) # hgame{g0_and_g0_http_5erv3r_nb}

ezvm

vm,調試確定輸入的長度應為32
對輸入的處理邏輯為:輸入的每個字符,左移1位,和一個值異或,然后比較
構造一個長度為32的輸入,得到經程序處理后的結果
逆向對輸入的處理邏輯,得到輸入的每個字符左移1位后,要去異或的值的集合
最后由真正的密文爆破出flag

# -*- coding:utf-8 -*- s="hgame{abcdefghijklmnopqrstuvwxy}"# 對輸入的處理邏輯:輸入的每個字符,左移1位,和一個值異或,然后比較print(hex((ord("h")<<1)^0x5e))# 0x8e print(hex((ord("g")<<1)^0x46))# 0x88# my_res: 構造的輸入s,經過程序處理后的結果 my_res=[0x8e,0x88,0xa3,0x99,0xc4,0xa5,0x8b,0xdb,0x97,0x96,0xfc,0xfb,0xe7,0x91,0xb1,0xef,0xb2,0xe3,0xcf,0xc4,0x85,0xde,0xc0,0xb4,0xa0,0xb6,0xdf,0xa2,0xad,0xd3,0x92,0xc1] # 逆向對輸入的處理邏輯,得到輸入的每個字符左移1位后,要去異或的值的集合 xor_box=[] for i in range(len(s)):tmp=(ord(s[i])<<1)&0xffxor_box.append(tmp^my_res[i])# res: 真正的密文 res=[0x8e,0x88,0xa3,0x99,0xc4,0xa5,0xc3,0xdd,0x19,0xec,0x6c,0x9b,0xf3,0x1b,0x8b,0x5b,0x3e,0x9b,0xf1,0x86,0xf3,0xf4,0xa4,0xf8,0xf8,0x98,0xab,0x86,0x89,0x61,0x22,0xc1] flag="" for i in range(len(res)):for j in range(32,128):if (j<<1)^xor_box[i]==res[i]:flag+=chr(j) print(flag) # hgame{Ea$Y-Vm-t0-PrOTeCT_cOde!!}

hardasm

近7000行的匯編指令,應該是有什么地方設計得很巧妙
起調試,構造一個長度為32的輸入"hgame{abcdefghijklmnopqrstuvwxy}"
在如下位置下斷點

程序斷下后,觀察此時[rsp+70h+var_50]上的數據
可以發現,前6個數據均為非0的0xFF,而后面的數據均為0
這是因為我們構造的輸入的前6個字符"hgame{“是正確的,而后面湊長度的字符是錯誤的

于是我們可以知道
可以通過[rsp+70h+var_50]上連續的0xFF的個數n,確定我們的輸入前n個字符是正確的
那么怎么知道[rsp+70h+var_50]上連續的0xFF的個數n呢?我們需要能夠打印的函數
程序最后會打印"success"或者"error”,我們可以利用這個打印函數
從框住的匯編指令處可以觀察到,我們的目標數據地址是借rcx寄存器傳入打印函數的

于是我們patch程序,將[rsp+70h+var_50]借rcx傳入打印函數,如下
(這里不知道怎么能直接實現lea rcx,[rsp+70h+var_50],如果有師傅知道,請在評論區留言,謝謝)

這樣程序在最后就不會打印"success"或者"error",而會打印[rsp+70h+var_50]上的數據
將patch應用到程序后,再起調試,同樣的輸入,在調用打印函數printf后下斷,觀察打印出的內容
可以看到雖然沒有打印出具體的字符(因為0xFF不可見),但是長度是正確的,為6

或者可以用python來確認

import subprocess flag="hgame{abcdefghijklmnopqrstuvwxy}" p = subprocess.Popen(["D:\\ctfdownloadfiles\\hardasm.exe"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) p.stdin.write(flag.encode()) p.stdin.close() out = p.stdout.read() print(len(out)) for c in out:print(hex(c)) # 6 # 0xff # 0xff # 0xff # 0xff # 0xff # 0xff

最后就是依次爆破每個位置上的字符
根據程序打印出的連續的0xFF的個數來確定某位置上的字符是否正確

# -*- coding:utf-8 -*- import subprocess real_flag="hgame{"#絕對正確的前6個字符 cur_index=6#當前爆破的位置 while cur_index<32:for i in range(32,128):#當前爆破的位置上的字符real_flag_arr = [0] * 32for j in range(len(real_flag)):#正確的先復制一下real_flag_arr[j]=ord(real_flag[j])real_flag_arr[len(real_flag_arr)-1]=ord("}")#最后一個字符"}"固定for j in range(len(real_flag_arr)-2,cur_index,-1):#除了當前爆破的位置,其他位置上都設置為32real_flag_arr[j]=32real_flag_arr[cur_index]=i#設置當前爆破的位置上的字符real_flag_arr_s="".join(chr(k) for k in real_flag_arr)#輸入到程序中的字符串p = subprocess.Popen(["D:\\ctfdownloadfiles\\hardasm.exe"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)p.stdin.write(real_flag_arr_s.encode())p.stdin.close()out = p.stdout.read()if len(out)>cur_index:#判斷程序打印出的0xFF的個數是否增加,增加則說明當前爆破的位置上的字符設置的是正確的real_flag+=chr(i)cur_index+=1print(real_flag)break # hgame{r # hgame{ri # hgame{rig # hgame{righ # hgame{right # hgame{right_ # hgame{right_y # hgame{right_yo # hgame{right_you # hgame{right_your # hgame{right_your_ # hgame{right_your_a # hgame{right_your_as # hgame{right_your_asm # hgame{right_your_asm_ # hgame{right_your_asm_i # hgame{right_your_asm_is # hgame{right_your_asm_is_ # hgame{right_your_asm_is_g # hgame{right_your_asm_is_go # hgame{right_your_asm_is_goo # hgame{right_your_asm_is_good # hgame{right_your_asm_is_good! # hgame{right_your_asm_is_good!! # hgame{right_your_asm_is_good!!} # hgame{right_your_asm_is_good!!} 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的REVERSE-COMPETITION-HGAME2022-Week4的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。