4

[NPC²CTF 2025]esrever

main函数无法反汇编,一片红,发现输出的right和wrong在前面,input flag在后面,是将汇编反着来的

image

image

可能是在校验flag的格式

image

image

image

image

两个两个换位

这个题能够纯猜出来,好像前面有函数能够控制顺序,所以也算是smc吧

感觉动调会更简单,但是我的环境不允许

[NPC²CTF 2025]ugly_world

很多算数函数(ai都能识别),感觉和UIUC2024 Summarize差不多,但是要复杂很多

image

这里就是一个循环的内容

  v9 = ((a[1] >> 1) + int32_1) ^ (a[1] + hex) ^ (int32_0 + (a[1] >> 1))
  a[2] = v9 + a[0]//有问题
  v17 = (int32_3 + (a[2] >> 1)) ^ (a[2] + hex) ^ (int32_2 + (a[2]) >> 1)
  a[2] = a[1] + v17//有问题

这里可以猜出来是tea系列的,对比加密,hex就是delta,每一轮都不一样,sum从0开始加delta

学到了,用python脚本去提取数据

import re


def extract_hex_numbers(code_text):
    """
    提取代码中所有0x开头的十六进制数
    :param code_text: 输入的代码文本
    :return: 找到的所有十六进制数列表
    """
    # 使用正则表达式匹配所有0x开头的十六进制数
    hex_pattern = r'0x[0-9A-Fa-f]+u?'
    hex_numbers = re.findall(hex_pattern, code_text)
    return hex_numbers


if __name__ == "__main__":
    # 读取代码文件
    with open('your_code.txt', 'r') as f:
        code = f.read()

    # 提取所有十六进制数
    hex_numbers = extract_hex_numbers(code)

    # 打印结果
    print("找到的所有十六进制数:")
    for i, num in enumerate(hex_numbers, 1):
        print(f"{i}. {num}")

输出可以发现有128个数字,也就是循环了128轮

# import re
#
#
# def extract_hex_numbers(code_text):
#     """提取代码中所有0x开头的十六进制数"""
#     hex_pattern = r'0x[0-9A-Fa-f]+u?'
#     return re.findall(hex_pattern, code_text)
#
#
# def extract_cycle_parameters(code_text):
#     """提取循环相关参数"""
#     results = {
#         'rol_shifts': [],  # rol的位移参数
#         'sal_shifts': []  # sal_1的位移参数
#     }
#
#     lines = [line.strip() for line in code_text.split('\n') if line.strip()]
#
#     for line in lines:
#         if '= rol(' in line:
#             parts = line.split('rol(')[1].split(')')[0].split(',')
#             if len(parts) == 2:
#                 results['rol_shifts'].append(parts[1].strip())
#
#         elif '= sal_1(' in line:
#             parts = line.split('sal_1(')[1].split(')')[0].split(',')
#             if len(parts) == 2:
#                 results['sal_shifts'].append(parts[1].strip())
#
#
#     return results
#
#
# if __name__ == "__main__":
#     with open('E:\\NSS\\your_code.txt', 'r') as f:
#         code = f.read()
#
#     # 提取所有参数
#     hex_numbers = extract_hex_numbers(code)
#     extracted = extract_cycle_parameters(code)
#
#     # 单行逗号分隔输出
#     print("十六进制数:")
#     print(','.join(hex_numbers))
#
#     print("\nROL位移参数:")
#     print(','.join(extracted['rol_shifts']))
#
#     print("\nSAL位移参数:")
#     print(','.join(extracted['sal_shifts']))

