# bananaScript## Reversing 450
#### shareef12
    Not too sure how to Interpret this, the lab member who wrote this "forgot" to    write any documentation. This shit, and him, is bananas. B, A-N-A-N-A-S.
We were initially given two files for this challenge; an ELF binary `monkeyDo`and a text file `banana.script`. At some point on Saturday the organizersreleased two additional script files: `test1.script` and `test2.script`.
    user@reversing:~/csaw/bananascript$ file *    banana.script: ASCII text, with very long lines, with CRLF line terminators    monkeyDo:      ELF 64-bit LSB executable, x86-64, version 1 (SYSV),    dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux    2.6.32, BuildID[sha1]=4e3e2b95c29bcb0f0da9761171d309ce92564cb2, stripped    test1.script:  ASCII text, with CRLF line terminators    test2.script:  ASCII text, with CRLF line terminators
Based on the description, `monkeyDo` is probably an interpreter for each of the script files. Running banana.script gives us the following results.
    user@reversing:~/csaw/bananascript$ ./monkeyDo banana.script    Hello! And welcome to the Flying Monkeys' Fantastic Falling Fan Trivia Game.
    Here, the council of monkeys will ask you questions, which will determine whether they choose to lift you away save you from your plummeting fate.
    "WRITE DOWN YOUR AGE," speaks the elder monkey.
    ...Only now do you notice the immense amount of banananasPiled around you on this falling stone platform.. The bananananasSeem to be used for everything, from the obvious food source to building materials to tooth brushes to toys to even glasses, but you can't imagine how well one could see through a pair of K-Vision goggles.
    One such monkey wearing these goggles hobbles up to you now, carrying a pile of limp banananananasSkins and a bananananananaPointPen. As this monkey hands you these materials, the black ends of the banananananananas(Where eyes might ought to go?) seem to peer into your soul, as though they know everything and more that there is to know about you, and they are very, very deeply conflicted about you due to a familial disagreement back in the chain... "Disgrace to our fine culture," you think you hear, but so soft that it could have just been the wind.  The monkey moves in closer and closer, so close that it could, and actually does bump into you, obviously unaware of where you are due to some odd oblong fruit obscuring its vision.
    test_input_1
    ~How can monkeys talk? And why am I following you their commands?~
    "WRITE DOWN YOUR SSN/CVV's/privatekeys- err I mean favorite food!," speaks the elder monkey.    test_input_2
    "GASP!" All the monkeys are dreadfully appaled, some of them even start to cry.  "How could you?" spits one monkey, covering the eyes of their child.  The conglomerate of monkeys take off from the platform, leaving you to fall to your death.
At this point we need to find a way to determine what inputs are valid for thesequestions. To do this, I started static analysis of `monkeyDo` in order to builda simple disassembler for the scripts. Opening it up in IDA, we see one of theugliest control flow graphs for `main()`. Due to the lack of other functions, wecan assume the bulk of the disassembler is implemented in this function.
![main() Control Flow Graph](img/cfg.png)
To name some of the c++ functions correctly, I created a test program with somec++ std types, compiled, and disassembled in order to compare functionality.Many of the top-level vector functions seemed to be exactly the same.
After verifying the correct argument count, we encounter the following basicblock, which calls two functions. The first, `read_lines` reads each line fromthe input script file, and splits each line by whitespace, returning a vector oflines, where each line is a vector of words.
![Read lines](img/read_lines.png)
The second function seems to initialize some form of hashmap mapping a "bananastring" to an ascii character. This hashmap will probably be used to translate"banana strings" to ascii strings.
![Character Encoding map](img/build_char_encoding_map.png)
Following this, we initialize 16 `std::basic_string` objects on the stack, whichhappen to be the "registers" for this interpreter. In the picture below, thefirst 8 registers are named r0-r8, and the next 8 a0-a8.
![Initializing Registers](img/initialize_registers.png)
Initially I didn't make the connection that these were the registers of theinterpreter until I started looking at some of the instructions. What gave itaway was for many instructions there was a cascading sequence of comparisons fora specific "banana string" and moving the address of one of these registers intoa specific location. Essentially this was the machine choosing a register tooperate on given a specific instruction operand.
In the below images, we see that the fourth word in the line (index 3) is anoperand. Based on the capitalization of the word "banANANS", we choose acorresponding register to operate on. It seems all registers started with"banA", and the remaining text corresponds to the binary value of the registerindex, with uppercase being a 1 and lowercase being a 0.
    banANAS = r7 or a7    banANAs = r6 or a6    banANaS = r5 or a5    ...    banAnas = r0 or a0
