Overview
The Wide challenge is a simple reverse-engineering task. The description says:
We've received reports that Draeger stashed a huge arsenal in the pocket dimension Flaggle Alpha. You managed to smuggle a discarded access terminal for the Widely Inflated Dimension Editor out of his headquarters, but the entry for the dimension is encrypted. Can you get in and take control?
You get two files: db.exe and wide. I usually start with the file command to see what I'm dealing with.
Inspecting the files
$ file db.ex
db.ex: data
$ file wide
wide: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=13869bb7ce2c22f474b95ba21c9d7e9ff74ecc3f, not stripped
As we can see the wide file is a linux binary and the db.exe is a data file. So lets try to read the content of db.exe
Inspecting db.ex
$ strings db.ex
Primus
people breathe variety practice
Our home dimension
Cheagaz
scene control river importance
The Ice Dimension
Byenoovia
fighting cast it parallel
The Berserk Dimension
Cloteprea
facing motor unusual heavy
The Hungry Dimension
Maraqa
stomach motion sale valuable
The Water Dimension
Aidor
feathers stream sides gate
The Bone Dimension
Flaggle Alpha
admin secret power hidden
HOt*
0ANe
$ hexdump -C db.ex
00000000 00 00 00 00 50 72 69 6d 75 73 00 00 00 00 00 00 |....Primus......|
00000010 00 00 00 00 70 65 6f 70 6c 65 20 62 72 65 61 74 |....people breat|
00000020 68 65 20 76 61 72 69 65 74 79 20 70 72 61 63 74 |he variety pract|
00000030 69 63 65 00 4f 75 72 20 68 6f 6d 65 20 64 69 6d |ice.Our home dim|
00000040 65 6e 73 69 6f 6e 00 00 00 00 00 00 00 00 00 00 |ension..........|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
000000b0 00 00 00 00 00 00 00 00 43 68 65 61 67 61 7a 00 |........Cheagaz.|
000000c0 00 00 00 00 00 00 00 00 73 63 65 6e 65 20 63 6f |........scene co|
000000d0 6e 74 72 6f 6c 20 72 69 76 65 72 20 69 6d 70 6f |ntrol river impo|
000000e0 72 74 61 6e 63 65 00 00 54 68 65 20 49 63 65 20 |rtance..The Ice |
000000f0 44 69 6d 65 6e 73 69 6f 6e 00 00 00 00 00 00 00 |Dimension.......|
00000100 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000160 00 00 00 00 00 00 00 00 00 00 00 00 42 79 65 6e |............Byen|
00000170 6f 6f 76 69 61 00 00 00 00 00 00 00 66 69 67 68 |oovia.......figh|
00000180 74 69 6e 67 20 63 61 73 74 20 69 74 20 70 61 72 |ting cast it par|
00000190 61 6c 6c 65 6c 00 00 00 00 00 00 00 54 68 65 20 |allel.......The |
000001a0 42 65 72 73 65 72 6b 20 44 69 6d 65 6e 73 69 6f |Berserk Dimensio|
000001b0 6e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |n...............|
000001c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000220 43 6c 6f 74 65 70 72 65 61 00 00 00 00 00 00 00 |Cloteprea.......|
00000230 66 61 63 69 6e 67 20 6d 6f 74 6f 72 20 75 6e 75 |facing motor unu|
00000240 73 75 61 6c 20 68 65 61 76 79 00 00 00 00 00 00 |sual heavy......|
00000250 54 68 65 20 48 75 6e 67 72 79 20 44 69 6d 65 6e |The Hungry Dimen|
00000260 73 69 6f 6e 00 00 00 00 00 00 00 00 00 00 00 00 |sion............|
00000270 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
000002d0 00 00 00 00 4d 61 72 61 71 61 00 00 00 00 00 00 |....Maraqa......|
000002e0 00 00 00 00 73 74 6f 6d 61 63 68 20 6d 6f 74 69 |....stomach moti|
000002f0 6f 6e 20 73 61 6c 65 20 76 61 6c 75 61 62 6c 65 |on sale valuable|
00000300 00 00 00 00 54 68 65 20 57 61 74 65 72 20 44 69 |....The Water Di|
00000310 6d 65 6e 73 69 6f 6e 00 00 00 00 00 00 00 00 00 |mension.........|
00000320 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000380 00 00 00 00 00 00 00 00 41 69 64 6f 72 00 00 00 |........Aidor...|
00000390 00 00 00 00 00 00 00 00 66 65 61 74 68 65 72 73 |........feathers|
000003a0 20 73 74 72 65 61 6d 20 73 69 64 65 73 20 67 61 | stream sides ga|
000003b0 74 65 00 00 00 00 00 00 54 68 65 20 42 6f 6e 65 |te......The Bone|
000003c0 20 44 69 6d 65 6e 73 69 6f 6e 00 00 00 00 00 00 | Dimension......|
000003d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000430 00 00 00 00 00 00 00 00 01 00 00 00 46 6c 61 67 |............Flag|
00000440 67 6c 65 20 41 6c 70 68 61 00 00 00 61 64 6d 69 |gle Alpha...admi|
00000450 6e 20 73 65 63 72 65 74 20 70 6f 77 65 72 20 68 |n secret power h|
00000460 69 64 64 65 6e 00 00 00 00 00 00 00 48 4f 74 2a |idden.......HOt*|
00000470 1f e8 cf 8e 87 80 7b 58 74 0e 1c a3 ee f8 95 30 |......{Xt......0|
00000480 41 4e 65 0b b9 d8 00 00 00 00 00 00 00 00 00 00 |ANe.............|
00000490 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
000004e0 00 00 00 00 00 00 00 00 00 00 00 00 |............|
000004ec
Looks like nothing special. Next, let's see which strings the wide binary contains.
Inspecting wide (strings)
$ strings wide
/lib64/ld-linux-x86-64.so.2
libc.so.6
exit
fopen
ftell
puts
mbstowcs
stdin
printf
strtol
fgets
calloc
fseek
fclose
wcscmp
fread
__cxa_finalize
__libc_start_main
GLIBC_2.2.5
_ITM_deregisterTMCloneTable
__gmon_start__
_ITM_registerTMCloneTable
AWAVI
AUATL
[]A\A]A^A_
Which dimension would you like to examine?
That option was invalid.
[X] That entry is encrypted - please enter your WIDE decryption key:
[X] Key was incorrect [X]
Usage: %s db.ex
[*] Welcome user: kr4eq4L2$12xb, to the Widely Inflated Dimension Editor [*]
[*] Serving your pocket dimension storage needs since 14,012.5 B [*]
[x] There was a problem accessing your database [x]
[*] Displaying Dimensions.... [*]
[*] Name | Code | Encrypted [*]
[X] %-16s | %-32s | %6s%c%7s [*]
;*3$"
GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
crtstuff.c
deregister_tm_clones
__do_global_dtors_aux
completed.7698
__do_global_dtors_aux_fini_array_entry
frame_dummy
__frame_dummy_init_array_entry
wide.c
__FRAME_END__
__init_array_end
_DYNAMIC
__init_array_start
__GNU_EH_FRAME_HDR
_GLOBAL_OFFSET_TABLE_
__libc_csu_fini
wcscmp@@GLIBC_2.2.5
_ITM_deregisterTMCloneTable
puts@@GLIBC_2.2.5
fread@@GLIBC_2.2.5
stdin@@GLIBC_2.2.5
mbstowcs@@GLIBC_2.2.5
_edata
fclose@@GLIBC_2.2.5
menu
printf@@GLIBC_2.2.5
__libc_start_main@@GLIBC_2.2.5
fgets@@GLIBC_2.2.5
calloc@@GLIBC_2.2.6
__data_start
ftell@@GLIBC_2.2.5
__gmon_start__
strtol@@GLIBC_2.2.5
__dso_handle
_IO_stdin_used
__libc_csu_init
fseek@@GLIBC_2.2.5
__bss_start
main
fopen@@GLIBC_2.2.5
exit@@GLIBC_2.2.5
__TMC_END__
_ITM_registerTMCloneTable
__cxa_finalize@@GLIBC_2.2.5
.symtab
.strtab
.shstrtab
.interp
.note.ABI-tag
.note.gnu.build-id
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_r
.rela.dyn
.rela.plt
.init
.plt.got
.text
.fini
.rodata
.eh_frame_hdr
.eh_frame
.init_array
.fini_array
.dynamic
.data
.bss
.comment
Looks like a little game - let's try running it.
Running the binary
$ ./wide db.ex
[*] Welcome user: kr4eq4L2$12xb, to the Widely Inflated Dimension Editor [*]
[*] Serving your pocket dimension storage needs since 14,012.5 B [*]
[*] Displaying Dimensions.... [*]
[*] Name | Code | Encrypted [*]
[X] Primus | people breathe variety practice | [*]
[X] Cheagaz | scene control river importance | [*]
[X] Byenoovia | fighting cast it parallel | [*]
[X] Cloteprea | facing motor unusual heavy | [*]
[X] Maraqa | stomach motion sale valuable | [*]
[X] Aidor | feathers stream sides gate | [*]
[X] Flaggle Alpha | admin secret power hidden | * [*]
Which dimension would you like to examine? 1
The Ice Dimension
Which dimension would you like to examine? 6
[X] That entry is encrypted - please enter your WIDE decryption key: test
[X] Key was incorrect [X]
Which dimension would you like to examine?
So, interesting... the Flaggle Alpha entry shows an encrypted field. I tried a random key and got the "Key was incorrect" message. Maybe we can decrypt that and get the flag. Time to fire up Ghidra and take a look at the decompiled binary.
Static analysis (Ghidra)

