5
[NepnepCTF2025]Crackme
校验的时候会先检验输入是不是16位小写字母a-f和数字组成的字符串的hex,后面的加密函数混淆非常多
crackme.exe会调用libcrypto.dll里面的函数
第一次MD5函数是对用户名,作为密钥,第二次是对用户名+"Showmaker11",作为最后判断的密文
加密结果和标准的不一样,可能是常数不一样,在MD5函数里面的return处断点能够找到加密后的数据

aes加密还给了函数名还行吧

这样找到了S盒

这里和标准的不一样,多异或了0x55
(好ai)
AES 加密流程推测
- 密钥扩展(Key Expansion)
dword_68155030 可能是 轮常量(Rcon)。
代码片段:
v75 = dword_68155030[v131] ^ v118 ^ v124 ^ (byte_68154000[v135] << 8) ^ byte_68154000[v135 >> 24];
*(v144 + 16) = v75; // 存储扩展后的密钥
符合 AES 密钥扩展逻辑。
- 字节替换(SubBytes)
byte_68154000 可能是 S-Box,用于字节替换:
LOBYTE(n626523479_1) = byte_68154000[*v65[0]];
*v65[0] = n626523479_1;
- 行移位(ShiftRows)
代码中有 循环左移操作(ROL4),可能是 ShiftRows:
LODWORD(v132) = __ROL4__(v34, 8 * v138);
- 列混淆(MixColumns)
部分代码涉及 GF(2^8) 乘法,可能是 MixColumns:
v127 = v152 ^ v53 ^ v111 ^ v42 ^ 0x55; // 多项式乘法
- 轮密钥加(AddRoundKey)
xor 操作 可能是轮密钥加:
*v133[0] = v141 ^ v139;
不愧是aes,脚本太难写了
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#define Nb 4
#define Nr 10
#define Nk 4
// 使用行优先存储(16字节数组)
typedef uint8_t state_t[16];
unsigned char sbox[256] = {
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
};
unsigned char rsbox[256] = {
0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
};
static uint8_t xtime(uint8_t x) {
return ((x << 1) ^ (((x >> 7) & 1) * 0x1b));
}
static uint8_t Multiply(uint8_t x, uint8_t y) {
return (((y & 1) * x) ^
((y >> 1 & 1) * xtime(x)) ^
((y >> 2 & 1) * xtime(xtime(x))) ^
((y >> 3 & 1) * xtime(xtime(xtime(x)))) ^
((y >> 4 & 1) * xtime(xtime(xtime(xtime(x))))));
}
// 逆向字节替换
static void InvSubBytes(state_t state) {
for (int i = 0; i < 16; ++i) {
state[i] = rsbox[state[i]];
}
}
// 密钥扩展
static void KeyExpansion(const uint8_t* Key, uint32_t* RoundKey) {
// 初始密钥拷贝
for (int i = 0; i < Nk; ++i) {
RoundKey[i] = ((uint32_t)Key[4*i]<<24) | ((uint32_t)Key[4*i+1]<<16) |
((uint32_t)Key[4*i+2]<<8) | (uint32_t)Key[4*i+3];
}
const uint32_t Rcon[10] = {
0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000
};
// 密钥扩展
for (int i = Nk; i < Nb*(Nr+1); ++i) {
uint32_t temp = RoundKey[i-1];
if (i % Nk == 0) {
temp = (temp << 8) | (temp >> 24);
temp = (sbox[(temp >> 24) & 0xFF] << 24) |
(sbox[(temp >> 16) & 0xFF] << 16) |
(sbox[(temp >> 8) & 0xFF] << 8) |
sbox[temp & 0xFF];
temp ^= Rcon[(i/Nk)-1];
}
RoundKey[i] = RoundKey[i-Nk] ^ temp;
}
}
// 轮密钥加
static void AddRoundKey(uint8_t round, state_t state, const uint32_t* RoundKey) {
for (int i = 0; i < 4; ++i) {
uint32_t kw = RoundKey[round*4 + i];
state[4*i] ^= (kw >> 24) & 0xFF;
state[4*i+1] ^= (kw >> 16) & 0xFF;
state[4*i+2] ^= (kw >> 8) & 0xFF;
state[4*i+3] ^= kw & 0xFF;
}
}
// 逆向行移位
static void InvShiftRows(state_t state) {
uint8_t temp;
// 第1行循环右移1字节
temp = state[13];
state[13] = state[9];
state[9] = state[5];
state[5] = state[1];
state[1] = temp;
// 第2行交换两个字节
temp = state[2];
state[2] = state[10];
state[10] = temp;
temp = state[6];
state[6] = state[14];
state[14] = temp;
// 第3行循环右移3字节
temp = state[3];
state[3] = state[7];
state[7] = state[11];
state[11] = state[15];
state[15] = temp;
}
// 逆向列混淆
static void InvMixColumns(state_t state) {
uint8_t tmp[4][4];
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
tmp[i][j] = state[i*4 + j] ^ 0x55;
}
}
for (int i = 0; i < 4; ++i) {
state[i*4] = Multiply(tmp[i][0], 0x0e) ^ Multiply(tmp[i][1], 0x0b) ^ Multiply(tmp[i][2], 0x0d) ^ Multiply(tmp[i][3], 0x09);
state[i*4+1] = Multiply(tmp[i][0], 0x09) ^ Multiply(tmp[i][1], 0x0e) ^ Multiply(tmp[i][2], 0x0b) ^ Multiply(tmp[i][3], 0x0d);
state[i*4+2] = Multiply(tmp[i][0], 0x0d) ^ Multiply(tmp[i][1], 0x09) ^ Multiply(tmp[i][2], 0x0e) ^ Multiply(tmp[i][3], 0x0b);
state[i*4+3] = Multiply(tmp[i][0], 0x0b) ^ Multiply(tmp[i][1], 0x0d) ^ Multiply(tmp[i][2], 0x09) ^ Multiply(tmp[i][3], 0x0e);
}
}
// 解密函数
static void InvCipher(state_t state, const uint32_t* RoundKey) {
// 初始轮密钥加
AddRoundKey(Nr, state, RoundKey);
// 9轮完整解密
for (int round = Nr-1; round > 0; --round) {
InvShiftRows(state);
InvSubBytes(state);
AddRoundKey(round, state, RoundKey);
InvMixColumns(state);
}
// 最后一轮
InvShiftRows(state);
InvSubBytes(state);
AddRoundKey(0, state, RoundKey);
}
// ECB解密
void AES_ECB_decrypt(const uint8_t* input, const uint8_t* key, uint8_t* output, size_t length) {
if (!input || !key || !output || length % 16 != 0) return;
uint32_t RoundKey[Nb*(Nr+1)];
KeyExpansion(key, RoundKey);
for (size_t i = 0; i < length; i += 16) {
state_t state;
memcpy(state, input+i, 16);
InvCipher(state, RoundKey);
memcpy(output+i, state, 16);
}
}
int main() {
uint8_t key[16] = {
0x24, 0x25, 0x8a, 0x5b, 0x6a, 0x20, 0x62, 0x5d,
0xd2, 0x71, 0x64, 0x32, 0xfd, 0xe7, 0x5e, 0xc4
};
uint8_t ciphertext[16] = {
0x22, 0xeb, 0xb5, 0x40, 0x91, 0x62, 0x9c, 0xf7,
0xe2, 0x13, 0xff, 0xa8, 0x8c, 0x54, 0xd9, 0x80
};
uint8_t decrypted[16];
AES_ECB_decrypt(ciphertext, key, decrypted, sizeof(ciphertext));
printf("解密结果: ");
for (int i = 0; i < sizeof(decrypted); i++) {
printf("%02x", decrypted[i]);
}
return 0;
}
在InvMixColumns函数里面是最后异或结果,所以解密的时候应该先异或回去再逆向列混淆
在网页看到有100个用户名,天塌了
直接利用libcrypto.dll的sign函数
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <windows.h> // 用于动态加载 DLL
#define Nb 4
#define Nr 10
#define Nk 4
typedef uint8_t state_t[16];
#define Nb 4
#define Nr 10
#define Nk 4
// 使用行优先存储(16字节数组)
typedef uint8_t state_t[16];
unsigned char sbox[256] = {
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
};
unsigned char rsbox[256] = {
0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
};
static uint8_t xtime(uint8_t x) {
return ((x << 1) ^ (((x >> 7) & 1) * 0x1b));
}
static uint8_t Multiply(uint8_t x, uint8_t y) {
return (((y & 1) * x) ^
((y >> 1 & 1) * xtime(x)) ^
((y >> 2 & 1) * xtime(xtime(x))) ^
((y >> 3 & 1) * xtime(xtime(xtime(x)))) ^
((y >> 4 & 1) * xtime(xtime(xtime(xtime(x))))));
}
// 逆向字节替换
static void InvSubBytes(state_t state) {
for (int i = 0; i < 16; ++i) {
state[i] = rsbox[state[i]];
}
}
// 密钥扩展
static void KeyExpansion(const uint8_t* Key, uint32_t* RoundKey) {
// 初始密钥拷贝
for (int i = 0; i < Nk; ++i) {
RoundKey[i] = ((uint32_t)Key[4*i]<<24) | ((uint32_t)Key[4*i+1]<<16) |
((uint32_t)Key[4*i+2]<<8) | (uint32_t)Key[4*i+3];
}
const uint32_t Rcon[10] = {
0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000
};
// 密钥扩展
for (int i = Nk; i < Nb*(Nr+1); ++i) {
uint32_t temp = RoundKey[i-1];
if (i % Nk == 0) {
temp = (temp << 8) | (temp >> 24);
temp = (sbox[(temp >> 24) & 0xFF] << 24) |
(sbox[(temp >> 16) & 0xFF] << 16) |
(sbox[(temp >> 8) & 0xFF] << 8) |
sbox[temp & 0xFF];
temp ^= Rcon[(i/Nk)-1];
}
RoundKey[i] = RoundKey[i-Nk] ^ temp;
}
}
// 轮密钥加
static void AddRoundKey(uint8_t round, state_t state, const uint32_t* RoundKey) {
for (int i = 0; i < 4; ++i) {
uint32_t kw = RoundKey[round*4 + i];
state[4*i] ^= (kw >> 24) & 0xFF;
state[4*i+1] ^= (kw >> 16) & 0xFF;
state[4*i+2] ^= (kw >> 8) & 0xFF;
state[4*i+3] ^= kw & 0xFF;
}
}
// 逆向行移位
static void InvShiftRows(state_t state) {
uint8_t temp;
// 第1行循环右移1字节
temp = state[13];
state[13] = state[9];
state[9] = state[5];
state[5] = state[1];
state[1] = temp;
// 第2行交换两个字节
temp = state[2];
state[2] = state[10];
state[10] = temp;
temp = state[6];
state[6] = state[14];
state[14] = temp;
// 第3行循环右移3字节
temp = state[3];
state[3] = state[7];
state[7] = state[11];
state[11] = state[15];
state[15] = temp;
}
// 逆向列混淆
static void InvMixColumns(state_t state) {
uint8_t tmp[4][4];
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
tmp[i][j] = state[i*4 + j] ^ 0x55;
}
}
for (int i = 0; i < 4; ++i) {
state[i*4] = Multiply(tmp[i][0], 0x0e) ^ Multiply(tmp[i][1], 0x0b) ^ Multiply(tmp[i][2], 0x0d) ^ Multiply(tmp[i][3], 0x09);
state[i*4+1] = Multiply(tmp[i][0], 0x09) ^ Multiply(tmp[i][1], 0x0e) ^ Multiply(tmp[i][2], 0x0b) ^ Multiply(tmp[i][3], 0x0d);
state[i*4+2] = Multiply(tmp[i][0], 0x0d) ^ Multiply(tmp[i][1], 0x09) ^ Multiply(tmp[i][2], 0x0e) ^ Multiply(tmp[i][3], 0x0b);
state[i*4+3] = Multiply(tmp[i][0], 0x0b) ^ Multiply(tmp[i][1], 0x0d) ^ Multiply(tmp[i][2], 0x09) ^ Multiply(tmp[i][3], 0x0e);
}
}
// 解密函数
static void InvCipher(state_t state, const uint32_t* RoundKey) {
// 初始轮密钥加
AddRoundKey(Nr, state, RoundKey);
// 9轮完整解密
for (int round = Nr-1; round > 0; --round) {
InvShiftRows(state);
InvSubBytes(state);
AddRoundKey(round, state, RoundKey);
InvMixColumns(state);
}
// 最后一轮
InvShiftRows(state);
InvSubBytes(state);
AddRoundKey(0, state, RoundKey);
}
// ECB解密
void AES_ECB_decrypt(const uint8_t* input, const uint8_t* key, uint8_t* output, size_t length) {
if (!input || !key || !output || length % 16 != 0) return;
uint32_t RoundKey[Nb*(Nr+1)];
KeyExpansion(key, RoundKey);
for (size_t i = 0; i < length; i += 16) {
state_t state;
memcpy(state, input+i, 16);
InvCipher(state, RoundKey);
memcpy(output+i, state, 16);
}
}
// ... (保留你原有的 AES 解密相关代码,包括 sbox, rsbox, xtime, Multiply, InvSubBytes, KeyExpansion 等)
// 定义 sign 函数的类型
typedef void (*sign_func_t)(const char*, int, uint8_t*);
// 动态加载 libcrypto.dll 并调用 sign 函数
void call_libcrypto_sign(const char* input, int len, uint8_t* output) {
HMODULE hLib = LoadLibraryA("libcrypto.dll");
if (!hLib) {
fprintf(stderr, "Failed to load libcrypto.dll\n");
exit(1);
}
sign_func_t sign_func = (sign_func_t)GetProcAddress(hLib, "sign");
if (!sign_func) {
fprintf(stderr, "Failed to find 'sign' function in libcrypto.dll\n");
FreeLibrary(hLib);
exit(1);
}
// 调用 sign 函数
sign_func(input, len, output);
FreeLibrary(hLib);
}
// 生成 key 和 ciphertext
void generate_key_and_ciphertext(const char* username, uint8_t* key, uint8_t* ciphertext) {
// key = sign(username)
call_libcrypto_sign(username, strlen(username), key);
// ciphertext = sign(username + "Showmaker11")
char buffer[256];
snprintf(buffer, sizeof(buffer), "%sShowmaker11", username);
call_libcrypto_sign(buffer, strlen(buffer), ciphertext);
}
// 解密所有用户名
void decrypt_all_usernames(const char** usernames, int count) {
for (int i = 0; i < count; i++) {
uint8_t key[16];
uint8_t ciphertext[16];
uint8_t decrypted[16];
// 生成 key 和 ciphertext
generate_key_and_ciphertext(usernames[i], key, ciphertext);
// 解密
AES_ECB_decrypt(ciphertext, key, decrypted, 16);
// 输出结果
printf("Username: %s\n", usernames[i]);
printf("Decrypted: ");
for (int j = 0; j < 16; j++) {
printf("%02x", decrypted[j]);
}
printf("\n\n");
}
}
int main() {
// 示例用户名列表(替换成你的 100 个用户名)
const char* usernames[] = {
"chengang",
"lijuanwang",
"ligh",
"zhangpeng",
"zf",
"zhangliang",
"chenyuying",
"ljh",
"xzchen",
"jingyang",
"fy",
"chenguiying",
"ma",
"wangyuying",
"vm",
"yb",
"xliu",
"ej",
"lgr",
"rn",
"lil",
"lingli",
"ny",
"wanggl",
"ug",
"wangguirong",
"huazhang",
"hongyang",
"lxy",
"liul",
"gw",
"rz",
"nazhang",
"liuqiang",
"ck",
"zgl",
"superadmin",
"ve",
"admin1",
"mw",
"wanggz",
"chenchen",
"flwang",
"yuanfang",
"jgwang",
"shulanwang",
"jn",
"wzhao",
"ychen",
"cgy",
"wangxin",
"zhangxue",
"zhangxin",
"zhoum",
"chengwang",
"taowang",
"tingtingli",
"wangna",
"zhangsz",
"tn",
"tc",
"ba",
"qz",
"fengli",
"lizhou",
"guizhizhang",
"zhoujing",
"to",
"liugang",
"gb",
"jianzhang",
"vd",
"hwang",
"xiuyinghuang",
"tf",
"tw",
"wangyz",
"jyang",
"ei",
"lyli",
"jliu",
"xywang",
"liuling",
"pengwang",
"yumeiwang",
"hd",
"chenjuan",
"wangfy",
"sli",
"zhangbo",
"zhangyy",
"yywang",
"vg",
"liming",
"gli",
"chenjun",
"zhoumin",
"minchen",
"zhangning",
"jgliu",
"inkey"
};
int num_usernames = sizeof(usernames) / sizeof(usernames[0]);
decrypt_all_usernames(usernames, num_usernames);
return 0;
}
手动填写网页就可以了