rol = [1,1,3,3,4,4,3,3,4,4,3,3,3,3,6,6,4,4,6,6,2,2,1,1,6,6,6,6,1,1,4,4,5,5,4,4,1,1,4,4,4,4,2,2,5,5,4,4,6,6,2,2,2,2,3,3,4,4,5,5,5,5,5,5,4,4,5,5,1,1,6,6,4,4,2,2,3,3,6,6,5,5,6,6,6,6,1,1,2,2,2,2,4,4,5,5,2,2,4,4,6,6,6,6,3,3,6,6,2,2,1,1,1,1,5,5,3,3,5,5,3,3,2,2,6,6,4,4,6,6,4,4,2,2,1,1,4,4,5,5,4,4,5,5,6,6,1,1,5,5,2,2,2,2,6,6,2,2,6,6,3,3,3,3,5,5,3,3,3,3,6,6,6,6,5,5,4,4,4,4,2,2,1,1,5,5,1,1,2,2,2,2,1,1,5,5,3,3,6,6,1,1,1,1,5,5,5,5,1,1,4,4,4,4,2,2,4,4,6,6,6,6,3,3,4,4,6,6,5,5,1,1,1,1,6,6,5,5,4,4,3,3,6,6,5,5,5,5,2,2,1,1,4,4,2,2]
sal = [1,1,4,4,6,6,6,6,1,1,2,2,3,3,3,3,6,6,3,3,2,2,5,5,6,6,2,2,5,5,4,4,5,5,6,6,3,3,4,4,2,2,3,3,4,4,2,2,3,3,3,3,2,2,2,2,4,4,6,6,4,4,2,2,2,2,4,4,1,1,3,3,4,4,2,2,4,4,1,1,1,1,5,5,1,1,1,1,5,5,5,5,4,4,5,5,2,2,1,1,4,4,3,3,1,1,6,6,5,5,3,3,1,1,5,5,4,4,4,4,2,2,1,1,1,1,6,6,1,1,3,3,5,5,6,6,5,5,2,2,4,4,3,3,2,2,3,3,6,6,1,1,3,3,3,3,6,6,2,2,4,4,2,2,4,4,1,1,4,4,3,3,2,2,3,3,6,6,5,5,5,5,5,5,4,4,6,6,5,5,1,1,2,2,3,3,6,6,5,5,6,6,5,5,4,4,2,2,6,6,2,2,5,5,1,1,6,6,1,1,4,4,6,6,6,6,3,3,2,2,6,6,2,2,6,6,2,2,3,3,5,5,1,1,1,1,6,6,4,4,2,2,4,4,3,3]
for i in range(0,len(rol),2):
    print(rol[i],end=',')

print()

for i in range(0,len(rol),2):
    print(sal[i],end=',')

提取其他参数

key也就是我用int32表达的数据是传入的a2,可以直接提取dword

0x11223344,0x55667788,0x9900AABB,0xCCDDEEFF

key的取法都是1,0,3,2

rol与sal参数每次循环使用两次且相同,密文为10个dword,对应循环5次的tea加密

#include <stdio.h>
#include <stdint.h>

int k[] = {0x11223344, 0x55667788, 0x9900AABB, 0xCCDDEEFF};