After decompiling with Ghidra we get the following code. Let's walk through it.
main() overview
undefined8 main(int param_1,undefined8 *param_2)
{
int iVar1;
FILE *__stream;
ulong uVar2;
void *__ptr;
uint uVar3;
int local_28;
if (param_1 < 2) {
printf("Usage: %s db.ex\n",*param_2);
/* WARNING: Subroutine does not return */
exit(-1);
}
puts("[*] Welcome user: kr4eq4L2$12xb, to the Widely Inflated Dimension Editor [*]");
puts("[*] Serving your pocket dimension storage needs since 14,012.5 B [*]");
__stream = fopen((char *)param_2[1],"r");
if (__stream == (FILE *)0x0) {
puts("[x] There was a problem accessing your database [x]");
/* WARNING: Subroutine does not return */
exit(-1);
}
fseek(__stream,0,2);
uVar2 = ftell(__stream);
fseek(__stream,0,0);
uVar2 = (uVar2 - uVar2 % 0xb4) / 0xb4;
iVar1 = (int)uVar2;
__ptr = calloc((long)iVar1,0xb4);
fread(__ptr,0xb4,(long)iVar1,__stream);
fclose(__stream);
puts("[*] Displaying Dimensions.... [*]");
puts("[*] Name | Code | Encrypted [*]");
for (local_28 = 0; local_28 < iVar1; local_28 = local_28 + 1) {
if (*(int *)((long)__ptr + (long)local_28 * 0xb4) == 0) {
uVar3 = 0x20;
}
else {
uVar3 = 0x2a;
}
printf("[X] %-16s | %-32s | %6s%c%7s [*]\n",(long)__ptr + (long)local_28 * 0xb4 + 4,
(long)__ptr + (long)local_28 * 0xb4 + 0x14,&DAT_0010132d,(ulong)uVar3,&DAT_0010132d);
}
menu(__ptr,uVar2 & 0xffffffff);
return 0;
}
At first glance, main expects two arguments. If db.ex isn't passed it exits. The program prints the welcome messages, reads the database into memory, closes the file, displays the entries, and then calls a function called menu. Let's check out menu.
menu() and entry parsing

