CG-ctf re 逆向基礎學習


 

Hello,RE!

下載程序后打開

 

把程序拖進ida 之后F5

查看到了代碼

選中字符串點擊R

可以得到 galfleW{emoc_oT_W_ERdlro}!

emmmm 不是   倒過來

程序結束了

flag{Welcome_To_RE_World!}

 ReadAsm2

給出了一段c代碼

int main(int argc, char const *argv[])
{
  char input[] = {0x0,  0x67, 0x6e, 0x62, 0x63, 0x7e, 0x74, 0x62, 0x69, 0x6d,
                  0x55, 0x6a, 0x7f, 0x60, 0x51, 0x66, 0x63, 0x4e, 0x66, 0x7b,
                  0x71, 0x4a, 0x74, 0x76, 0x6b, 0x70, 0x79, 0x66 , 0x1c};
  func(input, 28);//這里輸入兩個參數,及下面傳入的數組地址及 28
  printf("%s\n",input+1);
  return 0;
}
 
asm文件下載后打開

00000000004004e6 <func>://r開頭的寄存器存64位數據 e開頭的寄存器存32位數據
//↓指令對應的虛擬內存地址
//計算機指令↓
  4004e6: 55                    push   rbp//入棧 將寄存器的值壓入調用bp棧中
  4004e7: 48 89 e5              mov    rbp,rsp//建立新的棧幀,將被調函數的棧幀棧底地址rsp放入rbp 
  
//QWORD是四字 DWORD是雙字 一個字是2個字節(16位) 所以QWORD存儲64位數據 DWORD存儲32位數據 PTR pointer縮寫 即指針 4
004ea: 48 89 7d e8 mov QWORD PTR [rbp-0x18],rdi //rdi [rpb-0x18]處存第一個參數,數組的地址 4004ee: 89 75 e4 mov DWORD PTR [rbp-0x1c],esi //esi [rbp-0x1c]處存第二個參數,28 4004f1: c7 45 fc 01 00 00 00 mov DWORD PTR [rbp-0x4],0x1 //把1寫入[rbp-0x4] 計數器 4004f8: eb 28 jmp 400522 <func+0x3c> //跳轉到400522處 ------------------------------------------------------ 4004fa: 8b 45 fc mov eax,DWORD PTR [rbp-0x4] //[rbp-0x4]的值送入 eax ,即eax=1,取出計數器
4
004fd: 48 63 d0 movsxd rdx,eax   //把計數器值放入 rdx
//movsxd指令為帶符號擴展並傳送 rdx=1
400500: 48 8b 45 e8 mov rax,QWORD PTR [rbp-0x18] //第一個參數 [rbp-0x18],rax=input[0]//取出數組地址 400504: 48 01 d0 add rax,rdx          //rax+=rdx //尋址操作 400507: 8b 55 fc mov edx,DWORD PTR [rbp-0x4] //[rbp-0x4]的值給edx //取出計數器 40050a: 48 63 ca movsxd rcx,edx          //計數器放入rcx
//將edx的值帶符號擴展,並傳送至rcx中 rcx=1 4
0050d: 48 8b 55 e8 mov rdx,QWORD PTR [rbp-0x18] //rdx = input[0]//取出數組地址 400511: 48 01 ca add rdx,rcx //rdx += rcx ,rdx = input[1] //尋址操作 400514: 0f b6 0a movzx ecx,BYTE PTR [rdx] //ecx = input[1]//取出數據放入ecx 400517: 8b 55 fc mov edx,DWORD PTR [rbp-0x4] //edx = 0x1 //edx為計數器 40051a: 31 ca xor edx,ecx //edx與ecx異或 40051c: 88 10 mov BYTE PTR [rax],dl //rax = dl //將異或后的數據放入到原來的位置rax中 40051e: 83 45 fc 01 add DWORD PTR [rbp-0x4],0x1 //計數器加一 -------------------------------------------------------- 400522: 8b 45 fc mov eax,DWORD PTR [rbp-0x4] //讀取[rbp-0x4]//取出計數器
400525: 3b 45 e4 cmp eax,DWORD PTR [rbp-0x1c] //和28進行比較 400528: 7e d0 jle 4004fa <func+0x14> //eax < 28時.跳轉至4004fa
 
40052a: 90 nop                          //空指令
4
0052b: 5d pop rbp              //函數調用結束,彈出棧底指針
4
0052c: c3 ret

匯編太差,感覺匯編代碼還是從下往上看比較好

所以循環異或然后輸出

 

 

 

 Py交易

得到的pyc用NOTEpad++打開后亂碼,把代碼反編譯后得到源代碼  //反編譯網站:https://tool.lu/pyc/

把pyc拖進去

也就是flag

 

代碼很簡單 按照源代碼倒着寫 解一下base64,每個字符ASCII減去16 再與32

 

 WxyVM

打開下載文件

是個ELF文件,

