Skip to content

Commit bda49d0

Browse files
committed
TRX: Perfect Bird - Better phrasing and added script
1 parent 84d57e0 commit bda49d0

File tree

2 files changed

+97
-106
lines changed

2 files changed

+97
-106
lines changed

content/writeups/2025/trx/perfect-bird/index.md

Lines changed: 18 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,19 @@ As a _bird_ soaring through the sky, you seek the _perfect language_, and then..
1717

1818
## Writeup
1919

20-
Opening the `chall.db3` file, we find a strange javascript-like programming language.
21-
The code has some strange symbols and conventions, and without a guide, it's hard to understand what it does.
20+
Opening the `chall.db3` file, I come across a weird programming language that looks kind of like JavaScript. The code is full of strange symbols and conventions, and without a guide, it’s pretty hard to figure out what it does.
2221

23-
The first thing I try to always do is to look at the challenge description for hints. In this case, we have the words "bird" and "perfect language" in italic.
24-
I try to search the web for "bird perfect language programming".
25-
As the first result, I get the streamer ThePrimeTime, who has [a video on this "programming language"](https://www.youtube.com/watch?v=tDexugp8EmM).
22+
My go-to move is always to check the challenge description for hints. Here, the words _bird_ and _perfect language_ are italicized, which seems important. So, I search for "bird perfect language programming" online.
23+
24+
The first result is [a video by the streamer ThePrimeTime][video], where he talks about this exact programming language.
25+
26+
[video]: https://www.youtube.com/watch?v=tDexugp8EmM
2627

2728
![A Google search for "bird perfect language programming"](search.png)
2829

29-
From the description of the video, I get back to the GitHub repository describing this language: <https://github.com/TodePond/GulfOfMexico>
30+
From the video's description, I find my way back to the GitHub repository that explains this language: <https://github.com/TodePond/GulfOfMexico>.
3031

31-
Apparently the language was called "DreamBerd", but now it seems to be called "GulfOfMexico".
32+
It looks like it was originally called "DreamBerd," but now it goes by "GulfOfMexico."
3233

3334
## DreamBerd - A Perfect Language
3435

@@ -38,15 +39,17 @@ Apparently the language was called "DreamBerd", but now it seems to be called "G
3839
> print("Hello world")!
3940
> ```
4041
41-
I think about ways to decypher the code, and I come up with the idea of writing
42-
a script to convert the code to a more readable form. I first think about
43-
converting it to Python, but then I change my mind and decide to convert it to
44-
JavaScript, as it's more similar to the original language.
42+
I start thinking about ways to decipher the code and come up with the idea of writing a script to rewrite it into an existing language (one with an existing interpreter!).
43+
44+
At first, I consider converting it to Python, but then I realize JavaScript would be a better choice since it’s closer to the original language.
4545
46-
I write a Python script to convert the code to JavaScript, and then I run it to get the output.
46+
So, I write a Python script to convert the code to JavaScript and run it to see the output.
4747
4848
### Converting DreamBerd to JavaScript
4949
50+
The key here is that we don’t need a _perfect_ (pun intended) conversion—just something accurate enough to run the challenge code.
51+
It doesn’t have to handle every possible DreamBerd program, just this one.
52+
5053
The first thing we need to do is to fix the lifetimes in the code.
5154
5255
> Gulf of Mexico has a built-in garbage collector that will automatically clean
@@ -109,9 +112,6 @@ program = "".join(program)
109112
110113
Then we need to replace each "strange lang" construct with the corresponding JavaScript construct.
111114

112-
The thing to keep in mind here is that we don't need to be _perfect_ (pun intended) in the conversion. We just need to
113-
be accurate enough to run the challenge code (as opposed to EVERY DreamBerd code).
114-
115115
- `!` -> nothing
116116

117117
```python
@@ -207,7 +207,8 @@ $ node chall_ok.js
207207

208208
```
209209

210-
Apparently, the code is an array of integers. We can convert it to ASCII to get the flag.
210+
The result we get is an array of integers.
211+
We can convert it to ASCII to get the flag.
211212

212213
```python
213214
#!/bin/env python3
@@ -223,98 +224,9 @@ for i in range(0, len(m)):
223224
print(chr(m[i]), end="")
224225
```
225226

226-
And we get the flag.
227-
228227
```shell
229228
$ python3 decode.py
230229
TRX{tHi5_I5_th3_P3rf3ct_l4nGU4g3!!!!!!}
231230
```
232231

233-
## Full script
234-
235-
<details>
236-
237-
```python
238-
#!/bin/env python3
239-
import sys
240-
import re
241-
242-
243-
lines = sys.stdin.readlines()
244-
245-
246-
def fix_lifetimes(lines):
247-
new_lines = []
248-
249-
for i, line in enumerate(lines):
250-
match = re.match(r".+<(.+)>.+", line)
251-
if not match:
252-
new_lines.append(line)
253-
continue
254-
255-
lifetime = match.group(1)
256-
257-
if lifetime == "Infinity":
258-
new_lines.append(line)
259-
continue
260-
261-
lifetime = int(lifetime)
262-
263-
if lifetime >= 0:
264-
line = line.replace(f"<{lifetime}>", "")
265-
new_lines.append(line)
266-
continue
267-
268-
new_pos = max(len(new_lines) + lifetime, 0)
269-
270-
# remove the invalid lifetime
271-
line = line.replace(f"<{lifetime}>", "")
272-
new_lines.insert(new_pos, line)
273-
274-
print(f"Moved line {i + 1} -> {new_pos + 1}", file=sys.stderr)
275-
276-
return new_lines
277-
278-
279-
program = fix_lifetimes(lines)
280-
program = "".join(program)
281-
282-
283-
284-
program = re.sub(r"!+", "", program)
285-
for i in range(1, 100):
286-
program = re.sub(r";([\w|!|(|)]+)", r"!(\1)", program)
287-
288-
program = program.replace("const const const", "let")
289-
program = program.replace("const const", "let")
290-
program = program.replace("const var", "let")
291-
program = program.replace("var var", "let")
292-
293-
program = re.sub(r"let (\d+)", r"let var_\1", program)
294-
295-
296-
program = program.replace("42 +=", "var_42 +=")
297-
program = program.replace("42 -=", "var_42 -=")
298-
program = program.replace("42 *=", "var_42 *=")
299-
program = program.replace("42 ^ ", "var_42 ^ ")
300-
program = program.replace("42 = ", "var_42 = ")
301-
program = program.replace("42 * ", "var_42 * ")
302-
program = program.replace("42 / ", "var_42 / ")
303-
program = program.replace("42 % ", "var_42 % ")
304-
program = program.replace("42 + ", "var_42 + ")
305-
program = program.replace("42 - ", "var_42 - ")
306-
program = program.replace("!42", "!var_42")
307-
308-
309-
program = re.sub("<Infinity>", "", program)
310-
program = re.sub(r"functi (.+?) \(\) =>", r"function \1()", program)
311-
program = re.sub(r"print", "console.log", program)
312-
313-
# array starts at -1 ...
314-
program = re.sub(r"(\w+)\[(.+)\]", r"\1[\2 + 1]", program)
315-
316-
317-
print(program)
318-
```
319-
320-
</details>
232+
Full script: [perfect_bird.py](perfect_bird.py)
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#!/bin/env python3
2+
import sys
3+
import re
4+
5+
6+
lines = sys.stdin.readlines()
7+
8+
9+
def fix_lifetimes(lines):
10+
new_lines = []
11+
12+
for i, line in enumerate(lines):
13+
match = re.match(r".+<(.+)>.+", line)
14+
if not match:
15+
new_lines.append(line)
16+
continue
17+
18+
lifetime = match.group(1)
19+
20+
if lifetime == "Infinity":
21+
new_lines.append(line)
22+
continue
23+
24+
lifetime = int(lifetime)
25+
26+
if lifetime >= 0:
27+
line = line.replace(f"<{lifetime}>", "")
28+
new_lines.append(line)
29+
continue
30+
31+
new_pos = max(len(new_lines) + lifetime, 0)
32+
33+
# remove the invalid lifetime
34+
line = line.replace(f"<{lifetime}>", "")
35+
new_lines.insert(new_pos, line)
36+
37+
print(f"Moved line {i + 1} -> {new_pos + 1}", file=sys.stderr)
38+
39+
return new_lines
40+
41+
42+
program = fix_lifetimes(lines)
43+
program = "".join(program)
44+
45+
46+
program = re.sub(r"!+", "", program)
47+
for i in range(1, 100):
48+
program = re.sub(r";([\w|!|(|)]+)", r"!(\1)", program)
49+
50+
program = program.replace("const const const", "let")
51+
program = program.replace("const const", "let")
52+
program = program.replace("const var", "let")
53+
program = program.replace("var var", "let")
54+
55+
program = re.sub(r"let (\d+)", r"let var_\1", program)
56+
57+
58+
program = program.replace("42 +=", "var_42 +=")
59+
program = program.replace("42 -=", "var_42 -=")
60+
program = program.replace("42 *=", "var_42 *=")
61+
program = program.replace("42 ^ ", "var_42 ^ ")
62+
program = program.replace("42 = ", "var_42 = ")
63+
program = program.replace("42 * ", "var_42 * ")
64+
program = program.replace("42 / ", "var_42 / ")
65+
program = program.replace("42 % ", "var_42 % ")
66+
program = program.replace("42 + ", "var_42 + ")
67+
program = program.replace("42 - ", "var_42 - ")
68+
program = program.replace("!42", "!var_42")
69+
70+
71+
program = re.sub("<Infinity>", "", program)
72+
program = re.sub(r"functi (.+?) \(\) =>", r"function \1()", program)
73+
program = re.sub(r"print", "console.log", program)
74+
75+
# array starts at -1 ...
76+
program = re.sub(r"(\w+)\[(.+)\]", r"\1[\2 + 1]", program)
77+
78+
79+
print(program)

0 commit comments

Comments
 (0)