一
架构、硬件相关API
metal_gpio_get_input_pin
函数百度一下,是从针脚读数据:__inline__ int metal_gpio_get_input_pin(struct metal_gpio *gpio, int pin)
// Get the value of the GPIO pin.
bool __fastcall metal_gpio_get_input_pin(int device, char pin)
{
return device && (device->func(device) & (1 << pin)) != 0;
}
二
初始化
data[0:32) (32字节) = 0, 1, 2, 3, ... , 31
data[32:65) (32+1字节) = "ptm{REDACTEDREDACTEDREDACTEDRED}x00"
data[68:324) (256字节) = 0, 1, 2, 3, ... , 255
三
过程分析
v12 = &var644[(unsigned __int8)v10 + 1604];
v13 = &var644[(unsigned __int8)v11 + 1604];
v14 = *(v12 - 1604) + *(v13 - 1604);
*(v12 - 1604) = v14;
v15 = *(v13 - 1604);
*(v13 - 1604) = v14 - v15;
*(v12 - 1604) = v15 + *(v12 - 1604) - v14;
v12=var644 + v10 + 1604
,这是以栈顶指针的去索引数组,可能是编译器的锅,搞出来的代码有点混乱,后续的*(v12 - 1604)
等价于var644[v10]
:v14 = var644[v10] + var644[v11];
var644[v10] = v14;
v15 = var644[v11];
var644[v11] = v14 - v15;
var644[v10] = v15 + var644[v10] - v14;
unsigned char var644[1604]
逻辑上可以分成四个数组:_BYTE m32[32]; // &var644[0:32]
_BYTE input[33]; // &var644[32:64]
_BYTE m256[256]; // &var644[68:324]
_DWORD output[256]; // &var644[580:1604]
四
加密过程
重复1000次
随机交换m32的两个字节
重复10000次
随机交换m256的两个字节
IP置换:i: 0 -> 31
output[i] = input[m32[i]]
IP置换:i: 0 -> 31
input[i] = output[m32[i]]
P盒运算:i: 0 -> 31
input[i] = m256[input[i]]
i: 0 -> 31
input[i] ^= rand()
i: 0 -> 255
output[i] <<= 1
output[input[j]] ^= 1
output[input[j]] = 1 << (31-j)。
五
流程2 解密
a!=b
则output[a]&output[b]==0
为真。0x101
,行和第0位和第8位为1,表示该行中一个元素第0位为1,一个元素第8位为1,这两个元素可以相同。即该行存在0x100、0x1或0x101,其余为0。def get_bit_idx(x):
i = 0
res = []
while x:
if x & 1:
res.append(i)
i += 1
x >>= 1
return res
rows = [0]*32
cols = [0]*32
for r in range(16):
res = get_bit_idx(row_sums[r])
for a in res:
rows[a] = r
for c in range(16):
res = get_bit_idx(col_sums[c])
for a in res:
cols[a] = c
output = [0]*256
for i in range(32):
output[rows[i]*16 + cols[i]] |= 1 << i
output[input[j]] = 1 << (31-j)
(output[i] & (1 << j)) != 0
,则input[31-j] = i
inputs = [0]*32
for i in range(256):
res = get_bit_idx(output[i])
for j in res:
j = 31 - j
inputs[j] = i
print(inputs)
六
流程1 对称密码 解密
_BYTE m32s[1337 + 1][32]; // &var644[0]
_BYTE m256s[1337 + 1][256]; // &var644[68]
_BYTE xors[1337][32];
void decrypt(unsigned int seed, _BYTE* last_input) {
_BYTE input[33] = { 0, };
_DWORD output[256] = { 0, }; // &var644[580]
memcpy(input, last_input, 32);
int i, j;
_BYTE rm256[256];
// cache rand result
srand(seed);
for (i = 0; i != 32; ++i)
m32s[0][i] = i;
for (i = 0; i != 256; ++i)
m256s[0][i] = i;
for (j = 0; j < ROUNDS; j++) {
for (i = 0; i < 1000; i++) {
_BYTE a = (int)rand() % 32;
_BYTE b = (int)rand() % 32;
if (a != b)
{
_BYTE temp;
temp = m32s[j][a];
m32s[j][a] = m32s[j][b];
m32s[j][b] = temp;
}
};
for (i = 0; i < 10000; i++) {
_BYTE a = rand();
_BYTE b = rand();
if (a != b)
{
_BYTE temp;
temp = m256s[j][a];
m256s[j][a] = m256s[j][b];
m256s[j][b] = temp;
}
};
for (i = 0; i != 32; ++i)
xors[j][i] = rand();
// copy to next round
for (i = 0; i != 32; ++i)
m32s[j+1][i] = m32s[j][i];
for (i = 0; i != 256; ++i)
m256s[j+1][i] = m256s[j][i];
}
for (j = ROUNDS - 1; j >= 0; j--) {
// rbox
for (i = 0; i < 256; i++)
rm256[m256s[j][i]] = i;
// decrypt
for (i = 0; i != 32; ++i)
input[i] ^= xors[j][i];
for (i = 0; i != 32; ++i)
input[i] = rm256[input[i]];
for (i = 0; i != 32; ++i)
output[m32s[j][i]] = input[i];
for (i = 0; i != 32; ++i)
input[m32s[j][i]] = output[i];
};
// print input
printf("input = ");
for (i = 0; i < 33; i++)
printf("%u, ", input[i]);
putchar(10);
printf("input = %sn", input);
}
int main(int argc, const char** argv, const char** envp)
{
_BYTE last_input_flag[33] = { 47, 238, 122, 29, 149, 143, 143, 247, 59, 106, 136, 53, 69, 229, 45, 255, 13, 10, 226, 239, 237, 247, 7, 100, 159, 65, 44, 193, 159, 106, 155, 236, 0 };
decrypt(0, last_input_flag);
decrypt(1, last_input_flag);
return 0;
}
看雪ID:wx_御史神风
https://bbs.kanxue.com/user-home-907036.htm
# 往期推荐
2、恶意木马历险记
球分享
球点赞
球在看
点击阅读原文查看更多
原文始发于微信公众号(看雪学苑):m0leCon CTF 2025 Teaser re Embedded encryption RISCV 对称密码