CyberXbytes CTF 2025
Introduction
This write-up covers my solutions to the Reverse Engineering challenges from CyberXBytes CTF 2025, held on November 15, 2025.
timmy wish
Description: its a curse… its a storm full of whispers…Fairies with shadowed grins, hacks that hunger, what did the wand steal?
First, I load the binary into Ghidra and notice that the entry function refers to this function after printing a story.
This loop:
1
2
3
4
5
local_9 = 0x42;
for (local_18 = 0; local_18 < 0xe3; local_18++) {
DAT_00404040[i] = DAT_00402020[i] ^ local_9;
local_9 = local_9 * 0x11 + 0x5e;
}
- Reads encrypted bytes from
DAT_00402020 - XOR-decodes them using a rolling key
- Stores decoded bytes into
DAT_00404040
To read the decoded flag in the memory after the function execution, load the file into GDB and break the execution at the function FUN_00401126
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(gdb) break *0x0401126
Breakpoint 2 at 0x401126
(gdb) run
In the dim glow of his computer screen, young hacker Timmy tinkered with forbidden code.
One stormy night, he stumbled upon an ancient artifact: a glowing wand etched with binary runes.
"If only I had the ultimate hacking tool," Timmy whispered, waving the wand.
A puff of pink smoke filled the room, and a cheerful fairy appeared. "Your wish is my command!" she chimed.
The fairy waved her wand, and lines of enchanted code materialized, forming a virtual machine of pure magic.
Timmy ran the code, excitement bubbling. The VM hummed to life, granting his wish.
But as the fairy smiled, her eyes flickered red for a split second—devilish eyes, hiding a sinister gleam.
Timmy blinked—had he imagined it? The tool connected to a distant server, whispering secrets.
Unbeknownst to Timmy, the fairy was no benevolent sprite, but a vessel for ancient malice.
She pulled strings from the shadows, turning his hack into a C2 beacon, eyes ever watchful.
And so, the boy who dreamed of code became the cartoon we know, but the demon's whisper lingered...
The end.
Breakpoint 2, 0x0000000000401126 in ?? ()
Run the finish A command that will execute until the current function returns and then give you control back in the caller. After finish completes, dump the memory:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
(gdb) finish
Run till exit from #0 0x0000000000401126 in ?? ()
0x0000000000401a25 in ?? ()
(gdb) x/300bx 0x404040
0x404040: 0x19 0x42 0x00 0x01 0x01 0x05 0x06 0x00
0x404048: 0x01 0x01 0x3b 0x05 0x06 0x01 0x01 0x01
0x404050: 0x20 0x05 0x06 0x02 0x01 0x01 0x27 0x05
0x404058: 0x06 0x03 0x01 0x01 0x30 0x05 0x06 0x04
0x404060: 0x01 0x01 0xaa 0x17 0xaa 0x18 0x2b 0x00
0x404068: 0x16 0x05 0x03 0x01 0x1a 0x05 0x06 0x05
0x404070: 0x01 0x01 0x20 0x05 0x06 0x06 0x01 0x01
0x404078: 0x3b 0x05 0x06 0x07 0x01 0x01 0x36 0x05
0x404080: 0x06 0x08 0x01 0x01 0x27 0x05 0x06 0x09
0x404088: 0x01 0x01 0xaa 0x17 0xaa 0x18 0x53 0x00
0x404090: 0x16 0x05 0x03 0x01 0x31 0x05 0x06 0x0a
0x404098: 0x01 0x01 0x39 0x05 0x06 0x0b 0x01 0x01
0x4040a0: 0x06 0x05 0x06 0x0c 0x01 0x01 0x71 0x05
0x4040a8: 0x06 0x0d 0x01 0x01 0x34 0x05 0x06 0x0e
0x4040b0: 0x01 0x01 0xaa 0x17 0xaa 0x18 0x7b 0x00
0x4040b8: 0x16 0x05 0x03 0x01 0x73 0x05 0x06 0x0f
0x4040c0: 0x01 0x01 0x2e 0x05 0x06 0x10 0x01 0x01
0x4040c8: 0x73 0x05 0x06 0x11 0x01 0x01 0x31 0x05
0x4040d0: 0x06 0x12 0x01 0x01 0x2a 0x05 0x06 0x13
0x4040d8: 0x01 0x01 0xaa 0x17 0xaa 0x18 0xa3 0x00
0x4040e0: 0x16 0x05 0x03 0x01 0x1d 0x05 0x06 0x14
0x4040e8: 0x01 0x01 0x27 0x05 0x06 0x15 0x01 0x01
0x4040f0: 0x3b 0x05 0x06 0x16 0x01 0x01 0x27 0x05
0x4040f8: 0x06 0x17 0x01 0x01 0x31 0x05 0x06 0x18
0x404100: 0x01 0x01 0xaa 0x17 0xaa 0x18 0xcb 0x00
0x404108: 0x16 0x05 0x03 0x01 0x1d 0x05 0x06 0x19
0x404110: 0x01 0x01 0x21 0x05 0x06 0x1a 0x01 0x01
0x404118: 0x70 0x05 0x06 0x1b 0x01 0x01 0x3f 0x05
0x404120: 0x06 0x1c 0x01 0x00 0x00 0x00 0x00 0x00
0x404128: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x404130: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x404138: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x404140: 0x43 0x79 0x62 0x65 0x72 0x58 0x62 0x79
0x404148: 0x74 0x65 0x73 0x7b 0x44 0x33 0x76 0x31
0x404150: 0x6c 0x31 0x73 0x68 0x5f 0x65 0x79 0x65
0x404158: 0x73 0x5f 0x63 0x32 0x7d 0x00 0x00 0x00
0x404160: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x404168: 0x00 0x00 0x00 0x00
Everything before 0x404140 looks like structured VM instruction bytes, and the decoded flag is in these three addresses
1
2
3
0x404148: 0x74 0x65 0x73 0x7b 0x44 0x33 0x76 0x31
0x404150: 0x6c 0x31 0x73 0x68 0x5f 0x65 0x79 0x65
0x404158: 0x73 0x5f 0x63 0x32 0x7d 0x00 0x00 0x00
decode the hex values
1
2
hex_bytes = "43 79 62 65 72 58 62 79 74 65 73 7b 44 33 76 31 6c 31 73 68 5f 65 79 65 73 5f 63 32 7d"
print(bytes.fromhex(hex_bytes).decode())
1
2
$ python3 decode.py
CyberXbytes{D3v1l1sh_eyes_c2}
notpolite
Description: can you charm the beast, or does it devour?
1
2
3
4
5
6
$ file notpolite
notpolite: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=a0113d1c20566f9e4f0a65042365242e09dc7970, for GNU/Linux 3.2.0, stripped
$ ./notpolite
The algorithm was not polite
but handsome
and yeah, I think everyone can do it—do it, do it
This is the entry function. There is a call to the function FUN_00401126
Function FUN_00401126
The concept same as the first challenge, the program reads the encoded flag from DAT_00402020 XORs them with a pseudo-random byte, and writes the result to the memory address DAT_00404040.
Load the file into gdb and break the execution at the function FUN_00401126
1
2
3
4
5
6
7
8
9
10
11
(gdb) b *0x0401126
Breakpoint 1 at 0x401126
(gdb) run
The algorithm was not polite
but handsome
and yeah, I think everyone can do it—do it, do it
Breakpoint 1, 0x0000000000401126 in ?? ()
(gdb) finish
Run till exit from #0 0x0000000000401126 in ?? ()
0x0000000000401400 in ?? ()
Examine 509 bytes of memory starting at the address 0x404040
1
(gdb) x/300bx 0x404040
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
0x404040: 0x01 0x43 0x06 0x00 0x08 0x01 0x79 0x06
0x404048: 0x01 0x08 0x01 0x62 0x06 0x02 0x08 0x01
0x404050: 0x65 0x06 0x03 0x08 0x01 0x72 0x06 0x04
0x404058: 0x08 0x01 0x58 0x06 0x05 0x08 0x01 0x62
0x404060: 0x06 0x06 0x08 0x01 0x79 0x06 0x07 0x08
0x404068: 0x01 0x74 0x06 0x08 0x08 0x01 0x65 0x06
0x404070: 0x09 0x08 0x01 0x73 0x06 0x0a 0x08 0x01
0x404078: 0x7b 0x06 0x0b 0x08 0x01 0x65 0x06 0x0c
0x404080: 0x08 0x01 0x61 0x06 0x0d 0x08 0x01 0x73
0x404088: 0x06 0x0e 0x08 0x01 0x79 0x06 0x0f 0x08
0x404090: 0x01 0x5f 0x06 0x10 0x08 0x01 0x66 0x06
0x404098: 0x11 0x08 0x01 0x6c 0x06 0x12 0x08 0x01
0x4040a0: 0x61 0x06 0x13 0x08 0x01 0x67 0x06 0x14
0x4040a8: 0x08 0x01 0x7d 0x06 0x15 0x08 0x01 0x43
0x4040b0: 0x06 0x00 0x09 0x01 0x79 0x06 0x01 0x09
0x4040b8: 0x01 0x62 0x06 0x02 0x09 0x01 0x65 0x06
0x4040c0: 0x03 0x09 0x01 0x72 0x06 0x04 0x09 0x01
0x4040c8: 0x58 0x06 0x05 0x09 0x01 0x62 0x06 0x06
0x4040d0: 0x09 0x01 0x79 0x06 0x07 0x09 0x01 0x74
0x4040d8: 0x06 0x08 0x09 0x01 0x65 0x06 0x09 0x09
0x4040e0: 0x01 0x73 0x06 0x0a 0x09 0x01 0x7b 0x06
0x4040e8: 0x0b 0x09 0x01 0x74 0x06 0x0c 0x09 0x01
0x4040f0: 0x6f 0x06 0x0d 0x09 0x01 0x6f 0x06 0x0e
0x4040f8: 0x09 0x01 0x5f 0x06 0x0f 0x09 0x01 0x73
0x404100: 0x06 0x10 0x09 0x01 0x69 0x06 0x11 0x09
0x404108: 0x01 0x6d 0x06 0x12 0x09 0x01 0x70 0x06
0x404110: 0x13 0x09 0x01 0x6c 0x06 0x14 0x09 0x01
0x404118: 0x65 0x06 0x15 0x09 0x01 0x7d 0x06 0x16
0x404120: 0x09 0x10 0x64 0x00 0x00 0x00 0x16 0x18
0x404128: 0xe6 0x00 0x01 0x43 0x06 0x00 0x10 0x01
0x404130: 0x79 0x06 0x01 0x10 0x01 0x62 0x06 0x02
0x404138: 0x10 0x01 0x65 0x06 0x03 0x10 0x01 0x72
0x404140: 0x06 0x04 0x10 0x01 0x58 0x06 0x05 0x10
0x404148: 0x01 0x62 0x06 0x06 0x10 0x01 0x79 0x06
0x404150: 0x07 0x10 0x01 0x74 0x06 0x08 0x10 0x01
0x404158: 0x65 0x06 0x09 0x10 0x01 0x73 0x06 0x0a
0x404160: 0x10 0x01 0x7b 0x06 0x0b 0x10 0x01 0x68
0x404168: 0x06 0x0c 0x10 0x01 0x6d 0x06 0x0d 0x10
--Type <RET> for more, q to quit, c to continue without paging--
Type C to continue dumping the memory content
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
0x404170: 0x01 0x6d 0x06 0x0e 0x10 0x01 0x6d 0x06
0x404178: 0x0f 0x10 0x01 0x6d 0x06 0x10 0x10 0x01
0x404180: 0x6d 0x06 0x11 0x10 0x01 0x5f 0x06 0x12
0x404188: 0x10 0x01 0x69 0x06 0x13 0x10 0x01 0x5f
0x404190: 0x06 0x14 0x10 0x01 0x74 0x06 0x15 0x10
0x404198: 0x01 0x68 0x06 0x16 0x10 0x01 0x69 0x06
0x4041a0: 0x17 0x10 0x01 0x6e 0x06 0x18 0x10 0x01
0x4041a8: 0x6b 0x06 0x19 0x10 0x01 0x5f 0x06 0x1a
0x4041b0: 0x10 0x01 0x65 0x06 0x1b 0x10 0x01 0x76
0x4041b8: 0x06 0x1c 0x10 0x01 0x65 0x06 0x1d 0x10
0x4041c0: 0x01 0x72 0x06 0x1e 0x10 0x01 0x79 0x06
0x4041c8: 0x1f 0x10 0x01 0x31 0x06 0x20 0x10 0x01
0x4041d0: 0x5f 0x06 0x21 0x10 0x01 0x63 0x06 0x22
0x4041d8: 0x10 0x01 0x61 0x06 0x23 0x10 0x01 0x6e
0x4041e0: 0x06 0x24 0x10 0x01 0x5f 0x06 0x25 0x10
0x4041e8: 0x01 0x64 0x06 0x26 0x10 0x01 0x6f 0x06
0x4041f0: 0x27 0x10 0x01 0x69 0x06 0x28 0x10 0x01
0x4041f8: 0x74 0x06 0x29 0x10 0x01 0x64 0x06 0x2a
0x404200: 0x10 0x01 0x6f 0x06 0x2b 0x10 0x01 0x69
0x404208: 0x06 0x2c 0x10 0x01 0x74 0x06 0x2d 0x10
0x404210: 0x01 0x64 0x06 0x2e 0x10 0x01 0x6f 0x06
0x404218: 0x2f 0x10 0x01 0x69 0x06 0x30 0x10 0x01
0x404220: 0x74 0x06 0x31 0x10 0x01 0x67 0x06 0x32
0x404228: 0x10 0x01 0x6f 0x06 0x33 0x10 0x01 0x6f
0x404230: 0x06 0x34 0x10 0x01
When I tried to hex decode them, it resulted in garbled text for the last part
1
2
3
4
5
6
7
hex_val = """
01430600080179060108016206020801650603080172060408015806050801620606080179060708017406080801650609080173060A08017B060B080165060C080161060D080173060E080179060F08015F0610080166061108016C06120801610613080167061408017D06150801430600090179060109016206020901650603090172060409015806050901620606090179060709017406080901650609090173060A09017B060B090174060C09016F060D09016F060E09015F060F0901730610090169061109016D0612090170061309016C0614090165061509017D061609016D060E10016D060F10016D061010016D061110015F0612100169061310015F061410017406151001680616100169061710016E061810016B061910015F061A100165061B100176061C100165061D100172061E100179061F100131062010015F06211001630622100161062310016E062410015F0625100164062610016F062710016906281001740629100164062A10016F062B100169062C100174062D100164062E10016F062F10016906301001740631100167063210016F063310016F0634100101
"""
byte_data = bytes.fromhex(hex_val)
ascii_string = "".join(chr(b) for b in byte_data if 32 <= b <= 126)
print(ascii_string)
1
CyberXbytes{easy_flag}CyberXbytes{too_simple}mmmm_i_think_every1 _!c"a#n$_%d&o'i(t)d*o+i,t-d.o/i0t1g2o3o4
The reason we have two decoy flags and the last part results in random strings. It’s because the program writes the decoded strings into three memory regions using the VM instructions to write bytecodes into the target memory address, which is not as obvious as the first challenge. From the memory dump, we note that each 5-byte block encodes one character and its position and a group.
1
[ opcode | value | opcode2 | index | program_id ]
Example: Memory address 0x404040
1
0x01 0x43 0x06 0x00 0x08
- The first byte (
0x01) is always the same → VM instruction type. - The second byte (
0x43) is an ASCII value (0x43 = ‘C’). - The third byte (
0x06) is constant → separator or type. - The fourth byte (
00,01,02, …) increases → index in memory. - The fifth byte (
10,09,08) changes in groups.
The two flags were clear because the bytecode was sorted, but not for the last one
- First flag ends at address: 0x4040a8 group id
0x08 - Second flag: starts after the first flag and ends at address 0x404120 group id
0x09 - As for the last part, this one needs to be sorted.
Before sorting the last part, we need to continue dumping the memory after 0x404230
1
2
3
4
5
(gdb) x/300bx 0x404230
0x404230: 0x06 0x34 0x10 0x01 0x64 0x06 0x35 0x10
0x404238: 0x01 0x7d 0x06 0x36 0x10 0x00 0x00 0x00
0x404240: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
.....
The last part ends at 0x404238 the rest are zero. Now we need to write a Python code to sort the bytecodes of the last part based on the program ID (groups: 10, 9 , 8) and the index of the ASCII character.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#!/usr/bin/env python3
raw = [
0x01,0x43,0x06,0x00,0x08,0x01,0x79,0x06,0x01,0x08,0x01,0x62,0x06,0x02,0x08,
0x01,0x65,0x06,0x03,0x08,0x01,0x72,0x06,0x04,0x08,0x01,0x58,0x06,0x05,0x08,
0x01,0x62,0x06,0x06,0x08,0x01,0x79,0x06,0x07,0x08,0x01,0x74,0x06,0x08,0x08,
0x01,0x65,0x06,0x09,0x08,0x01,0x73,0x06,0x0a,0x08,0x01,0x7b,0x06,0x0b,0x08,
0x01,0x65,0x06,0x0c,0x08,0x01,0x61,0x06,0x0d,0x08,0x01,0x73,0x06,0x0e,0x08,
0x01,0x79,0x06,0x0f,0x08,0x01,0x5f,0x06,0x10,0x08,0x01,0x66,0x06,0x11,0x08,
0x01,0x6c,0x06,0x12,0x08,0x01,0x61,0x06,0x13,0x08,0x01,0x67,0x06,0x14,0x08,
0x01,0x7d,0x06,0x15,0x08,
0x01,0x43,0x06,0x00,0x09,0x01,0x79,0x06,0x01,0x09,0x01,0x62,0x06,0x02,0x09,
0x01,0x65,0x06,0x03,0x09,0x01,0x72,0x06,0x04,0x09,0x01,0x58,0x06,0x05,0x09,
0x01,0x62,0x06,0x06,0x09,0x01,0x79,0x06,0x07,0x09,0x01,0x74,0x06,0x08,0x09,
0x01,0x65,0x06,0x09,0x09,0x01,0x73,0x06,0x0a,0x09,0x01,0x7b,0x06,0x0b,0x09,
0x01,0x74,0x06,0x0c,0x09,0x01,0x6f,0x06,0x0d,0x09,0x01,0x6f,0x06,0x0e,0x09,
0x01,0x5f,0x06,0x0f,0x09,0x01,0x73,0x06,0x10,0x09,0x01,0x69,0x06,0x11,0x09,
0x01,0x6d,0x06,0x12,0x09,0x01,0x70,0x06,0x13,0x09,0x01,0x6c,0x06,0x14,0x09,
0x01,0x65,0x06,0x15,0x09,0x01,0x7d,0x06,0x16,0x09,
0x01,0x43,0x06,0x00,0x10,0x01,0x79,0x06,0x01,0x10,0x01,0x62,0x06,0x02,0x10,
0x01,0x65,0x06,0x03,0x10,0x01,0x72,0x06,0x04,0x10,0x01,0x58,0x06,0x05,0x10,
0x01,0x62,0x06,0x06,0x10,0x01,0x79,0x06,0x07,0x10,0x01,0x74,0x06,0x08,0x10,
0x01,0x65,0x06,0x09,0x10,0x01,0x73,0x06,0x0a,0x10,0x01,0x7b,0x06,0x0b,0x10,
0x01,0x68,0x06,0x0c,0x10,0x01,0x6d,0x06,0x0d,0x10,0x01,0x6d,0x06,0x0e,0x10,
0x01,0x6d,0x06,0x0f,0x10,0x01,0x6d,0x06,0x10,0x10,0x01,0x6d,0x06,0x11,0x10,
0x01,0x5f,0x06,0x12,0x10,0x01,0x69,0x06,0x13,0x10,0x01,0x5f,0x06,0x14,0x10,
0x01,0x74,0x06,0x15,0x10,0x01,0x68,0x06,0x16,0x10,0x01,0x69,0x06,0x17,0x10,
0x01,0x6e,0x06,0x18,0x10,0x01,0x6b,0x06,0x19,0x10,0x01,0x5f,0x06,0x1a,0x10,
0x01,0x65,0x06,0x1b,0x10,0x01,0x76,0x06,0x1c,0x10,0x01,0x65,0x06,0x1d,0x10,
0x01,0x72,0x06,0x1e,0x10,0x01,0x79,0x06,0x1f,0x10,0x01,0x31,0x06,0x20,0x10,
0x01,0x5f,0x06,0x21,0x10,0x01,0x63,0x06,0x22,0x10,0x01,0x61,0x06,0x23,0x10,
0x01,0x6e,0x06,0x24,0x10,0x01,0x5f,0x06,0x25,0x10,0x01,0x64,0x06,0x26,0x10,
0x01,0x6f,0x06,0x27,0x10,0x01,0x69,0x06,0x28,0x10,0x01,0x74,0x06,0x29,0x10,
0x01,0x64,0x06,0x2a,0x10,0x01,0x6f,0x06,0x2b,0x10,0x01,0x69,0x06,0x2c,0x10,
0x01,0x74,0x06,0x2d,0x10,0x01,0x64,0x06,0x2e,0x10,0x01,0x6f,0x06,0x2f,0x10,
0x01,0x69,0x06,0x30,0x10,0x01,0x74,0x06,0x31,0x10,0x01,0x67,0x06,0x32,0x10,
0x01,0x6f,0x06,0x33,0x10,0x01,0x6f,0x06,0x34,0x10,0x01,0x64,0x06,0x35,0x10,
0x01,0x7d,0x06,0x36,0x10
]
groups = {}
i = 0
while i < len(raw):
if raw[i] == 1:
ch = chr(raw[i+1])
pos = raw[i+3]
group = raw[i+4]
groups.setdefault(group, {})[pos] = ch
i += 5
else:
i += 1
for g in sorted(groups):
s = "".join(groups[g][i] for i in sorted(groups[g]))
print(f"Group {hex(g)}:", s)
1
2
3
4
python3 emulater2.py
Group 0x8: CyberXbytes{easy_flag}
Group 0x9: CyberXbytes{too_simple}
Group 0x10: CyberXbytes{hmmmmm_i_think_every1_can_doitdoitdoitgood}
The real flag is the one in the group 0x10
VeryPolite
Description: consider one thing. it’s very polite challenge.
1
2
file verypolite
verypolite: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=97c30421475a8c8879f8a3730996e8e1da643027, for GNU/Linux 3.2.0, stripped
The program does not print anything and enters a loop state if no arguments are passed.
Here is the entry function, which calls FUN_00404140 with a function pointer to FUN_004015c0
This is the function FUN_00401910that calculates the flag. I added comments and changed the code to make it more readable
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// ------------------------------------------------------------
// Decrypts 4 blocks of encoded data into a continuous output buffer.
// Each block has:
// - A size (number of 4-byte integers)
// - A starting XOR key
// - A pointer to encoded uint32 values
//
// Output is written sequentially to param_out and null-terminated.
// ------------------------------------------------------------
void decode_flag(uint8_t *out_buffer)
{
int block_index = 0;
int total_bytes_written = 0;
uint8_t *write_ptr = out_buffer;
// Iterate over 4 encrypted blocks
do {
// Number of uint32 values in this block (85 per dump)
int block_len = DAT_004790f0[block_index];
// Starting XOR key for this block (0x11, 0x22, 0x33, 0x44)
uint8_t xor_key = DAT_004790ec[block_index];
// Pointer to the encoded uint32 block
uint32_t *encoded_ptr = (uint32_t *)PTR_DAT_004a1e40[block_index];
if (block_len > 0)
{
uint8_t *cur_out = write_ptr;
// Process block_len 32-bit integers
for (int i = 0; i < block_len; i++)
{
uint32_t value = encoded_ptr[i];
// Extract each byte of the 32-bit value
for (int byte_index = 0; byte_index < 4; byte_index++)
{
uint8_t extracted_byte = (value >> (byte_index * 8)) & 0xFF;
// XOR with current key
uint8_t decoded = extracted_byte ^ xor_key;
// Write decoded byte to output
cur_out[byte_index] = decoded;
// Increment key for next byte
xor_key++;
}
// Move output pointer forward by 4 bytes
cur_out += 4;
}
// Move the main write pointer forward by total bytes processed
write_ptr += block_len * 4;
}
// Track total bytes written, for adding final '\0'
total_bytes_written += block_len * 4;
block_index++;
} while (block_index != 4);
// Null-terminate output string
out_buffer[total_bytes_written] = '\0';
}
From the code, the structure of the algorithm is as follows: The program iterates over 4 encrypted blocks, each block contains:
DAT_004790f0contain the size of each blockDAT_004790eccontain starting xor keyPTR_DAT_004a1e40contains a pointer to the actual encrypted blocks.
We need to read these three memory dumps to calculate the final flag. Load the binary into gdb and extract:
DAT_004790f0(4 integers)DAT_004790ec(4 bytes)PTR_DAT_004a1e40(4 pointers) each pointer points toiVar1* 4 bytes of encrypted data
1
2
3
4
5
6
7
(gdb) x/4wd 0x004790f0
0x4790f0: 55 55 55 55
(gdb) x/4bx 0x004790ec
0x4790ec: 0x11 0x22 0x33 0x44
(gdb) x/4gx 0x004a1e40
0x4a1e40: 0x00000000004793a0 0x00000000004792c0
0x4a1e50: 0x00000000004791e0 0x0000000000479100
Extract the data pointed by each pointer (Each block has 55(size)* 4 = 220 bytes.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
(gdb) x/220bx 0x4793a0 # block 0
0x4793a0: 0x3a 0x39 0x38 0x3f 0x3e 0x3d 0x3c 0x33
0x4793a8: 0x32 0x31 0x30 0x37 0x36 0x35 0x34 0x0b
0x4793b0: 0x0a 0x09 0x08 0x0f 0x0e 0x0d 0x0c 0x03
0x4793b8: 0x02 0x01 0x00 0x07 0x06 0x05 0x04 0x1b
0x4793c0: 0x1a 0x19 0x18 0x1f 0x1e 0x1d 0x1c 0x13
0x4793c8: 0x12 0x11 0x10 0x17 0x16 0x15 0x14 0x6b
0x4793d0: 0x6a 0x69 0x68 0x6f 0x6e 0x6d 0x6c 0x63
0x4793d8: 0x62 0x61 0x60 0x67 0x66 0x65 0x64 0x7b
0x4793e0: 0x7a 0x79 0x78 0x7f 0x7e 0x7d 0x7c 0x73
0x4793e8: 0x72 0x71 0x70 0x77 0x76 0x75 0x74 0x4b
0x4793f0: 0x4a 0x49 0x48 0x4f 0x4e 0x4d 0x4c 0x43
0x4793f8: 0x42 0x41 0x40 0x47 0x46 0x45 0x44 0x5b
0x479400: 0x5a 0x59 0x58 0x5f 0x5e 0x5d 0x5c 0x53
0x479408: 0x52 0x51 0x50 0x57 0x56 0x55 0x54 0xab
0x479410: 0xaa 0xa9 0xa8 0xaf 0xab 0xab 0xaa 0xa5
0x479418: 0xa4 0xa7 0xa5 0xa1 0xa0 0xa3 0xa1 0xbd
0x479420: 0xbc 0xbf 0xbe 0xb9 0xb8 0xbb 0xba 0xb6
0x479428: 0xb4 0xb7 0xb6 0xb1 0xb0 0xb0 0xb2 0x8d
0x479430: 0x8c 0x8f 0x8e 0x89 0x88 0x8b 0x8a 0x85
0x479438: 0x87 0x81 0x80 0x87 0x86 0x85 0x84 0x9b
0x479440: 0x9a 0x99 0x98 0x9a 0x98 0x9b 0x9a 0x95
0x479448: 0x94 0x97 0x96 0x91 0x90 0x93 0x92 0xed
0x479450: 0xec 0xef 0xee 0xe9 0xe8 0xeb 0xea 0xe5
0x479458: 0xe4 0xe7 0xe6 0xe1 0xe0 0xe3 0xe2 0xfd
0x479460: 0xfc 0xff 0xfe 0xf9 0xf8 0xfb 0xfa 0xf5
0x479468: 0xf4 0xf7 0xf6 0xf1 0xf0 0xf3 0xf2 0xcd
0x479470: 0xcc 0xcf 0xcd 0xcf 0xce 0xcd 0xcc 0xc3
0x479478: 0xc2 0xc1 0xc0 0xc7
(gdb) x/220bx 0x4792c0 # block 1
0x4792c0: 0x09 0x08 0x0f 0x0e 0x0d 0x0c 0x03 0x02
0x4792c8: 0x01 0x00 0x07 0x06 0x05 0x04 0x1b 0x1a
0x4792d0: 0x19 0x18 0x1f 0x1e 0x1d 0x1c 0x13 0x12
0x4792d8: 0x11 0x10 0x17 0x16 0x15 0x14 0x6b 0x6a
0x4792e0: 0x69 0x68 0x6f 0x6e 0x6d 0x6c 0x63 0x62
0x4792e8: 0x61 0x60 0x67 0x66 0x65 0x64 0x7b 0x7a
0x4792f0: 0x79 0x78 0x7f 0x7e 0x7d 0x7c 0x73 0x72
0x4792f8: 0x71 0x70 0x72 0x70 0x73 0x72 0x4d 0x4c
0x479300: 0x4f 0x4e 0x49 0x48 0x4b 0x4a 0x45 0x44
0x479308: 0x47 0x46 0x41 0x40 0x43 0x42 0x5d 0x5c
0x479310: 0x5f 0x5e 0x59 0x58 0x5b 0x5a 0x55 0x54
0x479318: 0x57 0x56 0x51 0x50 0x53 0x52 0xad 0xac
0x479320: 0xaf 0xae 0xa9 0xa8 0xab 0xaa 0xa5 0xa4
0x479328: 0xa7 0xa6 0xa1 0xa0 0xa3 0xa2 0xbd 0xbc
0x479330: 0xbf 0xbe 0xb9 0xb8 0xbb 0xba 0xb5 0xb4
0x479338: 0xb7 0xb6 0xb2 0xb6 0xb5 0xb4 0x8b 0x8a
0x479340: 0x89 0x88 0x8f 0x8e 0x8d 0x8c 0x83 0x82
0x479348: 0x81 0x80 0x87 0x86 0x85 0x84 0x9b 0x9a
0x479350: 0x99 0x98 0x9f 0x9e 0x9d 0x9c 0x93 0x92
0x479358: 0x91 0x90 0x97 0x96 0x95 0x94 0xeb 0xea
0x479360: 0xe9 0xe8 0xef 0xee 0xed 0xe9 0xe3 0xe2
0x479368: 0xe1 0xe0 0xe7 0xe6 0xe0 0xe4 0xfb 0xfa
0x479370: 0xf9 0xf8 0xff 0xfe 0xfd 0xfc 0xf3 0xf2
0x479378: 0xf1 0xf0 0xf7 0xf6 0xf5 0xf4 0xcb 0xca
0x479380: 0xc9 0xc8 0xca 0xc8 0xcb 0xca 0xc5 0xc4
0x479388: 0xc7 0xc6 0xc1 0xc0 0xc3 0xc2 0xdd 0xdc
0x479390: 0xdf 0xde 0xd9 0xd8 0xdb 0xda 0xd5 0xd4
0x479398: 0xd7 0xd6 0xd1 0xd0
(gdb) x/220bx 0x4791e0 # block 2
0x4791e0: 0x1e 0x19 0x1b 0x1b 0x1a 0x15 0x14 0x17
0x4791e8: 0x16 0x11 0x10 0x13 0x12 0x6d 0x6c 0x6f
0x4791f0: 0x6e 0x69 0x68 0x6b 0x6a 0x65 0x64 0x67
0x4791f8: 0x66 0x61 0x60 0x63 0x62 0x7d 0x7c 0x7f
0x479200: 0x7e 0x79 0x78 0x7b 0x7a 0x75 0x74 0x77
0x479208: 0x76 0x71 0x70 0x73 0x72 0x4d 0x4c 0x4f
0x479210: 0x4d 0x4f 0x4e 0x4d 0x4c 0x43 0x42 0x41
0x479218: 0x40 0x47 0x46 0x45 0x44 0x5b 0x5a 0x59
0x479220: 0x58 0x5f 0x5e 0x5d 0x5c 0x53 0x52 0x51
0x479228: 0x50 0x57 0x56 0x55 0x54 0xab 0xaa 0xa9
0x479230: 0xa8 0xaf 0xae 0xad 0xac 0xa3 0xa2 0xa1
0x479238: 0xa0 0xa7 0xa6 0xa5 0xa4 0xbb 0xba 0xb9
0x479240: 0xb8 0xba 0xb8 0xbb 0xba 0xb6 0xb2 0xb1
0x479248: 0xb0 0xb7 0xb6 0xb5 0xb4 0x8b 0x8a 0x89
0x479250: 0x88 0x8f 0x8e 0x8d 0x8c 0x83 0x82 0x84
0x479258: 0x86 0x81 0x80 0x83 0x82 0x9d 0x9c 0x9f
0x479260: 0x9e 0x99 0x98 0x9b 0x9a 0x95 0x94 0x97
0x479268: 0x96 0x91 0x90 0x93 0x92 0xed 0xec 0xef
0x479270: 0xee 0xe9 0xe8 0xeb 0xea 0xe5 0xe4 0xe7
0x479278: 0xe6 0xe1 0xe0 0xe3 0xe2 0xfd 0xfc 0xff
0x479280: 0xfe 0xf9 0xf8 0xfb 0xfa 0xf5 0xf4 0xf7
0x479288: 0xf6 0xf1 0xf0 0xf3 0xf2 0xcd 0xcc 0xcf
0x479290: 0xce 0xc9 0xc8 0xcb 0xca 0xc5 0xc4 0xc7
0x479298: 0xc5 0xc7 0xc6 0xc5 0xc4 0xdb 0xda 0xd9
0x4792a0: 0xd8 0xdf 0xde 0xdd 0xdc 0xd3 0xd2 0xd1
0x4792a8: 0xd0 0xd7 0xd6 0xd5 0xd4 0x2b 0x2a 0x29
0x4792b0: 0x28 0x2f 0x2e 0x2d 0x2c 0x23 0x22 0x21
0x4792b8: 0x20 0x27 0x26 0x25
(gdb) x/220bx 0x479100 # block 3
0x479100: 0x6f 0x6e 0x6d 0x6c 0x63 0x62 0x61 0x60
0x479108: 0x67 0x66 0x65 0x64 0x7b 0x7a 0x79 0x78
0x479110: 0x7f 0x7e 0x7d 0x7c 0x73 0x72 0x71 0x70
0x479118: 0x77 0x73 0x73 0x72 0x4d 0x4c 0x4f 0x4e
0x479120: 0x49 0x48 0x4b 0x4a 0x45 0x44 0x47 0x46
0x479128: 0x41 0x40 0x43 0x42 0x5d 0x5c 0x5f 0x5e
0x479130: 0x59 0x58 0x5b 0x5a 0x55 0x54 0x57 0x56
0x479138: 0x51 0x50 0x53 0x52 0xad 0xac 0xaf 0xae
0x479140: 0xa9 0xa8 0xab 0xaa 0xa5 0xa4 0xa7 0xa6
0x479148: 0xa1 0xa0 0xa3 0xa2 0xbd 0xbc 0xbf 0xbe
0x479150: 0xb9 0xb8 0xbb 0xba 0xb5 0xb7 0xb1 0xb0
0x479158: 0xb7 0xb6 0xb5 0xb4 0x8b 0x8a 0x89 0x88
0x479160: 0x8f 0x8e 0x8d 0x8c 0x83 0x82 0x81 0x80
0x479168: 0x87 0x86 0x85 0x84 0x9b 0x9a 0x99 0x98
0x479170: 0x9f 0x9e 0x9d 0x9c 0x93 0x92 0x91 0x90
0x479178: 0x97 0x96 0x95 0x94 0xeb 0xea 0xe9 0xe8
0x479180: 0xef 0xee 0xed 0xec 0xe3 0xe2 0xe1 0xe0
0x479188: 0xe7 0xe6 0xe5 0xe4 0xfb 0xfa 0xf9 0xf8
0x479190: 0xff 0xfe 0xfd 0xfc 0xf3 0xf2 0xf1 0xf0
0x479198: 0xf7 0xf3 0xf3 0xf2 0xcd 0xcc 0xcf 0xce
0x4791a0: 0xc9 0xc8 0xcb 0xca 0xc5 0xc4 0xc7 0xc6
0x4791a8: 0xc1 0xc0 0xc3 0xc2 0xdd 0xdc 0xdf 0xde
0x4791b0: 0xd9 0xd8 0xdb 0xda 0xd5 0xd4 0xd7 0xd6
0x4791b8: 0xd1 0xd0 0xd3 0xd2 0x2d 0x2c 0x2f 0x2e
0x4791c0: 0x29 0x28 0x2b 0x2a 0x25 0x24 0x27 0x26
0x4791c8: 0x21 0x20 0x23 0x22 0x3d 0x3c 0x3f 0x3e
0x4791d0: 0x39 0x38 0x3b 0x3a 0x35 0x34 0x37 0x36
0x4791d8: 0x31 0x30 0x33 0x31
Now we can build the decoder.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#!/usr/bin/env python3
# Reproduce FUN_00401910 decoding (blocks from 0x4793a0,0x4792c0,0x4791e0,0x479100)
# Keys: 0x11, 0x22, 0x33, 0x44
# Each block length: 55 words (55 * 4 = 220 bytes)
keys = [0x11, 0x22, 0x33, 0x44]
words_count = 55 # each block has 55 uint32 words
# Block bytes
block0 = [
0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c,0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34,0x0b,
0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c,0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04,0x1b,
0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c,0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14,0x6b,
0x6a,0x69,0x68,0x6f,0x6e,0x6d,0x6c,0x63,0x62,0x61,0x60,0x67,0x66,0x65,0x64,0x7b,
0x7a,0x79,0x78,0x7f,0x7e,0x7d,0x7c,0x73,0x72,0x71,0x70,0x77,0x76,0x75,0x74,0x4b,
0x4a,0x49,0x48,0x4f,0x4e,0x4d,0x4c,0x43,0x42,0x41,0x40,0x47,0x46,0x45,0x44,0x5b,
0x5a,0x59,0x58,0x5f,0x5e,0x5d,0x5c,0x53,0x52,0x51,0x50,0x57,0x56,0x55,0x54,0xab,
0xaa,0xa9,0xa8,0xaf,0xab,0xab,0xaa,0xa5,0xa4,0xa7,0xa5,0xa1,0xa0,0xa3,0xa1,0xbd,
0xbc,0xbf,0xbe,0xb9,0xb8,0xbb,0xba,0xb6,0xb4,0xb7,0xb6,0xb1,0xb0,0xb0,0xb2,0x8d,
0x8c,0x8f,0x8e,0x89,0x88,0x8b,0x8a,0x85,0x87,0x81,0x80,0x87,0x86,0x85,0x84,0x9b,
0x9a,0x99,0x98,0x9a,0x98,0x9b,0x9a,0x95,0x94,0x97,0x96,0x91,0x90,0x93,0x92,0xed,
0xec,0xef,0xee,0xe9,0xe8,0xeb,0xea,0xe5,0xe4,0xe7,0xe6,0xe1,0xe0,0xe3,0xe2,0xfd,
0xfc,0xff,0xfe,0xf9,0xf8,0xfb,0xfa,0xf5,0xf4,0xf7,0xf6,0xf1,0xf0,0xf3,0xf2,0xcd,
0xcc,0xcf,0xcd,0xcf,0xce,0xcd,0xcc,0xc3,0xc2,0xc1,0xc0,0xc7
]
block1 = [
0x09,0x08,0x0f,0x0e,0x0d,0x0c,0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04,0x1b,0x1a,
0x19,0x18,0x1f,0x1e,0x1d,0x1c,0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14,0x6b,0x6a,
0x69,0x68,0x6f,0x6e,0x6d,0x6c,0x63,0x62,0x61,0x60,0x67,0x66,0x65,0x64,0x7b,0x7a,
0x79,0x78,0x7f,0x7e,0x7d,0x7c,0x73,0x72,0x71,0x70,0x72,0x70,0x73,0x72,0x4d,0x4c,
0x4f,0x4e,0x49,0x48,0x4b,0x4a,0x45,0x44,0x47,0x46,0x41,0x40,0x43,0x42,0x5d,0x5c,
0x5f,0x5e,0x59,0x58,0x5b,0x5a,0x55,0x54,0x57,0x56,0x51,0x50,0x53,0x52,0xad,0xac,
0xaf,0xae,0xa9,0xa8,0xab,0xaa,0xa5,0xa4,0xa7,0xa6,0xa1,0xa0,0xa3,0xa2,0xbd,0xbc,
0xbf,0xbe,0xb9,0xb8,0xbb,0xba,0xb5,0xb4,0xb7,0xb6,0xb2,0xb6,0xb5,0xb4,0x8b,0x8a,
0x89,0x88,0x8f,0x8e,0x8d,0x8c,0x83,0x82,0x81,0x80,0x87,0x86,0x85,0x84,0x9b,0x9a,
0x99,0x98,0x9f,0x9e,0x9d,0x9c,0x93,0x92,0x91,0x90,0x97,0x96,0x95,0x94,0xeb,0xea,
0xe9,0xe8,0xef,0xee,0xed,0xe9,0xe3,0xe2,0xe1,0xe0,0xe7,0xe6,0xe0,0xe4,0xfb,0xfa,
0xf9,0xf8,0xff,0xfe,0xfd,0xfc,0xf3,0xf2,0xf1,0xf0,0xf7,0xf6,0xf5,0xf4,0xcb,0xca,
0xc9,0xc8,0xca,0xc8,0xcb,0xca,0xc5,0xc4,0xc7,0xc6,0xc1,0xc0,0xc3,0xc2,0xdd,0xdc,
0xdf,0xde,0xd9,0xd8,0xdb,0xda,0xd5,0xd4,0xd7,0xd6,0xd1,0xd0
]
block2 = [
0x1e,0x19,0x1b,0x1b,0x1a,0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12,0x6d,0x6c,0x6f,
0x6e,0x69,0x68,0x6b,0x6a,0x65,0x64,0x67,0x66,0x61,0x60,0x63,0x62,0x7d,0x7c,0x7f,
0x7e,0x79,0x78,0x7b,0x7a,0x75,0x74,0x77,0x76,0x71,0x70,0x73,0x72,0x4d,0x4c,0x4f,
0x4d,0x4f,0x4e,0x4d,0x4c,0x43,0x42,0x41,0x40,0x47,0x46,0x45,0x44,0x5b,0x5a,0x59,
0x58,0x5f,0x5e,0x5d,0x5c,0x53,0x52,0x51,0x50,0x57,0x56,0x55,0x54,0xab,0xaa,0xa9,
0xa8,0xaf,0xae,0xad,0xac,0xa3,0xa2,0xa1,0xa0,0xa7,0xa6,0xa5,0xa4,0xbb,0xba,0xb9,
0xb8,0xba,0xb8,0xbb,0xba,0xb6,0xb2,0xb1,0xb0,0xb7,0xb6,0xb5,0xb4,0x8b,0x8a,0x89,
0x88,0x8f,0x8e,0x8d,0x8c,0x83,0x82,0x84,0x86,0x81,0x80,0x83,0x82,0x9d,0x9c,0x9f,
0x9e,0x99,0x98,0x9b,0x9a,0x95,0x94,0x97,0x96,0x91,0x90,0x93,0x92,0xed,0xec,0xef,
0xee,0xe9,0xe8,0xeb,0xea,0xe5,0xe4,0xe7,0xe6,0xe1,0xe0,0xe3,0xe2,0xfd,0xfc,0xff,
0xfe,0xf9,0xf8,0xfb,0xfa,0xf5,0xf4,0xf7,0xf6,0xf1,0xf0,0xf3,0xf2,0xcd,0xcc,0xcf,
0xce,0xc9,0xc8,0xcb,0xca,0xc5,0xc4,0xc7,0xc5,0xc7,0xc6,0xc5,0xc4,0xdb,0xda,0xd9,
0xd8,0xdf,0xde,0xdd,0xdc,0xd3,0xd2,0xd1,0xd0,0xd7,0xd6,0xd5,0xd4,0x2b,0x2a,0x29,
0x28,0x2f,0x2e,0x2d,0x2c,0x23,0x22,0x21,0x20,0x27,0x26,0x25
]
block3 = [
0x6f,0x6e,0x6d,0x6c,0x63,0x62,0x61,0x60,0x67,0x66,0x65,0x64,0x7b,0x7a,0x79,0x78,
0x7f,0x7e,0x7d,0x7c,0x73,0x72,0x71,0x70,0x77,0x73,0x73,0x72,0x4d,0x4c,0x4f,0x4e,
0x49,0x48,0x4b,0x4a,0x45,0x44,0x47,0x46,0x41,0x40,0x43,0x42,0x5d,0x5c,0x5f,0x5e,
0x59,0x58,0x5b,0x5a,0x55,0x54,0x57,0x56,0x51,0x50,0x53,0x52,0xad,0xac,0xaf,0xae,
0xa9,0xa8,0xab,0xaa,0xa5,0xa4,0xa7,0xa6,0xa1,0xa0,0xa3,0xa2,0xbd,0xbc,0xbf,0xbe,
0xb9,0xb8,0xbb,0xba,0xb5,0xb7,0xb1,0xb0,0xb7,0xb6,0xb5,0xb4,0x8b,0x8a,0x89,0x88,
0x8f,0x8e,0x8d,0x8c,0x83,0x82,0x81,0x80,0x87,0x86,0x85,0x84,0x9b,0x9a,0x99,0x98,
0x9f,0x9e,0x9d,0x9c,0x93,0x92,0x91,0x90,0x97,0x96,0x95,0x94,0xeb,0xea,0xe9,0xe8,
0xef,0xee,0xed,0xec,0xe3,0xe2,0xe1,0xe0,0xe7,0xe6,0xe5,0xe4,0xfb,0xfa,0xf9,0xf8,
0xff,0xfe,0xfd,0xfc,0xf3,0xf2,0xf1,0xf0,0xf7,0xf3,0xf3,0xf2,0xcd,0xcc,0xcf,0xce,
0xc9,0xc8,0xcb,0xca,0xc5,0xc4,0xc7,0xc6,0xc1,0xc0,0xc3,0xc2,0xdd,0xdc,0xdf,0xde,
0xd9,0xd8,0xdb,0xda,0xd5,0xd4,0xd7,0xd6,0xd1,0xd0,0xd3,0xd2,0x2d,0x2c,0x2f,0x2e,
0x29,0x28,0x2b,0x2a,0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22,0x3d,0x3c,0x3f,0x3e,
0x39,0x38,0x3b,0x3a,0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x31
]
blocks = [block0, block1, block2, block3]
# check the block size. must be 55*4 = 220 bytes
for b in blocks:
if len(b) != words_count*4:
print("Warning: block length", len(b), "expected", words_count*4)
decoded = bytearray()
for bi, blk in enumerate(blocks):
key = keys[bi]
# iterate 4-byte words (little-endian)
for w in range(words_count):
base = w*4
# extract bytes in little-endian order
for j in range(4):
byte = blk[base + j]
decoded.append(byte ^ key)
key = (key + 1) & 0xff
# stop at first null if present (FUN_00401910 null-terminates)
if 0 in decoded:
decoded = decoded[:decoded.index(0)]
print("Decoded (raw bytes):")
print(decoded)
The result:
1
2
Decoded (raw bytes):
bytearray(b'++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.-----.---.--------.-----.----------.++++++++++.----------------------------------------------.+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.---------------------------------------------------------------.++++++++++++++++++++++++++++++++++++++++++.++++++.+++++++++++++++++++++.---------------------------.---------------------------------------------.++++++++++++++++++++++++++++++++++++++++++++++++.---.+++++++++++++++++.----------------------------------------------------------------.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.-----------------------------------------------------------.+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.-----------------------------------------------------------------.')
The characters extracted (+ - .) are Brainfuck instructions. See Basics of brainfuck for more info about BF instructions. Here is the Python BF decoder:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
def run_bf(code):
tape = [0] * 30000
ptr = 0
pc = 0
out = []
loop_stack = []
code_len = len(code)
while pc < code_len:
cmd = code[pc]
if cmd == '+':
tape[ptr] = (tape[ptr] + 1) & 0xFF
elif cmd == '-':
tape[ptr] = (tape[ptr] - 1) & 0xFF
elif cmd == '>':
ptr += 1
elif cmd == '<':
ptr -= 1
elif cmd == '.':
out.append(chr(tape[ptr]))
elif cmd == '[':
if tape[ptr] == 0:
# skip loop
open_brackets = 1
while open_brackets:
pc += 1
if code[pc] == '[':
open_brackets += 1
elif code[pc] == ']':
open_brackets -= 1
else:
loop_stack.append(pc)
elif cmd == ']':
if tape[ptr] != 0:
pc = loop_stack[-1]
else:
loop_stack.pop()
pc += 1
return "".join(out)
bf_code = """
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.-----.---.--------.-----.----------.++++++++++.----------------------------------------------.+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.---------------------------------------------------------------.++++++++++++++++++++++++++++++++++++++++++.++++++.+++++++++++++++++++++.---------------------------.---------------------------------------------.++++++++++++++++++++++++++++++++++++++++++++++++.---.+++++++++++++++++.----------------------------------------------------------------.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.-----------------------------------------------------------.+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.-----------------------------------------------------------------.
"""
decoded = run_bf(bf_code)
print("Output:")
print(decoded)
1
2
Output:
told_U_1t5_ez_2b_p0l1t3
Finally, we get the flag.