![Choosing Operands](img/operand_choose_1.png)![Choosing Operands](img/operand_choose_2.png)
After reversing a few of the opcodes and making extremely slow progress, Idecided to move to a more dynamic analysis. The interpreter loops through eachline, with the start of loop at `0x4074d7`. If we set a breakpoint at thisaddress and dump the machine registers, we can step through a script filemanually. To automate this process, I created a [gdb init script](.gdbinit) thatdefined some useful functions, automatically set a breakpoint, and loaded`banana.script`.
To help decode some of the runtime banana strings, I also wrote a simple[python script](convert.py) to decode them.
    user@reversing:~/csaw/bananascript$ gdb monkeyDo    Reading symbols from monkeyDo...(no debugging symbols found)...done.    Breakpoint 1 at 0x4074d7
    Breakpoint 1, 0x00000000004074d7 in ?? ()    => 0x00000000004074d7:    48 8d 85 f0 f2 ff ff    lea    rax,[rbp-0xd10]
     line: 0x7fffffffd210:    0x00000000
     r0: 0x7fffffffd4d0:    ""     r1: 0x7fffffffd4b0:    ""     r2: 0x7fffffffd490:    ""     r3: 0x7fffffffd470:    ""     r4: 0x7fffffffd450:    ""     r5: 0x7fffffffd430:    ""     r6: 0x7fffffffd410:    ""     r7: 0x7fffffffd3f0:    ""
     a0: 0x7fffffffd5d0:    ""     a1: 0x7fffffffd5b0:    ""     a2: 0x7fffffffd590:    ""     a3: 0x7fffffffd570:    ""     a4: 0x7fffffffd550:    ""     a5: 0x7fffffffd530:    ""     a6: 0x7fffffffd510:    ""     a7: 0x7fffffffd4f0:    ""    (gdb) c    Continuing.
    Breakpoint 1, 0x00000000004074d7 in ?? ()    => 0x00000000004074d7:    48 8d 85 f0 f2 ff ff    lea    rax,[rbp-0xd10]
     line: 0x7fffffffd210:    0x00000001
     ...     ...     ...    (gdb) c    Continuing.
    Breakpoint 1, 0x00000000004074d7 in ?? ()    => 0x00000000004074d7:    48 8d 85 f0 f2 ff ff    lea    rax,[rbp-0xd10]
     line: 0x7fffffffd210:    0x00000002
     ...     ...     ...    (gdb) c    Continuing.
    Breakpoint 1, 0x00000000004074d7 in ?? ()    => 0x00000000004074d7:    48 8d 85 f0 f2 ff ff    lea    rax,[rbp-0xd10]
     line: 0x7fffffffd210:    0x00000003
     ...     ...     ...    (gdb) c    Continuing.
    Breakpoint 1, 0x00000000004074d7 in ?? ()    => 0x00000000004074d7:    48 8d 85 f0 f2 ff ff    lea    rax,[rbp-0xd10]
     line: 0x7fffffffd210:    0x00000004
     r0: 0x62e2b0:    "baNANAs banAnAS banANaS banaNAs BANANAs BANaNas BANAnas bANanAS baNaNAs banaNAs bANaNas BaNaNaS baNanas BaNaNas BaNanas BaNANas baNAnaS banaNAS bANAnAs banANAS bAnaNAs BANAnAS BANAnas BaNANas bAnANas "...     r1: 0x62e0d0:    "BAnaNas BANANAS BAnAnAs BANANAS BAnAnAs BANANAS"     r2: 0x7fffffffd490:    ""     r3: 0x7fffffffd470:    ""     r4: 0x7fffffffd450:    ""     r5: 0x7fffffffd430:    ""     r6: 0x7fffffffd410:    ""     r7: 0x62e690:    "BaNANAs BANAnAS BANaNas BANaNas BANanaS bANaNas BanAnAS BAnaNaS BANanAs BANANas BanAnAS BAnAnaS BANAnAS BANaNas BANANaS BANanaS BANanAS BANAnAS BanAnAS BAnANas BANanaS BanAnAS BAnANas BANAnas BANAnAS "...
     a0: 0x7fffffffd5d0:    ""     a1: 0x7fffffffd5b0:    ""     a2: 0x7fffffffd590:    ""     a3: 0x7fffffffd570:    ""     a4: 0x7fffffffd550:    ""     a5: 0x7fffffffd530:    ""     a6: 0x7fffffffd510:    ""     a7: 0x7fffffffd4f0:    ""
    user@reversing:~/csaw/bananascript$ ./convert.py    > BaNANAs BANAnAS BANaNas BANaNas BANanaS bANaNas BanAnAS BAnaNaS BANanAs BANANas BanAnAS BAnAnaS BANAnAS BANaNas BANANaS BANanaS BANanAS BANAnAS BanAnAS BAnANas BANanaS BanAnAS BAnANas BANAnas BANAnAS    Hello! And welcome to the
    >
