Rating:

The logic of program is simple. The flag xor with a number generated by `gen_rand` function.

It is worth noting that the `memcmp` in PLT is modified to `sub_13A3` during the operation. The encrypted flag will xor with the state of random number generator before the comparison.

It can help you avoid many unnecessary mistakes using the c code generated by IDA directly.

```cpp
#include <bits/stdc++.h>

unsigned __int64 state = 0xFEEDF00DDEADBEEF;

#define BYTE1(x) ((x >> 8) & 0xFF)

unsigned __int32 flag_enc[12] = {
2423218208, 4086265774, 1587874300, 1362717661, 1584332255, 2240307368,
1385551804, 4085442933, 2500108983, 1734086218, 3205726547, 3245367604};

__int64 gen_rand() {
int j; // [rsp+1Ch] [rbp-24h]
int i; // [rsp+20h] [rbp-20h]
unsigned int v3; // [rsp+24h] [rbp-1Ch]
unsigned __int64 v4; // [rsp+28h] [rbp-18h]
unsigned __int64 v5; // [rsp+30h] [rbp-10h]
unsigned __int64 v6; // [rsp+38h] [rbp-8h]

v6 = state & 0x1FF;
v5 = ((unsigned __int64)state >> 9) & 0x7FF;
v4 = ((unsigned __int64)state >> 20) & 0x1FFF;
for (i = 0; i <= 31; ++i) {
for (j = 0; j <= 30; ++j) {
v6 = ((v6 >> 4) ^ BYTE1(v6)) & 1 | (2 * (__int16)v6) & 0x1FF;
v5 = (BYTE1(v5) ^ (v5 >> 10)) & 1 | (2 * (__int16)v5) & 0x7FF;
v4 = ((v4 >> 11) ^ (v4 >> 10) ^ (v4 >> 7) ^ (v4 >> 12)) & 1 |
(2 * (__int16)v4) & 0x1FFF;
}
v3 = (v5 & (unsigned __int8)v6 | (unsigned __int8)(~(__int8)v6 & v4)) &
1 |
(2 * v3);
}
state = v6 | (v4 << 20) | (v5 << 9);
return v3;
}

void sub_13A3(unsigned int *a1) {
state = (unsigned int)*a1 ^ (unsigned __int64)state;
}

int main() {
for (int i = 0; i < 12; i++) {
int v1 = gen_rand();
sub_13A3(flag_enc + i);
flag_enc[i] ^= v1;
}
printf("%s\n", flag_enc);
return 0;
}
// TSGCTF{h1dd3n_func7i0n_4nd_s31f_g07_0verwr173}
```

Original writeup (https://yasarli.com/posts/tsg-ctf-2024-reverse-writeup/).