Hello guys🤗! today i will write about a REV challenge that met at the CSCV2025 that named:Reezs.

First when you install the file and extract the folder you will have an .exe file like this:

Then I opened IDA and loaded the file to read the main function and understand the execution flow. In IDA View-A, the main function looks like this:

Let F5 to see that pseudocode:
int __fastcall main(int argc, const char **argv, const char **envp)
{
__int64 v3; // rdx
__int64 v4; // r8
__m128i si128; // xmm0
const char *v6; // rcx
_BYTE v8[32]; // [rsp+0h] [rbp-58h] BYREF
char Str[16]; // [rsp+20h] [rbp-38h] BYREF
__m128i v10; // [rsp+30h] [rbp-28h]
__int64 v11; // [rsp+40h] [rbp-18h]
__int64 v12; // [rsp+48h] [rbp-10h]
v10 = 0i64;
*(_OWORD *)Str = 0i64;
v11 = 0i64;
sub_1400010F0("Enter flag: ", argv, envp);
sub_140001170("%32s", Str);
if ( strlen(Str) != 32 )
{
puts("No");
if ( ((unsigned __int64)v8 ^ v12) == _security_cookie )
return 0;
LABEL_5:
__debugbreak();
}
si128 = _mm_load_si128((const __m128i *)&xmmword_14001E030);
*(__m128i *)Str = _mm_xor_si128(_mm_load_si128((const __m128i *)Str), si128);
v10 = _mm_xor_si128(si128, v10);
if ( _mm_movemask_epi8(
_mm_and_si128(
_mm_cmpeq_epi8(*(__m128i *)Str, (__m128i)xmmword_140029000),
_mm_cmpeq_epi8(v10, (__m128i)xmmword_140029010))) == 0xFFFF )
v6 = (const char *)&unk_140023E7C;
else
v6 = "No";
sub_1400010F0(v6, v3, v4);
if ( ((unsigned __int64)v8 ^ v12) != _security_cookie )
goto LABEL_5;
return 0;
}
What are the important parts of that code we should care about? Let me explain.
sub_1400010F0("Enter flag: ", argv, envp);
sub_140001170("%32s", Str);
This line ask us to type 32-byte strings input 32-byte strings(or we know the flag will have 32-byte strings not include the format flag)
si128 = _mm_load_si128((const __m128i *)&xmmword_14001E030);
This line point that it takes 16-byte constant of the xmmord_14001E030 adress into si128
*(__m128i *)Str = _mm_xor_si128(_mm_load_si128((const __m128i *)Str), si128);
This line is load 16-byte of Str XOR with si128 and the result is the first stage 16-byte strings of the Str
v10 = _mm_xor_si128(si128, v10);
v10 at first is assigned to 0i64, which is full of 0. If we XOR with si128, we will receive si128
if ( _mm_movemask_epi8(
_mm_and_si128(
_mm_cmpeq_epi8(*(__m128i *)Str, (__m128i)xmmword_140029000),
_mm_cmpeq_epi8(v10, (__m128i)xmmword_140029010))) == 0xFFFF )
This comparision can be analyze to smaller like this:
_mm_cmpeq_epi8(*(__m128i *)Str, (__m128i)xmmword_140029000),
=>Return 16-byte, each byte = 0xFF if (__m128i )Str == (__m128i)xmmword_140029000, else = 0x00
_mm_and_si128(
=>Only keep if both comparisons are equal at the same position
_mm_movemask_epi8(
=>take top 16-bit of each byte,if the result is 0xFFFF it means the 16-bit verified(or all 16 bytes were equal in both comparisons).
If both of conditions are true, the program will print:
(const char *)&unk_140023E7C
That is yes:
.rdata:0000000140023E7C unk_140023E7C db 59h ; Y ; DATA XREF: main:loc_1400010CA↑o
.rdata:0000000140023E7D db 65h ; e
.rdata:0000000140023E7E db 73h ; s
.rdata:0000000140023E7F db 0
And i find this when point to xmmword_140029010 and press X(jump to xref)
{
BOOL result; // eax
result = IsDebuggerPresent();
if ( !result )
{
xmmword_140029010 = xmmword_14001E010;
xmmword_140029000 = xmmword_14001E000;
}
return result;
}
=>If you run the binary in a debugger, those constants at 0x140029010 and 0x140029000 won’t be initialized=>an anti-debugger trick. And if you don’t run in a debugger, xmmword_140029010 will be xmmword_14001E010 and xmmword_140029000 will be xmmword_14001E000
So i will use what i explained below to extract the flag:
.rdata:000000014001E000 xmmword_14001E000 xmmword 939FCF9C9B9998C99DC8C9989ECFCB9Ah
.rdata:000000014001E010 xmmword_14001E010 xmmword 9F9D9D9DCB989A9B999A98CF9DCFCFCFh
.rdata:000000014001E030 xmmword_14001E030 xmmword 0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAh
+The first stage we take first 16-bytes of xmmword_14001E000 change into hex, then XOR with xmmword_14001E030
The the first 16-byte of xmmword_14001E000 is:
unsigned char ida_chars[] = {
0x9A, 0xCB, 0xCF, 0x9E, 0x98, 0xC9, 0xC8, 0x9D,
0xC9, 0x98, 0x99, 0x9B, 0x9C, 0xCF, 0x9F, 0x93
};
XOR with 0xaa(xmmword_14001E030) into hex:
30 61 65 34 32 63 62 37 63 32 33 31 36 65 35 39
ASCII:
0ae42cb7c2316e59
+The second stage we take first 16-bytes of xmmword_14001E010 change into hex, then XOR with xmmword_14001E030
The the first 16-byte of xmmword_14001E000 is:
unsigned char ida_chars[] = { 0xCF, 0xCF, 0xCF, 0x9D, 0xCF, 0x98, 0x9A, 0x99, 0x9B, 0x9A, 0x98, 0xCB, 0x9D, 0x9D, 0x9D, 0x9F };
XOR with 0xaa(xmmword_14001E030) into hex:
65 65 65 37 65 32 30 33 31 30 32 61 37 37 37 35
ASCII:
eee7e203102a7775
And the flag is CSCV2025{0ae42cb7c2316e59eee7e203102a7775}
That’s all of this challenge. Thanks for reading😘!
