s1gn1n
ida打开发现存在花指令
在这里我一开始犯了一个错误我把jz和jnz进行nop没有nop C7
解释下为什么C7也要nop,因为把前面的跳转nop留下单独一条C7,CPU会继续往下读取字节,形成一个完整的指令。后面的正常的代码会当作 C7
指令的操作数去解码/执行 → 指令流被破坏、程序会异常或崩溃。
int __cdecl sub_4014D0(int a1)
{int v2; // [esp+8h] [ebp-68h]int v3; // [esp+Ch] [ebp-64h]unsigned int j; // [esp+10h] [ebp-60h]int v5; // [esp+18h] [ebp-58h]unsigned int i; // [esp+20h] [ebp-50h]int v7; // [esp+24h] [ebp-4Ch] BYREFunsigned int v8; // [esp+28h] [ebp-48h] BYREFchar v9[64]; // [esp+2Ch] [ebp-44h] BYREFmemset(v9, 0, sizeof(v9));v7 = 0;v2 = sub_4012E0(a1);sub_401470(v2, v9, &v7); // 中序遍历v5 = sub_401100(v9, &v9[strlen(v9) + 1] - &v9[1], &v8);// base64for ( i = v8 - 1; i; --i ){*(i + v5) ^= *(i + v5 - 1);*(i + v5) ^= byte_404060[i];}v3 = -28;for ( j = 0; j < v8; ++j )v3 = v3 + *(j + v5) - 1;return v3;
}
for ( i = v8 - 1; i; --i ){*(i + v5) ^= *(i + v5 - 1);*(i + v5) ^= byte_404060[i];}
得到x[i]=x[i]⊕x[i−1]⊕k[i]
其中:
- x[i] 表示处理后的字节
- k[i]=byte_404060[i]
v3 = -28;
for (j = 0; j < v8; ++j)v3 = v3 + *(j + v5) - 1;
得到
所有项展开得到
因为循环没有处理第一项它的形式是
x[0]⊕k[0]
所以最终的求和形式为:
因为它把v3当做求和值来进行返回,我们要让函数不进行jnz跳转,所以当v3的值为0时才不会跳转
补充:
jnz为0继续执行下一条指令,不为0执行跳转
因为Sum(x[i]^x[i-1]^k[i])+x[0]^k[0]==0 可以逆推出v9
exp
k = [ 88, 105, 123, 6, 30, 56, 44, 32, 4, 15, 1, 7, 49, 107, 8, 14, 122, 10, 114, 114, 38, 55, 111, 73, 33, 22, 17, 47, 26, 13, 60, 31, 43, 50, 26, 52, 55, 127, 3, 68, 22, 14, 1, 40, 30, 104, 100, 35, 23, 9, 61, 100, 106, 105, 99, 24, 24, 10, 21, 112
] x = [0] * len(k)
x[0] = k[0] for i in range(1, len(k)): x[i] = x[i-1] ^ k[i] print("还原出来的 v9 数值序列:")
print(x) # 尝试转成 ASCIIprint("对应的 ASCII 字符串:")
print("".join(chr(c) if 32 <= c < 127 else '.' for c in x))
X1JLRjFfbmlkZ197MG5GaV9pQGVycnRMfTNzM21ucmlDZ2VubkV2X1RJRXM=
进行base64解密得到
RKF1_nidg3s3mnriCgennEv_TIEs
利用加密前后字符位置的映射,还原目标正确位置
flag1 = []
flag2 = "_RKF1_nidg_{0nFi_i@errtL}3s3mnriCgennEv_TIEs"
s1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr"
s2 = "fPgHhQiDjRkIlSmBnToJpUqErVKWAXLYFZMaCbNcGdOe"for i in range(44):c = s1[i]index = s2.index(c)flag1.append(flag2[index])
print("".join(flag1))# miniLCTF{esrevER_gnir33nignE_Is_K1nd_0F_@rt}
x96re
v9 = 0;v10 = 0;v11 = 0;v12 = 0;v13 = 0;v14 = 0;v15 = 0;v16 = 0;v17 = 0;v18 = 0;v19 = 0;v20 = 0;v21 = 0;v22 = 0;v6[0] = 0x35323032;v6[1] = 0x696E696D;v6[2] = 0x6674636C;v6[3] = 0x21212121; // 2025minilctf!!!!*s = 0;v24 = 0;v25 = 0;v26 = 0;v27 = 0;v28 = 0;v29 = 0;v30 = 0;v31 = 0;v32 = 0;v33 = 0;v34 = 0;v35 = 0;v7[0] = 0xDCBEE7D4;v7[1] = 0x78FB2439;v7[2] = 0xC06E8000;v7[3] = 0xD3C34A2C;v7[4] = 0xF53837D5;v7[5] = 0xA9C8D88D;v7[6] = 0x20CBDAE5;v7[7] = 0x2551D478;puts("please input flag:");if ( !fgets(s, 50, stdin) )goto LABEL_7;v5 = strlen(s);if ( v5 ){if ( s[v5 - 1] == 10 )s[--v5] = 0;}if ( v5 == 32 ){
LABEL_7:init();whathappened(); // xor 0x4cencode_fun(0x20u, v6, s, v8); // sm4for ( i = 0; i <= 0x1Fu; ++i ){if ( *(v8 + i) != *(v7 + i) ){printf("try again~~~");return 1;}}printf("congratulation!!!");return 0;}else{printf("Invalid length!got %zu\n", v5);return 1;}
}
分析代码知道whathappened()先进行了运算,encode_fun()后面进行了sm4
动调拿到whathappened()函数的内容,进行与0x4c的异或,正常的范围为0-31但是索引计算公式是 (counter - 1)
,实际被异或的索引范围是:-1-30所以最后两个字节不进行异或。
flag为3ac159d665b4ccfb25c0927c1a23edb3