REVERSE-PRACTICE-BUUCTF-12
- [FlareOn3]Challenge1
- [GUET-CTF2019]number_game
- [GWCTF 2019]re3
- [網鼎杯 2020 青龍組]singal
[FlareOn3]Challenge1
exe程式,運行后提示輸入密碼,輸入錯誤退出程式,無殼,ida分析
main函式邏輯清晰,讀取輸入,對輸入進行變表base64編碼,驗證編碼結果

之前遇到過變表base64的題目,見REVERSE-PRACTICE-BUUCTF-7或REVERSE-PRACTICE-BUUCTF-10或base64原理及其編解碼的python實作
這道題用一個工具,加密解密小玩具,來解,非常方便

[GUET-CTF2019]number_game
elf檔案,無殼,ida分析
main函式,獲取輸入,檢驗輸入長度是否為10且均為0~4的數字,先后經過先序遍歷和中序遍歷改變輸入中各個字符的位置,再順序地放入數獨“#”位置,最后檢驗數獨

sub_400758函式和sub_400807函式先后經過先序遍歷和中序遍歷改變輸入中各個字符的位置,本人一直想不通,于是動調,當輸入為0123456789時,sub_400807函式呼叫結束后的v7為7381940526,于是可以知道輸入中字符位置變換的規律
變換前的下標:0 1 2 3 4 5 6 7 8 9
變換后的下標:7 3 8 1 9 4 0 5 2 6
再解數獨,在sub_400917函式中可知為5x5的數獨

寫代碼換成正確的位置即可得到flag

由于輸入長度只有10位,且均為0~4的數字,也可以寫腳本爆破得到flag
[GWCTF 2019]re3
elf檔案,無殼,ida分析
main函式,讀取輸入,檢驗輸入長度是否為32,有一段SMC,自修改代碼

ida靜態分析,先寫idapython腳本完成smc
smc執行前,地址0x402219處是一大段資料

smc的idapython腳本
from idaapi import *
from idautils import *
start_addr = 0x402219
key = 0x99
for i in range(start_addr,start_addr+224):
PatchByte(i,Byte(i)^key)
smc執行完成后,按c轉換成代碼

在地址0x402219處右鍵->Edit function,將函式結束地址修改為retn指令所在地址,完成后F5反匯編
用插件Findcrypt發現sub_402219是對輸入的AES加密,密鑰為unk_603170,密文為res

遠程除錯elf,得到密鑰unk_603170

寫AES解密腳本即可得到flag

[網鼎杯 2020 青龍組]singal
exe程式,運行后提示輸入string,無殼,ida分析
main函式,分析可知是vm的題目,dword_403040中的資料作為opcode傳入vm_operad函式中

進入vm_operad函式,分析可知
opcode為10時,讀取輸入,長度為15
opcode為1時,v4被賦值
opcode為7時,v4和下一個opcode比較,于是7后面的opcode為密文
其余的opcode為input的相關運算
int __cdecl vm_operad(int *opcode, int a2)
{
int result; // eax
char input[100]; // [esp+13h] [ebp-E5h]
char v4[100]; // [esp+77h] [ebp-81h]
char v5; // [esp+DBh] [ebp-1Dh]
int v6; // [esp+DCh] [ebp-1Ch]
int v7; // [esp+E0h] [ebp-18h]
int v8; // [esp+E4h] [ebp-14h]
int v9; // [esp+E8h] [ebp-10h]
int opcode_index; // [esp+ECh] [ebp-Ch]
opcode_index = 0;
v9 = 0;
v8 = 0;
v7 = 0;
v6 = 0;
while ( 1 )
{
result = opcode_index;
if ( opcode_index >= a2 )
return result;
switch ( opcode[opcode_index] )
{
case 1: // 每當opcode為1時,v4被賦值
v4[v7] = v5;
++opcode_index;
++v7;
++v9;
break;
case 2: // 每當opcode為2時,v5被賦值為下一個opcode與input的和
v5 = opcode[opcode_index + 1] + input[v9];// 由于運算使用了下一個opcode,所以opcode_index加2
opcode_index += 2;
break;
case 3:
v5 = input[v9] - LOBYTE(opcode[opcode_index + 1]);// 每當opcode為3時,v5被賦值為input與下一個opcode的差
opcode_index += 2; // 由于運算使用了下一個opcode,所以opcode_index加2
break;
case 4:
v5 = opcode[opcode_index + 1] ^ input[v9];// 每當opcode為4時,v5被賦值為input與下一個opcode異或的值
opcode_index += 2; // 由于運算使用了下一個opcode,所以opcode_index加2
break;
case 5:
v5 = opcode[opcode_index + 1] * input[v9];// 每當opcode為5時,v5被賦值為input與下一個opcode乘積的值
opcode_index += 2; // 由于運算使用了下一個opcode,所以opcode_index加2
break;
case 6: // 每當opcode為6時,跳到下一個opcode
++opcode_index;
break;
case 7: // 每當opcode為7時,驗證v4和下一個opcode是否相等,意味著opcode等于7的下一個opcode為密文
if ( v4[v8] != opcode[opcode_index + 1] )
{
printf("what a shame...");
exit(0);
}
++v8;
opcode_index += 2; // 由于驗證使用了下一個opcode,所以opcode_index加2
break;
case 8: // 每當opcode為8時,input的值修改
input[v6] = v5;
++opcode_index;
++v6;
break;
case 10: // opcode的第一個值為10,所以先讀取輸入,長度為15
read(input);
++opcode_index;
break;
case 11: // 每當opcode為11時,v5被賦值為input與數字1的差
v5 = input[v9] - 1;
++opcode_index;
break;
case 12: // 每當opcode為12時,v5被賦值為input與數字1的和
v5 = input[v9] + 1;
++opcode_index;
break;
default:
continue;
}
}
}
提取出114個opcode,手動進行分類,并按照操作碼得到input[0~14]的變換程序

寫逆運算腳本即可得到flag

此題目也可以用angr一把梭
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/259054.html
標籤:其他