[NepnepCTF2025]SpeedMino
游戏启动之后flag一直在计算,ce修改游戏速度(不要太太太大,会卡死)加快计算,而且得分也是和时间的关系最大


[NepnepCTF2025]MoewBle喵泡
MeowBle_Data中level2有part1和part2

这个游戏能用il2cppdumper去dump

看到有die函数和health变量,但是我将die函数nop之后如果player受伤就会被罚站,但是看到有人是成功的,那就是我改炸了

分析.NET程序的结构,只有CE的7.5版本以上能够使用这个功能

使用lookup instances查找实例,实例窗口默认比较小,所以可以拉一下,修改health的值,这样角色就无敌了,玩通关(有隐藏关卡)就可以

科乐美秘技,即输入“↑ ↑ ↓ ↓ ← → ← → B A”来获得隐藏技能或彩蛋,这里可以在暂停的时候触发GM,获取flag7

或者调用方法,在点击右上角设置,也能触发GM面板

最后终点在起就能通关了,flag共9段
flag:NepCTF{94721248-773d-0b25-0e2d-db9cac299389}
round-1/rev01(没做完)
VM,C++写的,opcode是文件里面的,通过interpret函数解释字节码
[NewStar CTF 2024]easygui
sub_140001490有反调试,直接修改跳转

