Solution de juLPW pour Catch me if you can

intro reverse windows x86/x64

7 juin 2025

Table des matières

Introduction

On lance CATCHME.exe (par exemple avec wine sous Linux) et on tombe sur un petit jeu où il faut cliquer sur l’image de Leo. Problème : dès qu’on approche la souris, l’image bouge, donc impossible de cliquer.

Un petit strings CATCHME.exe | grep FCSC nous donne :

FCSC{%.32s}

Donc le flag est là, mais il faut contourner la logique du jeu.


Analyse

Je charge le binaire dans Ghidra.

j’arrive effectivement a retrouver cette chaine, et ou elle est utilisée, mais je n’arrive à rien. Je ne suis ni le roi du C, et encore moins de l’assembleur, alors ca me semble un peu coton. Cependant: Quand j’approche la souris de l’image elle se déplace Donc le programme doit bien récupérer la position de ma souris. Et pour cela, elle utilise les dll windows

Je vais donc voir ou est utilisé cette DLL dans le code

image_2

Je remarque que la fonction FUN_00401110 utilise GetCursorPos et renvoie un booléen. Voici ce qu’elle fait en C pseudo :

bool FUN_00401110(void) {
  HWND hWnd;
  int iVar1;
  bool bVar2;
  tagPOINT tStack_14;
  
  hWnd = GetDlgItem(DAT_0047c00c,DAT_0047c000);
  GetCursorPos(&tStack_14);
  ScreenToClient(hWnd,&tStack_14);
  iVar1 = tStack_14.x - _DAT_0047a020;
  if (iVar1 < 1) {
    iVar1 = -iVar1;
  }
  bVar2 = false;
  if (iVar1 < DAT_0047a028) {
    iVar1 = tStack_14.y - DAT_0047a024;
    if (iVar1 < 1) {
      iVar1 = -iVar1;
    }
    bVar2 = iVar1 < DAT_0047a02c;
  }
  return bVar2;

Et donc , je me dis qu’avec un peu de chance, ca renvoie True si on est proche de l’image et False si on est loin. Il suffit donc de lui faire tout le temps renvoyer False.

En plus c’est pratique, on a exactement la ligne:

bVar2 = false;

Et donc je regarde juste à quoi cela correspond en assembleur:

31 d2           XOR        EDX,EDX

Ainsi 32 D2 fait un XOR sur le registre EDX et donc cela genere forcément False. Puis le programme fait des choses sur sur ce registre et le retourne à la fin.

Patch

Du coup on ne va pas s’embéter: La fonction commence à l’offset 0x0510 (1296) et se termine à 0x0593 (1427). On écrase le tout par le patch et on remplit le reste avec des NOPs :

with open("CATCHME.EXE", "r+b") as f:
    a=f.seek(1296)
    f.write(b"\x31") 
    f.write(b"\xC0") 
    f.write(b"\xC3")
    for i in range(1427-1296-3):
        f.write(b"\x90")

et… voila , léo ne bouge plus :)