int sal[] = {1,4,6,6,1,2,3,3,6,3,2,5,6,2,5,4,5,6,3,4,2,3,4,2,3,3,2,2,4,6,4,2,2,4,1,3,4,2,4,1,1,5,1,1,5,5,4,5,2,1,4,3,1,6,5,3,1,5,4,4,2,1,1,6,1,3,5,6,5,2,4,3,2,3,6,1,3,3,6,2,4,2,4,1,4,3,2,3,6,5,5,5,4,6,5,1,2,3,6,5,6,5,4,2,6,2,5,1,6,1,4,6,6,3,2,6,2,6,2,3,5,1,1,6,4,2,4,3};
int rol[] = {1,3,4,3,4,3,3,6,4,6,2,1,6,6,1,4,5,4,1,4,4,2,5,4,6,2,2,3,4,5,5,5,4,5,1,6,4,2,3,6,5,6,6,1,2,2,4,5,2,4,6,6,3,6,2,1,1,5,3,5,3,2,6,4,6,4,2,1,4,5,4,5,6,1,5,2,2,6,2,6,3,3,5,3,3,6,6,5,4,4,2,1,5,1,2,2,1,5,3,6,1,1,5,5,1,4,4,2,4,6,6,3,4,6,5,1,1,6,5,4,3,6,5,5,2,1,4,2};
int delta[] = {0x3CA6F3E,0xF2E1C7F1,0x79A22843,0xD47FFC9D,0xDD10F4C,0x1DC368A1,0x11B15F8A,0x9469B3CD,0x45D6DB5F,0xBC6EE006,0xA76D8146,0xD542E337,0x242E1155,0xAA7F93DD,0x88625ECB,0x3738E499,0xCEF27BB0,0x134FF759,0x358CA57E,0x3461F310,0x28540EE7,0x81C0B176,0xF725EE9C,0xAF823A69,0x61E8ECB3,0xF4919548,0x6AF44E11,0x866162F3,0x867F7E65,0x6B26444C,0x10216241,0x9C1BA3CD,0x1268FEAD,0xF462B3B5,0x5F7DE761,0x72EAD5B6,0xFBCE0C75,0x44EF4142,0x54DCC3C0,0xAFFE805D,0xC8833729,0x3C944186,0x261169A,0xB547EA2F,0x9B499585,0xFE0190BF,0x1EC74BE7,0xAFC9292E,0xC32F4EEF,0x420A1A4,0x94BEAB2B,0xA0693238,0x4DD5ADC1,0x9F658F31,0x1732EA46,0x76BEE7DD,0x12C63095,0x9C202C7C,0xAC9BB4C4,0x1762AEAF,0xCA41991E,0xC0480F85,0xBF534431,0xF1C2780E,0x990A7D6F,0x69D22B81,0x34DDECDE,0x11ECD8F8,0x22BB55D2,0xFFA55B0,0x6CC1AFBF,0xA5610F61,0x13190C95,0xE09A5D29,0xE7514731,0x9AE21D7A,0xB8D90F5A,0x4C7299A9,0xC4FDB94E,0xA6475083,0xBFB62E5,0x8F7F77EB,0xDA2568BB,0x55C4DA9E,0xC2932973,0xCBC60B6D,0xC46720FD,0x2046D79D,0x629CBD81,0x932B1F48,0x72ED29C0,0xF4B566D3,0xCBC53B21,0x7836C87B,0xBA4357B1,0xCFD332E2,0x4D488FCB,0xA06DEFBF,0x68211846,0xC17F878D,0x33B10E2C,0xCFA0E756,0x4C3C0691,0x870BE107,0x55B3FAF0,0xFD39F8D7,0x4B9A7795,0x188CFA42,0xAA79A09D,0x620CF186,0xEFDE898A,0x2FA95D43,0xD67359DB,0x8625BC1B,0x7A1A3BBC,0xE6ECEF6C,0xBA27A5C6,0x559FE417,0xF01DF04D,0x3F910D52,0x382B7BE,0xAAECB195,0x2E440D8E,0xB3D58B0B,0x3CA704B8,0x63293098,0x714CFD4D,0x47C8D0F7};

void decrypt(int *v, int *k) {
	int v0 = v[0], v1 = v[1];
	int sum = 0;
	
	for(int i = 0; i < 128; i++) {
		sum += delta[i];
	}

	for(int i = 127; i >= 0; i--) {
		v1 -= ((v0 << sal[i]) + k[2]) ^ (v0 + sum) ^ ((v0 >> rol[i]) + k[3]);
		v0 -= ((v1 << sal[i]) + k[0]) ^ (v1 + sum) ^ ((v1 >> rol[i]) + k[1]);
		sum -= delta[i];
	}
	
	v[0] = v0;
	v[1] = v1;
}

int main() {
	int v[10] = {
		0xBD3BE58, 0xBE73BBFB, 0xC8C8AF4E, 0xB3C7D86,
		0xC0257C09, 0x1D8FE0B0, 0x8837180C, 0xF5CF9D23,
		0xB7A8B599, 0xAE630F3D
	};
	
	for(int i = 0; i < 5; i++) {
		int temp[2] = {v[i*2], v[i*2+1]};
		decrypt(temp, k);

		for(int j = 0; j < 4; j++) {
			char c = (temp[0] >> (j * 8)) & 0xFF;
			printf("%c", c);
		}
		
		for(int j = 0; j < 4; j++) {
			char c = (temp[1] >> (j * 8)) & 0xFF; 
			printf("%c", c);
		}
	}
	return 0;
}
//flag{UG1y_T3A_m@k35_[m3]_fe31_NaU5Eou5!}

