# Another Python Game \[Rev]

<figure><img src="https://3959829653-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKsbQ7f9jhHpgfkJbVM1s%2Fuploads%2FdlZ1g6HjeFNxJ52F8DUC%2Fimage.png?alt=media&#x26;token=5334ee52-3019-4fe9-958c-dec03e82cf2f" alt="" width="370"><figcaption></figcaption></figure>

For this challenge, a Python-compiled executable and a background file are provided to us.

<figure><img src="https://3959829653-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKsbQ7f9jhHpgfkJbVM1s%2Fuploads%2FXZippCwVGPP879fvFKZb%2Fimage.png?alt=media&#x26;token=fd58f79d-2019-45a0-8072-9b3f96c449cc" alt="" width="375"><figcaption></figcaption></figure>

We can confirm that the executable given is a Python-compiled executable by using `strings`

```
strings source.exe
```

If `strings` reveal strings such as `python` or `py`, it is a huge giveaway that the executable was compiled using Python, specifically with the `pyinstaller` library. Therefore, the source code of the executable can be recovered using `pyinstxtractor`. `pyinstxtractor` can be downloaded here:

{% embed url="<https://github.com/extremecoders-re/pyinstxtractor.git>" %}

From here, just execute `pyinstxtractor.py` followed by the executable given, and it will extract `.pyc` files which are compiled bytecode of the source code. Compiled bytecode is a type of intermediary code that a compiler creates by translating source code into bytecode.

<figure><img src="https://3959829653-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKsbQ7f9jhHpgfkJbVM1s%2Fuploads%2FmoF4CnG3o1XCcVfZ9pmI%2Fimage.png?alt=media&#x26;token=56026af0-c241-4740-8f69-ad40862db47a" alt=""><figcaption></figcaption></figure>

As a general rule of thumb, locate the `.pyc` file that has the same name as the executable that we received from the challenge. In this case, it will be `source.pyc`.

<figure><img src="https://3959829653-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKsbQ7f9jhHpgfkJbVM1s%2Fuploads%2FkG7c2r3lyDggcJiOkPVO%2Fimage.png?alt=media&#x26;token=2a76bf21-595e-4497-8012-a288bd34db31" alt=""><figcaption></figcaption></figure>

The `.pyc` file contains the source code of the executable. However, it is not human-readable as mentioned before, they are compiled bytecode. For this reason, `decompyle3` is needed to decompile the bytecode into human-readable code. `decompyle3` can be installed through `pip`:

```
pip3 install decompyle3
```

Lastly, execute `decompyle3` followed by `source.pyc`.

```
┌──(jigsaw㉿jigsaw)-[~/Desktop/pyinstxtractor/source.exe_extracted]
└─$ decompyle3 source.pyc 
```

Using `decompyle3` we managed to recover the source code of the executable!

```python
# decompyle3 version 3.9.1
# Python bytecode version base 3.8.0 (3413)
# Decompiled from: Python 3.11.9 (main, Apr 10 2024, 13:16:36) [GCC 13.2.0]
# Embedded file name: source.py
import pygame, sys
pygame.init()
screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("CTF Challenge")
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
font = pygame.font.Font(None, 74)
small_font = pygame.font.Font(None, 36)
flag_hidden = True
flag_text = "OSCTF{1_5W3ar_I_D1dn'7_BruT3f0rc3}"
hidden_combination = ["up","up","down","down","left","right","left","right"]
input_combination = []
player_size = 50
player_pos = [screen_width // 2, screen_height // 2]
player_color = BLUE
player_speed = 5
background_image = pygame.image.load("background.png")
background_image = pygame.transform.scale(background_image, (screen_width, screen_height))

def show_message(text, font, color, pos):
    message = font.render(text, True, color)
    screen.blit(message, pos)


running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP:
                input_combination.append("up")
            elif event.key == pygame.K_DOWN:
                input_combination.append("down")
            elif event.key == pygame.K_LEFT:
                input_combination.append("left")
            elif event.key == pygame.K_RIGHT:
                input_combination.append("right")
            if input_combination == hidden_combination:
                flag_hidden = False
            if len(input_combination) > len(hidden_combination):
                input_combination.clear()
            keys = pygame.key.get_pressed()

    if keys[pygame.K_LEFT]:
        player_pos[0] -= player_speed
    if keys[pygame.K_RIGHT]:
        player_pos[0] += player_speed
    if keys[pygame.K_UP]:
        player_pos[1] -= player_speed
    if keys[pygame.K_DOWN]:
        player_pos[1] += player_speed
    player_pos[0] = max(0, min(player_pos[0], screen_width - player_size))
    player_pos[1] = max(0, min(player_pos[1], screen_height - player_size))
    screen.blit(background_image, (0, 0))
    if flag_hidden:
        show_message("Find the hidden combination to reveal the flag!", small_font, WHITE, (50,
                                                                                            50))
    else:
        show_message(flag_text, small_font, WHITE, (0, 0))
    pygame.draw.rect(screen, player_color, (*player_pos, player_size, player_size))
    pygame.display.flip()
    pygame.time.Clock().tick(30)

# okay decompiling source.pyc

```

Reading through the source code, one of the variables is the flag!

```
flag: OSCTF{1_5W3ar_I_D1dn'7_BruT3f0rc3}
```