At this point, it's time to start reversing specific operands. Since `monkeyDo`seemed to implement many more opcodes that the script used, I started with thefirst instruction in the script and began reversing to figure out what that linedid, and implemented that functionality in the disassembler. This step probablytook the longest amount of time. `banana.script` ended up using 8 differentoperations.
1. store rX, CONST - Store a constant banana string in a general purpose    register.2. store aX, CONST - Store a constant banana string in an arithmetic register2. xor   rX, rY    - Perform a repeated xor of rX and rY for the length of rX,    storing the result in rX.3. put   rX        - Convert register banana string to ascii and print to stdout4. get   rX        - Get ascii input, convert to banana string, and store in register    rX.5. sge   rX, rY    - Hash two registers, and skip the next instruction if rX > rY.    The hash always appeared to be greater if len(rX) > len(rY)6. se    rX, rY    - Skip if equal7. jmp   aX        - Jump forward the amount of instructions indicated in register aX.8. mix   rX, rY    - Mix the input of rY into rX (I didn't spend the time to fully    reverse this operation).
The full disassembly of banana.script using the custom[disassembler](disassemble.py) is below.
    user@reversing:~/csaw/bananascript$ ./disassemble.py banana.script     0: store r0, "baNANAs banAnAS banANaS banaNAs BANANAs BANaNas BANAnas bANa..."     1: store r7, "bANaNas banaNas baNANAs banAnAS baNaNaS BanAnAS bAnanaS baNA..."     2: store r1, "BAnaNas BANANAS BAnAnAs BANANAS BAnAnAs BANANAS"     3: xor   r7, r1     4: put   r7     5: store r1, "BanAnAS"     6: put   r1     7: store r7, "bAnANAS banAnAs banAnAs banaNas BanaNaS bANAnAs baNANaS bana..."     8: store r1, "BAnaNas BANANAS BANAnAs BANanaS BANanaS BANAnAs BANanaS BANa..."     9: xor   r7, r1     a: put   r7     b: store r1, "BanAnAS"     c: put   r1     d: store r7, "BaNAnas bAnanaS bAnAnAs bAnaNAs bANANas baNanAS bANanas banA..."     e: store r1, "BANANAs BANAnAS BAnANAs BANanAs BANAnAS BAnANAs BANanAs BANA..."     f: xor   r7, r1    10: put   r7    11: store r1, "BanAnAS"    12: put   r1    13: store r7, "BAnAnAs BaNAnAS BAnAnas bananaS baNanAS baNaNAs bANAnAs baNa..."    14: store r1, "BaNANaS BaNAnaS BaNanAs BaNaNas BAnaNaS BaNaNAs BaNaNAs BAna..."    15: xor   r7, r1    16: put   r7    17: store r1, "BanAnAS"    18: put   r1    19: store r7, "bAnaNaS banANaS banAnaS bANaNas bananas baNANas baNanas bANA..."    1a: store r1, "BANANAs BANANAS BANanAs BANANAS BANanAs BANANAS BAnANaS BANa..."    1b: xor   r7, r1    1c: put   r7    1d: store r1, "BanAnAS"    1e: put   r1    1f: get   r7    20: store a7, "BanaNAS"    21: store a6, "Bananas"    22: store r2, "BanAnas BananaS"    23: sge   r7, r2    24: jmp   a7    25: jmp   a6    26: store r1, "BanAnAS"    27: put   r1    28: store r7, "BaNaNas bANanas banaNAs baNanAS bANAnAs bANaNaS banAnaS bANa..."    29: store r1, "BAnAnaS BaNANAs BAnaNAS BAnanAs BANaNAS BAnanAs BANaNAS BAna..."    2a: xor   r7, r1    2b: put   r7    2c: store a7, "BanaNAS BanAnaS BanAnaS"    2d: jmp   a7    2e: put   r1    2f: store r1, "BanaNas bAnANAS bananas baNaNAS bANaNas banANAS banANAs bana..."    30: store r2, "BANANAs BANANAS BANanAs BANanaS BANanAs BANanaS BANanaS BANa..."    31: xor   r1, r2    32: put   r1    33: store r1, "BanAnAS"    34: put   r1    35: store r4, "BaNaNAS baNAnaS bAnaNaS bAnaNaS banANaS bANaNAs bAnAnaS baNA..."    36: store r1, "BANanaS BANAnas BaNANAS BaNaNAS BAnanAs BANAnas BANAnAS BANa..."    37: xor   r4, r1    38: put   r4    39: get   r4    3a: store r2, "BAnaNas BANANAS BANanAs BANANAS BaNAnas BAnaNaS BAnANaS bANa..."    3b: store a7, "BanaNAS"    3c: store a6, "Bananas"    3d: se    r4, r2    3e: jmp   a7    3f: jmp   a6    40: store r1, "BanAnAS"    41: put   r1    42: store r4, "BaNanas bAnAnas banAnas bANANAs bANAnAs BanANas BaNAnas baNA..."    43: store r1, "BANaNAS BANanAS BANaNAS BAnANaS BAnANaS BAnANas BANAnas BANA..."    44: xor   r4, r1    45: put   r4    46: store a7, "BanaNAS BanAnaS BanAnaS"    47: jmp   a7    48: store r1, "BanAnAS"    49: put   r1    4a: store r1, "banaNAS bANANas banAnaS baNaNaS bANANAs banANas banAnAs bAnA..."    4b: store r2, "bANanAs BANanAS BANanaS BANanAs BANaNaS BANAnAS BAnaNAS BAna..."    4c: xor   r1, r2    4d: put   r1    4e: store r1, "BanaNas bAnAnaS bananAS bANanas bAnANas bAnanaS bAnaNaS baNA..."    4f: store r2, "BaNANas BANanaS BANaNAS BANanAs BaNAnaS BAnaNAS BaNANaS BaNa..."    50: xor   r1, r2    51: put   r1    52: store r1, "BanAnAS"    53: put   r1    54: store r5, "BaNaNaS bANAnAs banAnaS bAnANAs bANanAs bANANas baNanAS bana..."    55: store r1, "BANanAs BANanaS BANaNAs BANaNaS BaNANaS BANanAS BAnanas BaNA..."    56: xor   r5, r1    57: put   r5    58: get   r5    59: store r1, "BanAnAS"    5a: put   r1    5b: store r1, "BAnanaS banAnAS banAnaS bANAnAs bANanaS bAnAnAS baNaNaS baNA..."    5c: store r2, "BANaNAS BanANAS BaNaNAS BaNAnas BAnanAs BAnanaS BaNaNas BAnA..."    5d: xor   r1, r2    5e: put   r1    5f: store r1, "BanAnAS"    60: put   r1    61: store r6, "BANAnAS bAnAnAs banANas bANAnas banAnAs banaNas bANaNaS baNA..."    62: store r2, "BANANAs BANANAS BaNAnas BAnaNaS BaNAnas BAnaNaS BaNAnas BAna..."    63: xor   r6, r2    64: put   r6    65: get   r6    66: put   r1    67: store r1, "BanANAs bANaNaS banaNAS baNANas baNanAS baNanas bANAnAS bAna..."    68: store r2, "BANANAS BANanas BANanas BANaNas BANAnAS BAnANaS BANANAS BAnA..."    69: xor   r1, r2    6a: put   r1    6b: store r1, "BanAnAS"    6c: put   r1    6d: mix   r4, r7    6e: mix   r4, r6    6f: mix   r4, r5    70: xor   r0, r4    71: store r3, "BanANaS bAnAnaS baNaNAs baNANAS baNaNAs bANANas baNAnaS baNA..."    72: store r2, "BANanaS BAnANaS BANaNAS BAnANAs BANaNAS BAnANaS"    73: xor   r3, r2    74: put   r3    75: put   r0
Examining this disassembly, we find that the answers the first two questions areprobably "18" for the first question, and "BanaNAs!" for the second. Assuming wepass the second question prompt, we see that all four of our answers are mixedtogether using a mix operation, and that result is used as a rolling xor keywith a banana string constant to generate the flag.
Since all answers are mixed into the answer for the second question, we knowthat the key length is 8 bytes. Since we also know that the flag will probablystart with "flag{", we can calculate the first 5 bytes of the xor key and bruteforce the rest.
```python#!/usr/bin/env python
import itertoolsimport string
from convert import encodingimport disassemble
FLAG_CHARS = string.ascii_letters + string.digits + "_"
banana_ct = "baNANAs banAnAS banANaS banaNAs BANANAs BANaNas BANAnas bANanAS baNaNAs banaNAs bANaNas BaNaNaS baNanas BaNaNas BaNanas BaNANas baNAnaS banaNAS bANAnAs banANAS bAnaNAs BANAnAS BANAnas BaNANas bAnANas BaNaNaS banAnAs bANAnAs baNaNas BanaNaS bANANas banaNas bAnANaS bANANaS BaNAnas baNanAs baNanAS BaNAnAs bANANas banAnas bAnanaS banANaS bANaNAS banANaS baNanAS BaNanAS BANAnAS BaNanaS"
tokens = disassemble.tokenize(banana_ct)ct = [t.val for t in tokens]
def rolling_xor(ct, key):    pt = []    for i, c in enumerate(ct):        char = c ^ key[i % (len(key))]        pt.append(char)    return pt
key = [ 0x64, 0x7f, 0x72, 0x7f, 0x56]#for i in xrange(256):#    try:#        if encoding[i ^ ct[4]] == '{':#            print hex(i)#            exit(1)#    except:#        pass
for i, seq in enumerate(itertools.product(range(256), repeat=3)):    guess = key + list(seq)    pt = rolling_xor(ct, guess)    try:        pt = "".join(encoding[c] for c in pt)        if all(c in string.printable for c in pt) and pt[-1] == "}" and \           all(c in FLAG_CHARS for c in pt[5:-1]):            print pt    except:        pass```
Running this script produces 52 flags, the last one of which was the solution.
    flag{lr4ng3_3R3_ch1pper_1_h474_n07_s4L_b4n4n4Ss}    flag{kr4ng3_3Q3_ch1ppfr_1_h475_n07_s4K_b4n4n4Ts}    flag{jr4ng3_3P3_ch1ppgr_1_h472_n07_s4N_b4n4n4Us}    flag{ir4ng3_3O3_ch1pphr_1_h473_n07_s4M_b4n4n4Vs}    flag{pr4ng3_3V3_ch1ppar_1_h478_n07_s4H_b4n4n4Os}    flag{or4ng3_3U3_ch1ppbr_1_h479_n07_s4G_b4n4n4Ps}    flag{nr4ng3_3T3_ch1ppcr_1_h476_n07_s4J_b4n4n4Qs}    flag{mr4ng3_3S3_ch1ppdr_1_h477_n07_s4I_b4n4n4Rs}    flag{dr4ng3_3J3_ch1ppmr_1_h47Y_n07_s4T_b4n4n4Ks}    flag{cr4ng3_3I3_ch1ppnr_1_h47Z_n07_s4S_b4n4n4Ls}    flag{br4ng3_3H3_ch1ppor_1_h47W_n07_s4V_b4n4n4Ms}    flag{ar4ng3_3G3_ch1pppr_1_h47X_n07_s4U_b4n4n4Ns}    flag{hr4ng3_3N3_ch1ppir_1_h470_n07_s4P_b4n4n4Gs}    flag{gr4ng3_3M3_ch1ppjr_1_h471_n07_s4O_b4n4n4Hs}    flag{zr4ng3_333_ch1ppwr_1_h47O_n07_s41_b4n4n48s}    flag{yr4ng3_323_ch1ppxr_1_h47P_n07_s40_b4n4n49s}    flag{Fr4ng3_393_ch1ppqr_1_h47U_n07_s4X_b4n4n42s}    flag{Er4ng3_383_ch1pprr_1_h47V_n07_s4W_b4n4n43s}    flag{Dr4ng3_373_ch1ppsr_1_h47S_n07_s4Z_b4n4n44s}    flag{Cr4ng3_363_ch1pptr_1_h47T_n07_s4Y_b4n4n45s}    flag{rr4ng3_3X3_ch1ppEr_1_h47G_n07_s49_b4n4n40s}    flag{qr4ng3_3W3_ch1ppFr_1_h47H_n07_s48_b4n4n41s}    flag{xr4ng3_313_ch1ppyr_1_h47M_n07_s43_b4n4n4Ws}    flag{wr4ng3_303_ch1ppzr_1_h47N_n07_s42_b4n4n4Xs}    flag{Rr4ng3_3l3_ch1ppKr_1_h47A_n07_s4f_b4n4n4ms}    flag{Qr4ng3_3k3_ch1ppLr_1_h47B_n07_s4e_b4n4n4ns}    flag{Pr4ng3_3j3_ch1ppMr_1_h47y_n07_s4h_b4n4n4os}    flag{Or4ng3_3i3_ch1ppNr_1_h47z_n07_s4g_b4n4n4ps}    flag{Vr4ng3_3p3_ch1ppGr_1_h47E_n07_s4b_b4n4n4is}    flag{Ur4ng3_3o3_ch1ppHr_1_h47F_n07_s4a_b4n4n4js}    flag{Tr4ng3_3n3_ch1ppIr_1_h47C_n07_s4d_b4n4n4ks}    flag{Sr4ng3_3m3_ch1ppJr_1_h47D_n07_s4c_b4n4n4ls}    flag{Jr4ng3_3d3_ch1ppSr_1_h47s_n07_s4n_b4n4n4es}    flag{Ir4ng3_3c3_ch1ppTr_1_h47t_n07_s4m_b4n4n4fs}    flag{Hr4ng3_3b3_ch1ppUr_1_h47q_n07_s4p_b4n4n4gs}    flag{Gr4ng3_3a3_ch1ppVr_1_h47r_n07_s4o_b4n4n4hs}    flag{Nr4ng3_3h3_ch1ppOr_1_h47w_n07_s4j_b4n4n4as}    flag{Mr4ng3_3g3_ch1ppPr_1_h47x_n07_s4i_b4n4n4bs}    flag{Lr4ng3_3f3_ch1ppQr_1_h47u_n07_s4l_b4n4n4cs}    flag{Kr4ng3_3e3_ch1ppRr_1_h47v_n07_s4k_b4n4n4ds}    flag{3r4ng3_3z3_ch1pp0r_1_h47i_n07_s4x_b4n4n4Es}    flag{2r4ng3_3y3_ch1pp1r_1_h47j_n07_s4w_b4n4n4Fs}    flag{9r4ng3_3F3_ch1ppWr_1_h47o_n07_s4r_b4n4n4ys}    flag{8r4ng3_3E3_ch1ppXr_1_h47p_n07_s4q_b4n4n4zs}    flag{7r4ng3_3D3_ch1ppYr_1_h47m_n07_s4t_b4n4n4As}    flag{6r4ng3_3C3_ch1ppZr_1_h47n_n07_s4s_b4n4n4Bs}    flag{Zr4ng3_3t3_ch1pp6r_1_h47c_n07_s4D_b4n4n4us}    flag{Yr4ng3_3s3_ch1pp7r_1_h47d_n07_s4C_b4n4n4vs}    flag{Xr4ng3_3r3_ch1pp8r_1_h47a_n07_s4F_b4n4n4ws}    flag{Wr4ng3_3q3_ch1pp9r_1_h47b_n07_s4E_b4n4n4xs}    flag{1r4ng3_3x3_ch1pp2r_1_h47g_n07_s4z_b4n4n4qs}    flag{0r4ng3_3w3_ch1pp3r_1_h47h_n07_s4y_b4n4n4rs}
#### Shortcuts
Solving this challenge may have been much faster from a purely dynamicperspective. Dumping the registers and examining the transformations from thatperspective would have almost certainly been faster and easier. The providedscript was fairly naive with only two operations that mixed the contents ofregisters. Furthermore, if one realizes that the flag result is simply a rollingxor between two registers, it would have been trivial to skip the majority ofstatic reversing of earlier opcodes and skip straight to analysis of the finalxor.