[NPC²CTF 2025]randomXor

image

这里面srand和rand函数都是自定义的

image

image

后续用这些函数生成的伪随机数单字节异或加密

这样的话就可以动调或者将函数复制出来

#include <stdio.h>

unsigned int mt[128]; 
unsigned short index1; //显式表示__int16

void srand(int seed) {
	mt[0] = seed;
	for (int i = 1; i <= 0x71; ++i)
		mt[i] = (-1482534043 * (mt[i - 1] ^ (mt[i - 1] >> 30)) + i) ^ 0x56;
	index1 = 114; 
}

int rand() {
	if (index1 > 0x71) {
		for (int i = 0; i <= 0x71; ++i) {
			unsigned int v3 = ((mt[i] & 0x80000) | (mt[(i + 1) % 0x72] & 0x7FFFF)) >> 1;
			if (mt[(i + 1) % 0x72] & 1)
				v3 ^= 0x8908B0DF;
			mt[i] = mt[(i + 514) % 0x72] ^ v3;
		}
		index1 = 0;
	}
	unsigned int v4 = mt[index1++];
	unsigned int v5 = (v4 ^ (v4 >> 11) ^ (((v4 ^ (v4 >> 11)) << 7)) & 0x9D2C5680);//注意运算优先级的问题
	return (v5 ^ ((v5 << 15) & 0xEFC60000)) ^ (((v5 ^ ((v5 << 15) & 0xEFC60000)) >> 18));
}

int main() {
	char enc[] = {
		0xCD,0xC7,0xE2,0x86,0x3A,0x19,0xB9,0xB6,0xF1,0x81,0x45,0xB4,0xB6,0xE5,0xD,0xD4,
		0xB4,0xA6,0xD3,0xF7,0x33,0x5D,0x5F,0x9,0x95,0xAF,0x9A,0xBE,0x89,0xEA,0x54,0x71,
		0x68,0xC6,0x8B,0x84,0x5,0x14,0xBB,0x41,0xDD,0x34,0x91,0x1B,0x21,0x83,0xDE,0x15,
		0x52,0x22,0x8A,0xE1,0xBD,0x33,0x4D,0x7E,0xD2,0xA3,0xA9,0x12,0xF1,0xE9,0x88,0x60,
		0x24,0xE6,0xAB,0x54,0xCF,0x2,0x1B,0x6B,0x6B,0xBA,0x26,0x9,0xFB,0x10,0x97,0xDF,
		0x17,0xBF,0xCC,0xE7,0xB0,0x42,0xE5,0x32,0x4C,0xF,0xE0,0x60,0x47,0xD0,0x5A,0xE8,
		0x48,0xAE,0x74,0x4D,0x98,0x7A,0xB3,0xD2,0xDE,0x1B,0x96,0x91,0x7A,0x3,0x67,0xCF,
		0xF0,0x31,0x32,0x49,0x9A,0xE0,0xC2,0x3B,0x51,0x63,0xFF,0x84,0x60,0x5B,0xC1,0x8E
	};
	
	srand(114514); 
	for (int i = 0; i < 128; i++)
		enc[i] ^= rand(); // XOR 解密
	
	for (int i = 0; i < 128; i++)
		printf("%c", (unsigned char)enc[i]);
	
	return 0;
}

注意运算的优先级的问题,特别是我标注出来的那个地方,卡了很久就是因为那里

ida里面没有用括号显示出来,但是其实能看出来,而且ai能给的逻辑也是最后来异或的

[tgctf2025]randomsystem

sub_412370是主函数

这四个函数都有花

去花

先去第四个函数的花

sub_41105F

nop完方框内的

