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縮寫 即指針
4004ea: 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,取出計數器
4004fd: 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
40050d: 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 //空指令
40052b: 5d pop rbp //函數調用結束,彈出棧底指針
40052c: 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 = '')