加密和比较函数都挺明显的
加密:对输入的字节进行查表替换,每四个字节一组循环右移3位,rc4加密
查表替换

循环右移

rc4加密

rc4解密可以利用程序的自解密,也可以直接算,是标准的

动调提取v29,位运算,查表替换
#include <stdio.h>
#include <stdint.h>
// 加密函数
void encrypt(uint8_t *data, int len) {
for (int k = 0; k < len; k += 4) {
uint8_t a = data[k];
uint8_t b = data[k+1];
uint8_t c = data[k+2];
uint8_t d = data[k+3];
data[k+3] = ((a >> 5) & 0x7) | ((d << 3) & 0xf8);
data[k+2] = ((d >> 5) & 0x7) | ((c << 3) & 0xf8);
data[k+1] = ((c >> 5) & 0x7) | ((b << 3) & 0xf8);
data[k] = ((b >> 5) & 0x7) | ((a << 3) & 0xf8);
}
}
uint8_t v29[] = {
0x31, 0x74, 0x54, 0x20, 0x03, 0x53, 0x78, 0x70, 0x3A, 0x35,
0x65, 0x42, 0x04, 0x6B, 0x1F, 0x43,
0x06, 0x37, 0x00, 0x76, 0x21, 0x08, 0x0B, 0x13, 0x52, 0x4B,
0x2F, 0x1A, 0x59, 0x2C, 0x56, 0x51,
0x7F, 0x3B, 0x0E, 0x05, 0x26, 0x15, 0x25, 0x63, 0x64, 0x7A,
0x3C, 0x29, 0x41, 0x2A, 0x12, 0x17,
0x2E, 0x39, 0x57, 0x3D, 0x66, 0x33, 0x44, 0x6C, 0x6F, 0x47,
0x16, 0x71, 0x5F, 0x1C, 0x14, 0x5A,
0x0C, 0x4F, 0x01, 0x30, 0x1B, 0x68, 0x0F, 0x62, 0x3F, 0x18,
0x69, 0x6D, 0x7E, 0x5D, 0x6A, 0x28,
0x22, 0x5B, 0x55, 0x72, 0x09, 0x5E, 0x02, 0x3E, 0x50, 0x7B,
0x46, 0x45, 0x38, 0x10, 0x48, 0x79,
0x60, 0x36, 0x61, 0x6E, 0x2D, 0x49, 0x7C, 0x2B, 0x34, 0x27,
0x11, 0x7D, 0x0D, 0x0A, 0x77, 0x73,
0x58, 0x5C, 0x4C, 0x32, 0x4D, 0x1E, 0x24, 0x40, 0x67, 0x4A,
0x4E, 0x1D, 0x07, 0x75, 0x19, 0x23
};
char find_char(uint8_t value) {
for (int i = 0; i < 128; i++) {
if (v29[i] == value) {
return (char)i;
}
}
return '?'; // 没找到
}
int main() {
uint8_t Src[] = {
0x6F,0x81,0xA6,0xC5, 0x63,0xAC,0x4B,0xC7, 0x8F,0x29,
0x87,0xA4, 0x27,0xAA,0xA6,0x69, 0x4F,0x27,0xAE,0xEC,
0x27,0x2E,0xE7,0xA9, 0x69,0x87,0x2E,0xE5, 0x2F,0x24,
0xE6,0x6F, 0x44,0x87,0xA9,0x89, 0x4F,0x26,0x47,0x21,
0xAB,0x01,0xA7,0xAE
};
int len = sizeof(Src)/sizeof(Src[0]);
encrypt(Src, len);
for (int i = 0; i < len; i++) {
printf("%c", find_char(Src[i]));
}
return 0;
}
[HDCTF 2023]easy_asm