主函数里面传入的参数只有两个,Destinationv11

sub_411307

用nomoreflower脚本跑一下,再进入函数

按C强制转换

sub_411334

call无意义的地址,就将call指令(E9)删掉,如下图

nop

sub_4112DA

00413113的E9也要nop

TlsCallback_0_0

__int64 __fastcall TlsCallback_0_0(int a1, int a2, int a3, int a4, int a5)
{
  int v5; // eax
  __int64 v7; // [esp-4h] [ebp-1FCh]
  int v8; // [esp+0h] [ebp-1F8h]
  int j; // [esp+D0h] [ebp-128h]
  int i; // [esp+DCh] [ebp-11Ch]
  int v11; // [esp+E8h] [ebp-110h]
  _DWORD v12[65]; // [esp+F4h] [ebp-104h] BYREF
  int savedregs; // [esp+1F8h] [ebp+0h] BYREF

  v5 = v8;
  Seed = 2025;
  v12[0] = 1;
  v12[1] = 1;
  v12[2] = 0;
  v12[3] = 1;
  v12[4] = 0;
  v12[5] = 0;
  v12[6] = 1;
  v12[7] = 0;
  v12[8] = 0;
  v12[9] = 1;
  v12[10] = 1;
  v12[11] = 0;
  v12[12] = 0;
  v12[13] = 1;
  v12[14] = 0;
  v12[15] = 1;
  v12[16] = 0;
  v12[17] = 0;
  v12[18] = 1;
  v12[19] = 1;
  v12[20] = 0;
  v12[21] = 1;
  v12[22] = 1;
  memset(&v12[23], 0, 16);
  v12[27] = 1;
  v12[28] = 0;
  v12[29] = 1;
  v12[30] = 0;
  v12[31] = 1;
  v12[32] = 0;
  v12[33] = 1;
  v12[34] = 0;
  v12[35] = 0;
  v12[36] = 1;
  v12[37] = 0;
  v12[38] = 1;
  memset(&v12[39], 0, 24);
  v12[45] = 1;
  v12[46] = 0;
  v12[47] = 1;
  memset(&v12[48], 0, 24);
  v12[54] = 1;
  v12[55] = 1;
  v12[56] = 0;
  v12[57] = 1;
  v12[58] = 1;
  memset(&v12[59], 0, 16);
  v12[63] = 1;
  v11 = 0;
  for ( i = 0; i < 8; ++i )
  {
    for ( j = 0; j < 8; ++j )
    {
      a2 = v12[v11];
      dword_41C368[8 * i + j] = a2;
      ++v11;
    }
    v5 = i + 1;
  }
  sub_41120D(&savedregs, &dword_411B50, v5, a2);
  return v7;
}

回到开头

学习的是liv:https://tkazer.github.io/2025/04/13/TGCTF2025/index.html

a=[5,2,6,5,5,6,6,5,5,2,6,5,5,3,6,5]
for i in a:
  print(f"{i:04b}",end='')

所以something应该是0101001001100101010101100110010101010010011001010101001101100101

image

转为字符就是最后异或的key

#include <stdio.h>

int main() {
	int v17[64] ={0};
	v17[0] = 376;
	v17[1] = 356;
	v17[2] = 169;
	v17[3] = 501;
	v17[4] = 277;
	v17[5] = 329;
	v17[6] = 139;
	v17[7] = 342;
	v17[8] = 380;
	v17[9] = 365;
	v17[10] = 162;
	v17[11] = 258;
	v17[12] = 381;
	v17[13] = 339;
	v17[14] = 347;
	v17[15] = 307;
	v17[16] = 263;
	v17[17] = 359;
	v17[18] = 162;
	v17[19] = 484;
	v17[20] = 310;
	v17[21] = 333;
	v17[22] = 346;
	v17[23] = 339;
	v17[24] = 150;
	v17[25] = 194;
	v17[26] = 175;
	v17[27] = 344;
	v17[28] = 158;
	v17[29] = 250;
	v17[30] = 128;
	v17[31] = 175;
	v17[32] = 158;
	v17[33] = 173;
	v17[34] = 152;
	v17[35] = 379;
	v17[36] = 158;
	v17[37] = 292;
	v17[38] = 130;
	v17[39] = 365;
	v17[40] = 197;
	v17[41] = 20;
	v17[42] = 197;
	v17[43] = 161;
	v17[44] = 198;
	v17[45] = 10;
	v17[46] = 207;
	v17[47] = 244;
	v17[48] = 202;
	v17[49] = 14;
	v17[50] = 204;
	v17[51] = 176;
	v17[52] = 193;
	v17[53] = 255;
	v17[54] = 35;
	v17[55] = 7;
	v17[56] = 158;
	v17[57] = 181;
	v17[58] = 145;
	v17[59] = 353;
	v17[60] = 153;
	v17[61] = 357;
	v17[62] = 246;
	v17[63] = 151;
	char key[] = "ReVeReSe";
	for(int i=0;i<64;i++){
		printf("%d,",v17[i] ^ key[i%8]);
	}
}//298,257,255,400,327,300,216,307,302,264,244,359,303,310,264,342,341,258,244,385,356,296,265,310,196,167,249,317,204,159,211,202,204,200,206,286,204,321,209,264,151,113,147,196,148,111,156,145,152,107,154,213,147,154,112,98,204,208,199,260,203,256,165,242

由于是矩阵乘法的运算,所以要先求逆矩阵

这个地方具体的先留一下

做之后的

https://rrefcalculator.top/zh/逆矩阵计算器/ (求逆矩阵)

image

https://www.lddgo.net/math/matrix-calculator(算乘法)

image

#include <stdio.h>

int main() {
	int v17[64] ={102 , 100 , 49  , 49  , 118 , 53  , 54  , 100,
		52  , 53  , 52  , 114 , 54  , 102 , 52  , 97 ,
		99  , 98  , 45  , 49  , 101 , 97  , 56  , 100,
		45  , 54  , 102 , 121 , 56  , 48  , 55  , 57 ,
		53  , 97  , 102 , 56  , 51  , 122 , 102 , 114,
		98  , 56  , 45  , 99  , 100 , 54  , 99  , 100,
		99  , 50  , 52  , 116 , 99  , 97  , 55  , 53 ,
		53  , 57  , 102 , 97  , 48  , 57  , 57  , 45 };

	for(int i=0;i<64;i++){
		printf("%c",v17[i]);
	}
}//fd11v56d454r6f4acb-1ea8d-6fy80795af83zfrb8-cd6cdc24tca7559fa099-

回调函数里面seed=2025

#include <stdint.h>

int main() {
	srand(2025);
	
	for (int i = 0; i < 1000; i++) {
		printf("%d,",(rand())%32);
	}

	return 0;
}//27, 26, 25, 23, 28, 1, 6, 10, 20, 7, 15, 14, 31, 18, 19, 21, 9, 30, 22, 24, 8, 2, 29, 3, 12, 11, 17, 0, 13, 16, 4, 5

ai协助去重复的内容

按照这个顺序就可以恢复了

#include <stdio.h>

int main() {
	int a[]={27, 26, 25, 23, 28, 1, 6, 10, 20, 7, 15, 14, 31, 18, 19, 21, 9, 30, 22, 24, 8, 2, 29, 3, 12, 11, 17, 0, 13, 16, 4, 5};
	char flag[]="fd11v56d454r6f4acb-1ea8d-6fy80795af83zfrb8-cd6cdc24tca7559fa099-";
	for(int i=0;i<32;i++){
		char temp =0;
		temp = flag[i];
		flag[i] = flag[64 - a[i]-1];
		flag[64 - a[i]-1] = temp;
	}
	printf("%s",flag);
}//3zfb899ac5c256d-7a8r59f0tcc-4daf6b8vfd111-a44ff04r8-6dce5697da5y
posted @ 2025-07-27 21:26  zzz222666  阅读(24)  评论(0)    收藏  举报