2023SYCTF的Syclang這道題還怪有意思的,作者寫了一個簡單的反編譯器,將源代碼輸出中間指令、asm等格式。

然后,我們今天要來頭鐵分析一下IR中間代碼(個人感覺像Go語言hhh)
主要調出幾個典型的指令進行一個分析,然后就可以逆出這段程序的大致意思了。
感覺分析完這個中間指令,對程序的理解又更進了一步。
程序的邏輯很簡單,就是多個循環,加減加密,然后與密文比較。
在文章的結束,將會把附件上傳,大家也可以下載下來分析。
(作者水平有限,如有錯誤,請大佬指出)
調了幾個很典型的指令,CTF題給了800多行代碼,都是由這些指令組成的。
//聲明一個結構體 STRUCT exp : ARRAY .key(int)[24]<+0>//int類型,這里占8個字節,8*24=192 ARRAY .L(int)[8]<+192> ARRAY .R(int)[8]<+256> ARRAY .X(int)[8]<+320>
定義函數
FUNCTION read - 8 : PARAM var2<+8> LABEL Flabelread : FUNCTION writes - 0 : LABEL Flabelwrites : FUNCTION writef - 0 : LABEL Flabelwritef : FUNCTION exit - 0 : LABEL Flabelexit :
入口main函數
char類型在這里占一個字節,int類型占了8字節。
<+n>這個表示偏移,理解一下就可以。
FUNCTION main - 1640 : ARRAY var11(char)[24]<+0>//char類型占一個字節 STRUCT var22(exp)<+488> STRUCT var23(exp)<+872> STRUCT var24(exp)<+1256> STRUCT var25(exp)<+1640> ARG var11<+24> temp1 := CALL read //調用函數,獲取我們的flag temp2 := #0 var15<+56> := temp2
分析第一個循環結構,其他的循環結構都是類似的。
//第一個循環,運算1
LABEL label4 :
temp4 := #24 //temp4=24 類似go語言的匿名變量
IF var15<+56> < temp4 GOTO label3 //一個循環結構
GOTO label2
LABEL label3 :
temp5 := #0
var12<+32> := temp5
var16<+64> := var15<+56>
#!tempa := {#1}*{var16<+64>} //這句就是將 某個變化的值賦值給一個臨時的變量,理解為:tempa = var16 + 1 char類型就是一個字節
var12<+32> ::= var11<+1><+tempa> //var12 = input[i]
temp6 := #23
temp7 := temp6 - var15<+56>
var18<+80> := temp7
#!tempa := {#8}*{var18<+80>} //創建臨時變量
var22(@exp.key[0])<+8><+488><+tempa> := var12<+32>
//var22(@exp.key[0])<+8><+488>獲得exp結構體數組的起始地址,exp.key[23-i] = var12 = input[i]
temp3 := #1
var15<+56> := var15<+56> + temp3
GOTO label4
//第二個循環,運算2
LABEL label2 :
temp8 := #23
var15<+56> := temp8
LABEL label11 :
temp10 := #0
IF var15<+56> > temp10 GOTO label10
GOTO label9
.......//其他代碼
一個循環可以提取出來C代碼:
for (int i = 0; i < 24; i++) {
var22.key[23 - i] = inputflag[i];
}
分析第二個循環結構
//第二個循環,運算2
LABEL label2 :
temp8 := #23
var15<+56> := temp8
LABEL label11 :
temp10 := #0
IF var15<+56> > temp10 GOTO label10 //終止條件
GOTO label9
LABEL label10 :
var18<+80> := var15<+56>
#!tempa := {#8}*{var18<+80>}
var19<+88> := var22(@exp.key[0])<+8><+488><+tempa>
temp11 := #1
temp12 := var15<+56> - temp11 // i-1
var16<+64> := temp12
#!tempa := {#8}*{var16<+64>}
var17<+72> := var22(@exp.key[0])<+8><+488><+tempa>
temp13 := var19<+88> - var17<+72>
var21<+104> := temp13
#!tempa := {#8}*{var15<+56>} //i
var22(@exp.key[0])<+8><+488><+tempa> := var21<+104> // exp.key[i] =exp.key[i] - exp.key[i-1]
temp9 := #1
var15<+56> := var15<+56> - temp9
GOTO label11
//初始化數組區
LABEL label9 :
第二個循環轉換為c代碼如下:
for (int i = 23; i > 0; i--) {
var22.key[i] = var22.key[i] - var22.key[i - 1];
}
初始化數組區,就是很常見的賦值。
LABEL label9 : temp15 := #0 var22(@exp.L[0])<+200><+488> := temp15 temp17 := #8 var22(@exp.R[0])<+264><+488> := temp17 temp19 := #11 var22(@exp.X[0])<+328><+488> := temp19 temp21 := #15 var22(@exp.L[1])<+208><+488> := temp21 temp23 := #23 var22(@exp.R[1])<+272><+488> := temp23 temp25 := #0 temp26 := #13 temp27 := temp25 - temp26 var22(@exp.X[1])<+336><+488> := temp27 temp29 := #2 var22(@exp.L[2])<+216><+488> := temp29 temp31 := #11 var22(@exp.R[2])<+280><+488> := temp31 temp33 := #17 var22(@exp.X[2])<+344><+488> := temp33 temp35 := #10 var22(@exp.L[3])<+224><+488> := temp35 temp37 := #20 var22(@exp.R[3])<+288><+488> := temp37 temp39 := #0 temp40 := #19 temp41 := temp39 - temp40 var22(@exp.X[3])<+352><+488> := temp41 ......
其它的循環和賦值都是類似了,這里不在詳細分析了。
這里貼一下,翻譯后的大致偽代碼。
感謝s0rry師傅的幫助~
typedef struct {
long long int key[24];
long long int L[8];
long long int R[8];
long long int X[8];
} exp;
int main() {
exp var22;
exp var23;
exp var24;
exp var25;
var22.L[0] = 0;
var22.R[0] = 8;
var22.X[0] = 11;
var22.L[1] = 15;
var22.R[1] = 23;
var22.X[1] = -13;
var22.L[2] = 2;
var22.R[2] = 11;
var22.X[2] = 17;
var22.L[3] = 10;
var22.R[3] = 20;
var22.X[3] = -19;
var22.L[4] = 6;
var22.R[4] = 13;
var22.X[4] = 23;
var22.L[5] = 9;
var22.R[5] = 21;
var22.X[5] = -29;
var22.L[6] = 1;
var22.R[6] = 19;
var22.X[6] = 31;
var22.L[7] = 4;
var22.R[7] = 17;
var22.X[7] = -37;
var23.key[0] = 252;
var23.key[1] = 352;
var23.key[2] = 484;
var23.key[3] = 470;
var23.key[4] = 496;
var23.key[5] = 487;
var23.key[6] = 539;
var23.key[7] = 585;
var23.key[8] = 447;
var23.key[9] = 474;
var23.key[10] = 577;
var23.key[11] = 454;
var23.key[12] = 466;
var23.key[13] = 345;
var23.key[14] = 344;
var23.key[15] = 486;
var23.key[16] = 501;
var23.key[17] = 423;
var23.key[18] = 490;
var23.key[19] = 375;
var23.key[20] = 257;
var23.key[21] = 203;
var23.key[22] = 265;
var23.key[23] = 125;
//初始化
for (int i = 0; i < 24; i++) {
var22.key[23 - i] = input[i];
}
for (int i = 23; i > 0; i--) {
var22.key[i] = var22.key[i] - var22.key[i - 1];
}
//對flag加密
for (int i = 0; i < 8; i++) {
var22.key[var22.L[i]] += var22.X[i];
var22.key[var22.R[i]] -= var22.X[i];
}
for (int i = 1; i < 24; i++) {
var22.key[i] += var22.key[i - 1];
}
//對var23密文進行運算
for (int i = 23; i > 0; i--) {
var23.key[i] -= var23.key[i - 1];
}
for (int i = 0; i < 8; i++) {
var23.key[var22.L[i]] -= var22.key[i * 3];
var23.key[var22.R[i]] += var22.key[i * 3];
}
for (int i = 1; i < 24; i++) {
var23.key[i] += var23.key[i - 1];
}
//比較密文和輸入flag的密文
for (int i = 0; i < 24; i++) {
if (var22.key[i] != var23.key[i]) {
exit;//不相等則退出
}
}
return 0;
}
D1Net
信息安全與通信保密雜志社
信息安全與通信保密雜志社
安全牛
CNCERT國家工程研究中心
系統安全運維
安全牛
關鍵基礎設施安全應急響應中心
黑白之道
天億網絡安全
看雪學苑
云計算和網絡安全技術實踐