Description
A Windows executable announces the flag but first takes a very long sleep. Use Frida to hook and bypass the Sleep call so the binary wakes up immediately and prints the flag.
Unzip with the password picoctf to obtain bininst1.exe. The challenge needs a Windows machine (or VM) with Python and Frida installed.
Install Frida tools: pip install frida-tools. You may also need the Visual C++ Redistributable from Microsoft.
Run the binary once to see what it says. It will announce the flag but then sleep for a very long time.
Create a JavaScript Frida script that intercepts the Sleep function in kernel32.dll and returns immediately instead of waiting.
pip install frida-tools# Run the binary to see the sleep behavior:bininst1.exe# The binary says it will print the flag but needs a nap firstSolution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1Hook Sleep with a Frida script
ObservationThe binary announces it will print the flag and then sleeps for a very long time. Replace the Sleep call in kernel32.dll with Frida and execution reaches the output immediately.Write a Frida JavaScript file that locates Sleep in kernel32.dll and replaces it with a function that just returns immediately. Run the binary under frida to apply the hook.js// kill_sleep.js var sleep = Module.getExportByName("kernel32.dll", "Sleep"); Interceptor.replace(sleep, new NativeCallback(function(ms) { return; }, "void", ["uint32"]));bashfrida bininst1.exe -l kill_sleep.jsWhat didn't work first
Tried: Using Interceptor.attach instead of Interceptor.replace to hook Sleep.
Interceptor.attach lets you run code on entry and exit but does not prevent the original function from executing, so the binary still sleeps. Interceptor.replace swaps the entire function pointer with your NativeCallback, ensuring Sleep never actually waits.
Tried: Attaching Frida to the already-running bininst1.exe process with frida -n bininst1.exe -l kill_sleep.js after the binary has started.
Sleep is called very early. Attach by name and the thread is already deep inside the wait, so the hook lands too late. Spawn the binary through Frida instead and the hook is in place before any of its code runs.
Learn more
Frida is a dynamic binary instrumentation toolkit that lets you inject JavaScript into running processes. It works by attaching to a process (or spawning one) and loading a JavaScript engine into it, giving you full access to the process memory, function hooks, and API interception. Frida is widely used for security research, reverse engineering, and CTF challenges on Windows, macOS, Linux, iOS, and Android.
Module.getExportByNamelooks up a named export from a loaded DLL by name.Interceptor.replacereplaces the function at that address with a customNativeCallbackwritten in JavaScript. The callback here accepts the millisecond argument Sleep normally takes and simply returns without doing anything - effectively making Sleep a no-op and letting the binary continue immediately.The Windows
Sleepfunction lives inkernel32.dlland pauses the current thread for the specified number of milliseconds. Malware and anti-analysis binaries commonly call Sleep with enormous values (hours or even days) to frustrate dynamic analysis tools that time out after a few seconds. Hooking Sleep is one of the first things analysts do when running a suspicious sample in a sandbox.Step 2Decode the Base64 output
ObservationThe output starts with cGljb0NURn, the Base64 encoding of the literal picoCTF{ prefix. One decode gives the plaintext.With Sleep bypassed, the binary wakes up and prints the flag as a Base64-encoded string. Decode it to recover the picoCTF flag.bash# The binary prints something like:bash# Ok, I'm Up! The flag is: cGljb0NURnt3NGtlX20zX3VwX3cxdGhfZnIxZGFfZjI3YS4uLn0=bash# Decode with:bashecho 'cGljb0NURnt3NGtlX20zX3VwX3cxdGhfZnIxZGFfZjI3YS4uLn0=' | base64 -dExpected output
picoCTF{w4ke_m3_up_w1th_fr1da_f27a...}What didn't work first
Tried: Running strings on bininst1.exe to find the flag without using Frida.
The flag is Base64-encoded in the program's logic rather than sitting as a literal in read-only data. strings would only show the encoded form if it were a literal, and even then Base64 text is easy to skim past. The binary has to run past the hook to emit it.
Tried: Piping the binary's output through CyberChef using 'From Base64' with the URL-safe alphabet.
The output uses the standard Base64 alphabet, which is also CyberChef's default, so it works. Pick the URL-safe alphabet by mistake and the bytes come out corrupted. The command-line decoder always uses the standard one.
Learn more
Base64 is a reversible encoding that represents binary data using 64 printable ASCII characters. Because it encodes three input bytes at a time, a fixed prefix produces a fixed output prefix:
picoCTF{always encodes tocGljb0NURn, so any encoded picoCTF flag starts with those characters. Spotting this pattern is the fastest way to identify encoded flags in binary output or network captures.The binary encodes its output as Base64 to avoid the flag appearing as a plain string in the executable's read-only data section. A naive
stringsscan of the binary would not immediately reveal the flag, making the Frida instrumentation approach necessary rather than optional.
Interactive tools
- Strings ExtractorPull printable text from any binary, library, or image. ASCII and UTF-16 detection, configurable minimum length, flag-like highlight, no command line needed.
- Hex ViewerView text or raw hex bytes as a xxd-style hex dump with byte offset, hex columns, and ASCII sidebar. Highlights printable characters and null bytes.
Flag
Reveal flag
picoCTF{w4ke_m3_up_w1th_fr1da_...}
Install Frida, write a one-function kill_sleep.js that replaces Sleep with a no-op, and run the binary under frida to get the Base64 flag output.