拖進ida。找到main函數 按F5看C代碼

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  char v4; // [rsp+Bh] [rbp-5h]
  signed int i; // [rsp+Ch] [rbp-4h]

  puts("[WxyVM 0.0.1]");
  puts("input your flag:");
  scanf("%s", &byte_604B80);//獲取用戶輸入一個字符串保存在地址604B80的位置. 
  v4 = 1;
  sub_4005B6();//調用了一個函數
  if ( strlen(&byte_604B80) != 24 ) //我們的輸入的flag必須等於24
    v4 = 0;
  for ( i = 0; i <= 23; ++i )
  {
    if ( *(&byte_604B80 + i) != dword_601060[i] )//比較404B80加上i的地址處保存的值必須與601060處的值相等
      v4 = 0;
  }
  if ( v4 )
    puts("correct");
  else
    puts("wrong");
  return 0LL;
}

好了,sub_4005B6()這個函數干啥了,dword_601060是啥。

 

 

雙擊函數直接查看可以看出&byte_604B80 + result   這個函數對我們的輸入進行了運算操作

 通過上圖可以看出,dword_601060是經過sub_4005B6()函數處理后,用來做對比24個16進制數。

__int64 sub_4005B6()
{
  unsigned int v0; // ST04_4    定義無符號整形v0
  __int64 result; // rax        定義64位整數result
  signed int i; // [rsp+0h] [rbp-10h] 
  char v3; // [rsp+8h] [rbp-8h]      

  for ( i = 0; i <= 14999; i += 3 )   //循環5000次 
  {
    v0 = byte_6010C0[i];         
    v3 = byte_6010C0[i + 2];
    result = v0;     
    switch ( v0 )    //根據v0看進哪種運算
    {
      case 1u:
        result = byte_6010C0[i + 1];
        *(&byte_604B80 + result) += v3;  //&byte_604B80 + result 對我們的輸入進行了修改
        break;
      case 2u:
        result = byte_6010C0[i + 1];
        *(&byte_604B80 + result) -= v3;
        break;
      case 3u:
        result = byte_6010C0[i + 1];
        *(&byte_604B80 + result) ^= v3;
        break;
      case 4u:
        result = byte_6010C0[i + 1];
        *(&byte_604B80 + result) *= v3;
        break;
      case 5u:
        result = byte_6010C0[i + 1];
        *(&byte_604B80 + result) ^= *(&byte_604B80 + byte_6010C0[i + 2]);
        break;
      default:
        continue;
    }
  }
  return result;
}

 

 

6010C0是一個長度為15000的數組,每3個分為一組,分別為v0,v3,result.一共5000組。v0是檢測進行哪種運算,一共有5種運算,加減乘異或。result是選擇輸入的哪一位進行運算,v3是運算數。

最后與601060中的數據進行比較。所以解題思路就是用601060中的數據將上面的運算進行逆運算,這樣就可以得到正確輸入。

 

 

那么思路就出來了

可以逆推或者對24位的數據進行爆破

將6010c0處的數組保存下來提取數據

 

 

b =''
c =[]
d =[]
e =[]
s =['0xc4','0x34','0x22','0xb1','0xd3','0x11','0x97','0x7','0xdb','0x37','0xc4','0x6','0x1d','0xfc','0x5b','0xed','0x98','0xdf','0x94','0xd8','0xb3','0x84','0xcc','0x8']

with open('test.txt','r')as f:

whileTrue:
a = f.readline()# 整行讀取數據
if not a:
break

b += a[:24]+a[25:]

for i in range(0,len(b),9):

c.append(int(b[i:i+2]))

d.append(int(b[i+3:i+5],16))

e.append(int(b[i+6:i+8],16))

defrplus(s,x,y):

    s[x]=(s[x]+y)%2**8

defrsub(s,x,y):
    s[x]=(s[x]- y)%2**8
    defrxor(s,x,y):
    s[x]=(s[x]^y)%2**8

defcase(s,i,x,y):
    if i ==1:
        rplus(s,x, y)
    elif i ==2:
        rsub(s,x, y)

    elif i ==3:
        rxor(s,x, y)
count =0

flag =[0for i in range(24)]
result =''
    for k in range(24):
        for j in range(33,128):
            flag[k]= j
            for i in range(len(c)):
                case(flag,c[i], d[i], e[i])
                if hex(flag[k])==s[k]:
                        result += chr(j)
                        print chr(j)
                        break
                        print result 

逆推:

 

tmp=[1,  16,  37,   3,  13,  10,   2,  11,  40,   2............... ]   

final=[196, 52, 34, 177, 211, 17,   151, 7,   219,   55,
       196, 6,  29,  252, 91, 237, 152,  223, 148,  216,
       179,  132,   204, 8]
i = 14997
while i>0:
v0 = tmp[i]
v3 = tmp[i+2]

result =  tmp[i+1]
if v0 == 1:
    final[result] -= v3
elif v0 == 2:
    final[result] += v3
elif v0 == 3:
    final[result] ^= v3
elif v0 == 4:
    final[result] /= v3!
elif v0 == 5:
    final[result] ^= final[v3]

final[result]&=0xFF     //需要注意的地方,因為ascii字符碼范圍為0~127,可能發生越界
i -= 3

for x in final:
    print(chr(x), end = '')

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM