1. 程式人生 > 其它 >2021CISCN-逆向-galss復現及總結

2021CISCN-逆向-galss復現及總結

一、apk檔案逆向

  沒有接觸過app開發,臨時學習:

 1.apk檔案逆向工具:jadx 、jeb 、jd-gui

選擇jadx的gui工具,反編譯apk檔案(程式碼閱讀為請教tx,app開發需要補課)

在主活動中檢視主要的程式碼,

大致邏輯為在主活動中通過checkflag()函式對使用者的輸入進行比較,一致則right,而loadlibrary("native-lib")則說明了checkflag函式在某個so檔案中,可以在資原始檔下找到:

只需要反編譯so檔案完成逆向既可以找到flag。

將.apk字尾更改為.zip,解壓縮,在資料夾中可以拿到libnative-lib.so檔案

拖入ida進行分析。

分析checkflag()函式

二、異或逆向

自下往上進行解密,第一個加密函式是對傳入的值完成異或加密

提取出最後的結果

unsigned char result[] =
{
  0xA3, 0x1A, 0xE3, 0x69, 0x2F, 0xBB, 0x1A, 0x84, 0x65, 0xC2, 
  0xAD, 0xAD, 0x9E, 0x96, 0x05, 0x02, 0x1F, 0x8E, 0x36, 0x4F, 
  0xE1, 0xEB, 0xAF, 0xF0, 0xEA, 0xC4, 0xA8, 0x2D, 0x42, 0xC7, 
  0x6E, 0x3F, 0xB0, 0xD3, 0xCC, 0x78, 0xF9, 0x98, 0x3F
};

復現一下異或加密過程

key='12345678'
result[k]=result[k]^key[k%8]

for(i=0;i<len(result);i+=3){
  result[i]=result[i]^result[i+2];
  result[i+2]=result[i+2]^result[i+1]
  result[i+1]=result[i+1]^result[i]^result[i+2]
}
此異或過程的逆向分析如下:
以前三位舉例
new_r[0]=old_r[0]^old_r[2]
new_r[2]=old_r[2]^old_r[1]
new_r[1]=old_r[1]^old_r[0]^old_r[2]
//new是已知的,old是待求的

new_r[1]=old_r[1]^new_r[0]
=>
old_r[1]=new_r[1]^new_r[0]

new_r[2]=old_r[2]^old_r[1]  //old_r[1]在上一步後為已知
=>
old_r[2]=old_r[1]^new_r[2]

new_r[0]=old_r[0]^old_r[2]  //old_r[2]在上一步後為已知
=>
old_r[0]=new_r[0]^old_r[2]

 解密指令碼:

 for i in range(0,39,3):
        res[i+1]=res[i+1]^res[i]
        res[i+2]=res[i+2]^res[i+1]
        res[i]=res[i]^res[i+2]

#應當注意異或運算的逆向過程,核心是把握對稱性,其次要關注在多次的異或運算中後面的值是使用的新值還是舊值

三、RC4

後面兩個函式,可以看出是RC4加密演算法,

第一個為S表、T表的初始化,第二個函式為加密過程,注意RC4為對稱加密,只需要按照虛擬碼的邏輯正著實現即可

res=[0xA3,0x1A,0xE3,0x69,0x2F,0xBB,0x1A,0x84,
0x65,0xC2,0xAD,0xAD,0x9E,0x96,0x05,0x02,
0x1F,0x8E,0x36,0x4F,0xE1,0xEB,0xAF,0xF0,
0xEA,0xC4,0xA8,0x2D,0x42,0xC7,0x6E,0x3F,
0xB0,0xD3,0xCC,0x78,0xF9,0x98,0x3F]

key='12345678'
s=[0]*256
t=[0]*256

def rc4_init():
    global s
    global t
    global key
    
    for i in range(0,256):
        s[i]=i
        t[i]=ord(key[i%8])
    v9=0
    for i in range(0,256):
        middle=s[i]
        v9=(v9+s[i]+t[i])%256
        s[i]=s[v9]
        s[v9]=middle

def rc4_encrpto():
    v4=0
    v3=0
    v5=0
    global s
    global res
    for i in range(0,38):
        v4=(v4+1)%256
        v5=s[v4]
        v3=(v3+s[v4])%256
        s[v4]=s[v3]
        s[v3]=s[v5]
        res[i]^=s[(v5+s[v4])%256] 

參考:rc4:帶你學加密丨RC4 (qq.com)

#注意識別RC4的加密特徵,初始化的S表和T表(迴圈交換位置),初始化和加密都有個明顯的swap()過程;另外注意對稱加密的解密過程,演算法一致

四、python寫解題指令碼的收穫

res=[0xA3,0x1A,0xE3,0x69,0x2F,0xBB,0x1A,0x84,
     0x65,0xC2,0xAD,0xAD,0x9E,0x96,0x05,0x02,
     0x1F,0x8E,0x36,0x4F,0xE1,0xEB,0xAF,0xF0,
     0xEA,0xC4,0xA8,0x2D,0x42,0xC7,0x6E,0x3F,
     0xB0,0xD3,0xCC,0x78,0xF9,0x98,0x3F]

key='12345678'
s=[0]*256
t=[0]*256
def rc4_init():
    global s
    global t
    global key
    
    for i in range(0,256):
        s[i]=i
        t[i]=ord(key[i%8])
    v9=0
    for i in range(0,256):
        middle=s[i]
        v9=(v9+s[i]+t[i])%256
        s[i]=s[v9]
        s[v9]=middle
    print('s:',s)

def rc4_encrpto():
    v4=0
    v3=0
    v5=0
    global s
    global res
    for i in range(0,38):
        v4=(v4+1)%256
        v5=s[v4]
        v3=(v3+s[v4])%256
        s[v4]=s[v3]
        s[v3]=s[v5]
        res[i]^=s[(v5+s[v4])%256]

        
if __name__=='__main__':
    flag=''
    for j in range(0,39):
        res[j]=res[j]^ord(key[j%8])
    print(res)
    for i in range(0,39,3):
        res[i+1]=res[i+1]^res[i]
        res[i+2]=res[i+2]^res[i+1]
        res[i]=res[i]^res[i+2]
        
    print('old res:',res)
    rc4_init()
    rc4_encrpto()
    
    for i in range(len(res)):
        flag+=chr(res[i])
    print('now res:',res)
    print(flag)
    
    

  #注意使用global關鍵字來定義全域性變數

  #if __name__=='__main__':定義主函式

  #格外注意python中的資料型別轉換,key='12345678',在運算中使用到的key[i]均是使用的字元所對應的ascall碼,

    ord()和chr()函式可以實現字元和物件ascall碼之間的轉換。