← Back to Writeups
CUSTOMEasyReversing

Dop Dop Yes (Skibidi Toilet Reverse)

XESXOR9/2/20267 min read
#reversing#custom#easy#**-custom-xor-based-cipher-rev#mouse-cursor-position-constrai#multi-layer-decoding-(binary--#pe64-disassembly-and-analysis

Dop Dop Yes (Skibidi Toilet Reverse)

Platform: CUSTOM | Category: Reversing | Type: Challenge | Difficulty: Easy | OS: N/A | **Author: XESXOR Techniques: Custom XOR-based cipher reverse engineering, Mouse cursor position constraint solving, Multi-layer decoding (binary -> ASCII -> Base64), PE64 disassembly and analysis

Summary

Walkthrough of the CUSTOM Reversing Dop Dop Yes (Skibidi Toilet Reverse). Task: Reverse "Dop Dop Yes" — Skibidi Toilet. Solution: Meme-based reverse, TikTok culture reference.

Description

"Я нашёл это у своего внука на компьютере. Очень не понимаю, почему там какие-то туалеты и роботы. Может, вы знаете?"

(I found this on my grandson's computer. I don't understand why there are some toilets and robots. Do you know?)

The task name "доп доп ес" = "dop dop yes" is a reference to the Skibidi Toilet meme.

Files

  • tv2.0.exe - PE32+ executable (console) x86-64, MinGW-compiled
  • Multiple PNG images with Skibidi Toilet theme (camera.png, car.png, tvman.png, etc.) ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Analysis

Step 1: Initial Reconnaissance

The executable is a Windows PE64 binary compiled with MinGW. The accompanying PNG images are all Skibidi Toilet meme-related, which is a hint from the task name.

bash
file tv2.0.exe
# tv2.0.exe: PE32+ executable (console) x86-64, for MS Windows

Step 2: Disassembly Analysis

Using objdump to disassemble the binary:

bash
objdump -d tv2.0.exe > disasm.txt

Key findings in the disassembly:

Mouse Position Checks (at 0x401771-0x4017c1)

asm
401771: 8b 85 c8 09 00 00    movl   0x9c8(%rbp), %eax    # X coordinate
401777: 35 37 13 37 13       xorl   $0x13371337, %eax
40177c: 3d bd 13 37 13       cmpl   $0x133713bd, %eax
401781: 0f 8e 81 03 00 00    jle    0x401b08             # Jump if (X ^ 0x13371337) <= 0x133713bd
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

401787: 8b 85 cc 09 00 00    movl   0x9cc(%rbp), %eax    # Y coordinate
40178d: 35 36 13 37 13       xorl   $0x13371336, %eax
401792: 3d c1 13 37 13       cmpl   $0x133713c1, %eax
401797: 0f 8f 6b 03 00 00    jg     0x401b08             # Jump if (Y ^ 0x13371336) > 0x133713c1

# Y % 121 == 16 check (using multiplication trick)
4017a3: ba 5b 3d 3b 04       movl   $0x43b3d5b, %edx
4017a8: 89 c8                movl   %ecx, %eax
4017aa: f7 ea                imull  %edx
# ... modulo 121 calculation
4017ba: 6b c0 79             imull  $0x79, %eax, %eax    # 0x79 = 121
4017be: 83 f8 10             cmpl   $0x10, %eax          # Check if remainder == 16

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

The conditions are:

  1. (X ^ 0x13371337) > 0x133713bd
  2. (Y ^ 0x13371336) <= 0x133713c1
  3. Y % 121 == 16
  4. X == Y (from earlier comparison)

Step 3: Solving for X and Y

python
# Condition 1: (X ^ 0x13371337) > 0x133713bd
# Condition 2: (Y ^ 0x13371336) <= 0x133713c1
# Condition 3: Y % 121 == 16
# Condition 4: X == Y

# For X = Y:
# (X ^ 0x13371337) > 0x133713bd
# (X ^ 0x13371336) <= 0x133713c1
# X % 121 == 16

# Testing X = 137:
# 137 ^ 0x13371337 = 0x133713be > 0x133713bd  ✓
# 137 ^ 0x13371336 = 0x133713bf <= 0x133713c1 ✓
# 137 % 121 = 16 ✓
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

X = Y = 137

Step 4: Encrypted Data Location

At offset 0x4017cb, the code loads encrypted data:

asm
4017cb: 48 8d 15 4e 28 00 00  leaq   0x284e(%rip), %rdx  # 0x404020
4017d2: b9 b9 09 00 00        movl   $0x9b9, %ecx        # Size = 2489 bytes

The encrypted data is at file offset 0x2820 (RVA 0x404020), size 0x9b9 (2489) bytes.

Step 5: Reverse Engineering the Cipher

The encryption algorithm (at 0x40181a-0x401a6d) performs 18 operations per byte:

python
def transform(data, X, Y):
    result = bytearray()
    prev = 0
    
    for i, b in enumerate(data):
        original = b  # Save original for prev update
        
        # Step 1: XOR with prev
        b ^= prev
        # Step 2: XOR with 0xAF
        b ^= 0xAF
        # Step 3: XOR with Y
        b ^= Y
        # Step 4: XOR with 0x3C
        b ^= 0x3C
        # Step 5: ADD ((prev + 0x34) ^ (X + i))
        b = (b + ((prev + 0x34) ^ (X + i))) & 0xFF
        # Step 6: XOR with (prev + Y), then XOR 0x19
        b = (prev + Y) ^ b ^ 0x19
        # Step 7: ADD (X ^ 0x50)
        b = (b + (X ^ 0x50)) & 0xFF
        # Step 8: SUB 0x34
        b = (b - 0x34) & 0xFF
        # Step 9: SUB (i ^ 0xAB)
        b = (b - (i ^ 0xAB)) & 0xFF
        # Step 10: XOR with (prev + i + 0x74)
        b = (prev + i + 0x74) ^ b
        # Step 11: XOR with prev
        b ^= prev
        # Step 12: SUB prev
        b = (b - prev) & 0xFF
        # Step 13: XOR 0xCC
        b ^= 0xCC
        # Step 14: ADD i
        b = (b + i) & 0xFF
        # Step 15: XOR 0xAA
        b ^= 0xAA
        # Step 16: ADD 0x31
        b = (b + 0x31) & 0xFF
        # Step 17: XOR 0x44
        b ^= 0x44
        
        result.append(b)
        prev = original  # Key insight: prev = original encrypted byte
    
    return bytes(result)

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Critical insight: The prev variable is updated with the original encrypted byte, not the decrypted one. This is visible in the assembly at 0x401a6d-0x401a7a.

Solution

Full Decryption Script

python
#!/usr/bin/env python3
import base64

def extract_encrypted_data(filename):
    """Extract encrypted data from PE file at offset 0x2820"""
    with open(filename, 'rb') as f:
        f.seek(0x2820)
        return f.read(0x9b9)

def transform(data, X, Y):
    """Apply the transformation algorithm"""
    result = bytearray()
    prev = 0
    
    for i, b in enumerate(data):
        original = b
        
        b ^= prev
        b ^= 0xAF
        b ^= Y
        b ^= 0x3C
        b = (b + ((prev + 0x34) ^ (X + i))) & 0xFF
        b = (prev + Y) ^ b ^ 0x19
        b = (b + (X ^ 0x50)) & 0xFF
        b = (b - 0x34) & 0xFF
        b = (b - (i ^ 0xAB)) & 0xFF
        b = (prev + i + 0x74) ^ b
        b ^= prev
        b = (b - prev) & 0xFF
        b ^= 0xCC
        b = (b + i) & 0xFF
        b ^= 0xAA
        b = (b + 0x31) & 0xFF
        b ^= 0x44
        
        result.append(b)
        prev = original
    
    return bytes(result)
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

def binary_to_ascii(binary_string):
    """Convert space-separated binary strings to ASCII"""
    result = ""
    for byte_str in binary_string.split():
        if len(byte_str) == 8:
            result += chr(int(byte_str, 2))
    return result

# Main
encrypted = extract_encrypted_data("tv2.0.exe")
X = Y = 137

# Apply transformation
decrypted = transform(encrypted, X, Y)

# Decode as UTF-8 (binary strings)
binary_text = decrypted.decode('utf-8', errors='ignore')
print("Binary strings (first 200 chars):", binary_text[:200])
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# Convert binary to ASCII
ascii_text = binary_to_ascii(binary_text)
print("\nASCII text:", ascii_text)

# Decode Base64
try:
    final = base64.b64decode(ascii_text).decode('utf-8')
    print("\nFinal message:", final)
except Exception as e:
    print(f"Base64 decode error: {e}")

Decoding Chain

  1. Apply transformation with X=Y=137 to encrypted data
  2. Result: Space-separated binary strings (8 bits per character)
    01010000 01101100 01100101 01100001 01110011 01100101 ...
    
  3. Convert binary to ASCII: Each 8-bit group becomes a character
  4. Result: Base64 encoded string
  5. Decode Base64: Final message with flag ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Output

Binary strings: 01010000 01101100 01100101 01100001 01110011 01100101 ...

ASCII text: UGxlYXNlIGRvIG5vdCBydW4gdW5mYW1pbGlhciBmaWxlcyBvbiB5b3VyIHN5c3RlbS4g...

Final message: Please do not run unfamiliar files on your system. Always analyze 
them before running them, as the damage of laziness may be more than wasting some 
time. CODEBY{REDACTED}

Lessons Learned

  1. Meme references matter: The task name "dop dop yes" directly references Skibidi Toilet, setting the theme
  2. Constraint solving: Mouse position checks can be solved algebraically
  3. prev variable tracking: In cipher analysis, carefully track which value updates the state variable
  4. Multi-layer encoding: Be prepared for nested encodings (binary -> ASCII -> Base64)
  5. Security message: The flag itself is a reminder to analyze files before running them ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

References

  • Skibidi Toilet - The meme referenced in the task
  • PE file format analysis
  • XOR cipher reverse engineering ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Key Takeaways / Lessons

  • Mastering Custom XOR-based cipher reverse engineering, Mouse cursor position constraint solving, Multi-layer decoding (binary -> ASCII -> Base64), PE64 disassembly and analysis was key to this challenge.
  • Always check for common misconfigurations and verify assumptions.

Crafted by XESXOR Research • 2025-12-25 • CUSTOM • Dop Dop Yes (Skibidi Toilet Reverse) • Difficulty: Easy