很明显主要是异或加密,cl是0x10,al就是密文
#include<stdio.h>
int main(){
int a[]={0x4E,0x6F,0x74,0x20,0x65,0x71,0x75,0x61,0x6C,0x21,0x24,
0x45,0x71,0x75,0x61,0x6C,0x21,0x24,0x58,0x54,0x53,0x44,
0x56,0x6B,0x5A,0x65,0x63,0x64,0x4F,0x71,0x4F,0x75,0x23,
0x63,0x69,0x4F,0x71,0x43,0x7D,0x6D,0x24,};
for(int i=0;i<41;i++){
printf("%c",a[i]^0x10);
}
}
flag周围带有乱码
[LitCTF 2023]程序和人有一个能跑就行了
直接反编译看到是rc4加密,用程序解密的话得到的是fake flag
看图有两份密文,但是反编译只能看到一份,并且是错的

更换密文

[NewStar CTF 2024]ezrust
动调发现输入,之后又是cmp,所以enc函数只能是在中间

看到loverust字符串
在loverust上面下一个硬件断点,会直接段在这里(好厉害)

a3是输入
异或结果不对

v7=7,v6=8,所以这里对key的索引应该是逆序的
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include<stdint.h>
int main()
{
unsigned char v4[27]={0};
v4[0] = 18;
v4[1] = 31;
v4[2] = 20;
v4[3] = 21;
v4[4] = 30;
v4[5] = 15;
v4[6] = 95;
v4[7] = 57;
v4[8] = 43;
v4[9] = 51;
v4[10] = 7;
v4[11] = 65;
v4[12] = 58;
v4[13] = 79;
v4[14] = 95;
v4[15] = 3;
v4[16] = 16;
v4[17] = 44;
v4[18] = 53;
v4[19] = 6;
v4[20] = 58;
v4[21] = 4;
v4[22] = 26;
v4[23] = 31;
v4[24] = 0;
v4[25] = 14;
char key[]="tsurevol";
for(int i=0;i<27;i++){
printf("%c",v4[i]^key[i%8]);
}
}

浙公网安备 33010602011771号