
Python typically compiles.pysource into bytecode before running it. Bytecode is a sequence of instructions (load a value, call a function, jump, compare, etc.) similar to assembly that the Python virtual machine executes.
This design gives Python several advantages. Bytecode is mostly platform-independent. It also enables dynamic features such as runtime type changes, reflection, dynamic imports, and on-the-fly code execution, all of which are difficult to support in compiled languages like C.You can use thedismodule in Python to generate the bytecode of any function and see it for yourself:

In this challenge, you were presented withdis.dis()output of a flag checker function.
The function validates an input string calledflag. It rejects (returnsFalse) on any mismatch and only succeeds (returnsTrue) if every check matches.Python bytecode operates on a stack. Instructions push values onto the stack, pop them off for operations, and compare or store results. You can see that the code is broken into sections separated by a newline and a number in the first column. This is a debugging artifact that tells you which line number in the source code that bytecode corresponds to. This makes it easier for us to review.The first number in each line for each instruction is the byte offset in the bytecode. It tells you the position (in bytes) where that instruction starts in the compiled bytecode sequence. We can ignore it for this.|
Let’s walk through the first few instructions:

LOAD_GLOBALpushes thelenfunction onto the stack. LOAD_FASTpushes theflagparameter.CALL 1pops both, callslen(flag), and pushes the result.LOAD_CONSTpushes30.COMPARE_OP 55pops both values and compares them with!=. If true, the jump is skipped and the function returnsFalse. Otherwise execution continues.In other words, this section corresponds toif len(flag) != 30: return False Later in the bytecode:

This loadsord, then loadsflag[i]usingBINARY_SUBSCR(subscript operator), callsord(flag[i]), loads181, and performs XOR (^). This section corresponds toord(flag[i]) ^ 181 You can manually trace through the entire bytecode this way or use a tool to help.In reconstructed Python, the function looks like this:

There are two loops. The first loop checks indices 1, 3, 5, and so on. The other loop checks indices 0, 2, 4, and so on. Each loop usesi // 2to map the string index into a 15-element table. That matches the fact that a 30-character string has 15 even indices and 15 odd indices. Each character is converted to an integer withord(), XORed with a constant, and compared to a stored value. XOR is reversible. Ifa ^ k = b, thena = b ^ k. That lets us recover the original characters from the tables:

Then interleave them to rebuild the full string:

Running this produces the single 30-character string accepted by the bytecode, which is the flag.