void menu(long param_1,int param_2)
{
int iVar1;
long lVar2;
undefined8 *puVar3;
long in_FS_OFFSET;
uint local_1d4;
wchar_t local_1c8 [16];
undefined8 local_188;
undefined8 local_180;
undefined8 local_178;
undefined8 local_170;
undefined8 local_168;
undefined8 local_160;
undefined4 local_158;
undefined4 uStack_154;
undefined4 local_150;
undefined4 uStack_14c;
undefined4 local_148;
undefined4 uStack_144;
undefined4 local_140;
undefined4 uStack_13c;
undefined4 local_138;
undefined4 uStack_134;
undefined4 local_130;
undefined4 uStack_12c;
undefined4 local_128;
undefined4 uStack_124;
undefined4 local_120;
undefined4 uStack_11c;
undefined4 local_118;
undefined4 uStack_114;
undefined4 local_110;
undefined4 uStack_10c;
undefined4 local_108;
undefined4 uStack_104;
undefined4 local_100;
undefined4 uStack_fc;
undefined4 local_f8;
undefined4 uStack_f4;
undefined4 local_f0;
undefined4 uStack_ec;
undefined4 local_e8;
undefined4 uStack_e4;
undefined4 local_e0;
undefined4 uStack_dc;
undefined4 local_d8;
char local_c8 [16];
undefined8 local_b8;
undefined8 local_b0;
undefined8 local_a8;
undefined8 local_a0;
undefined8 local_98;
undefined8 local_90;
undefined8 local_88;
undefined8 local_80;
undefined8 local_78;
undefined8 local_70;
undefined8 local_68;
undefined8 local_60;
undefined8 local_58;
undefined8 local_50;
undefined8 local_48;
undefined8 local_40;
undefined8 local_38;
undefined8 local_30;
undefined8 local_28;
undefined8 local_20;
undefined8 local_10;
local_10 = *(undefined8 *)(in_FS_OFFSET + 0x28);
local_b8 = 0;
local_b0 = 0;
local_a8 = 0;
local_a0 = 0;
do {
while( true ) {
while( true ) {
printf("Which dimension would you like to examine? ");
fgets((char *)&local_b8,0x20,stdin);
lVar2 = strtol((char *)&local_b8,(char **)0x0,10);
iVar1 = (int)lVar2;
if ((-1 < iVar1) && (iVar1 < param_2)) break;
puts("That option was invalid.");
}
puVar3 = (undefined8 *)(param_1 + (long)iVar1 * 0xb4);
local_188 = *puVar3;
local_180 = puVar3[1];
local_178 = puVar3[2];
local_170 = puVar3[3];
local_168 = puVar3[4];
local_160 = puVar3[5];
local_158 = (undefined4)puVar3[6];
uStack_154 = (undefined4)((ulong)puVar3[6] >> 0x20);
local_150 = (undefined4)puVar3[7];
uStack_14c = (undefined4)((ulong)puVar3[7] >> 0x20);
local_148 = (undefined4)puVar3[8];
uStack_144 = (undefined4)((ulong)puVar3[8] >> 0x20);
local_140 = (undefined4)puVar3[9];
uStack_13c = (undefined4)((ulong)puVar3[9] >> 0x20);
local_138 = (undefined4)puVar3[10];
uStack_134 = (undefined4)((ulong)puVar3[10] >> 0x20);
local_130 = (undefined4)puVar3[0xb];
uStack_12c = (undefined4)((ulong)puVar3[0xb] >> 0x20);
local_128 = (undefined4)puVar3[0xc];
uStack_124 = (undefined4)((ulong)puVar3[0xc] >> 0x20);
local_120 = (undefined4)puVar3[0xd];
uStack_11c = (undefined4)((ulong)puVar3[0xd] >> 0x20);
local_118 = (undefined4)puVar3[0xe];
uStack_114 = (undefined4)((ulong)puVar3[0xe] >> 0x20);
local_110 = (undefined4)puVar3[0xf];
uStack_10c = (undefined4)((ulong)puVar3[0xf] >> 0x20);
local_108 = (undefined4)puVar3[0x10];
uStack_104 = (undefined4)((ulong)puVar3[0x10] >> 0x20);
local_100 = (undefined4)puVar3[0x11];
uStack_fc = (undefined4)((ulong)puVar3[0x11] >> 0x20);
local_f8 = (undefined4)puVar3[0x12];
uStack_f4 = (undefined4)((ulong)puVar3[0x12] >> 0x20);
local_f0 = (undefined4)puVar3[0x13];
uStack_ec = (undefined4)((ulong)puVar3[0x13] >> 0x20);
local_e8 = (undefined4)puVar3[0x14];
uStack_e4 = (undefined4)((ulong)puVar3[0x14] >> 0x20);
local_e0 = (undefined4)puVar3[0x15];
uStack_dc = (undefined4)((ulong)puVar3[0x15] >> 0x20);
local_d8 = *(undefined4 *)(puVar3 + 0x16);
if ((int)local_188 != 0) break;
puts((char *)&uStack_154);
}
local_98 = CONCAT44(local_150,uStack_154);
local_90 = CONCAT44(local_148,uStack_14c);
local_88 = CONCAT44(local_140,uStack_144);
local_80 = CONCAT44(local_138,uStack_13c);
local_78 = CONCAT44(local_130,uStack_134);
local_70 = CONCAT44(local_128,uStack_12c);
local_68 = CONCAT44(local_120,uStack_124);
local_60 = CONCAT44(local_118,uStack_11c);
local_58 = CONCAT44(local_110,uStack_114);
local_50 = CONCAT44(local_108,uStack_10c);
local_48 = CONCAT44(local_100,uStack_104);
local_40 = CONCAT44(local_f8,uStack_fc);
local_38 = CONCAT44(local_f0,uStack_f4);
local_30 = CONCAT44(local_e8,uStack_ec);
local_28 = CONCAT44(local_e0,uStack_e4);
local_20 = CONCAT44(local_d8,uStack_dc);
printf("[X] That entry is encrypted - please enter your WIDE decryption key: ");
fgets(local_c8,0x10,stdin);
mbstowcs(local_1c8,local_c8,0x10);
iVar1 = wcscmp(local_1c8,L"sup3rs3cr3tw1d3");
if (iVar1 == 0) {
for (local_1d4 = 0;
(local_1d4 < 0x80 && (*(char *)((long)&local_98 + (long)(int)local_1d4) != '\0'));
local_1d4 = local_1d4 + 1) {
*(byte *)((long)&local_98 + (long)(int)local_1d4) =
*(byte *)((long)&local_98 + (long)(int)local_1d4) ^
(char)(local_1d4 * 0x1b) + (char)((int)(local_1d4 * 0x1b) / 0xff);
}
puts((char *)&local_98);
}
else {
puts("[X] Key was incorrect [X]");
}
} while( true );
}
Niceeee :D this shows how the program handles encrypted entries. There's a hardcoded decryption key: sup3rs3cr3tw1d3. If you enter that key, the program reveals the flag:
<game-snip>
[X] That entry is encrypted - please enter your WIDE decryption key: sup3rs3cr3tw1d3
HTB{som3_str1ng5_4r3_w1d3}
Easy, right? Truth is, lots of binaries contain hardcoded credentials which can make reversing quick. Let's dig deeper and extract the flag without running the original binary. If you look closer, the following snippet contains the relevant logic:
printf("[X] That entry is encrypted - please enter your WIDE decryption key: ");
fgets(local_c8,0x10,stdin);
mbstowcs(local_1c8,local_c8,0x10);
iVar1 = wcscmp(local_1c8,L"sup3rs3cr3tw1d3");
if (iVar1 == 0) {
for (local_1d4 = 0;
(local_1d4 < 0x80 && (*(char *)((long)&local_98 + (long)(int)local_1d4) != '\0'));
local_1d4 = local_1d4 + 1) {
*(byte *)((long)&local_98 + (long)(int)local_1d4) =
*(byte *)((long)&local_98 + (long)(int)local_1d4) ^
(char)(local_1d4 * 0x1b) + (char)((int)(local_1d4 * 0x1b) / 0xff);
}
puts((char *)&local_98);
}
else {
puts("[X] Key was incorrect [X]");
}
The program reads input from stdin and compares it to the hardcoded key. If they match, it proceeds. You might wonder why the code checks for iVar1 == 0 - in C, wcscmp returns 0 when the strings are equal.
Return value of wcscmp
Negative value ifÂ
lhs appears beforeÂrhs in lexicographical order. Zero ifÂlhs andÂrhs compare equal. Positive value ifÂlhs appears afterÂrhs in lexicographical order.
Now let's reverse the loop. I'll simplify the variable names because the decompiler's names are slop.
for (local_1d4 = 0;
(local_1d4 < 0x80 && (*(char *)((long)&local_98 + (long)(int)local_1d4) != '\0'));
local_1d4 = local_1d4 + 1)
- Replace the local_1d4 variable with a simple
ivariable - The hexvalue
0x80means128in decimal (*(char *)((long)&local_98 + (long)(int)i)accesses the byte at positionistarting fromlocal_98. Although it looks complicated, it's equivalent tolocal_98[i], which is why we can treatlocal_98as a character array (or buffer).
So the loop condition can be rewritten as:
for (i= 0; i < 128 && local_98[i] != '\0'; i++)
Now let's rewrite the loop body to make the character logic obvious.
{
*(byte *)((long)&local_98 + (long)(int)local_1d4) =
*(byte *)((long)&local_98 + (long)(int)local_1d4) ^
(char)(local_1d4 * 0x1b) + (char)((int)(local_1d4 * 0x1b) / 0xff);
}
- Replace
local_1d4withi. - Replace
(byte *)((long)&local_98 + i)withlocal_98[i]. - Convert
0x1bto27and0xffto255. - The expression
(i * 27) + ((i * 27) / 255)calculates a key based on the current index. ^is the XOR operator, so each byte inlocal_98is XORed with this key, decrypting (or encrypting) the string.
So the decrypted loop looks like this:
for (i= 0; i < 128 && local_98[i] != '\0'; i++)
{
local_98[i] ^= (i * 27) + ((i * 27) / 255);
}
Decrypting the flag with custom C code
What we can do now is write a small C program that reproduces the decryption routine and extracts the flag without executing the original binary. Since we already understand the XOR algorithm, the only remaining task is to figure out what data is stored inside the local_98 buffer.
local_98 is the buffer that gets decrypted by the following loop:
for (i = 0; i < 128 && local_98[i] != '\0'; i++)
{
local_98[i] ^= (i * 27) + ((i * 27) / 255);
}
The loop itself does not generate any data, it only transforms the bytes that are already present in local_98. This means that the encrypted flag must be loaded into this buffer before the decryption happens.
Looking further up in the function, we can see that local_98 is filled from data copied from param_1:
local_98 = CONCAT44(local_150, uStack_154);
local_90 = CONCAT44(local_148, uStack_14c);
local_88 = CONCAT44(local_140, uStack_144);
...
local_20 = CONCAT44(local_d8, uStack_dc);
These assignments reconstruct a 128-byte buffer. The values come from the selected entry in the database.
To understand where this data originates, we need to look at the main() function. There we find:
__ptr = calloc((long)iVar1, 0xb4);
fread(__ptr,0xb4,(long)iVar1,__stream);
The program reads a database file into memory. Each entry has a fixed size of 0xb4 bytes (180 bytes). The structure of an entry can be reconstructed as:
Offset Size Description
-----------------------------------------
0x00 4 bytes encrypted flag
0x04 16 bytes name
0x14 32 bytes code
0x34 128 bytes encrypted data
The last 128 bytes are the data that eventually become local_98.
Therefore, instead of running the original binary, we can directly read the database file, extract the encrypted 128-byte field, apply the XOR decryption routine, and recover the plaintext.
So rather than running the original binary, we can read the database file, pull out the 128-byte field, run the XOR routine ourselves, and recover the plaintext.
Once we know the correct key and the decryption algorithm, the check becomes irrelevant. We can bypass the program logic completely and reproduce only the interesting part: extracting the encrypted bytes and decrypting them ourselves.
#include <stdio.h>
#include <stdint.h>
typedef struct {
int encrypted;
char name[16];
char code[32];
unsigned char secret[128];
} Entry;
int main(void)
{
FILE *fp = fopen("db.ex", "rb");
if (!fp) {
perror("db.ex");
return 1;
}
Entry e;
while (fread(&e, sizeof(Entry), 1, fp) == 1) {
if (e.encrypted) {
for (int i = 0; i < 128 && e.secret[i] != '\0'; i++) {
e.secret[i] ^= (i * 27) + ((i * 27) / 255);
}
printf("Name : %s\n", e.name);
printf("Code : %s\n", e.code);
printf("Text : %s\n\n", e.secret);
}
}
fclose(fp);
return 0;
}
Save the code snippet code.c to a file and compile it with gcc code.c -o decrypter . Now if we run the custom c code, we will get the flag
$ ./decrypter
Name : Flaggle Alpha
Code : admin secret power hidden
Text : HTB{som3_str1ng5_4r3_w1d3}
Conclusion
This was a compact exercise in static analysis and reproducing a decryption routine. By inspecting the binary we found a hardcoded key and the XOR-based transformation, then recreated that logic in a tiny C program to extract the flag without running the original executable. It's a good reminder: embedding secrets in binaries makes them trivial to recover, avoid hardcoding keys and prefer proper secret management.