{
    "version": "https://jsonfeed.org/version/1",
    "title": "yype.site",
    "home_page_url": "https://yype.site/",
    "feed_url": "https://yype.site/feed.json",
    "description": "hacking & exploring",
    "icon": "https://yype.site/apple-touch-icon.png",
    "favicon": "https://yype.site/favicon.ico",
    "expired": false,
    
    "author": "{"twitter"=>nil, "name"=>nil, "avatar"=>nil, "email"=>nil, "url"=>nil}",
    
"items": [
    
    
        
        
        
        {
            "id": "https://yype.site/2020/10/23/n1vault",
            "title": "N1CTF2020 n1vault, Thoughts & Solutions",
            "summary": null,
            "content_text": "IntroI designed the RE challenge n1vault in the recent CTF N1CTF2020. In this post, I will talk about details about this chal and offer some possible solutions.The core part of this challenge is to craft a file’s CRC to an arbitrary value(zero) by modifying some specified bytes (of the same bit size as the CRC value) in the file.As for the binary n1vault, it uses SHA256 to digest all the bytes inside the file(credencial.png) except for the even-numbered bytes in the last 25 bytes(some twists were added to the sha256_update function, paving the way for the backdoor). Once the file’s CRC is faked to 0, a secret logic(backdoor) will be triggered by an exception FPE_INTDIV, since the verification inside the function main has an unnecessary comparison 4764888639493207598 / (crc32_result | crc64_result) == 1, which will trigger an FPE_INTDIV when both crc32_result and crc64_result are zero, and will be evaluated to true when given the original file credential.png. Players’ job is to to craft an input to trigger the backdoor, send the crafted bytes to the judging bot and receive the flag.SolutionThe reverse engineering part of the binary program is quite easy. Some junk codes with fixed patterns are inserted into the main logic, which can be bypassed by a simple pattern searching &amp; replacing. Afterward, the program logic is straightforward, and we only have to solve the math problem left.CRC has a property that the final result can be viewed as the linear combination of the influences of each bit in the message and an initial offset, on $GF(2)$. This can be described as follows:\\[f(x)=f(0) + \\sum_{i=0}^{CRC\\_SIZE-1} x_i \\cdot influence_i,\\]where $f(0)$ is the initial offset, specifically for this challenge, is the CRC of the credential with all the even-numbered bytes in the last 25 bytes set to zero. Given this property, if we have enough $x_i$ to control, we can easily construct a matrix and solve each $x_i$ using gaussian elimination. The trick here is we have to ensure that both $f(x)=CRC32(credential)$ and $g(x)=CRC64(credential)$ are equal to zero. In fact, if we let $h(x)=(f(x) &lt; &lt; 64)+g(x)$ and focus on making $h(x)=0$, it has the same effect as making both $f(x)$ and $g(x)$ zero.I wrote a tool based on this interesting property of CRC, allowing us to arbitrarily craft a file’s CRC by specifying certain bits available for modification. It can output all the available solutions and allows for fewer available bits than the bit size of the CRC result. You can check the tool here:  https://github.com/yype/crcolliderUsing this tool we can easily solve the problem using the following Python code:from crcollider import collcrcfrom crc_funcs import crc64, crc32def crc96(m):    return (crc32(m) &lt;&lt; 64) + crc64(m)def solve_chal():    with open('credential.png', 'rb') as f:        org_img = f.read()    rg = list(range(len(org_img)*8))    available_bits = []    for i in range(12):        # even bytes in the last 25 bytes        available_bits += rg[len(rg)-16*i-16:len(rg)-16*i-8]    sol_num, sols = collcrc(crc96, 96, org_img, available_bits, 0x0)        print(f'{sol_num} solution(s) found')    for i, each in enumerate(sols):        file_out = f'credential_sol{i}.png'        print(f'Outputting sol{i} to {file_out}...')        with open(file_out, 'wb') as f:            f.write(each)if __name__ == '__main__':    solve_chal()There are totally 4 solutions available for this challenge. One of them contains only visible characters, which is n1vaultadmin(intentionally crafted), while others are not. It might be better if I put some constraints to ensure that only one solution is available though.solution&gt; python3 .\\main.py4 solution(s) foundOutputting sol0 to credential_sol0.png...Outputting sol1 to credential_sol1.png...Outputting sol2 to credential_sol2.png...Outputting sol3 to credential_sol3.png...The source code of this challenge and a duplicate of this post are uploaded to GitHub. Check them out at: https://github.com/Nu1LCTF/n1ctf-2020/tree/main/RE/n1vault.",
            "content_html": "<h2 id=\"intro\">Intro</h2><p>I designed the RE challenge <em>n1vault</em> in the recent CTF <a href=\"https://ctftime.org/event/1099\" target=\"_blank\">N1CTF2020</a>. In this post, I will talk about details about this chal and offer some possible solutions.</p><p>The core part of this challenge is to craft a file’s CRC to an arbitrary value(zero) by modifying some specified bytes (of the same bit size as the CRC value) in the file.</p><p>As for the binary <code class=\"language-plaintext highlighter-rouge\">n1vault</code>, it uses SHA256 to digest all the bytes inside the file(<code class=\"language-plaintext highlighter-rouge\">credencial.png</code>) except for the even-numbered bytes in the last 25 bytes(some twists were added to the <em>sha256_update</em> function, paving the way for the backdoor). Once the file’s CRC is faked to 0, a secret logic(backdoor) will be triggered by an exception <em>FPE_INTDIV</em>, since the verification inside the function <code class=\"language-plaintext highlighter-rouge\">main</code> has an unnecessary comparison <code class=\"language-plaintext highlighter-rouge\">4764888639493207598 / (crc32_result | crc64_result) == 1</code>, which will trigger an <em>FPE_INTDIV</em> when both crc32_result and crc64_result are zero, and will be evaluated to <em>true</em> when given the original file <code class=\"language-plaintext highlighter-rouge\">credential.png</code>. Players’ job is to to craft an input to trigger the backdoor, send the crafted bytes to the judging bot and receive the flag.</p><h2 id=\"solution\">Solution</h2><p>The reverse engineering part of the binary program is quite easy. Some junk codes with fixed patterns are inserted into the main logic, which can be bypassed by a simple pattern searching &amp; replacing. Afterward, the program logic is straightforward, and we only have to solve the math problem left.</p><p>CRC has a property that the final result can be viewed as the linear combination of the influences of each bit in the message and an initial offset, on $GF(2)$. This can be described as follows:</p>\\[f(x)=f(0) + \\sum_{i=0}^{CRC\\_SIZE-1} x_i \\cdot influence_i,\\]<p>where $f(0)$ is the initial offset, specifically for this challenge, is the CRC of the credential with all the even-numbered bytes in the last 25 bytes set to zero. Given this property, if we have enough $x_i$ to control, we can easily construct a matrix and solve each $x_i$ using gaussian elimination. The trick here is we have to ensure that both $f(x)=CRC32(credential)$ and $g(x)=CRC64(credential)$ are equal to zero. In fact, if we let $h(x)=(f(x) &lt; &lt; 64)+g(x)$ and focus on making $h(x)=0$, it has the same effect as making both $f(x)$ and $g(x)$ zero.</p><p>I wrote a tool based on this interesting property of CRC, allowing us to arbitrarily craft a file’s CRC by specifying certain bits available for modification. It can output all the available solutions and allows for fewer available bits than the bit size of the CRC result. You can check the tool here:</p><blockquote>  <p><a href=\"https://github.com/yype/crcollider\" target=\"_blank\">https://github.com/yype/crcollider</a></p></blockquote><p>Using this tool we can easily solve the problem using the following Python code:</p><div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">from</span> <span class=\"nn\">crcollider</span> <span class=\"kn\">import</span> <span class=\"n\">collcrc</span><span class=\"kn\">from</span> <span class=\"nn\">crc_funcs</span> <span class=\"kn\">import</span> <span class=\"n\">crc64</span><span class=\"p\">,</span> <span class=\"n\">crc32</span><span class=\"k\">def</span> <span class=\"nf\">crc96</span><span class=\"p\">(</span><span class=\"n\">m</span><span class=\"p\">):</span>    <span class=\"k\">return</span> <span class=\"p\">(</span><span class=\"n\">crc32</span><span class=\"p\">(</span><span class=\"n\">m</span><span class=\"p\">)</span> <span class=\"o\">&lt;&lt;</span> <span class=\"mi\">64</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"n\">crc64</span><span class=\"p\">(</span><span class=\"n\">m</span><span class=\"p\">)</span><span class=\"k\">def</span> <span class=\"nf\">solve_chal</span><span class=\"p\">():</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"s\">'credential.png'</span><span class=\"p\">,</span> <span class=\"s\">'rb'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>        <span class=\"n\">org_img</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>    <span class=\"n\">rg</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">org_img</span><span class=\"p\">)</span><span class=\"o\">*</span><span class=\"mi\">8</span><span class=\"p\">))</span>    <span class=\"n\">available_bits</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">12</span><span class=\"p\">):</span>        <span class=\"c1\"># even bytes in the last 25 bytes</span>        <span class=\"n\">available_bits</span> <span class=\"o\">+=</span> <span class=\"n\">rg</span><span class=\"p\">[</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">rg</span><span class=\"p\">)</span><span class=\"o\">-</span><span class=\"mi\">16</span><span class=\"o\">*</span><span class=\"n\">i</span><span class=\"o\">-</span><span class=\"mi\">16</span><span class=\"p\">:</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">rg</span><span class=\"p\">)</span><span class=\"o\">-</span><span class=\"mi\">16</span><span class=\"o\">*</span><span class=\"n\">i</span><span class=\"o\">-</span><span class=\"mi\">8</span><span class=\"p\">]</span>    <span class=\"n\">sol_num</span><span class=\"p\">,</span> <span class=\"n\">sols</span> <span class=\"o\">=</span> <span class=\"n\">collcrc</span><span class=\"p\">(</span><span class=\"n\">crc96</span><span class=\"p\">,</span> <span class=\"mi\">96</span><span class=\"p\">,</span> <span class=\"n\">org_img</span><span class=\"p\">,</span> <span class=\"n\">available_bits</span><span class=\"p\">,</span> <span class=\"mh\">0x0</span><span class=\"p\">)</span>        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">sol_num</span><span class=\"si\">}</span><span class=\"s\"> solution(s) found'</span><span class=\"p\">)</span>    <span class=\"k\">for</span> <span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"n\">each</span> <span class=\"ow\">in</span> <span class=\"nb\">enumerate</span><span class=\"p\">(</span><span class=\"n\">sols</span><span class=\"p\">):</span>        <span class=\"n\">file_out</span> <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'credential_sol</span><span class=\"si\">{</span><span class=\"n\">i</span><span class=\"si\">}</span><span class=\"s\">.png'</span>        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'Outputting sol</span><span class=\"si\">{</span><span class=\"n\">i</span><span class=\"si\">}</span><span class=\"s\"> to </span><span class=\"si\">{</span><span class=\"n\">file_out</span><span class=\"si\">}</span><span class=\"s\">...'</span><span class=\"p\">)</span>        <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">file_out</span><span class=\"p\">,</span> <span class=\"s\">'wb'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>            <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">each</span><span class=\"p\">)</span><span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>    <span class=\"n\">solve_chal</span><span class=\"p\">()</span></code></pre></div></div><p>There are totally 4 solutions available for this challenge. One of them contains only visible characters, which is <code class=\"language-plaintext highlighter-rouge\">n1vaultadmin</code>(intentionally crafted), while others are not. It might be better if I put some constraints to ensure that only one solution is available though.</p><div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>solution&gt; python3 .\\main.py4 solution(s) foundOutputting sol0 to credential_sol0.png...Outputting sol1 to credential_sol1.png...Outputting sol2 to credential_sol2.png...Outputting sol3 to credential_sol3.png...</code></pre></div></div><p>The source code of this challenge and a duplicate of this post are uploaded to GitHub. Check them out at: <a href=\"https://github.com/Nu1LCTF/n1ctf-2020/tree/main/RE/n1vault\" target=\"_blank\">https://github.com/Nu1LCTF/n1ctf-2020/tree/main/RE/n1vault</a>.</p>",
            "url": "https://yype.site/2020/10/23/n1vault",
            
            
            
            "tags": ["CTF","Reverse Engineering","N1CTF2020"],
            
            "date_published": "2020-10-23T00:00:00+00:00",
            "date_modified": "2020-10-23T00:00:00+00:00",
            
                "author": 
                "{"twitter"=>nil, "name"=>nil, "avatar"=>nil, "email"=>nil, "url"=>nil}"
                
            
        }
        
    
        
        ,
        
        {
            "id": "https://yype.site/2020/04/20/hypercard-over-windows",
            "title": "PlaidCTF2020 The Watness 2 Write-up",
            "summary": null,
            "content_text": "  Intro  Environment  Challenge SolutionIntroRecently in PlaidCTF2020 there was an RE challenge called The Watness 2. This is a game that requires HyperCard to run. Since I did not have a Macbook computer, I had been struggling figuring out ways to run this game over my Windows 10 laptop. Here is how I finally managed to do that.Environment      Install StuffitExpander      Open the .rc1 file  Follow this video tutorial  Download StuffitExpander, add it to the volumes’ list, install it inside the VM  Download HyperCard 2.4, install it inside the VM as described above  Extract the .rc1 file from the .sit file and open it with a simple double-clickChallenge SolutionExtract the stack’s script code:          Extract the stack’s script code    on openCard  Send colorMe to this card  pass openCardend openCardon closeCard  global prev_card  get the id of this cd  put it into prev_card  lock screen  pass closeCardend closeCardon colorMe  AddColor colorCard,stamp,0end colorMeon openStack  AddColor install  setupMenu  go to card \"tun-1-n\"  pass openStackend openStackon closeStack  AddColor remove  pass closeStackend closeStackon genPuzzle  send \"doMenu New Button\" to Hypercardend genPuzzleon initCard  answer prev_cardend initCardon menuReset  setupMenu  pass menuResetend menuReseton setupMenu  if there is not a menu \"Watness\" then    create menu \"Watness\"    put \"Generate Puzzle\"&amp;return&amp;\"Init Card\"&amp;return&amp;\"Set up Nav\"&amp;return&amp;\"Create Puzzle\" into menu \"Watness\" with menuMsg genPuzzle,initCard,setupNav,constructPuzzle  end ifend setupMenuon setupNav  ask \"What is the name of this card\"  set name of this cd to it  ask \"Where should the left go?\"  put it into left_loc  send \"doMenu New Button\" to Hypercard  set height of the last button to 342  set width of the last button to 100  set topleft of the last button to \"0,0\"  set style of the last button to \"transparent\"  set name of the last button to \"\"  put \"on mouseUp\"&amp;return&amp;\"go to card \"&amp;quote&amp;\"\"&amp;left_loc&amp;quote&amp;return&amp;\"end mouseUp\" into left_script  set script of last button to left_script  ask \"Where should the right go?\"  put it into right_loc  send \"doMenu New Button\" to Hypercard  set height of the last button to 342  set width of the last button to 100  set topleft of the last button to \"412,0\"  set style of the last button to \"transparent\"  set name of the last button to \"\"  put \"on mouseUp\"&amp;return&amp;\"go to card \"&amp;quote&amp;\"\"&amp;right_loc&amp;quote&amp;return&amp;\"end mouseUp\" into right_script  set script of last button to right_script  ask \"Where should fwd go?\"  put it into fwd_loc  send \"doMenu New Button\" to Hypercard  set height of the last button to 342  set width of the last button to 311  set the top of the last button to 0  set the left of the last button to 100  set style of the last button to \"transparent\"  set name of the last button to \"\"  put \"on mouseUp\"&amp;return&amp;\"go to card \"&amp;quote&amp;\"\"&amp;fwd_loc&amp;quote&amp;return&amp;\"end mouseUp\" into fwd_script  set script of last button to fwd_script  get the script of this card  put it into cd_script  put cd_script&amp;return into cd_script  put cd_script&amp;\"on arrowKey key\"&amp;return into cd_script  put cd_script&amp;\" if key = \"&amp;quote&amp;\"left\"&amp;quote&amp;\"then\"&amp;return into cd_script  put cd_script&amp;\"  go to cd \"&amp;quote&amp;left_loc&amp;quote&amp;return into cd_script  put cd_script&amp;\" end if\"&amp;return into cd_script  put cd_script&amp;\" if key = \"&amp;quote&amp;\"right\"&amp;quote&amp;\"then\"&amp;return into cd_script  put cd_script&amp;\"  go to cd \"&amp;quote&amp;right_loc&amp;quote&amp;return into cd_script  put cd_script&amp;\" end if\"&amp;return into cd_script  put cd_script&amp;\" if key = \"&amp;quote&amp;\"up\"&amp;quote&amp;\"then\"&amp;return into cd_script  put cd_script&amp;\"  go to cd \"&amp;quote&amp;fwd_loc&amp;quote&amp;return into cd_script  put cd_script&amp;\" end if\"&amp;return into cd_script  put cd_script&amp;\"end arrowKey\"&amp;return into cd_script  set the script of this cd to cd_scriptend setupNavon makeNode  global node  send \"doMenu New Button\" to Hypercard  put the id of the last button into nodeend makeNodeon constructPuzzle  global node,constraints  ask \"What are the constraints\"  put it into constraints  get the script of this cd  put it into cd_script  put cd_script&amp;return into cd_script  put cd_script&amp;\"on openCard\"&amp;return into cd_script  put cd_script&amp;\"  global constraints,path,cursor_x,cursor_y,\" into cd_script  put 0 into i  repeat for 8        put 0 into j    repeat for 8      put cd_script&amp;\"active_\"&amp;i&amp;\"_\"&amp;j&amp;\",\" into cd_script            put j+1 into j    end repeat        put i+1 into i  end repeat  put cd_script&amp;\"dummy\"&amp;return into cd_script  put cd_script&amp;\"  colorme\"&amp;return into cd_script  put cd_script&amp;\"  put -1 into cursor_x\"&amp;return into cd_script  put cd_script&amp;\"  put 0 into cursor_y\"&amp;return into cd_script  put cd_script&amp;\"  put \"&amp;quote&amp;quote&amp;\" into path\"&amp;return into cd_script  put cd_script&amp;\"  put \"&amp;quote&amp;constraints&amp;quote&amp;\" into constraints\"&amp;return into cd_script  put 1 into c_i  put 0 into i  repeat for 7        put 0 into j    repeat for 7      get char (j*7+i+1) of constraints      put it into letter            if letter &lt;&gt; \" \" then        makeNode                set the width of button id node to 10        set the height of button id node to 10                set the top of button id node to (76 + j * 30)        set the left of button id node to (161 + i * 30)                set the style of button id node to \"opaque\"        set showName of button id node to false                if letter = \"r\" then          put \"65535,0,0\" into node_color        end if        if letter = \"g\" then          put \"0,65535,0\" into node_color        end if        if letter = \"b\" then          put \"0,0,65535\" into node_color        end if                if letter &lt;&gt; \" \" then          addColor colorButton, cd, node, node_color                    put cd_script&amp;\"  addColor colorButton, cd, \"&amp;node&amp;\", \"&amp;quote&amp;node_color&amp;quote&amp;return into cd_script        end if      end if​      ​            put j+1 into j    end repeat        put i+1 into i  end repeat    put 0 into i  repeat for 8        put 0 into j    repeat for 8      put cd_script&amp;\"  put \"&amp;quote&amp;quote&amp;\" into active_\"&amp;i&amp;\"_\"&amp;j&amp;return into cd_script            put j+1 into j    end repeat        put i+1 into i  end repeat  makeNode  set the width of button id node to 10  set the height of button id node to 15  set the left of button id node to 356  set the top of button id node to 276  set the name of button id node to \"path_extension\"  set showName of button id node to false  set the style of button id node to opaque  addcolor colorButton, cd, node, \"37632,30208,12288\"  put \"\" into node_script  put node_script&amp;\"on checkYoSelf\"&amp;return into node_script  put node_script&amp;\"  addcolor colorButton, cd, \"&amp;node&amp;\", \"&amp;quote&amp;\"65535,65535,30000\"&amp;quote&amp;return into node_script  put node_script&amp;\"end checkYoSelf\"&amp;return into node_script  set the script of button id node to node_script  put cd_script&amp;\"  addcolor colorButton, cd, \"&amp;node&amp;\", \"&amp;quote&amp;\"37632,30208,12288\"&amp;quote&amp;return into cd_script  makeNode  set the width of button id node to 10  set the height of button id node to 10  set the left of button id node to 356  set the top of button id node to 286  set the name of button id node to \"finale\"  set showName of button id node to false  set the style of button id node to oval  addcolor colorButton, cd, node, \"37632,30208,12288\"  put \"\" into node_script  put node_script&amp;\"on mouseUp\"&amp;return into node_script  put node_script&amp;\"  global cursor_x, cursor_y\"&amp;return into node_script  put node_script&amp;\"  if (cursor_x = 7) and (cursor_y = 7) then\"&amp;return into node_script  put node_script&amp;\"    addcolor colorButton, cd, \"&amp;node&amp;\", \"&amp;quote&amp;\"65535,65535,30000\"&amp;quote&amp;return into node_script  put node_script&amp;\"    send \"&amp;quote&amp;\"checkYoSelf\"&amp;quote&amp;\" to button path_extension\"&amp;return into node_script  put node_script&amp;\"    send \"&amp;quote&amp;\"checkSolution\"&amp;quote&amp;\" to this cd\"&amp;return into node_script  put node_script&amp;\"  end if\"&amp;return into node_script  put node_script&amp;\"end mouseUp\"&amp;return into node_script  set the script of button id node to node_script  put cd_script&amp;\"  addcolor colorButton, cd, \"&amp;node&amp;\", \"&amp;quote&amp;\"37632,30208,12288\"&amp;quote&amp;return into cd_script  put 0 into i  repeat for 7        put 0 into j    repeat for 8      makeNode            set the width of button id node to 30      set the height of button id node to 10            set the top of button id node to (61 + 30 * j)      set the left of button id node to (151 + 30 * i)            set the style of button id node to opaque      set the name of button id node to \"h_path_\"&amp;i&amp;\"_\"&amp;j            set showName of button id node to false            addcolor colorButton, cd, node, \"37632,30208,12288\"            put cd_script&amp;\"  addcolor colorButton, cd, \"&amp;node&amp;\", \"&amp;quote&amp;\"37632,30208,12288\"&amp;quote&amp;return into cd_script            get the script of button id node      put it into node_script            put \"active_\"&amp;i&amp;\"_\"&amp;j into f_node      put \"active_\"&amp;(i+1)&amp;\"_\"&amp;j into s_node            put node_script&amp;return into node_script      put node_script&amp;\"on checkYoSelf\"&amp;return into node_script      put node_script&amp;\"  global \"&amp;f_node&amp;\",\"&amp;s_node&amp;return into node_script      put node_script&amp;\"  if (\"&amp;f_node&amp;\" = true) and (\"&amp;s_node&amp;\" = true) then\"&amp;return into node_script      put node_script&amp;\"    addcolor colorButton, cd, \"&amp;node&amp;\", \"&amp;quote&amp;\"65535,65535,30000\"&amp;quote&amp;return into node_script      put node_script&amp;\"  end if\"&amp;return into node_script      put node_script&amp;\"end checkYoSelf\"&amp;return into node_script            set the script of button id node to node_script            put j+1 into j    end repeat        put i+1 into i  end repeat  put 0 into i  repeat for 8        put 0 into j    repeat for 7      makeNode            set the width of button id node to 10      set the height of button id node to 30            set the top of button id node to (66 + 30 * j)      set the left of button id node to (146 + 30 * i)            set the style of button id node to opaque      set the name of button id node to \"v_path_\"&amp;i&amp;\"_\"&amp;j            set showName of button id node to false            addcolor colorButton, cd, node, \"37632,30208,12288\"            put cd_script&amp;\"  addcolor colorButton, cd, \"&amp;node&amp;\", \"&amp;quote&amp;\"37632,30208,12288\"&amp;quote&amp;return into cd_script            get the script of button id node      put it into node_script            put \"active_\"&amp;i&amp;\"_\"&amp;j into f_node      put \"active_\"&amp;i&amp;\"_\"&amp;(j+1) into s_node            put node_script&amp;return into node_script      put node_script&amp;\"on checkYoSelf\"&amp;return into node_script      put node_script&amp;\"  global \"&amp;f_node&amp;\",\"&amp;s_node&amp;return into node_script      put node_script&amp;\"  if (\"&amp;f_node&amp;\" = true) and (\"&amp;s_node&amp;\" = true) then\"&amp;return into node_script      put node_script&amp;\"    addcolor colorButton, cd, \"&amp;node&amp;\", \"&amp;quote&amp;\"65535,65535,30000\"&amp;quote&amp;return into node_script      put node_script&amp;\"  end if\"&amp;return into node_script      put node_script&amp;\"end checkYoSelf\"&amp;return into node_script            set the script of button id node to node_script            put j+1 into j    end repeat        put i+1 into i  end repeat  put 0 into i  repeat for 8        put 0 into j    repeat for 8      makeNode            set the width of button id node to 10      set the height of button id node to 10            set the top of button id node to (61 + 30 * j)      set the left of button id node to (146 + 30 * i)            set the style of button id node to oval      set the name of button id node to \"button_\"&amp;i&amp;\"_\"&amp;j            set showName of button id node to false            addcolor colorButton, cd, node, \"37632,30208,12288\"            put \"active_\"&amp;i&amp;\"_\"&amp;j into v_name            put \"\" into node_script      put node_script&amp;\"on mouseUp\"&amp;return into node_script      put node_script&amp;\"  global \"&amp;v_name&amp;\",cursor_x,cursor_y\"&amp;return into node_script      put node_script&amp;\"  put cursor_x into prev_x\"&amp;return into node_script      put node_script&amp;\"  put cursor_y into prev_y\"&amp;return into node_script      put node_script&amp;\"  put abs(cursor_x-\"&amp;i&amp;\") into dx\"&amp;return into node_script      put node_script&amp;\"  put abs(cursor_y-\"&amp;j&amp;\") into dy\"&amp;return into node_script      put node_script&amp;\"  if (\"&amp;v_name&amp;\" = \"&amp;quote&amp;quote&amp;\") and ((dx = 1 and dy = 0) or (dx = 0 and dy = 1)) then\"&amp;return into node_script      put node_script&amp;\"    put true into \"&amp;v_name&amp;return into node_script      put node_script&amp;\"    send \"&amp;quote&amp;\"updateState \"&amp;i&amp;\",\"&amp;j&amp;quote&amp;\" to this cd\"&amp;return into node_script      put node_script&amp;\"    addcolor colorButton, cd, \"&amp;node&amp;\", \"&amp;quote&amp;\"65535,65535,30000\"&amp;quote&amp;return into node_script      put node_script&amp;\"  end if\"&amp;return into node_script      put node_script&amp;\"end mouseUp\"&amp;return into node_script            set the script of button id node to node_script            put cd_script&amp;\"  addcolor colorButton, cd, \"&amp;node&amp;\", \"&amp;quote&amp;\"37632,30208,12288\"&amp;quote&amp;return into cd_script            put j+1 into j    end repeat        put i+1 into i  end repeat  set the width of button button_0_0 to 30  set the height of button button_0_0 to 30  set the top of button button_0_0 to 51  set the left of button button_0_0 to 136  get the id of button button_0_0  addColor colorButton, cd, it, \"37632,30208,12288\"  put cd_script&amp;\"end openCard\"&amp;return into cd_script  set the script of this cd to cd_scriptend constructPuzzleon checkSolution  global puzzle_id,path,constraints,flag_1,flag_2,flag_3  watnesssolver constraints,path  put the result into success  if success = \"true\" then    if puzzle_id = 1 then      decoder path,\"clrtffxpry\"      put the result into flag_1    end if    if puzzle_id = 2 then      decoder path,\"nyghq7xksg\"      put the result into flag_2    end if    if puzzle_id = 3 then      decoder path,\"ppyyvn}1{7\"      put the result into flag_3    end if  else    send opencard to this cd  end ifend checkSolutionon updateState i,j  global path,cursor_x,cursor_y  if (i &lt;&gt; 0) or (j &lt;&gt; 0) then    if (cursor_y = j+1) and (cursor_x = i) then      put path&amp;\"U\" into path    end if    if (cursor_y = j) and (cursor_x = i - 1) then      put path&amp;\"R\" into path    end if    if (cursor_y = j-1) and (cursor_x = i) then      put path&amp;\"D\" into path    end if    if (cursor_y = j) and (cursor_x = i + 1) then      put path&amp;\"L\" into path    end if  end if  if cursor_x &gt;= 0 and cursor_y &gt;= 0 then    put \"h_path_\"&amp;min(cursor_x, i)&amp;\"_\"&amp;min(cursor_y, j) into h_path    put \"v_path_\"&amp;min(cursor_x, i)&amp;\"_\"&amp;min(cursor_y, j) into v_path        if i = cursor_x then      send checkYoSelf to button v_path    end if        if j = cursor_y then      send checkYoSelf to button h_path    end if  end if  put i into cursor_x  put j into cursor_yend updateState  The card’s script code can also be extracted (puzzle 1):  on openCard  global puzzle_id,constraints,path,cursor_x,cursor_y,active_0_0,active_0_1,active_0_2,active_0_3,active_0_4,active_0_5,active_0_6,active_0_7,active_1_0,active_1_1,active_1_2,active_1_3,active_1_4,active_1_5,active_1_6,active_1_7,active_2_0,active_2_1,active_2_2,active_2_3,active_2_4,active_2_5,active_2_6,active_2_7,active_3_0,active_3_1,active_3_2,active_3_3,active_3_4,active_3_5,active_3_6,active_3_7,active_4_0,active_4_1,active_4_2,active_4_3,active_4_4,active_4_5,active_4_6,active_4_7,active_5_0,active_5_1,active_5_2,active_5_3,active_5_4,active_5_5,active_5_6,active_5_7,active_6_0,active_6_1,active_6_2,active_6_3,active_6_4,active_6_5,active_6_6,active_6_7,active_7_0,active_7_1,active_7_2,active_7_3,active_7_4,active_7_5,active_7_6,active_7_7,dummy  colorme  put 1 into puzzle_id  put -1 into cursor_x  put 0 into cursor_y  put \"\" into path  put \"rbrr rgb rb  r brgrbrgb  grrgbbg grg bgrg  bbgrbg\" into constraints  addColor colorButton, cd, 1, \"65535,0,0\"  ...end openCardon arrowKey key  if key = \"left\"then    go to cd \"entry-3-n\"  end if  if key = \"right\"then    go to cd \"entry-3-n\"  end if  if key = \"up\"then    go to cd \"\"  end ifend arrowKey  Now we get the constraint string of this puzzle \"rbrr rgb rb  r brgrbrgb  grrgbbg grg bgrg  bbgrbg\", these constraints, along with the path that goes to the lower right corner, are passed into one thing called XCMD which checks the path’s correctness natively (it contains binary instructions that directly run over the 68k CPU). There are 2 XCMD binaries which can be extracted by this tool, which seem can only run under MacOS. So I’m using the extracted binary from this great post for now instead.What’s more, I found that I can set breakpoints in the script and debug the game, I could even watch the variables on the fly:         DebuggingAs for the XCMD part, it’s basically just a few hours’ reverse engineering work. Since there are currently no reliable decompilers for the 68k architecture, I have to read the assembly. It wasn’t too hard, but I did spend several hours learning the basic concepts of 68k’s instruction set.After the reverse engineering work, the watnesssolver’s checking methods can be rewritten in Python as:def build_automaton(constraints: str):    trans = str.maketrans(' rgb', '0123')    return [int(c) for c in constraints.translate(trans)]def choose_empty(r, g, b):    if g == 0 and b == 0:        return 0    if b &lt; g:        return 2    else:        return 3def choose_red(r, g, b):    if r != 2 and r != 3:        return 0    if b == 0 or g == 0:        return 0    return 1def choose_green(r, g, b):    if r &lt;= 4:        if b &lt;= 4:            if r == 2 or r == 3:                return 1            else:                return 2        else:            return 3    else:        return 0def choose_blue(r, g, b):    if r &lt;= 4:        if g &lt;= 4:            if r == 2 or r == 3:                return 1            else:                return 3        else:            return 2    else:        return 0def is_red(constraints, x, y):    if not (x &gt;= 0 and x &lt; 7 and y &gt;= 0 and y &lt; 7):        return False    return constraints[x+y*7] == 1def get_neighbors(constraints, x, y, color):    sum = 0    for bias_y in range(-1, 2):        for bias_x in range(-1, 2):            if (bias_x != 0 or bias_y != 0) and (y + bias_y &gt;= 0 and y + bias_y &lt; 7) and \\                    (x + bias_x &gt;= 0 and x + bias_x &lt; 7) and constraints[(x+bias_x)+(y+bias_y)*7] == color:                sum += 1    return sumdef step_automaton(constraints):    new_constraints = constraints[:]    for y in range(7):        for x in range(7):            r, g, b = \\                get_neighbors(constraints, x, y, 1), \\                get_neighbors(constraints, x, y, 2), \\                get_neighbors(constraints, x, y, 3)            if constraints[x+y*7] == 0:                new_constraints[x+y*7] = choose_empty(r, g, b)            elif constraints[x+y*7] == 1:                new_constraints[x+y*7] = choose_red(r, g, b)            elif constraints[x+y*7] == 2:                new_constraints[x+y*7] = choose_green(r, g, b)            elif constraints[x+y*7] == 3:                new_constraints[x+y*7] = choose_blue(r, g, b)    return new_constraintsdef perform_move(constraints, mem, x, y, d):    bias_x, bias_y = 0, 0    if d == 'U':        bias_x, bias_y = 0, -1    elif d == 'D':        bias_x, bias_y = 0, 1    elif d == 'L':        bias_x, bias_y = -1, 0    elif d == 'R':        bias_x, bias_y = 1, 0    if not (x+bias_x &gt;= 0 and x+bias_x &lt; 8 and y+bias_y &gt;= 0 and y+bias_y &lt; 8):        return False, x, y        min_x = min(x, x+bias_x)    min_y = min(y, y+bias_y)        if bias_y == 0:        if not (is_red(constraints, min_x, y) or is_red(constraints, min_x, y-1)):            return False, x, y    else:        if not (is_red(constraints, x, min_y) or is_red(constraints, x-1, min_y)):            return False, x, y        if mem[x+bias_x][y+bias_y] == 1:        return False, x, y        mem[x+bias_x][y+bias_y] = 1        return True, x+bias_x, y+bias_ydef solver(path, constraints):    x = y = 0    constraints = build_automaton(constraints)    mem = [[0 for i in range(8)] for j in range(8)]  # been to or not    mem[0][0] = 1    for each in path:        yes, new_x, new_y = perform_move(constraints, mem, x, y, each)        if yes:            if new_x == 7 and new_y == 7:                # print(f'Path `{path}` is great ' + '!' * 20)                return True, True            x, y = new_x, new_y            constraints = step_automaton(constraints)        else:            #print(f'Path `{path}` is bad')            return False, False    return True, FalseLooking around in the game, we’ll know that there are 3 puzzles we need to solve. So we can simply run 3 DFS searches on these contraints and three unique solutions will be printed out.def dfs(depth, path, constraints):    if depth &gt; 24: # figured out after multiple tests        return    mov, end = solver(path, constraints)    if end == True:        print(f'Path {path} is ok')    if mov == False:        return    for d in 'LRUD':        n_path = path + d        dfs(depth+1, n_path, constraints)if __name__ == '__main__':    constraints_stage1 = 'rbrr rgb rb  r brgrbrgb  grrgbbg grg bgrg  bbgrbg'    constraints_stage2 = 'rbr  bbggrgrggb   bggbb b  b bbrbbgg gbrrbgrbbb g'    constraints_stage3 = 'rrbrb rg g  bgrbgggr ggrgr gr rg brr  b  bggrbgbb'    print('Stage1 solution:')    dfs(0, '', constraints_stage1)    print('Stage2 solution:')    dfs(0, '', constraints_stage2)    print('Stage3 solution:')    dfs(0, '', constraints_stage3)Output:Stage1 solution:Path RDDDRURRRDLLDLDRRURRDDDR is okStage2 solution:Path RDDRURDDDRURULURRDDDDDRD is okStage3 solution:Path DRDDDDRUURRRULURRDDDDDDR is okInput these solutions to each puzzle, after that, we could go to the lock-like thing on the white gate to reveal the flag:         flag",
            "content_html": "<ul id=\"markdown-toc\">  <li><a href=\"#intro\" id=\"markdown-toc-intro\">Intro</a></li>  <li><a href=\"#environment\" id=\"markdown-toc-environment\">Environment</a></li>  <li><a href=\"#challenge-solution\" id=\"markdown-toc-challenge-solution\">Challenge Solution</a></li></ul><h2 id=\"intro\">Intro</h2><p>Recently in PlaidCTF2020 there was an RE challenge called <em>The Watness 2</em>. This is a game that requires <em>HyperCard</em> to run. Since I did not have a Macbook computer, I had been struggling figuring out ways to run this game over my Windows 10 laptop. Here is how I finally managed to do that.</p><h2 id=\"environment\">Environment</h2><div class=\"photoswipe-gallery center\">  <p><a class=\"photoswipe photo\" href=\"/assets/HypercardOverWindows/1587369699146.png\" target=\"_blank\" data-cropped=\"true\" data-pswp-width=\"803\" data-pswp-height=\"640\">  <img class=\"image\" src=\"/assets/HypercardOverWindows/1587369699146.png\" width=\"200\" height=\"200\" alt=\"Install StuffitExpander\" />  <span class=\"badge\">Install StuffitExpander</span></a></p>  <p><a class=\"photoswipe photo\" href=\"/assets/HypercardOverWindows/1587369949569.png\" target=\"_blank\" data-cropped=\"true\" data-pswp-width=\"932\" data-pswp-height=\"656\">  <img class=\"image\" src=\"/assets/HypercardOverWindows/1587369949569.png\" width=\"200\" height=\"200\" alt=\"Open the .rc1 file\" />  <span class=\"badge\">Open the .rc1 file</span></a></p></div><ul>  <li>Follow <a href=\"https://www.youtube.com/watch?v=TY3pjSGg1y4\">this video tutorial</a></li>  <li>Download <a href=\"https://www.macintoshrepository.org/2475-stuffit-expander-and-dropstuff-5-5\">StuffitExpander</a>, add it to the volumes’ list, install it inside the VM</li>  <li>Download <a href=\"https://macintoshgarden.org/apps/hypercard-241\">HyperCard 2.4</a>, install it inside the VM as described above</li>  <li>Extract the .rc1 file from the .sit file and open it with a simple double-click</li></ul><h2 id=\"challenge-solution\">Challenge Solution</h2><p>Extract the stack’s script code:</p><details>  <div class=\"photoswipe-gallery center\">    <p><a class=\"photoswipe photo\" href=\"/assets/HypercardOverWindows/1587389434804.png\" target=\"_blank\" data-cropped=\"true\" data-pswp-width=\"892\" data-pswp-height=\"729\">  <img class=\"image\" src=\"/assets/HypercardOverWindows/1587389434804.png\" width=\"300\" height=\"300\" alt=\"Extract the stack’s script code\" />  <span class=\"badge\">Extract the stack’s script code</span></a></p>  </div>  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>on openCard  Send colorMe to this card  pass openCardend openCardon closeCard  global prev_card  get the id of this cd  put it into prev_card  lock screen  pass closeCardend closeCardon colorMe  AddColor colorCard,stamp,0end colorMeon openStack  AddColor install  setupMenu  go to card \"tun-1-n\"  pass openStackend openStackon closeStack  AddColor remove  pass closeStackend closeStackon genPuzzle  send \"doMenu New Button\" to Hypercardend genPuzzleon initCard  answer prev_cardend initCardon menuReset  setupMenu  pass menuResetend menuReseton setupMenu  if there is not a menu \"Watness\" then    create menu \"Watness\"    put \"Generate Puzzle\"&amp;return&amp;\"Init Card\"&amp;return&amp;\"Set up Nav\"&amp;return&amp;\"Create Puzzle\" into menu \"Watness\" with menuMsg genPuzzle,initCard,setupNav,constructPuzzle  end ifend setupMenuon setupNav  ask \"What is the name of this card\"  set name of this cd to it  ask \"Where should the left go?\"  put it into left_loc  send \"doMenu New Button\" to Hypercard  set height of the last button to 342  set width of the last button to 100  set topleft of the last button to \"0,0\"  set style of the last button to \"transparent\"  set name of the last button to \"\"  put \"on mouseUp\"&amp;return&amp;\"go to card \"&amp;quote&amp;\"\"&amp;left_loc&amp;quote&amp;return&amp;\"end mouseUp\" into left_script  set script of last button to left_script  ask \"Where should the right go?\"  put it into right_loc  send \"doMenu New Button\" to Hypercard  set height of the last button to 342  set width of the last button to 100  set topleft of the last button to \"412,0\"  set style of the last button to \"transparent\"  set name of the last button to \"\"  put \"on mouseUp\"&amp;return&amp;\"go to card \"&amp;quote&amp;\"\"&amp;right_loc&amp;quote&amp;return&amp;\"end mouseUp\" into right_script  set script of last button to right_script  ask \"Where should fwd go?\"  put it into fwd_loc  send \"doMenu New Button\" to Hypercard  set height of the last button to 342  set width of the last button to 311  set the top of the last button to 0  set the left of the last button to 100  set style of the last button to \"transparent\"  set name of the last button to \"\"  put \"on mouseUp\"&amp;return&amp;\"go to card \"&amp;quote&amp;\"\"&amp;fwd_loc&amp;quote&amp;return&amp;\"end mouseUp\" into fwd_script  set script of last button to fwd_script  get the script of this card  put it into cd_script  put cd_script&amp;return into cd_script  put cd_script&amp;\"on arrowKey key\"&amp;return into cd_script  put cd_script&amp;\" if key = \"&amp;quote&amp;\"left\"&amp;quote&amp;\"then\"&amp;return into cd_script  put cd_script&amp;\"  go to cd \"&amp;quote&amp;left_loc&amp;quote&amp;return into cd_script  put cd_script&amp;\" end if\"&amp;return into cd_script  put cd_script&amp;\" if key = \"&amp;quote&amp;\"right\"&amp;quote&amp;\"then\"&amp;return into cd_script  put cd_script&amp;\"  go to cd \"&amp;quote&amp;right_loc&amp;quote&amp;return into cd_script  put cd_script&amp;\" end if\"&amp;return into cd_script  put cd_script&amp;\" if key = \"&amp;quote&amp;\"up\"&amp;quote&amp;\"then\"&amp;return into cd_script  put cd_script&amp;\"  go to cd \"&amp;quote&amp;fwd_loc&amp;quote&amp;return into cd_script  put cd_script&amp;\" end if\"&amp;return into cd_script  put cd_script&amp;\"end arrowKey\"&amp;return into cd_script  set the script of this cd to cd_scriptend setupNavon makeNode  global node  send \"doMenu New Button\" to Hypercard  put the id of the last button into nodeend makeNodeon constructPuzzle  global node,constraints  ask \"What are the constraints\"  put it into constraints  get the script of this cd  put it into cd_script  put cd_script&amp;return into cd_script  put cd_script&amp;\"on openCard\"&amp;return into cd_script  put cd_script&amp;\"  global constraints,path,cursor_x,cursor_y,\" into cd_script  put 0 into i  repeat for 8        put 0 into j    repeat for 8      put cd_script&amp;\"active_\"&amp;i&amp;\"_\"&amp;j&amp;\",\" into cd_script            put j+1 into j    end repeat        put i+1 into i  end repeat  put cd_script&amp;\"dummy\"&amp;return into cd_script  put cd_script&amp;\"  colorme\"&amp;return into cd_script  put cd_script&amp;\"  put -1 into cursor_x\"&amp;return into cd_script  put cd_script&amp;\"  put 0 into cursor_y\"&amp;return into cd_script  put cd_script&amp;\"  put \"&amp;quote&amp;quote&amp;\" into path\"&amp;return into cd_script  put cd_script&amp;\"  put \"&amp;quote&amp;constraints&amp;quote&amp;\" into constraints\"&amp;return into cd_script  put 1 into c_i  put 0 into i  repeat for 7        put 0 into j    repeat for 7      get char (j*7+i+1) of constraints      put it into letter            if letter &lt;&gt; \" \" then        makeNode                set the width of button id node to 10        set the height of button id node to 10                set the top of button id node to (76 + j * 30)        set the left of button id node to (161 + i * 30)                set the style of button id node to \"opaque\"        set showName of button id node to false                if letter = \"r\" then          put \"65535,0,0\" into node_color        end if        if letter = \"g\" then          put \"0,65535,0\" into node_color        end if        if letter = \"b\" then          put \"0,0,65535\" into node_color        end if                if letter &lt;&gt; \" \" then          addColor colorButton, cd, node, node_color                    put cd_script&amp;\"  addColor colorButton, cd, \"&amp;node&amp;\", \"&amp;quote&amp;node_color&amp;quote&amp;return into cd_script        end if      end if​      ​            put j+1 into j    end repeat        put i+1 into i  end repeat    put 0 into i  repeat for 8        put 0 into j    repeat for 8      put cd_script&amp;\"  put \"&amp;quote&amp;quote&amp;\" into active_\"&amp;i&amp;\"_\"&amp;j&amp;return into cd_script            put j+1 into j    end repeat        put i+1 into i  end repeat  makeNode  set the width of button id node to 10  set the height of button id node to 15  set the left of button id node to 356  set the top of button id node to 276  set the name of button id node to \"path_extension\"  set showName of button id node to false  set the style of button id node to opaque  addcolor colorButton, cd, node, \"37632,30208,12288\"  put \"\" into node_script  put node_script&amp;\"on checkYoSelf\"&amp;return into node_script  put node_script&amp;\"  addcolor colorButton, cd, \"&amp;node&amp;\", \"&amp;quote&amp;\"65535,65535,30000\"&amp;quote&amp;return into node_script  put node_script&amp;\"end checkYoSelf\"&amp;return into node_script  set the script of button id node to node_script  put cd_script&amp;\"  addcolor colorButton, cd, \"&amp;node&amp;\", \"&amp;quote&amp;\"37632,30208,12288\"&amp;quote&amp;return into cd_script  makeNode  set the width of button id node to 10  set the height of button id node to 10  set the left of button id node to 356  set the top of button id node to 286  set the name of button id node to \"finale\"  set showName of button id node to false  set the style of button id node to oval  addcolor colorButton, cd, node, \"37632,30208,12288\"  put \"\" into node_script  put node_script&amp;\"on mouseUp\"&amp;return into node_script  put node_script&amp;\"  global cursor_x, cursor_y\"&amp;return into node_script  put node_script&amp;\"  if (cursor_x = 7) and (cursor_y = 7) then\"&amp;return into node_script  put node_script&amp;\"    addcolor colorButton, cd, \"&amp;node&amp;\", \"&amp;quote&amp;\"65535,65535,30000\"&amp;quote&amp;return into node_script  put node_script&amp;\"    send \"&amp;quote&amp;\"checkYoSelf\"&amp;quote&amp;\" to button path_extension\"&amp;return into node_script  put node_script&amp;\"    send \"&amp;quote&amp;\"checkSolution\"&amp;quote&amp;\" to this cd\"&amp;return into node_script  put node_script&amp;\"  end if\"&amp;return into node_script  put node_script&amp;\"end mouseUp\"&amp;return into node_script  set the script of button id node to node_script  put cd_script&amp;\"  addcolor colorButton, cd, \"&amp;node&amp;\", \"&amp;quote&amp;\"37632,30208,12288\"&amp;quote&amp;return into cd_script  put 0 into i  repeat for 7        put 0 into j    repeat for 8      makeNode            set the width of button id node to 30      set the height of button id node to 10            set the top of button id node to (61 + 30 * j)      set the left of button id node to (151 + 30 * i)            set the style of button id node to opaque      set the name of button id node to \"h_path_\"&amp;i&amp;\"_\"&amp;j            set showName of button id node to false            addcolor colorButton, cd, node, \"37632,30208,12288\"            put cd_script&amp;\"  addcolor colorButton, cd, \"&amp;node&amp;\", \"&amp;quote&amp;\"37632,30208,12288\"&amp;quote&amp;return into cd_script            get the script of button id node      put it into node_script            put \"active_\"&amp;i&amp;\"_\"&amp;j into f_node      put \"active_\"&amp;(i+1)&amp;\"_\"&amp;j into s_node            put node_script&amp;return into node_script      put node_script&amp;\"on checkYoSelf\"&amp;return into node_script      put node_script&amp;\"  global \"&amp;f_node&amp;\",\"&amp;s_node&amp;return into node_script      put node_script&amp;\"  if (\"&amp;f_node&amp;\" = true) and (\"&amp;s_node&amp;\" = true) then\"&amp;return into node_script      put node_script&amp;\"    addcolor colorButton, cd, \"&amp;node&amp;\", \"&amp;quote&amp;\"65535,65535,30000\"&amp;quote&amp;return into node_script      put node_script&amp;\"  end if\"&amp;return into node_script      put node_script&amp;\"end checkYoSelf\"&amp;return into node_script            set the script of button id node to node_script            put j+1 into j    end repeat        put i+1 into i  end repeat  put 0 into i  repeat for 8        put 0 into j    repeat for 7      makeNode            set the width of button id node to 10      set the height of button id node to 30            set the top of button id node to (66 + 30 * j)      set the left of button id node to (146 + 30 * i)            set the style of button id node to opaque      set the name of button id node to \"v_path_\"&amp;i&amp;\"_\"&amp;j            set showName of button id node to false            addcolor colorButton, cd, node, \"37632,30208,12288\"            put cd_script&amp;\"  addcolor colorButton, cd, \"&amp;node&amp;\", \"&amp;quote&amp;\"37632,30208,12288\"&amp;quote&amp;return into cd_script            get the script of button id node      put it into node_script            put \"active_\"&amp;i&amp;\"_\"&amp;j into f_node      put \"active_\"&amp;i&amp;\"_\"&amp;(j+1) into s_node            put node_script&amp;return into node_script      put node_script&amp;\"on checkYoSelf\"&amp;return into node_script      put node_script&amp;\"  global \"&amp;f_node&amp;\",\"&amp;s_node&amp;return into node_script      put node_script&amp;\"  if (\"&amp;f_node&amp;\" = true) and (\"&amp;s_node&amp;\" = true) then\"&amp;return into node_script      put node_script&amp;\"    addcolor colorButton, cd, \"&amp;node&amp;\", \"&amp;quote&amp;\"65535,65535,30000\"&amp;quote&amp;return into node_script      put node_script&amp;\"  end if\"&amp;return into node_script      put node_script&amp;\"end checkYoSelf\"&amp;return into node_script            set the script of button id node to node_script            put j+1 into j    end repeat        put i+1 into i  end repeat  put 0 into i  repeat for 8        put 0 into j    repeat for 8      makeNode            set the width of button id node to 10      set the height of button id node to 10            set the top of button id node to (61 + 30 * j)      set the left of button id node to (146 + 30 * i)            set the style of button id node to oval      set the name of button id node to \"button_\"&amp;i&amp;\"_\"&amp;j            set showName of button id node to false            addcolor colorButton, cd, node, \"37632,30208,12288\"            put \"active_\"&amp;i&amp;\"_\"&amp;j into v_name            put \"\" into node_script      put node_script&amp;\"on mouseUp\"&amp;return into node_script      put node_script&amp;\"  global \"&amp;v_name&amp;\",cursor_x,cursor_y\"&amp;return into node_script      put node_script&amp;\"  put cursor_x into prev_x\"&amp;return into node_script      put node_script&amp;\"  put cursor_y into prev_y\"&amp;return into node_script      put node_script&amp;\"  put abs(cursor_x-\"&amp;i&amp;\") into dx\"&amp;return into node_script      put node_script&amp;\"  put abs(cursor_y-\"&amp;j&amp;\") into dy\"&amp;return into node_script      put node_script&amp;\"  if (\"&amp;v_name&amp;\" = \"&amp;quote&amp;quote&amp;\") and ((dx = 1 and dy = 0) or (dx = 0 and dy = 1)) then\"&amp;return into node_script      put node_script&amp;\"    put true into \"&amp;v_name&amp;return into node_script      put node_script&amp;\"    send \"&amp;quote&amp;\"updateState \"&amp;i&amp;\",\"&amp;j&amp;quote&amp;\" to this cd\"&amp;return into node_script      put node_script&amp;\"    addcolor colorButton, cd, \"&amp;node&amp;\", \"&amp;quote&amp;\"65535,65535,30000\"&amp;quote&amp;return into node_script      put node_script&amp;\"  end if\"&amp;return into node_script      put node_script&amp;\"end mouseUp\"&amp;return into node_script            set the script of button id node to node_script            put cd_script&amp;\"  addcolor colorButton, cd, \"&amp;node&amp;\", \"&amp;quote&amp;\"37632,30208,12288\"&amp;quote&amp;return into cd_script            put j+1 into j    end repeat        put i+1 into i  end repeat  set the width of button button_0_0 to 30  set the height of button button_0_0 to 30  set the top of button button_0_0 to 51  set the left of button button_0_0 to 136  get the id of button button_0_0  addColor colorButton, cd, it, \"37632,30208,12288\"  put cd_script&amp;\"end openCard\"&amp;return into cd_script  set the script of this cd to cd_scriptend constructPuzzleon checkSolution  global puzzle_id,path,constraints,flag_1,flag_2,flag_3  watnesssolver constraints,path  put the result into success  if success = \"true\" then    if puzzle_id = 1 then      decoder path,\"clrtffxpry\"      put the result into flag_1    end if    if puzzle_id = 2 then      decoder path,\"nyghq7xksg\"      put the result into flag_2    end if    if puzzle_id = 3 then      decoder path,\"ppyyvn}1{7\"      put the result into flag_3    end if  else    send opencard to this cd  end ifend checkSolutionon updateState i,j  global path,cursor_x,cursor_y  if (i &lt;&gt; 0) or (j &lt;&gt; 0) then    if (cursor_y = j+1) and (cursor_x = i) then      put path&amp;\"U\" into path    end if    if (cursor_y = j) and (cursor_x = i - 1) then      put path&amp;\"R\" into path    end if    if (cursor_y = j-1) and (cursor_x = i) then      put path&amp;\"D\" into path    end if    if (cursor_y = j) and (cursor_x = i + 1) then      put path&amp;\"L\" into path    end if  end if  if cursor_x &gt;= 0 and cursor_y &gt;= 0 then    put \"h_path_\"&amp;min(cursor_x, i)&amp;\"_\"&amp;min(cursor_y, j) into h_path    put \"v_path_\"&amp;min(cursor_x, i)&amp;\"_\"&amp;min(cursor_y, j) into v_path        if i = cursor_x then      send checkYoSelf to button v_path    end if        if j = cursor_y then      send checkYoSelf to button h_path    end if  end if  put i into cursor_x  put j into cursor_yend updateState</code></pre></div>  </div></details><p>The card’s script code can also be extracted (puzzle 1):</p><details>  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>on openCard  global puzzle_id,constraints,path,cursor_x,cursor_y,active_0_0,active_0_1,active_0_2,active_0_3,active_0_4,active_0_5,active_0_6,active_0_7,active_1_0,active_1_1,active_1_2,active_1_3,active_1_4,active_1_5,active_1_6,active_1_7,active_2_0,active_2_1,active_2_2,active_2_3,active_2_4,active_2_5,active_2_6,active_2_7,active_3_0,active_3_1,active_3_2,active_3_3,active_3_4,active_3_5,active_3_6,active_3_7,active_4_0,active_4_1,active_4_2,active_4_3,active_4_4,active_4_5,active_4_6,active_4_7,active_5_0,active_5_1,active_5_2,active_5_3,active_5_4,active_5_5,active_5_6,active_5_7,active_6_0,active_6_1,active_6_2,active_6_3,active_6_4,active_6_5,active_6_6,active_6_7,active_7_0,active_7_1,active_7_2,active_7_3,active_7_4,active_7_5,active_7_6,active_7_7,dummy  colorme  put 1 into puzzle_id  put -1 into cursor_x  put 0 into cursor_y  put \"\" into path  put \"rbrr rgb rb  r brgrbrgb  grrgbbg grg bgrg  bbgrbg\" into constraints  addColor colorButton, cd, 1, \"65535,0,0\"  ...end openCardon arrowKey key  if key = \"left\"then    go to cd \"entry-3-n\"  end if  if key = \"right\"then    go to cd \"entry-3-n\"  end if  if key = \"up\"then    go to cd \"\"  end ifend arrowKey</code></pre></div>  </div></details><p>Now we get the constraint string of this puzzle <code class=\"language-plaintext highlighter-rouge\">\"rbrr rgb rb  r brgrbrgb  grrgbbg grg bgrg  bbgrbg\"</code>, these constraints, along with the path that goes to the lower right corner, are passed into one thing called <em>XCMD</em> which checks the path’s correctness natively (it contains binary instructions that directly run over the 68k CPU). There are 2 XCMD binaries which can be extracted by <a href=\"https://github.com/PierreLorenzi/HyperCardPreview\">this tool</a>, which seem can only run under MacOS. So I’m using the extracted binary from <a href=\"https://ctf.harrisongreen.me/2020/plaidctf/the_watness_2/\">this</a> great post for now instead.</p><p>What’s more, I found that I can set breakpoints in the script and debug the game, I could even watch the variables on the fly:</p><div class=\"photoswipe-gallery center\">  <p> </p>  <p><a class=\"photoswipe photo\" href=\"/assets/HypercardOverWindows/1588514193878.png\" target=\"_blank\" data-cropped=\"true\" data-pswp-width=\"1093\" data-pswp-height=\"700\">  <img class=\"image\" src=\"/assets/HypercardOverWindows/1588514193878.png\" width=\"300\" height=\"300\" alt=\"Debugging\" />  <span class=\"badge\">Debugging</span></a></p></div><p>As for the XCMD part, it’s basically just a few hours’ reverse engineering work. Since there are currently no reliable decompilers for the 68k architecture, I have to read the assembly. It wasn’t too hard, but I did spend several hours learning the basic concepts of 68k’s instruction set.</p><p>After the reverse engineering work, the watnesssolver’s checking methods can be rewritten in Python as:</p><div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">build_automaton</span><span class=\"p\">(</span><span class=\"n\">constraints</span><span class=\"p\">:</span> <span class=\"nb\">str</span><span class=\"p\">):</span>    <span class=\"n\">trans</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">.</span><span class=\"n\">maketrans</span><span class=\"p\">(</span><span class=\"s\">' rgb'</span><span class=\"p\">,</span> <span class=\"s\">'0123'</span><span class=\"p\">)</span>    <span class=\"k\">return</span> <span class=\"p\">[</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">c</span><span class=\"p\">)</span> <span class=\"k\">for</span> <span class=\"n\">c</span> <span class=\"ow\">in</span> <span class=\"n\">constraints</span><span class=\"p\">.</span><span class=\"n\">translate</span><span class=\"p\">(</span><span class=\"n\">trans</span><span class=\"p\">)]</span><span class=\"k\">def</span> <span class=\"nf\">choose_empty</span><span class=\"p\">(</span><span class=\"n\">r</span><span class=\"p\">,</span> <span class=\"n\">g</span><span class=\"p\">,</span> <span class=\"n\">b</span><span class=\"p\">):</span>    <span class=\"k\">if</span> <span class=\"n\">g</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">b</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>        <span class=\"k\">return</span> <span class=\"mi\">0</span>    <span class=\"k\">if</span> <span class=\"n\">b</span> <span class=\"o\">&lt;</span> <span class=\"n\">g</span><span class=\"p\">:</span>        <span class=\"k\">return</span> <span class=\"mi\">2</span>    <span class=\"k\">else</span><span class=\"p\">:</span>        <span class=\"k\">return</span> <span class=\"mi\">3</span><span class=\"k\">def</span> <span class=\"nf\">choose_red</span><span class=\"p\">(</span><span class=\"n\">r</span><span class=\"p\">,</span> <span class=\"n\">g</span><span class=\"p\">,</span> <span class=\"n\">b</span><span class=\"p\">):</span>    <span class=\"k\">if</span> <span class=\"n\">r</span> <span class=\"o\">!=</span> <span class=\"mi\">2</span> <span class=\"ow\">and</span> <span class=\"n\">r</span> <span class=\"o\">!=</span> <span class=\"mi\">3</span><span class=\"p\">:</span>        <span class=\"k\">return</span> <span class=\"mi\">0</span>    <span class=\"k\">if</span> <span class=\"n\">b</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"n\">g</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>        <span class=\"k\">return</span> <span class=\"mi\">0</span>    <span class=\"k\">return</span> <span class=\"mi\">1</span><span class=\"k\">def</span> <span class=\"nf\">choose_green</span><span class=\"p\">(</span><span class=\"n\">r</span><span class=\"p\">,</span> <span class=\"n\">g</span><span class=\"p\">,</span> <span class=\"n\">b</span><span class=\"p\">):</span>    <span class=\"k\">if</span> <span class=\"n\">r</span> <span class=\"o\">&lt;=</span> <span class=\"mi\">4</span><span class=\"p\">:</span>        <span class=\"k\">if</span> <span class=\"n\">b</span> <span class=\"o\">&lt;=</span> <span class=\"mi\">4</span><span class=\"p\">:</span>            <span class=\"k\">if</span> <span class=\"n\">r</span> <span class=\"o\">==</span> <span class=\"mi\">2</span> <span class=\"ow\">or</span> <span class=\"n\">r</span> <span class=\"o\">==</span> <span class=\"mi\">3</span><span class=\"p\">:</span>                <span class=\"k\">return</span> <span class=\"mi\">1</span>            <span class=\"k\">else</span><span class=\"p\">:</span>                <span class=\"k\">return</span> <span class=\"mi\">2</span>        <span class=\"k\">else</span><span class=\"p\">:</span>            <span class=\"k\">return</span> <span class=\"mi\">3</span>    <span class=\"k\">else</span><span class=\"p\">:</span>        <span class=\"k\">return</span> <span class=\"mi\">0</span><span class=\"k\">def</span> <span class=\"nf\">choose_blue</span><span class=\"p\">(</span><span class=\"n\">r</span><span class=\"p\">,</span> <span class=\"n\">g</span><span class=\"p\">,</span> <span class=\"n\">b</span><span class=\"p\">):</span>    <span class=\"k\">if</span> <span class=\"n\">r</span> <span class=\"o\">&lt;=</span> <span class=\"mi\">4</span><span class=\"p\">:</span>        <span class=\"k\">if</span> <span class=\"n\">g</span> <span class=\"o\">&lt;=</span> <span class=\"mi\">4</span><span class=\"p\">:</span>            <span class=\"k\">if</span> <span class=\"n\">r</span> <span class=\"o\">==</span> <span class=\"mi\">2</span> <span class=\"ow\">or</span> <span class=\"n\">r</span> <span class=\"o\">==</span> <span class=\"mi\">3</span><span class=\"p\">:</span>                <span class=\"k\">return</span> <span class=\"mi\">1</span>            <span class=\"k\">else</span><span class=\"p\">:</span>                <span class=\"k\">return</span> <span class=\"mi\">3</span>        <span class=\"k\">else</span><span class=\"p\">:</span>            <span class=\"k\">return</span> <span class=\"mi\">2</span>    <span class=\"k\">else</span><span class=\"p\">:</span>        <span class=\"k\">return</span> <span class=\"mi\">0</span><span class=\"k\">def</span> <span class=\"nf\">is_red</span><span class=\"p\">(</span><span class=\"n\">constraints</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">):</span>    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"p\">(</span><span class=\"n\">x</span> <span class=\"o\">&gt;=</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">x</span> <span class=\"o\">&lt;</span> <span class=\"mi\">7</span> <span class=\"ow\">and</span> <span class=\"n\">y</span> <span class=\"o\">&gt;=</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">y</span> <span class=\"o\">&lt;</span> <span class=\"mi\">7</span><span class=\"p\">):</span>        <span class=\"k\">return</span> <span class=\"bp\">False</span>    <span class=\"k\">return</span> <span class=\"n\">constraints</span><span class=\"p\">[</span><span class=\"n\">x</span><span class=\"o\">+</span><span class=\"n\">y</span><span class=\"o\">*</span><span class=\"mi\">7</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"k\">def</span> <span class=\"nf\">get_neighbors</span><span class=\"p\">(</span><span class=\"n\">constraints</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">):</span>    <span class=\"nb\">sum</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>    <span class=\"k\">for</span> <span class=\"n\">bias_y</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">):</span>        <span class=\"k\">for</span> <span class=\"n\">bias_x</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">):</span>            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">bias_x</span> <span class=\"o\">!=</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"n\">bias_y</span> <span class=\"o\">!=</span> <span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"p\">(</span><span class=\"n\">y</span> <span class=\"o\">+</span> <span class=\"n\">bias_y</span> <span class=\"o\">&gt;=</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">y</span> <span class=\"o\">+</span> <span class=\"n\">bias_y</span> <span class=\"o\">&lt;</span> <span class=\"mi\">7</span><span class=\"p\">)</span> <span class=\"ow\">and</span> \\                    <span class=\"p\">(</span><span class=\"n\">x</span> <span class=\"o\">+</span> <span class=\"n\">bias_x</span> <span class=\"o\">&gt;=</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">x</span> <span class=\"o\">+</span> <span class=\"n\">bias_x</span> <span class=\"o\">&lt;</span> <span class=\"mi\">7</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"n\">constraints</span><span class=\"p\">[(</span><span class=\"n\">x</span><span class=\"o\">+</span><span class=\"n\">bias_x</span><span class=\"p\">)</span><span class=\"o\">+</span><span class=\"p\">(</span><span class=\"n\">y</span><span class=\"o\">+</span><span class=\"n\">bias_y</span><span class=\"p\">)</span><span class=\"o\">*</span><span class=\"mi\">7</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"n\">color</span><span class=\"p\">:</span>                <span class=\"nb\">sum</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span>    <span class=\"k\">return</span> <span class=\"nb\">sum</span><span class=\"k\">def</span> <span class=\"nf\">step_automaton</span><span class=\"p\">(</span><span class=\"n\">constraints</span><span class=\"p\">):</span>    <span class=\"n\">new_constraints</span> <span class=\"o\">=</span> <span class=\"n\">constraints</span><span class=\"p\">[:]</span>    <span class=\"k\">for</span> <span class=\"n\">y</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">7</span><span class=\"p\">):</span>        <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">7</span><span class=\"p\">):</span>            <span class=\"n\">r</span><span class=\"p\">,</span> <span class=\"n\">g</span><span class=\"p\">,</span> <span class=\"n\">b</span> <span class=\"o\">=</span> \\                <span class=\"n\">get_neighbors</span><span class=\"p\">(</span><span class=\"n\">constraints</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">),</span> \\                <span class=\"n\">get_neighbors</span><span class=\"p\">(</span><span class=\"n\">constraints</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">),</span> \\                <span class=\"n\">get_neighbors</span><span class=\"p\">(</span><span class=\"n\">constraints</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">)</span>            <span class=\"k\">if</span> <span class=\"n\">constraints</span><span class=\"p\">[</span><span class=\"n\">x</span><span class=\"o\">+</span><span class=\"n\">y</span><span class=\"o\">*</span><span class=\"mi\">7</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>                <span class=\"n\">new_constraints</span><span class=\"p\">[</span><span class=\"n\">x</span><span class=\"o\">+</span><span class=\"n\">y</span><span class=\"o\">*</span><span class=\"mi\">7</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">choose_empty</span><span class=\"p\">(</span><span class=\"n\">r</span><span class=\"p\">,</span> <span class=\"n\">g</span><span class=\"p\">,</span> <span class=\"n\">b</span><span class=\"p\">)</span>            <span class=\"k\">elif</span> <span class=\"n\">constraints</span><span class=\"p\">[</span><span class=\"n\">x</span><span class=\"o\">+</span><span class=\"n\">y</span><span class=\"o\">*</span><span class=\"mi\">7</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>                <span class=\"n\">new_constraints</span><span class=\"p\">[</span><span class=\"n\">x</span><span class=\"o\">+</span><span class=\"n\">y</span><span class=\"o\">*</span><span class=\"mi\">7</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">choose_red</span><span class=\"p\">(</span><span class=\"n\">r</span><span class=\"p\">,</span> <span class=\"n\">g</span><span class=\"p\">,</span> <span class=\"n\">b</span><span class=\"p\">)</span>            <span class=\"k\">elif</span> <span class=\"n\">constraints</span><span class=\"p\">[</span><span class=\"n\">x</span><span class=\"o\">+</span><span class=\"n\">y</span><span class=\"o\">*</span><span class=\"mi\">7</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">2</span><span class=\"p\">:</span>                <span class=\"n\">new_constraints</span><span class=\"p\">[</span><span class=\"n\">x</span><span class=\"o\">+</span><span class=\"n\">y</span><span class=\"o\">*</span><span class=\"mi\">7</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">choose_green</span><span class=\"p\">(</span><span class=\"n\">r</span><span class=\"p\">,</span> <span class=\"n\">g</span><span class=\"p\">,</span> <span class=\"n\">b</span><span class=\"p\">)</span>            <span class=\"k\">elif</span> <span class=\"n\">constraints</span><span class=\"p\">[</span><span class=\"n\">x</span><span class=\"o\">+</span><span class=\"n\">y</span><span class=\"o\">*</span><span class=\"mi\">7</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">3</span><span class=\"p\">:</span>                <span class=\"n\">new_constraints</span><span class=\"p\">[</span><span class=\"n\">x</span><span class=\"o\">+</span><span class=\"n\">y</span><span class=\"o\">*</span><span class=\"mi\">7</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">choose_blue</span><span class=\"p\">(</span><span class=\"n\">r</span><span class=\"p\">,</span> <span class=\"n\">g</span><span class=\"p\">,</span> <span class=\"n\">b</span><span class=\"p\">)</span>    <span class=\"k\">return</span> <span class=\"n\">new_constraints</span><span class=\"k\">def</span> <span class=\"nf\">perform_move</span><span class=\"p\">(</span><span class=\"n\">constraints</span><span class=\"p\">,</span> <span class=\"n\">mem</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">d</span><span class=\"p\">):</span>    <span class=\"n\">bias_x</span><span class=\"p\">,</span> <span class=\"n\">bias_y</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span>    <span class=\"k\">if</span> <span class=\"n\">d</span> <span class=\"o\">==</span> <span class=\"s\">'U'</span><span class=\"p\">:</span>        <span class=\"n\">bias_x</span><span class=\"p\">,</span> <span class=\"n\">bias_y</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mi\">1</span>    <span class=\"k\">elif</span> <span class=\"n\">d</span> <span class=\"o\">==</span> <span class=\"s\">'D'</span><span class=\"p\">:</span>        <span class=\"n\">bias_x</span><span class=\"p\">,</span> <span class=\"n\">bias_y</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span>    <span class=\"k\">elif</span> <span class=\"n\">d</span> <span class=\"o\">==</span> <span class=\"s\">'L'</span><span class=\"p\">:</span>        <span class=\"n\">bias_x</span><span class=\"p\">,</span> <span class=\"n\">bias_y</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">0</span>    <span class=\"k\">elif</span> <span class=\"n\">d</span> <span class=\"o\">==</span> <span class=\"s\">'R'</span><span class=\"p\">:</span>        <span class=\"n\">bias_x</span><span class=\"p\">,</span> <span class=\"n\">bias_y</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">0</span>    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"p\">(</span><span class=\"n\">x</span><span class=\"o\">+</span><span class=\"n\">bias_x</span> <span class=\"o\">&gt;=</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">x</span><span class=\"o\">+</span><span class=\"n\">bias_x</span> <span class=\"o\">&lt;</span> <span class=\"mi\">8</span> <span class=\"ow\">and</span> <span class=\"n\">y</span><span class=\"o\">+</span><span class=\"n\">bias_y</span> <span class=\"o\">&gt;=</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">y</span><span class=\"o\">+</span><span class=\"n\">bias_y</span> <span class=\"o\">&lt;</span> <span class=\"mi\">8</span><span class=\"p\">):</span>        <span class=\"k\">return</span> <span class=\"bp\">False</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span>        <span class=\"n\">min_x</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"o\">+</span><span class=\"n\">bias_x</span><span class=\"p\">)</span>    <span class=\"n\">min_y</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"o\">+</span><span class=\"n\">bias_y</span><span class=\"p\">)</span>        <span class=\"k\">if</span> <span class=\"n\">bias_y</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"p\">(</span><span class=\"n\">is_red</span><span class=\"p\">(</span><span class=\"n\">constraints</span><span class=\"p\">,</span> <span class=\"n\">min_x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"n\">is_red</span><span class=\"p\">(</span><span class=\"n\">constraints</span><span class=\"p\">,</span> <span class=\"n\">min_x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)):</span>            <span class=\"k\">return</span> <span class=\"bp\">False</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span>    <span class=\"k\">else</span><span class=\"p\">:</span>        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"p\">(</span><span class=\"n\">is_red</span><span class=\"p\">(</span><span class=\"n\">constraints</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">min_y</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"n\">is_red</span><span class=\"p\">(</span><span class=\"n\">constraints</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"n\">min_y</span><span class=\"p\">)):</span>            <span class=\"k\">return</span> <span class=\"bp\">False</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span>        <span class=\"k\">if</span> <span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">x</span><span class=\"o\">+</span><span class=\"n\">bias_x</span><span class=\"p\">][</span><span class=\"n\">y</span><span class=\"o\">+</span><span class=\"n\">bias_y</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>        <span class=\"k\">return</span> <span class=\"bp\">False</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span>        <span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">x</span><span class=\"o\">+</span><span class=\"n\">bias_x</span><span class=\"p\">][</span><span class=\"n\">y</span><span class=\"o\">+</span><span class=\"n\">bias_y</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>        <span class=\"k\">return</span> <span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"o\">+</span><span class=\"n\">bias_x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"o\">+</span><span class=\"n\">bias_y</span><span class=\"k\">def</span> <span class=\"nf\">solver</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">,</span> <span class=\"n\">constraints</span><span class=\"p\">):</span>    <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>    <span class=\"n\">constraints</span> <span class=\"o\">=</span> <span class=\"n\">build_automaton</span><span class=\"p\">(</span><span class=\"n\">constraints</span><span class=\"p\">)</span>    <span class=\"n\">mem</span> <span class=\"o\">=</span> <span class=\"p\">[[</span><span class=\"mi\">0</span> <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">8</span><span class=\"p\">)]</span> <span class=\"k\">for</span> <span class=\"n\">j</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">8</span><span class=\"p\">)]</span>  <span class=\"c1\"># been to or not</span>    <span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>    <span class=\"k\">for</span> <span class=\"n\">each</span> <span class=\"ow\">in</span> <span class=\"n\">path</span><span class=\"p\">:</span>        <span class=\"n\">yes</span><span class=\"p\">,</span> <span class=\"n\">new_x</span><span class=\"p\">,</span> <span class=\"n\">new_y</span> <span class=\"o\">=</span> <span class=\"n\">perform_move</span><span class=\"p\">(</span><span class=\"n\">constraints</span><span class=\"p\">,</span> <span class=\"n\">mem</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">each</span><span class=\"p\">)</span>        <span class=\"k\">if</span> <span class=\"n\">yes</span><span class=\"p\">:</span>            <span class=\"k\">if</span> <span class=\"n\">new_x</span> <span class=\"o\">==</span> <span class=\"mi\">7</span> <span class=\"ow\">and</span> <span class=\"n\">new_y</span> <span class=\"o\">==</span> <span class=\"mi\">7</span><span class=\"p\">:</span>                <span class=\"c1\"># print(f'Path `{path}` is great ' + '!' * 20)</span>                <span class=\"k\">return</span> <span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"bp\">True</span>            <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">new_x</span><span class=\"p\">,</span> <span class=\"n\">new_y</span>            <span class=\"n\">constraints</span> <span class=\"o\">=</span> <span class=\"n\">step_automaton</span><span class=\"p\">(</span><span class=\"n\">constraints</span><span class=\"p\">)</span>        <span class=\"k\">else</span><span class=\"p\">:</span>            <span class=\"c1\">#print(f'Path `{path}` is bad')</span>            <span class=\"k\">return</span> <span class=\"bp\">False</span><span class=\"p\">,</span> <span class=\"bp\">False</span>    <span class=\"k\">return</span> <span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"bp\">False</span></code></pre></div></div><p>Looking around in the game, we’ll know that there are 3 puzzles we need to solve. So we can simply run 3 DFS searches on these contraints and three unique solutions will be printed out.</p><div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">dfs</span><span class=\"p\">(</span><span class=\"n\">depth</span><span class=\"p\">,</span> <span class=\"n\">path</span><span class=\"p\">,</span> <span class=\"n\">constraints</span><span class=\"p\">):</span>    <span class=\"k\">if</span> <span class=\"n\">depth</span> <span class=\"o\">&gt;</span> <span class=\"mi\">24</span><span class=\"p\">:</span> <span class=\"c1\"># figured out after multiple tests</span>        <span class=\"k\">return</span>    <span class=\"n\">mov</span><span class=\"p\">,</span> <span class=\"n\">end</span> <span class=\"o\">=</span> <span class=\"n\">solver</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">,</span> <span class=\"n\">constraints</span><span class=\"p\">)</span>    <span class=\"k\">if</span> <span class=\"n\">end</span> <span class=\"o\">==</span> <span class=\"bp\">True</span><span class=\"p\">:</span>        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'Path </span><span class=\"si\">{</span><span class=\"n\">path</span><span class=\"si\">}</span><span class=\"s\"> is ok'</span><span class=\"p\">)</span>    <span class=\"k\">if</span> <span class=\"n\">mov</span> <span class=\"o\">==</span> <span class=\"bp\">False</span><span class=\"p\">:</span>        <span class=\"k\">return</span>    <span class=\"k\">for</span> <span class=\"n\">d</span> <span class=\"ow\">in</span> <span class=\"s\">'LRUD'</span><span class=\"p\">:</span>        <span class=\"n\">n_path</span> <span class=\"o\">=</span> <span class=\"n\">path</span> <span class=\"o\">+</span> <span class=\"n\">d</span>        <span class=\"n\">dfs</span><span class=\"p\">(</span><span class=\"n\">depth</span><span class=\"o\">+</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"n\">n_path</span><span class=\"p\">,</span> <span class=\"n\">constraints</span><span class=\"p\">)</span><span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>    <span class=\"n\">constraints_stage1</span> <span class=\"o\">=</span> <span class=\"s\">'rbrr rgb rb  r brgrbrgb  grrgbbg grg bgrg  bbgrbg'</span>    <span class=\"n\">constraints_stage2</span> <span class=\"o\">=</span> <span class=\"s\">'rbr  bbggrgrggb   bggbb b  b bbrbbgg gbrrbgrbbb g'</span>    <span class=\"n\">constraints_stage3</span> <span class=\"o\">=</span> <span class=\"s\">'rrbrb rg g  bgrbgggr ggrgr gr rg brr  b  bggrbgbb'</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Stage1 solution:'</span><span class=\"p\">)</span>    <span class=\"n\">dfs</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"s\">''</span><span class=\"p\">,</span> <span class=\"n\">constraints_stage1</span><span class=\"p\">)</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Stage2 solution:'</span><span class=\"p\">)</span>    <span class=\"n\">dfs</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"s\">''</span><span class=\"p\">,</span> <span class=\"n\">constraints_stage2</span><span class=\"p\">)</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Stage3 solution:'</span><span class=\"p\">)</span>    <span class=\"n\">dfs</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"s\">''</span><span class=\"p\">,</span> <span class=\"n\">constraints_stage3</span><span class=\"p\">)</span></code></pre></div></div><p>Output:</p><div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Stage1 solution:Path RDDDRURRRDLLDLDRRURRDDDR is okStage2 solution:Path RDDRURDDDRURULURRDDDDDRD is okStage3 solution:Path DRDDDDRUURRRULURRDDDDDDR is ok</code></pre></div></div><p>Input these solutions to each puzzle, after that, we could go to the lock-like thing on the white gate to reveal the flag:</p><div class=\"photoswipe-gallery center\">  <p> </p>  <p><a class=\"photoswipe photo\" href=\"/assets/HypercardOverWindows/1588514105474.png\" target=\"_blank\" data-cropped=\"true\" data-pswp-width=\"788\" data-pswp-height=\"448\">  <img class=\"image\" src=\"/assets/HypercardOverWindows/1588514105474.png\" width=\"300\" height=\"300\" alt=\"flag\" />  <span class=\"badge\">flag</span></a></p></div>",
            "url": "https://yype.site/2020/04/20/hypercard-over-windows",
            
            
            
            "tags": ["Write-up","Reverse Engineering","Hypercard","CTF","PlaidCTF2020"],
            
            "date_published": "2020-04-20T00:00:00+00:00",
            "date_modified": "2020-04-20T00:00:00+00:00",
            
                "author": 
                "{"twitter"=>nil, "name"=>nil, "avatar"=>nil, "email"=>nil, "url"=>nil}"
                
            
        }
        
    
        
        ,
        
        {
            "id": "https://yype.site/2020/02/20/ancient-game-v2",
            "title": "D^3CTF2019 Ancient Game V2, Thoughts & Solutions",
            "summary": null,
            "content_text": "IntroI designed the RE challenge Ancient Game V2 in D^3CTF2019. This post talks about some designs behind this challenge along with its solution.ChallengeThe challenge uses a virtual architecture similar to OISC to implement a classic Sudoku verification algorithm. There are four types of instructions: input, output, jcc, and NAND. As a whole, they can be seen as a NAND OISC with two I/O interrupts.All logical operations such as XOR, AND, and OR are implemented through combinations of NAND gates. For example:xor x,y =&gt;xor_tmp[0] = y NAND yxor_tmp[1] = x NAND xor_tmp[0]xor_tmp[2] = x NAND xxor_tmp[3] = y NAND xor_tmp[2]x = xor_tmp[1] NAND xor_tmp[3]This is based on the fact that:Q = A XOR B = [ B NAND ( A NAND A ) ] NAND [ A NAND ( B NAND B ) ]The following is an excerpt of the Sudoku verification algorithm written in a custom DSL:welcome = mkstr(\"**************************\\n**  Welcome To D^3CTF   **\\n**   Ancient Game V2    **\\n**************************\\n\\nInput Flag:\")wrong = mkstr(\"\\nSorry, please try again.\\n\")correct = mkstr(\"\\nCorrect.\\n\")flag = new(50)// distract = new(1000)grid = new(81)// initialize the puzzleset(grid[0],9)set(grid[5],8)set(grid[9],1)set(grid[10],3)set(grid[14],9)set(grid[16],7)...set(grid[71],6)set(grid[75],9)set(grid[80],1)__code_start__// print the welcome messageprint(welcome)// get inputinput(flag[0])input(flag[1])input(flag[2])input(flag[3])input(flag[4])input(flag[5])...input(flag[46])input(flag[47])input(flag[48])input(flag[49])// transfer chars in the flag into the gridslong_transfer(flag[0],grid[1])long_transfer(flag[1],grid[2])...long_transfer(flag[47],grid[77])long_transfer(flag[48],grid[78])long_transfer(flag[49],grid[79])// xor with xor_table, which is introduced //   for generating different flags to different teamsgrid[1] = grid[1] ^ xor_table[0]grid[2] = grid[2] ^ xor_table[1]grid[3] = grid[3] ^ xor_table[2]grid[4] = grid[4] ^ xor_table[3]grid[6] = grid[6] ^ xor_table[4]grid[7] = grid[7] ^ xor_table[5]...grid[77] = grid[77] ^ xor_table[47]grid[78] = grid[78] ^ xor_table[48]grid[79] = grid[79] ^ xor_table[49]// verify the sudoku game// rowsjmp _label_wrong if grid[4] == grid[5]jmp _label_wrong if grid[4] == grid[6]jmp _label_wrong if grid[4] == grid[7]...jmp _label_wrong if grid[3] == grid[7]jmp _label_wrong if grid[3] == grid[8]// columnsjmp _label_wrong if grid[0] == grid[9]jmp _label_wrong if grid[0] == grid[18]jmp _label_wrong if grid[0] == grid[27]...jmp _label_wrong if grid[62] == grid[80]jmp _label_wrong if grid[71] == grid[80]// subgridsjmp _label_wrong if grid[0] == grid[1]jmp _label_wrong if grid[0] == grid[2]jmp _label_wrong if grid[0] == grid[9]jmp _label_wrong if grid[0] == grid[10]...jmp _label_wrong if grid[78] == grid[79]jmp _label_wrong if grid[78] == grid[80]jmp _label_wrong if grid[79] == grid[80]// check rangejmp _label_wrong if outofnumbers(grid[1])jmp _label_wrong if outofnumbers(grid[2])jmp _label_wrong if outofnumbers(grid[3])jmp _label_wrong if outofnumbers(grid[4])...jmp _label_wrong if outofnumbers(grid[76])jmp _label_wrong if outofnumbers(grid[77])jmp _label_wrong if outofnumbers(grid[78])jmp _label_wrong if outofnumbers(grid[79])_label_correct:print(correct)return_label_wrong:print(wrong)returnI wrote a compiler for this DSL, which was then used to compile the algorithm into an OISC program executable by the OISC VM. The OISC program is then packed together with the OISC VM as a standalone binary, which is delievered to the players.Multiple Solutions - Behind the ScenesDuring the competition, I was surprised to notice that multiple solutions exist. A quick debugging revealed the cause: the implementation of outofnumbers (var) in the compiler was incorrectly written in a way similar to return var not in range [0...9]. Since the Sudoku map is supposed to only contain 1 ~ 9, the correct implementation should be return var not in range [1...9]. Under such a scenario, multiple solutions exist because we allow the grids to be filled with 0.Sudoku Map      Sudoku MapSolutionTo solve this challenge, there is no need to simplify all the logical operations. Since there is no complicated loop in the actual control flow, we can locate the conditions preventing the control flow from jumping to the part which outputs “Sorry” through simple control flow tracing and (manual/automated) symbolic analysis. Along the way, we extract the constraints for the non-Sorry branches. Finally, we can use an SMT solver to solve the constraints. (That’s how ThinerDAS solved this challenge.)Flag: d3ctf{g5lk9t28zz47y3l6m2kosbajd2vk9e2dwghxgfktcki}  Referenceable solution script: sol.py by ByaiduThe source code of this challenge (except for the compiler) and a duplicate of this post are uploaded to GitHub, check them out at: https://github.com/yype/D3CTF_Rev/tree/master/AncientGameV2.More..I’ve always found OISC interesting. This challenge is just a demo of one of my ideas. I’m considering doing more interesting works related to OISC in the upcoming future.",
            "content_html": "<h2 id=\"intro\">Intro</h2><p>I designed the RE challenge <em>Ancient Game V2</em> in D^3CTF2019. This post talks about some designs behind this challenge along with its solution.</p><h2 id=\"challenge\">Challenge</h2><p>The challenge uses a virtual architecture similar to OISC to implement a classic Sudoku verification algorithm. There are four types of instructions: input, output, jcc, and NAND. As a whole, they can be seen as a NAND OISC with two I/O interrupts.</p><p>All logical operations such as XOR, AND, and OR are implemented through combinations of NAND gates. For example:</p><div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>xor x,y =&gt;xor_tmp[0] = y NAND yxor_tmp[1] = x NAND xor_tmp[0]xor_tmp[2] = x NAND xxor_tmp[3] = y NAND xor_tmp[2]x = xor_tmp[1] NAND xor_tmp[3]</code></pre></div></div><p>This is based on the fact that:</p><div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Q = A XOR B = [ B NAND ( A NAND A ) ] NAND [ A NAND ( B NAND B ) ]</code></pre></div></div><p>The following is an excerpt of the Sudoku verification algorithm written in a custom DSL:</p><div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>welcome = mkstr(\"**************************\\n**  Welcome To D^3CTF   **\\n**   Ancient Game V2    **\\n**************************\\n\\nInput Flag:\")wrong = mkstr(\"\\nSorry, please try again.\\n\")correct = mkstr(\"\\nCorrect.\\n\")flag = new(50)// distract = new(1000)grid = new(81)// initialize the puzzleset(grid[0],9)set(grid[5],8)set(grid[9],1)set(grid[10],3)set(grid[14],9)set(grid[16],7)...set(grid[71],6)set(grid[75],9)set(grid[80],1)__code_start__// print the welcome messageprint(welcome)// get inputinput(flag[0])input(flag[1])input(flag[2])input(flag[3])input(flag[4])input(flag[5])...input(flag[46])input(flag[47])input(flag[48])input(flag[49])// transfer chars in the flag into the gridslong_transfer(flag[0],grid[1])long_transfer(flag[1],grid[2])...long_transfer(flag[47],grid[77])long_transfer(flag[48],grid[78])long_transfer(flag[49],grid[79])// xor with xor_table, which is introduced //   for generating different flags to different teamsgrid[1] = grid[1] ^ xor_table[0]grid[2] = grid[2] ^ xor_table[1]grid[3] = grid[3] ^ xor_table[2]grid[4] = grid[4] ^ xor_table[3]grid[6] = grid[6] ^ xor_table[4]grid[7] = grid[7] ^ xor_table[5]...grid[77] = grid[77] ^ xor_table[47]grid[78] = grid[78] ^ xor_table[48]grid[79] = grid[79] ^ xor_table[49]// verify the sudoku game// rowsjmp _label_wrong if grid[4] == grid[5]jmp _label_wrong if grid[4] == grid[6]jmp _label_wrong if grid[4] == grid[7]...jmp _label_wrong if grid[3] == grid[7]jmp _label_wrong if grid[3] == grid[8]// columnsjmp _label_wrong if grid[0] == grid[9]jmp _label_wrong if grid[0] == grid[18]jmp _label_wrong if grid[0] == grid[27]...jmp _label_wrong if grid[62] == grid[80]jmp _label_wrong if grid[71] == grid[80]// subgridsjmp _label_wrong if grid[0] == grid[1]jmp _label_wrong if grid[0] == grid[2]jmp _label_wrong if grid[0] == grid[9]jmp _label_wrong if grid[0] == grid[10]...jmp _label_wrong if grid[78] == grid[79]jmp _label_wrong if grid[78] == grid[80]jmp _label_wrong if grid[79] == grid[80]// check rangejmp _label_wrong if outofnumbers(grid[1])jmp _label_wrong if outofnumbers(grid[2])jmp _label_wrong if outofnumbers(grid[3])jmp _label_wrong if outofnumbers(grid[4])...jmp _label_wrong if outofnumbers(grid[76])jmp _label_wrong if outofnumbers(grid[77])jmp _label_wrong if outofnumbers(grid[78])jmp _label_wrong if outofnumbers(grid[79])_label_correct:print(correct)return_label_wrong:print(wrong)return</code></pre></div></div><p>I wrote a compiler for this DSL, which was then used to compile the algorithm into an OISC program executable by the OISC VM. The OISC program is then packed together with the OISC VM as a standalone binary, which is delievered to the players.</p><p><strong>Multiple Solutions - Behind the Scenes</strong></p><p>During the competition, I was surprised to notice that multiple solutions exist. A quick debugging revealed the cause: the implementation of <code class=\"language-plaintext highlighter-rouge\">outofnumbers (var)</code> in the compiler was incorrectly written in a way similar to <code class=\"language-plaintext highlighter-rouge\">return var not in range [0...9]</code>. Since the Sudoku map is supposed to only contain 1 ~ 9, the correct implementation should be <code class=\"language-plaintext highlighter-rouge\">return var not in range [1...9]</code>. Under such a scenario, multiple solutions exist because we allow the grids to be filled with 0.</p><p><strong>Sudoku Map</strong></p><div class=\"photoswipe-gallery center\">  <p><a class=\"photoswipe photo\" href=\"/assets/AncientGameV2/map.png\" target=\"_blank\" data-cropped=\"true\" data-pswp-width=\"500\" data-pswp-height=\"500\">  <img class=\"image\" src=\"/assets/AncientGameV2/map.png\" width=\"250\" height=\"250\" alt=\"Sudoku Map\" />  <span class=\"badge\">Sudoku Map</span></a></p></div><p><strong>Solution</strong></p><p>To solve this challenge, there is no need to simplify all the logical operations. Since there is no complicated loop in the actual control flow, we can locate the conditions preventing the control flow from jumping to the part which outputs “Sorry” through simple control flow tracing and (manual/automated) symbolic analysis. Along the way, we extract the constraints for the non-Sorry branches. Finally, we can use an SMT solver to solve the constraints. (That’s how ThinerDAS solved this challenge.)</p><p>Flag: d3ctf{g5lk9t28zz47y3l6m2kosbajd2vk9e2dwghxgfktcki}</p><blockquote>  <p>Referenceable solution script: <a href=\"https://github.com/0h2o/D3CTF_Rev/blob/master/AncientGameV2/sol.py\">sol.py</a> by <a href=\"https://github.com/byaidu\">Byaidu</a></p></blockquote><p>The source code of this challenge (except for the compiler) and a duplicate of this post are uploaded to GitHub, check them out at: <a href=\"https://github.com/yype/D3CTF_Rev/tree/master/AncientGameV2\" target=\"_blank\">https://github.com/yype/D3CTF_Rev/tree/master/AncientGameV2</a>.</p><h2 id=\"more\">More..</h2><p>I’ve always found OISC interesting. This challenge is just a demo of one of my ideas. I’m considering doing more interesting works related to OISC in the upcoming future.</p>",
            "url": "https://yype.site/2020/02/20/ancient-game-v2",
            
            
            
            "tags": ["CTF","Reverse Engineering","D^3CTF2019","OISC"],
            
            "date_published": "2020-02-20T00:00:00+00:00",
            "date_modified": "2020-02-20T00:00:00+00:00",
            
                "author": 
                "{"twitter"=>nil, "name"=>nil, "avatar"=>nil, "email"=>nil, "url"=>nil}"
                
            
        }
        
    
    ]
}