<?xml version="1.0" encoding="utf-8"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>Posts about writeup</title><link>https://chriswarrick.com/</link><atom:link href="https://chriswarrick.com/blog/tags/writeup.xml" rel="self" type="application/rss+xml" /><description>A rarely updated blog, mostly about programming.</description><lastBuildDate>Thu, 03 Aug 2017 10:45:40 GMT</lastBuildDate><generator>https://github.com/Kwpolska/YetAnotherBlogGenerator</generator><item><title>Gynvael’s Mission 11 (en): Python bytecode reverse-engineering</title><dc:creator>Chris Warrick</dc:creator><link>https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/</link><pubDate>Thu, 03 Aug 2017 10:45:40 GMT</pubDate><guid>https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/</guid><description>
Gynvael Coldwind is a security researcher at Google, who hosts weekly livestreams about security and programming in Polish and English). As part of the streams, he gives out missions — basically, CTF-style reverse engineering tasks. Yesterday’s mission was about Elvish — I mean Paint — I mean Python programming and bytecode.
</description><content:encoded><![CDATA[
<p>Gynvael Coldwind is a security researcher at Google, who hosts weekly livestreams about security and programming in <a class="reference external" href="https://gaming.youtube.com/user/GynvaelColdwind/live">Polish</a> and <a class="reference external" href="https://gaming.youtube.com/user/GynvaelEN/live">English</a>). As part of the streams, he gives out missions — basically, CTF-style reverse engineering tasks. Yesterday’s mission was about Elvish — I mean Paint — I mean Python programming and bytecode.</p>



<div class="code"><pre class="code text"><a id="rest_code_a8243f6403b44a13a671955d2b908777-1" name="rest_code_a8243f6403b44a13a671955d2b908777-1" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_a8243f6403b44a13a671955d2b908777-1"></a>MISSION 011               goo.gl/13Bia9             DIFFICULTY: ██████░░░░ [6╱10]
<a id="rest_code_a8243f6403b44a13a671955d2b908777-2" name="rest_code_a8243f6403b44a13a671955d2b908777-2" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_a8243f6403b44a13a671955d2b908777-2"></a>┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅
<a id="rest_code_a8243f6403b44a13a671955d2b908777-3" name="rest_code_a8243f6403b44a13a671955d2b908777-3" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_a8243f6403b44a13a671955d2b908777-3"></a>
<a id="rest_code_a8243f6403b44a13a671955d2b908777-4" name="rest_code_a8243f6403b44a13a671955d2b908777-4" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_a8243f6403b44a13a671955d2b908777-4"></a>Finally some real work!
<a id="rest_code_a8243f6403b44a13a671955d2b908777-5" name="rest_code_a8243f6403b44a13a671955d2b908777-5" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_a8243f6403b44a13a671955d2b908777-5"></a>
<a id="rest_code_a8243f6403b44a13a671955d2b908777-6" name="rest_code_a8243f6403b44a13a671955d2b908777-6" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_a8243f6403b44a13a671955d2b908777-6"></a>One of our field agents managed to infiltrate suspects hideout and steal a
<a id="rest_code_a8243f6403b44a13a671955d2b908777-7" name="rest_code_a8243f6403b44a13a671955d2b908777-7" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_a8243f6403b44a13a671955d2b908777-7"></a>pendrive possibly containing important information. However, the pendrive
<a id="rest_code_a8243f6403b44a13a671955d2b908777-8" name="rest_code_a8243f6403b44a13a671955d2b908777-8" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_a8243f6403b44a13a671955d2b908777-8"></a>actually requires one to authenticate themselves before accessing the stored
<a id="rest_code_a8243f6403b44a13a671955d2b908777-9" name="rest_code_a8243f6403b44a13a671955d2b908777-9" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_a8243f6403b44a13a671955d2b908777-9"></a>files.
<a id="rest_code_a8243f6403b44a13a671955d2b908777-10" name="rest_code_a8243f6403b44a13a671955d2b908777-10" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_a8243f6403b44a13a671955d2b908777-10"></a>
<a id="rest_code_a8243f6403b44a13a671955d2b908777-11" name="rest_code_a8243f6403b44a13a671955d2b908777-11" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_a8243f6403b44a13a671955d2b908777-11"></a>We gave the pendrive to our laboratory and they managed to dump the firmware. We
<a id="rest_code_a8243f6403b44a13a671955d2b908777-12" name="rest_code_a8243f6403b44a13a671955d2b908777-12" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_a8243f6403b44a13a671955d2b908777-12"></a>looked at the deadlisting they sent and for our best knowledge it&#39;s some form of
<a id="rest_code_a8243f6403b44a13a671955d2b908777-13" name="rest_code_a8243f6403b44a13a671955d2b908777-13" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_a8243f6403b44a13a671955d2b908777-13"></a>Elvish. We can&#39;t read it.
<a id="rest_code_a8243f6403b44a13a671955d2b908777-14" name="rest_code_a8243f6403b44a13a671955d2b908777-14" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_a8243f6403b44a13a671955d2b908777-14"></a>
<a id="rest_code_a8243f6403b44a13a671955d2b908777-15" name="rest_code_a8243f6403b44a13a671955d2b908777-15" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_a8243f6403b44a13a671955d2b908777-15"></a>Here is the firmware: goo.gl/axsAHt
<a id="rest_code_a8243f6403b44a13a671955d2b908777-16" name="rest_code_a8243f6403b44a13a671955d2b908777-16" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_a8243f6403b44a13a671955d2b908777-16"></a>
<a id="rest_code_a8243f6403b44a13a671955d2b908777-17" name="rest_code_a8243f6403b44a13a671955d2b908777-17" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_a8243f6403b44a13a671955d2b908777-17"></a>And off you go. Bring us back the password.
<a id="rest_code_a8243f6403b44a13a671955d2b908777-18" name="rest_code_a8243f6403b44a13a671955d2b908777-18" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_a8243f6403b44a13a671955d2b908777-18"></a>
<a id="rest_code_a8243f6403b44a13a671955d2b908777-19" name="rest_code_a8243f6403b44a13a671955d2b908777-19" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_a8243f6403b44a13a671955d2b908777-19"></a>Good luck!
<a id="rest_code_a8243f6403b44a13a671955d2b908777-20" name="rest_code_a8243f6403b44a13a671955d2b908777-20" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_a8243f6403b44a13a671955d2b908777-20"></a>
<a id="rest_code_a8243f6403b44a13a671955d2b908777-21" name="rest_code_a8243f6403b44a13a671955d2b908777-21" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_a8243f6403b44a13a671955d2b908777-21"></a>---------------------------------------------------------------------------------
<a id="rest_code_a8243f6403b44a13a671955d2b908777-22" name="rest_code_a8243f6403b44a13a671955d2b908777-22" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_a8243f6403b44a13a671955d2b908777-22"></a>
<a id="rest_code_a8243f6403b44a13a671955d2b908777-23" name="rest_code_a8243f6403b44a13a671955d2b908777-23" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_a8243f6403b44a13a671955d2b908777-23"></a>If you decode the answer, put it in the comments under this video! If you write
<a id="rest_code_a8243f6403b44a13a671955d2b908777-24" name="rest_code_a8243f6403b44a13a671955d2b908777-24" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_a8243f6403b44a13a671955d2b908777-24"></a>a blogpost / post your solution online, please add a link in the comments too!
<a id="rest_code_a8243f6403b44a13a671955d2b908777-25" name="rest_code_a8243f6403b44a13a671955d2b908777-25" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_a8243f6403b44a13a671955d2b908777-25"></a>
<a id="rest_code_a8243f6403b44a13a671955d2b908777-26" name="rest_code_a8243f6403b44a13a671955d2b908777-26" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_a8243f6403b44a13a671955d2b908777-26"></a>P.S. I&#39;ll show/explain the solution on the stream in ~two weeks.
<a id="rest_code_a8243f6403b44a13a671955d2b908777-27" name="rest_code_a8243f6403b44a13a671955d2b908777-27" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_a8243f6403b44a13a671955d2b908777-27"></a>P.S.2. Bonus points for recreating the original high-level code.
</pre></div>
<p>Here’s the firmware:</p>
<div class="code"><pre class="code text"><a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-1" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-1" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-1"></a>co_argcount 1
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-2" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-2" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-2"></a>co_consts (None, &#39;4e5d4e92865a4e495a86494b5a5d49525261865f5758534d4a89&#39;, &#39;hex&#39;, 89, 255, 115, 50)
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-3" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-3" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-3"></a>co_flags 67
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-4" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-4" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-4"></a>co_name check_password
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-5" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-5" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-5"></a>co_names (&#39;decode&#39;, &#39;len&#39;, &#39;False&#39;, &#39;all&#39;, &#39;zip&#39;, &#39;ord&#39;)
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-6" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-6" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-6"></a>co_nlocals 4
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-7" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-7" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-7"></a>co_stacksize 6
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-8" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-8" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-8"></a>co_varnames (&#39;s&#39;, &#39;good&#39;, &#39;cs&#39;, &#39;cg&#39;)
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-9" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-9" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-9"></a>              0 LOAD_CONST               1
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-10" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-10" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-10"></a>              3 LOAD_ATTR                0
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-11" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-11" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-11"></a>              6 LOAD_CONST               2
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-12" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-12" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-12"></a>              9 CALL_FUNCTION            1
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-13" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-13" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-13"></a>             12 STORE_FAST               1
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-14" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-14" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-14"></a>             15 LOAD_GLOBAL              1
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-15" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-15" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-15"></a>             18 LOAD_FAST                0
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-16" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-16" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-16"></a>             21 CALL_FUNCTION            1
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-17" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-17" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-17"></a>             24 LOAD_GLOBAL              1
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-18" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-18" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-18"></a>             27 LOAD_FAST                1
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-19" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-19" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-19"></a>             30 CALL_FUNCTION            1
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-20" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-20" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-20"></a>             33 COMPARE_OP               3 (!=)
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-21" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-21" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-21"></a>             36 POP_JUMP_IF_FALSE       43
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-22" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-22" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-22"></a>             39 LOAD_GLOBAL              2
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-23" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-23" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-23"></a>             42 RETURN_VALUE
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-24" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-24" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-24"></a>        &gt;&gt;   43 LOAD_GLOBAL              3
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-25" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-25" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-25"></a>             46 BUILD_LIST               0
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-26" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-26" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-26"></a>             49 LOAD_GLOBAL              4
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-27" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-27" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-27"></a>             52 LOAD_FAST                0
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-28" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-28" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-28"></a>             55 LOAD_FAST                1
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-29" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-29" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-29"></a>             58 CALL_FUNCTION            2
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-30" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-30" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-30"></a>             61 GET_ITER
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-31" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-31" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-31"></a>        &gt;&gt;   62 FOR_ITER                52 (to 117)
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-32" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-32" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-32"></a>             65 UNPACK_SEQUENCE          2
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-33" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-33" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-33"></a>             68 STORE_FAST               2
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-34" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-34" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-34"></a>             71 STORE_FAST               3
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-35" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-35" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-35"></a>             74 LOAD_GLOBAL              5
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-36" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-36" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-36"></a>             77 LOAD_FAST                2
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-37" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-37" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-37"></a>             80 CALL_FUNCTION            1
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-38" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-38" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-38"></a>             83 LOAD_CONST               3
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-39" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-39" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-39"></a>             86 BINARY_SUBTRACT
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-40" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-40" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-40"></a>             87 LOAD_CONST               4
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-41" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-41" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-41"></a>             90 BINARY_AND
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-42" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-42" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-42"></a>             91 LOAD_CONST               5
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-43" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-43" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-43"></a>             94 BINARY_XOR
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-44" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-44" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-44"></a>             95 LOAD_CONST               6
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-45" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-45" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-45"></a>             98 BINARY_XOR
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-46" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-46" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-46"></a>             99 LOAD_GLOBAL              5
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-47" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-47" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-47"></a>            102 LOAD_FAST                3
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-48" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-48" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-48"></a>            105 CALL_FUNCTION            1
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-49" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-49" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-49"></a>            108 COMPARE_OP               2 (==)
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-50" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-50" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-50"></a>            111 LIST_APPEND              2
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-51" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-51" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-51"></a>            114 JUMP_ABSOLUTE           62
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-52" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-52" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-52"></a>        &gt;&gt;  117 CALL_FUNCTION            1
<a id="rest_code_ee28059f26f346f09e4a2ab239ddd619-53" name="rest_code_ee28059f26f346f09e4a2ab239ddd619-53" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ee28059f26f346f09e4a2ab239ddd619-53"></a>            120 RETURN_VALUE
</pre></div>
<p>To the uninitiated, this might look like <em>Elvish</em>. In reality, this is Python bytecode — the instruction set understood by Python’s (CPython 2.7) virtual machine. Python, like many other languages, uses a compiler to translate human-readable source code into something more appropriate for computers. Python code compiles to bytecode, which is then executed by CPython’s virtual machine. CPython bytecode can be ported between different hardware, while machine code cannot. However, machine code can often be faster than languages based on virtual machines and bytecode. (Java and C# work the same way as Python, C compiles directly to machine code)</p>
<p>This is the internal representation of a Python function. The first few lines are the member variables of the <code class="docutils literal">f.__code__</code> object of our function. We know that:</p>
<ul class="simple">
<li><p>it takes 1 argument</p></li>
<li><p>it has 7 constants: None, a long string of hex digits, the string <code class="docutils literal">'hex'</code>, and numbers: 89, 255, 115, 50.</p></li>
<li><p>its <a class="reference external" href="https://docs.python.org/2.7/library/inspect.html#code-objects-bit-flags">flags</a> are set to 67 (CO_NOFREE, CO_NEWLOCALS, CO_OPTIMIZED). This is the “standard” value that most uncomplicated functions take.</p></li>
<li><p>its name is <code class="docutils literal">check_password</code></p></li>
<li><p>it uses the following globals or attribute names: <code class="docutils literal">decode</code>, <code class="docutils literal">len</code>, <code class="docutils literal">False</code>, <code class="docutils literal">all</code>, <code class="docutils literal">zip</code>, <code class="docutils literal">ord</code></p></li>
<li><p>it has 4 local variables</p></li>
<li><p>it uses a stack of size 6</p></li>
<li><p>its variables are named <code class="docutils literal">s</code>, <code class="docutils literal">good</code>, <code class="docutils literal">cs</code>, <code class="docutils literal">cg</code></p></li>
</ul>
<p>There are two ways to solve this task: you can re-assemble the <code class="docutils literal">dis</code> output with the help of the <code class="docutils literal">opcode</code> module, or try to re-create the function by hand, using the bytecode. I chose the latter method.</p>
<section id="reverse-engineering-python-bytecode-re-creating-the-function-by-hand">
<h1>Reverse-engineering Python bytecode: re-creating the function by hand</h1>
<p>I started by recreating the original firmware file. I created an empty function and wrote some code to print out <code class="docutils literal">__code__</code> contents and <code class="docutils literal">dis.dis</code> output. I also added color-coding to help me read it:</p>
<div class="code"><pre class="code python"><a id="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-1" name="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-1" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_db3df9519cfe4fcebd1d69fff256cc2e-1"></a><span class="ch">#!/usr/bin/env python2</span>
<a id="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-2" name="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-2" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_db3df9519cfe4fcebd1d69fff256cc2e-2"></a><span class="kn">import</span><span class="w"> </span><span class="nn">dis</span>
<a id="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-3" name="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-3" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_db3df9519cfe4fcebd1d69fff256cc2e-3"></a><span class="kn">import</span><span class="w"> </span><span class="nn">sys</span>
<a id="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-4" name="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-4" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_db3df9519cfe4fcebd1d69fff256cc2e-4"></a>
<a id="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-5" name="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-5" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_db3df9519cfe4fcebd1d69fff256cc2e-5"></a><span class="c1"># Write code here</span>
<a id="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-6" name="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-6" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_db3df9519cfe4fcebd1d69fff256cc2e-6"></a><span class="k">def</span><span class="w"> </span><span class="nf">check_password</span><span class="p">(</span><span class="n">s</span><span class="p">):</span>
<a id="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-7" name="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-7" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_db3df9519cfe4fcebd1d69fff256cc2e-7"></a>    <span class="k">pass</span>
<a id="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-8" name="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-8" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_db3df9519cfe4fcebd1d69fff256cc2e-8"></a>
<a id="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-9" name="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-9" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_db3df9519cfe4fcebd1d69fff256cc2e-9"></a><span class="c1"># Reverse engineering the code</span>
<a id="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-10" name="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-10" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_db3df9519cfe4fcebd1d69fff256cc2e-10"></a><span class="n">cnames</span> <span class="o">=</span> <span class="p">(</span><span class="s1">&#39;co_argcount&#39;</span><span class="p">,</span> <span class="s1">&#39;co_consts&#39;</span><span class="p">,</span> <span class="s1">&#39;co_flags&#39;</span><span class="p">,</span> <span class="s1">&#39;co_name&#39;</span><span class="p">,</span> <span class="s1">&#39;co_names&#39;</span><span class="p">,</span> <span class="s1">&#39;co_nlocals&#39;</span><span class="p">,</span> <span class="s1">&#39;co_stacksize&#39;</span><span class="p">,</span> <span class="s1">&#39;co_varnames&#39;</span><span class="p">)</span>
<a id="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-11" name="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-11" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_db3df9519cfe4fcebd1d69fff256cc2e-11"></a><span class="n">cvalues</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="s1">&#39;4e5d4e92865a4e495a86494b5a5d49525261865f5758534d4a89&#39;</span><span class="p">,</span> <span class="s1">&#39;hex&#39;</span><span class="p">,</span> <span class="mi">89</span><span class="p">,</span> <span class="mi">255</span><span class="p">,</span> <span class="mi">115</span><span class="p">,</span> <span class="mi">50</span><span class="p">),</span> <span class="mi">67</span><span class="p">,</span> <span class="s1">&#39;check_password&#39;</span><span class="p">,</span> <span class="p">(</span><span class="s1">&#39;decode&#39;</span><span class="p">,</span> <span class="s1">&#39;len&#39;</span><span class="p">,</span> <span class="s1">&#39;False&#39;</span><span class="p">,</span> <span class="s1">&#39;all&#39;</span><span class="p">,</span> <span class="s1">&#39;zip&#39;</span><span class="p">,</span> <span class="s1">&#39;ord&#39;</span><span class="p">),</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="p">(</span><span class="s1">&#39;s&#39;</span><span class="p">,</span> <span class="s1">&#39;good&#39;</span><span class="p">,</span> <span class="s1">&#39;cs&#39;</span><span class="p">,</span> <span class="s1">&#39;cg&#39;</span><span class="p">))</span>
<a id="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-12" name="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-12" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_db3df9519cfe4fcebd1d69fff256cc2e-12"></a>
<a id="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-13" name="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-13" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_db3df9519cfe4fcebd1d69fff256cc2e-13"></a><span class="k">for</span> <span class="n">n</span><span class="p">,</span> <span class="n">ov</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">cnames</span><span class="p">,</span> <span class="n">cvalues</span><span class="p">):</span>
<a id="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-14" name="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-14" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_db3df9519cfe4fcebd1d69fff256cc2e-14"></a>    <span class="n">v</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">check_password</span><span class="o">.</span><span class="vm">__code__</span><span class="p">,</span> <span class="n">n</span><span class="p">)</span>
<a id="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-15" name="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-15" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_db3df9519cfe4fcebd1d69fff256cc2e-15"></a>    <span class="k">if</span> <span class="n">v</span> <span class="o">==</span> <span class="n">ov</span><span class="p">:</span>
<a id="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-16" name="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-16" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_db3df9519cfe4fcebd1d69fff256cc2e-16"></a>        <span class="n">sys</span><span class="o">.</span><span class="n">stderr</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s1">&#39;</span><span class="se">\033</span><span class="s1">[1;32m&#39;</span><span class="p">)</span>
<a id="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-17" name="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-17" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_db3df9519cfe4fcebd1d69fff256cc2e-17"></a>    <span class="k">else</span><span class="p">:</span>
<a id="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-18" name="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-18" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_db3df9519cfe4fcebd1d69fff256cc2e-18"></a>        <span class="n">sys</span><span class="o">.</span><span class="n">stderr</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s1">&#39;</span><span class="se">\033</span><span class="s1">[1;31m&#39;</span><span class="p">)</span>
<a id="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-19" name="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-19" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_db3df9519cfe4fcebd1d69fff256cc2e-19"></a>    <span class="n">sys</span><span class="o">.</span><span class="n">stderr</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span>
<a id="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-20" name="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-20" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_db3df9519cfe4fcebd1d69fff256cc2e-20"></a>
<a id="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-21" name="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-21" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_db3df9519cfe4fcebd1d69fff256cc2e-21"></a>    <span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="o">+</span> <span class="s2">&quot; &quot;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="o">+</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">)</span>
<a id="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-22" name="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-22" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_db3df9519cfe4fcebd1d69fff256cc2e-22"></a>    <span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span>
<a id="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-23" name="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-23" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_db3df9519cfe4fcebd1d69fff256cc2e-23"></a>
<a id="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-24" name="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-24" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_db3df9519cfe4fcebd1d69fff256cc2e-24"></a>    <span class="n">sys</span><span class="o">.</span><span class="n">stderr</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s1">&#39;</span><span class="se">\033</span><span class="s1">[0m&#39;</span><span class="p">)</span>
<a id="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-25" name="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-25" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_db3df9519cfe4fcebd1d69fff256cc2e-25"></a>    <span class="n">sys</span><span class="o">.</span><span class="n">stderr</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span>
<a id="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-26" name="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-26" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_db3df9519cfe4fcebd1d69fff256cc2e-26"></a>
<a id="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-27" name="rest_code_db3df9519cfe4fcebd1d69fff256cc2e-27" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_db3df9519cfe4fcebd1d69fff256cc2e-27"></a><span class="n">dis</span><span class="o">.</span><span class="n">dis</span><span class="p">(</span><span class="n">check_password</span><span class="p">)</span>
</pre></div>
<p>If we run this solver, we get the following output (text in brackets added by me):</p>
<div class="code"><pre class="code text"><a id="rest_code_27f66539bcdd4afa8277aa02dff98f11-1" name="rest_code_27f66539bcdd4afa8277aa02dff98f11-1" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_27f66539bcdd4afa8277aa02dff98f11-1"></a>co_argcount 1            [OK]
<a id="rest_code_27f66539bcdd4afa8277aa02dff98f11-2" name="rest_code_27f66539bcdd4afa8277aa02dff98f11-2" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_27f66539bcdd4afa8277aa02dff98f11-2"></a>co_consts (None,)        [1/7 match]
<a id="rest_code_27f66539bcdd4afa8277aa02dff98f11-3" name="rest_code_27f66539bcdd4afa8277aa02dff98f11-3" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_27f66539bcdd4afa8277aa02dff98f11-3"></a>co_flags 67              [OK]
<a id="rest_code_27f66539bcdd4afa8277aa02dff98f11-4" name="rest_code_27f66539bcdd4afa8277aa02dff98f11-4" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_27f66539bcdd4afa8277aa02dff98f11-4"></a>co_name check_password   [OK]
<a id="rest_code_27f66539bcdd4afa8277aa02dff98f11-5" name="rest_code_27f66539bcdd4afa8277aa02dff98f11-5" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_27f66539bcdd4afa8277aa02dff98f11-5"></a>co_names ()              [0/6 match]
<a id="rest_code_27f66539bcdd4afa8277aa02dff98f11-6" name="rest_code_27f66539bcdd4afa8277aa02dff98f11-6" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_27f66539bcdd4afa8277aa02dff98f11-6"></a>co_nlocals 1             [should be 4]
<a id="rest_code_27f66539bcdd4afa8277aa02dff98f11-7" name="rest_code_27f66539bcdd4afa8277aa02dff98f11-7" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_27f66539bcdd4afa8277aa02dff98f11-7"></a>co_stacksize 1           [should be 6]
<a id="rest_code_27f66539bcdd4afa8277aa02dff98f11-8" name="rest_code_27f66539bcdd4afa8277aa02dff98f11-8" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_27f66539bcdd4afa8277aa02dff98f11-8"></a>co_varnames (&#39;s&#39;,)       [1/4 match]
<a id="rest_code_27f66539bcdd4afa8277aa02dff98f11-9" name="rest_code_27f66539bcdd4afa8277aa02dff98f11-9" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_27f66539bcdd4afa8277aa02dff98f11-9"></a>  7           0 LOAD_CONST               0 (None)
<a id="rest_code_27f66539bcdd4afa8277aa02dff98f11-10" name="rest_code_27f66539bcdd4afa8277aa02dff98f11-10" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_27f66539bcdd4afa8277aa02dff98f11-10"></a>              3 RETURN_VALUE
</pre></div>
<p>We can see (with the help of colors, not reproduced here), that we’ve got <code class="docutils literal">co_argcount</code>, <code class="docutils literal">co_flags</code>, <code class="docutils literal">co_name</code> correctly. We also have one constant (<code class="docutils literal">None</code>, in every function) and one variable name (<code class="docutils literal">s</code>, the argument name). We can also see <code class="docutils literal">dis.dis()</code> output. While it looks similar to the assignment, there are a few noticeable differences: there is no <code class="docutils literal">7</code> (line number) at the start, and <code class="docutils literal">LOAD_CONST</code> instructions in the original code did not have anything in parentheses (only comparisions and loops did).  This makes reading bytecode harder, but still possible. (I originally thought about using <code class="docutils literal">diff</code> for help, but it’s not hard to do it by hand. I did use <code class="docutils literal">diff</code> for the final checking after a manual “conversion”)</p>
<p>Let’s stop to look at the constants and names for a second. The long string is followed by <code class="docutils literal">hex</code>, and one of the constants is <code class="docutils literal">decode</code>. This means that we need to use <code class="docutils literal"><span class="pre">str.decode('hex')</span></code> to create a (byte)string of some information. Puzzle answers tend to be human-readable, and this string isn’t — so we need to do some more work.</p>
<p>So, let’s try reproducing the start of the original mission code using what we’ve just discussed. Python’s VM is based on a stack. In the bytecode above, you can see that instructions take 0 or 1 arguments. Some of them put things on the stack, others do actions and remove them. Most instruction names are self-explanatory, but the full list can be found in the <a class="reference external" href="https://docs.python.org/2/library/dis.html#python-bytecode-instructions">dis module documentation</a>.</p>
<p>Instructions like <code class="docutils literal">LOAD</code> and <code class="docutils literal">STORE</code> refer to indices in the constants/names/varnames tuples. To make it easier, here’s a “table” of them:</p>
<div class="code"><pre class="code text"><a id="rest_code_8c089b4cab264b4f851b62c686149db7-1" name="rest_code_8c089b4cab264b4f851b62c686149db7-1" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_8c089b4cab264b4f851b62c686149db7-1"></a>constants
<a id="rest_code_8c089b4cab264b4f851b62c686149db7-2" name="rest_code_8c089b4cab264b4f851b62c686149db7-2" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_8c089b4cab264b4f851b62c686149db7-2"></a> 0     1                                                       2      3   4    5    6
<a id="rest_code_8c089b4cab264b4f851b62c686149db7-3" name="rest_code_8c089b4cab264b4f851b62c686149db7-3" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_8c089b4cab264b4f851b62c686149db7-3"></a>(None, &#39;4e5d4e92865a4e495a86494b5a5d49525261865f5758534d4a89&#39;, &#39;hex&#39;, 89, 255, 115, 50)
<a id="rest_code_8c089b4cab264b4f851b62c686149db7-4" name="rest_code_8c089b4cab264b4f851b62c686149db7-4" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_8c089b4cab264b4f851b62c686149db7-4"></a>
<a id="rest_code_8c089b4cab264b4f851b62c686149db7-5" name="rest_code_8c089b4cab264b4f851b62c686149db7-5" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_8c089b4cab264b4f851b62c686149db7-5"></a>names (globals, attributes)
<a id="rest_code_8c089b4cab264b4f851b62c686149db7-6" name="rest_code_8c089b4cab264b4f851b62c686149db7-6" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_8c089b4cab264b4f851b62c686149db7-6"></a> 0         1      2        3      4      5
<a id="rest_code_8c089b4cab264b4f851b62c686149db7-7" name="rest_code_8c089b4cab264b4f851b62c686149db7-7" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_8c089b4cab264b4f851b62c686149db7-7"></a>(&#39;decode&#39;, &#39;len&#39;, &#39;False&#39;, &#39;all&#39;, &#39;zip&#39;, &#39;ord&#39;)
<a id="rest_code_8c089b4cab264b4f851b62c686149db7-8" name="rest_code_8c089b4cab264b4f851b62c686149db7-8" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_8c089b4cab264b4f851b62c686149db7-8"></a>
<a id="rest_code_8c089b4cab264b4f851b62c686149db7-9" name="rest_code_8c089b4cab264b4f851b62c686149db7-9" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_8c089b4cab264b4f851b62c686149db7-9"></a>varnames (locals, _fast)
<a id="rest_code_8c089b4cab264b4f851b62c686149db7-10" name="rest_code_8c089b4cab264b4f851b62c686149db7-10" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_8c089b4cab264b4f851b62c686149db7-10"></a> 0    1       2     3
<a id="rest_code_8c089b4cab264b4f851b62c686149db7-11" name="rest_code_8c089b4cab264b4f851b62c686149db7-11" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_8c089b4cab264b4f851b62c686149db7-11"></a>(&#39;s&#39;, &#39;good&#39;, &#39;cs&#39;, &#39;cg&#39;)
</pre></div>
<p>In order to improve readability, I will use “new” <code class="docutils literal">dis</code> output with names in parentheses below:</p>
<div class="code"><pre class="code text"><a id="rest_code_fb6ce8efa1624395b2049e1148156b1c-1" name="rest_code_fb6ce8efa1624395b2049e1148156b1c-1" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_fb6ce8efa1624395b2049e1148156b1c-1"></a> 0 LOAD_CONST               1 (&#39;4e5d4e92865a4e495a86494b5a5d49525261865f5758534d4a89&#39;)
<a id="rest_code_fb6ce8efa1624395b2049e1148156b1c-2" name="rest_code_fb6ce8efa1624395b2049e1148156b1c-2" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_fb6ce8efa1624395b2049e1148156b1c-2"></a> 3 LOAD_ATTR                0 (decode)
<a id="rest_code_fb6ce8efa1624395b2049e1148156b1c-3" name="rest_code_fb6ce8efa1624395b2049e1148156b1c-3" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_fb6ce8efa1624395b2049e1148156b1c-3"></a> 6 LOAD_CONST               2 (&#39;hex&#39;)
<a id="rest_code_fb6ce8efa1624395b2049e1148156b1c-4" name="rest_code_fb6ce8efa1624395b2049e1148156b1c-4" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_fb6ce8efa1624395b2049e1148156b1c-4"></a> 9 CALL_FUNCTION            1 # function takes 1 argument from stack
<a id="rest_code_fb6ce8efa1624395b2049e1148156b1c-5" name="rest_code_fb6ce8efa1624395b2049e1148156b1c-5" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_fb6ce8efa1624395b2049e1148156b1c-5"></a>12 STORE_FAST               1 (good)
</pre></div>
<p>As I guessed before, the first line of our function is as follows:</p>
<div class="code"><pre class="code python"><a id="rest_code_85beff924755471e8039dad55a327578-1" name="rest_code_85beff924755471e8039dad55a327578-1" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_85beff924755471e8039dad55a327578-1"></a><span class="k">def</span><span class="w"> </span><span class="nf">check_password</span><span class="p">(</span><span class="n">s</span><span class="p">):</span>
<a id="rest_code_85beff924755471e8039dad55a327578-2" name="rest_code_85beff924755471e8039dad55a327578-2" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_85beff924755471e8039dad55a327578-2"></a>    <span class="n">good</span> <span class="o">=</span> <span class="s1">&#39;4e5d4e92865a4e495a86494b5a5d49525261865f5758534d4a89&#39;</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s1">&#39;hex&#39;</span><span class="p">)</span>  <span class="c1"># new</span>
</pre></div>
<p>If we run the solver again, we’ll see that the first 12 bytes of our bytecode match the mission text. We can also see that <code class="docutils literal">varnames</code> is filled in half, we’ve added two constants, and one name.  The next few lines are as follows:</p>
<div class="code"><pre class="code text"><a id="rest_code_506359919e4b49e6b2cd2712f3301286-1" name="rest_code_506359919e4b49e6b2cd2712f3301286-1" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_506359919e4b49e6b2cd2712f3301286-1"></a>15 LOAD_GLOBAL              1
<a id="rest_code_506359919e4b49e6b2cd2712f3301286-2" name="rest_code_506359919e4b49e6b2cd2712f3301286-2" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_506359919e4b49e6b2cd2712f3301286-2"></a>18 LOAD_FAST                0
<a id="rest_code_506359919e4b49e6b2cd2712f3301286-3" name="rest_code_506359919e4b49e6b2cd2712f3301286-3" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_506359919e4b49e6b2cd2712f3301286-3"></a>21 CALL_FUNCTION            1
<a id="rest_code_506359919e4b49e6b2cd2712f3301286-4" name="rest_code_506359919e4b49e6b2cd2712f3301286-4" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_506359919e4b49e6b2cd2712f3301286-4"></a>24 LOAD_GLOBAL              1
<a id="rest_code_506359919e4b49e6b2cd2712f3301286-5" name="rest_code_506359919e4b49e6b2cd2712f3301286-5" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_506359919e4b49e6b2cd2712f3301286-5"></a>27 LOAD_FAST                1
<a id="rest_code_506359919e4b49e6b2cd2712f3301286-6" name="rest_code_506359919e4b49e6b2cd2712f3301286-6" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_506359919e4b49e6b2cd2712f3301286-6"></a>30 CALL_FUNCTION            1
<a id="rest_code_506359919e4b49e6b2cd2712f3301286-7" name="rest_code_506359919e4b49e6b2cd2712f3301286-7" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_506359919e4b49e6b2cd2712f3301286-7"></a>33 COMPARE_OP               3 (!=)
<a id="rest_code_506359919e4b49e6b2cd2712f3301286-8" name="rest_code_506359919e4b49e6b2cd2712f3301286-8" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_506359919e4b49e6b2cd2712f3301286-8"></a>36 POP_JUMP_IF_FALSE       43
<a id="rest_code_506359919e4b49e6b2cd2712f3301286-9" name="rest_code_506359919e4b49e6b2cd2712f3301286-9" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_506359919e4b49e6b2cd2712f3301286-9"></a>39 LOAD_GLOBAL              2
<a id="rest_code_506359919e4b49e6b2cd2712f3301286-10" name="rest_code_506359919e4b49e6b2cd2712f3301286-10" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_506359919e4b49e6b2cd2712f3301286-10"></a>42 RETURN_VALUE
</pre></div>
<p>We can see that we’re putting a global object on stack and calling it with one argument. In both cases, the global has the index 1, that’s <code class="docutils literal">len</code>. The two arguments are <code class="docutils literal">s</code> and <code class="docutils literal">good</code>. We put both lengths on stack, then compare them. If the comparison fails (they’re equal), we jump to the instruction starting at byte 43, otherwise we continue execution to load the second global (False) and return it.  This wall of text translates to the following simple code:</p>
<div class="code"><pre class="code python"><a id="rest_code_ff50cca92832460f9863e211d84e2c63-1" name="rest_code_ff50cca92832460f9863e211d84e2c63-1" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ff50cca92832460f9863e211d84e2c63-1"></a><span class="k">def</span><span class="w"> </span><span class="nf">check_password</span><span class="p">(</span><span class="n">s</span><span class="p">):</span>
<a id="rest_code_ff50cca92832460f9863e211d84e2c63-2" name="rest_code_ff50cca92832460f9863e211d84e2c63-2" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ff50cca92832460f9863e211d84e2c63-2"></a>    <span class="n">good</span> <span class="o">=</span> <span class="s1">&#39;4e5d4e92865a4e495a86494b5a5d49525261865f5758534d4a89&#39;</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s1">&#39;hex&#39;</span><span class="p">)</span>
<a id="rest_code_ff50cca92832460f9863e211d84e2c63-3" name="rest_code_ff50cca92832460f9863e211d84e2c63-3" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ff50cca92832460f9863e211d84e2c63-3"></a>    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">!=</span> <span class="nb">len</span><span class="p">(</span><span class="n">good</span><span class="p">):</span>  <span class="c1"># new</span>
<a id="rest_code_ff50cca92832460f9863e211d84e2c63-4" name="rest_code_ff50cca92832460f9863e211d84e2c63-4" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_ff50cca92832460f9863e211d84e2c63-4"></a>        <span class="k">return</span> <span class="kc">False</span>         <span class="c1"># new</span>
</pre></div>
<p>Let’s take another look at our names. We can see we’re missing <code class="docutils literal">all</code>, <code class="docutils literal">zip</code>, <code class="docutils literal">ord</code>. You can already see a common pattern here: we will iterate over both strings at once (using <code class="docutils literal">zip</code>), do some math based on the character’s codes (<code class="docutils literal">ord</code>), and then check if <code class="docutils literal">all</code> results (of a comparison, usually) are truthy.</p>
<p>Here’s the bytecode with value annotations and comments, which explain what happens where:</p>
<div class="code"><pre class="code text"><a id="rest_code_600c535191904a66bf231f1cfe9efc77-1" name="rest_code_600c535191904a66bf231f1cfe9efc77-1" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-1"></a>&gt;&gt;   43 LOAD_GLOBAL              3 (all)
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-2" name="rest_code_600c535191904a66bf231f1cfe9efc77-2" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-2"></a>     46 BUILD_LIST               0
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-3" name="rest_code_600c535191904a66bf231f1cfe9efc77-3" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-3"></a>     49 LOAD_GLOBAL              4 (zip)
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-4" name="rest_code_600c535191904a66bf231f1cfe9efc77-4" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-4"></a>     52 LOAD_FAST                0 (s)
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-5" name="rest_code_600c535191904a66bf231f1cfe9efc77-5" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-5"></a>     55 LOAD_FAST                1 (good)
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-6" name="rest_code_600c535191904a66bf231f1cfe9efc77-6" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-6"></a>     58 CALL_FUNCTION            2           # zip(s, good)
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-7" name="rest_code_600c535191904a66bf231f1cfe9efc77-7" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-7"></a>     61 GET_ITER                             # Start iterating: iter()
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-8" name="rest_code_600c535191904a66bf231f1cfe9efc77-8" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-8"></a>&gt;&gt;   62 FOR_ITER                52 (to 117)  # for loop iteration start (if iterator exhausted, jump +52 bytes to position 117)
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-9" name="rest_code_600c535191904a66bf231f1cfe9efc77-9" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-9"></a>     65 UNPACK_SEQUENCE          2           # unpack a sequence (a, b = sequence)
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-10" name="rest_code_600c535191904a66bf231f1cfe9efc77-10" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-10"></a>     68 STORE_FAST               2 (cs)      # cs = item from s
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-11" name="rest_code_600c535191904a66bf231f1cfe9efc77-11" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-11"></a>     71 STORE_FAST               3 (cg)      # cg = item from good
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-12" name="rest_code_600c535191904a66bf231f1cfe9efc77-12" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-12"></a>     74 LOAD_GLOBAL              5 (ord)
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-13" name="rest_code_600c535191904a66bf231f1cfe9efc77-13" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-13"></a>     77 LOAD_FAST                2 (cs)
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-14" name="rest_code_600c535191904a66bf231f1cfe9efc77-14" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-14"></a>     80 CALL_FUNCTION            1           # put ord(cs) on stack
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-15" name="rest_code_600c535191904a66bf231f1cfe9efc77-15" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-15"></a>     83 LOAD_CONST               3 (89)
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-16" name="rest_code_600c535191904a66bf231f1cfe9efc77-16" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-16"></a>     86 BINARY_SUBTRACT                      # - 89   [subtract 89 from topmost value]
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-17" name="rest_code_600c535191904a66bf231f1cfe9efc77-17" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-17"></a>     87 LOAD_CONST               4 (255)
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-18" name="rest_code_600c535191904a66bf231f1cfe9efc77-18" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-18"></a>     90 BINARY_AND                           # &amp; 255  [bitwise AND with topmost value]
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-19" name="rest_code_600c535191904a66bf231f1cfe9efc77-19" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-19"></a>     91 LOAD_CONST               5 (115)
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-20" name="rest_code_600c535191904a66bf231f1cfe9efc77-20" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-20"></a>     94 BINARY_XOR                           # ^ 115  [bitwise XOR with topmost value]
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-21" name="rest_code_600c535191904a66bf231f1cfe9efc77-21" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-21"></a>     95 LOAD_CONST               6 (50)
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-22" name="rest_code_600c535191904a66bf231f1cfe9efc77-22" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-22"></a>     98 BINARY_XOR                           # ^ 50   [bitwise XOR with topmost value]
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-23" name="rest_code_600c535191904a66bf231f1cfe9efc77-23" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-23"></a>     99 LOAD_GLOBAL              5 (ord)
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-24" name="rest_code_600c535191904a66bf231f1cfe9efc77-24" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-24"></a>    102 LOAD_FAST                3 (cg)
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-25" name="rest_code_600c535191904a66bf231f1cfe9efc77-25" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-25"></a>    105 CALL_FUNCTION            1           # put ord(cs) on stack
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-26" name="rest_code_600c535191904a66bf231f1cfe9efc77-26" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-26"></a>    108 COMPARE_OP               2 (==)      # compare the two values on stack
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-27" name="rest_code_600c535191904a66bf231f1cfe9efc77-27" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-27"></a>    111 LIST_APPEND              2           # append topmost value to the list in topmost-1; pop topmost (append to list created in comprehension)
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-28" name="rest_code_600c535191904a66bf231f1cfe9efc77-28" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-28"></a>    114 JUMP_ABSOLUTE           62           # jump back to start of loop
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-29" name="rest_code_600c535191904a66bf231f1cfe9efc77-29" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-29"></a>&gt;&gt;  117 CALL_FUNCTION            1           # after loop: call all([list comprehension result])
<a id="rest_code_600c535191904a66bf231f1cfe9efc77-30" name="rest_code_600c535191904a66bf231f1cfe9efc77-30" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_600c535191904a66bf231f1cfe9efc77-30"></a>    120 RETURN_VALUE                         # return value returned by all()
</pre></div>
<p>We can now write the full answer.</p>
<p><a class="reference external" href="link://listing/listings/gynvaels-mission-11-en/mission11.py">listings/gynvaels-mission-11-en/mission11.py</a>  <a class="reference external" href="link://listing_source/listings/gynvaels-mission-11-en/mission11.py">(Source)</a></p>
<div class="code"><table class="codetable"><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_937a75fde167457d96c306bb9cde4520-1"><code data-line-number="1"></code></a></td><td class="code"><code><a id="rest_code_937a75fde167457d96c306bb9cde4520-1" name="rest_code_937a75fde167457d96c306bb9cde4520-1"></a><span class="k">def</span><span class="w"> </span><span class="nf">check_password</span><span class="p">(</span><span class="n">s</span><span class="p">):</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_937a75fde167457d96c306bb9cde4520-2"><code data-line-number="2"></code></a></td><td class="code"><code><a id="rest_code_937a75fde167457d96c306bb9cde4520-2" name="rest_code_937a75fde167457d96c306bb9cde4520-2"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">good</span> <span class="o">=</span> <span class="s1">&#39;4e5d4e92865a4e495a86494b5a5d49525261865f5758534d4a89&#39;</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s1">&#39;hex&#39;</span><span class="p">)</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_937a75fde167457d96c306bb9cde4520-3"><code data-line-number="3"></code></a></td><td class="code"><code><a id="rest_code_937a75fde167457d96c306bb9cde4520-3" name="rest_code_937a75fde167457d96c306bb9cde4520-3"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">!=</span> <span class="nb">len</span><span class="p">(</span><span class="n">good</span><span class="p">):</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_937a75fde167457d96c306bb9cde4520-4"><code data-line-number="4"></code></a></td><td class="code"><code><a id="rest_code_937a75fde167457d96c306bb9cde4520-4" name="rest_code_937a75fde167457d96c306bb9cde4520-4"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">return</span> <span class="kc">False</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_937a75fde167457d96c306bb9cde4520-5"><code data-line-number="5"></code></a></td><td class="code"><code><a id="rest_code_937a75fde167457d96c306bb9cde4520-5" name="rest_code_937a75fde167457d96c306bb9cde4520-5"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_937a75fde167457d96c306bb9cde4520-6"><code data-line-number="6"></code></a></td><td class="code"><code><a id="rest_code_937a75fde167457d96c306bb9cde4520-6" name="rest_code_937a75fde167457d96c306bb9cde4520-6"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">return</span> <span class="nb">all</span><span class="p">([</span><span class="nb">ord</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span> <span class="o">-</span> <span class="mi">89</span> <span class="o">&amp;</span> <span class="mi">255</span> <span class="o">^</span> <span class="mi">115</span> <span class="o">^</span> <span class="mi">50</span> <span class="o">==</span> <span class="nb">ord</span><span class="p">(</span><span class="n">cg</span><span class="p">)</span> <span class="k">for</span> <span class="n">cs</span><span class="p">,</span> <span class="n">cg</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">good</span><span class="p">)])</span>
</code></td></tr></table></div><p>In the end, our <code class="docutils literal">dis.dis()</code> output matches the mission text (except the removed values, but their IDs do match), our <code class="docutils literal">co_*</code> variables are all green, and we can get to work on solving the puzzle itself!</p>
<p><strong>Side note:</strong> this task uses a list comprehension. You might want to optimize it, remove the brackets, and end up with a generator expression. This would make the task harder, since would require working with the internal generator code object as well:</p>
<div class="code"><pre class="code text"><a id="rest_code_2486792360754ae283652134d687e43c-1" name="rest_code_2486792360754ae283652134d687e43c-1" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_2486792360754ae283652134d687e43c-1"></a>co_consts (None, &#39;4e5d4e92865a4e495a86494b5a5d49525261865f5758534d4a89&#39;, &#39;hex&#39;, &lt;code object &lt;genexpr&gt; at 0x104a86c30, file &quot;mission11-genexpr.py&quot;, line 11&gt;)
<a id="rest_code_2486792360754ae283652134d687e43c-2" name="rest_code_2486792360754ae283652134d687e43c-2" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_2486792360754ae283652134d687e43c-2"></a>
<a id="rest_code_2486792360754ae283652134d687e43c-3" name="rest_code_2486792360754ae283652134d687e43c-3" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_2486792360754ae283652134d687e43c-3"></a>46 LOAD_CONST               3 (&lt;code object &lt;genexpr&gt; at 0x104a86c30, file &quot;mission11-genexpr.py&quot;, line 11&gt;)
</pre></div>
<p><code class="docutils literal">BINARY_*</code> and <code class="docutils literal">ord</code> disappeared from the new listing. You can see the <a class="reference external" href="https://chriswarrick.com/listings/gynvaels-mission-11-en/mission11-genexpr.py.html">modified code</a> (which differs by two bytes) and <a class="reference external" href="https://chriswarrick.com/listings/gynvaels-mission-11-en/mission11-genexpr.txt.html">solver output</a>.</p>
</section>
<section id="solving-the-real-puzzle">
<h1>Solving the real puzzle</h1>
<p>I solved the extra credit part of the puzzle. The <em>real</em> aim of the puzzle was to recover the password — the text for which <code class="docutils literal">check_password()</code> will return True.</p>
<p>This part is pretty boring. I built a dictionary, where I mapped every byte (0…255) to the result of the calculation done in the <code class="docutils literal">check_password()</code> function’s loop. Then I used that to recover the original text.</p>
<div class="code"><pre class="code python"><a id="rest_code_0f5c1acbabcc4365a8eccce0dc13f132-1" name="rest_code_0f5c1acbabcc4365a8eccce0dc13f132-1" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_0f5c1acbabcc4365a8eccce0dc13f132-1"></a><span class="n">pass_values</span> <span class="o">=</span> <span class="p">{}</span>
<a id="rest_code_0f5c1acbabcc4365a8eccce0dc13f132-2" name="rest_code_0f5c1acbabcc4365a8eccce0dc13f132-2" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_0f5c1acbabcc4365a8eccce0dc13f132-2"></a><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">256</span><span class="p">):</span>
<a id="rest_code_0f5c1acbabcc4365a8eccce0dc13f132-3" name="rest_code_0f5c1acbabcc4365a8eccce0dc13f132-3" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_0f5c1acbabcc4365a8eccce0dc13f132-3"></a>    <span class="n">result</span> <span class="o">=</span> <span class="n">i</span> <span class="o">-</span> <span class="mi">89</span> <span class="o">&amp;</span> <span class="mi">255</span> <span class="o">^</span> <span class="mi">115</span> <span class="o">^</span> <span class="mi">50</span>
<a id="rest_code_0f5c1acbabcc4365a8eccce0dc13f132-4" name="rest_code_0f5c1acbabcc4365a8eccce0dc13f132-4" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_0f5c1acbabcc4365a8eccce0dc13f132-4"></a>    <span class="n">pass_values</span><span class="p">[</span><span class="n">result</span><span class="p">]</span> <span class="o">=</span> <span class="n">i</span>
<a id="rest_code_0f5c1acbabcc4365a8eccce0dc13f132-5" name="rest_code_0f5c1acbabcc4365a8eccce0dc13f132-5" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_0f5c1acbabcc4365a8eccce0dc13f132-5"></a>
<a id="rest_code_0f5c1acbabcc4365a8eccce0dc13f132-6" name="rest_code_0f5c1acbabcc4365a8eccce0dc13f132-6" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_0f5c1acbabcc4365a8eccce0dc13f132-6"></a><span class="n">good</span> <span class="o">=</span> <span class="s1">&#39;4e5d4e92865a4e495a86494b5a5d49525261865f5758534d4a89&#39;</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s1">&#39;hex&#39;</span><span class="p">)</span>
<a id="rest_code_0f5c1acbabcc4365a8eccce0dc13f132-7" name="rest_code_0f5c1acbabcc4365a8eccce0dc13f132-7" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_0f5c1acbabcc4365a8eccce0dc13f132-7"></a><span class="n">password</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>
<a id="rest_code_0f5c1acbabcc4365a8eccce0dc13f132-8" name="rest_code_0f5c1acbabcc4365a8eccce0dc13f132-8" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_0f5c1acbabcc4365a8eccce0dc13f132-8"></a><span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">good</span><span class="p">:</span>
<a id="rest_code_0f5c1acbabcc4365a8eccce0dc13f132-9" name="rest_code_0f5c1acbabcc4365a8eccce0dc13f132-9" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_0f5c1acbabcc4365a8eccce0dc13f132-9"></a>    <span class="n">password</span> <span class="o">+=</span> <span class="nb">chr</span><span class="p">(</span><span class="n">pass_values</span><span class="p">[</span><span class="nb">ord</span><span class="p">(</span><span class="n">c</span><span class="p">)])</span>
<a id="rest_code_0f5c1acbabcc4365a8eccce0dc13f132-10" name="rest_code_0f5c1acbabcc4365a8eccce0dc13f132-10" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_0f5c1acbabcc4365a8eccce0dc13f132-10"></a>
<a id="rest_code_0f5c1acbabcc4365a8eccce0dc13f132-11" name="rest_code_0f5c1acbabcc4365a8eccce0dc13f132-11" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_0f5c1acbabcc4365a8eccce0dc13f132-11"></a><span class="nb">print</span><span class="p">(</span><span class="n">password</span><span class="p">)</span>
<a id="rest_code_0f5c1acbabcc4365a8eccce0dc13f132-12" name="rest_code_0f5c1acbabcc4365a8eccce0dc13f132-12" href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_0f5c1acbabcc4365a8eccce0dc13f132-12"></a><span class="nb">print</span><span class="p">(</span><span class="n">check_password</span><span class="p">(</span><span class="n">password</span><span class="p">))</span>
</pre></div>
<p><strong>The password is:</strong> <code class="docutils literal">huh, that actually worked!</code>.</p>
</section>
<section id="what-was-that-paint-thing-about">
<h1>What was that Paint thing about?</h1>
<blockquote>Yesterday’s mission was about Elvish — <strong>I mean Paint</strong> — I mean Python programming.<footer>yours truly in this post’s teaser</footer></blockquote><p>Most of my readers were probably puzzled by the mention of Paint. Long-time viewers of Gynvael’s streams in Polish remember the Python 101 video he posted on April Fools last year. See <a class="reference external" href="https://www.youtube.com/watch?v=7VJaprmuHcw">original video</a>, <a class="reference external" href="http://gynvael.coldwind.pl/?id=599">explanation</a>, <a class="reference external" href="https://github.com/gynvael/stream/tree/master/007-python-101">code</a> (video and explanation are both Polish; you can get the gist of the video without hearing the audio commentary though.) <strong>Spoilers ahead.</strong></p>
<p>In that prank, Gynvael taught Python basics. The first part concerned itself with writing bytecode by hand. The second part (starts around 12:00) was about drawing custom Python modules. In Paint. Yes, Paint, the simple graphics program included with Microsoft Windows. He drew a custom Python module in Paint, and saved it using the BMP format. It looked like this (zoomed PNG below; <a class="reference external" href="https://chriswarrick.com/pub/gynvaels-mission-11-en/gynmod.bmp">download gynmod.bmp</a>):</p>
<img alt="/images/gynvaels-mission-11-en/gynmod-zoom.png" class="align-center" src="https://chriswarrick.com/images/gynvaels-mission-11-en/gynmod-zoom.png">
<p>How was this done? There are three things that come into play:</p>
<ul class="simple">
<li><p>Python can import modules from a ZIP file (if it’s appended to sys.path). Some tools that produce <code class="docutils literal">.exe</code> files of Python code use this technique; the old <code class="docutils literal">.egg</code> file format also used ZIPs this way.</p></li>
<li><p>BMP files have their header at the start of a file.</p></li>
<li><p>ZIP files have their header at the end of a file.</p></li>
<li><p>Thus, one file can be a valid BMP and ZIP at the same time.</p></li>
</ul>
<p>I took the code of <code class="docutils literal">check_password</code> and put it in <code class="docutils literal">mission11.py</code> (which I already cited above). Then I compiled to <code class="docutils literal">.pyc</code> and created a <code class="docutils literal">.zip</code> out of it.</p>
<p><a class="reference external" href="link://listing/listings/gynvaels-mission-11-en/mission11.py">listings/gynvaels-mission-11-en/mission11.py</a>  <a class="reference external" href="link://listing_source/listings/gynvaels-mission-11-en/mission11.py">(Source)</a></p>
<div class="code"><table class="codetable"><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_bec3e104bb384b61922373724d0100a2-1"><code data-line-number="1"></code></a></td><td class="code"><code><a id="rest_code_bec3e104bb384b61922373724d0100a2-1" name="rest_code_bec3e104bb384b61922373724d0100a2-1"></a><span class="k">def</span><span class="w"> </span><span class="nf">check_password</span><span class="p">(</span><span class="n">s</span><span class="p">):</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_bec3e104bb384b61922373724d0100a2-2"><code data-line-number="2"></code></a></td><td class="code"><code><a id="rest_code_bec3e104bb384b61922373724d0100a2-2" name="rest_code_bec3e104bb384b61922373724d0100a2-2"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">good</span> <span class="o">=</span> <span class="s1">&#39;4e5d4e92865a4e495a86494b5a5d49525261865f5758534d4a89&#39;</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s1">&#39;hex&#39;</span><span class="p">)</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_bec3e104bb384b61922373724d0100a2-3"><code data-line-number="3"></code></a></td><td class="code"><code><a id="rest_code_bec3e104bb384b61922373724d0100a2-3" name="rest_code_bec3e104bb384b61922373724d0100a2-3"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">!=</span> <span class="nb">len</span><span class="p">(</span><span class="n">good</span><span class="p">):</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_bec3e104bb384b61922373724d0100a2-4"><code data-line-number="4"></code></a></td><td class="code"><code><a id="rest_code_bec3e104bb384b61922373724d0100a2-4" name="rest_code_bec3e104bb384b61922373724d0100a2-4"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">return</span> <span class="kc">False</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_bec3e104bb384b61922373724d0100a2-5"><code data-line-number="5"></code></a></td><td class="code"><code><a id="rest_code_bec3e104bb384b61922373724d0100a2-5" name="rest_code_bec3e104bb384b61922373724d0100a2-5"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_bec3e104bb384b61922373724d0100a2-6"><code data-line-number="6"></code></a></td><td class="code"><code><a id="rest_code_bec3e104bb384b61922373724d0100a2-6" name="rest_code_bec3e104bb384b61922373724d0100a2-6"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">return</span> <span class="nb">all</span><span class="p">([</span><span class="nb">ord</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span> <span class="o">-</span> <span class="mi">89</span> <span class="o">&amp;</span> <span class="mi">255</span> <span class="o">^</span> <span class="mi">115</span> <span class="o">^</span> <span class="mi">50</span> <span class="o">==</span> <span class="nb">ord</span><span class="p">(</span><span class="n">cg</span><span class="p">)</span> <span class="k">for</span> <span class="n">cs</span><span class="p">,</span> <span class="n">cg</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">good</span><span class="p">)])</span>
</code></td></tr></table></div><p>Since I’m not an expert in any of the formats, I booted my Windows virtual machine and blindly copied the <a class="reference external" href="http://gynvael.coldwind.pl/img/secapr16_3.png">parameters used by Gynvael</a> to open the ZIP file (renamed <code class="docutils literal">.raw</code>) in IrfanView and saved as <code class="docutils literal">.bmp</code>. I changed the size to 83×2, because my ZIP file was 498 bytes long (3 BPP * 83 px * 2 px = 498 bytes) — by doing that, and through sheer luck with the size, I could avoid adding comments and editing the ZIP archive. I ended up with this (PNG again; <a class="reference external" href="https://chriswarrick.com/pub/gynvaels-mission-11-en/mission11.bmp">download mission11.bmp</a>):</p>
<img alt="/images/gynvaels-mission-11-en/mission11-zoom.png" class="align-center" src="https://chriswarrick.com/images/gynvaels-mission-11-en/mission11-zoom.png">
<p>The <code class="docutils literal">.bmp</code> file is runnable! We can use this code:</p>
<p><a class="reference external" href="link://listing/listings/gynvaels-mission-11-en/ziprunner.py">listings/gynvaels-mission-11-en/ziprunner.py</a>  <a class="reference external" href="link://listing_source/listings/gynvaels-mission-11-en/ziprunner.py">(Source)</a></p>
<div class="code"><table class="codetable"><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_2c416583ffef4a72a08094db61f84464-1"><code data-line-number="1"></code></a></td><td class="code"><code><a id="rest_code_2c416583ffef4a72a08094db61f84464-1" name="rest_code_2c416583ffef4a72a08094db61f84464-1"></a><span class="ch">#!/usr/bin/env python2</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_2c416583ffef4a72a08094db61f84464-2"><code data-line-number="2"></code></a></td><td class="code"><code><a id="rest_code_2c416583ffef4a72a08094db61f84464-2" name="rest_code_2c416583ffef4a72a08094db61f84464-2"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_2c416583ffef4a72a08094db61f84464-3"><code data-line-number="3"></code></a></td><td class="code"><code><a id="rest_code_2c416583ffef4a72a08094db61f84464-3" name="rest_code_2c416583ffef4a72a08094db61f84464-3"></a><span class="kn">import</span><span class="w"> </span><span class="nn">sys</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_2c416583ffef4a72a08094db61f84464-4"><code data-line-number="4"></code></a></td><td class="code"><code><a id="rest_code_2c416583ffef4a72a08094db61f84464-4" name="rest_code_2c416583ffef4a72a08094db61f84464-4"></a><span class="n">sys</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;mission11.bmp&quot;</span><span class="p">)</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_2c416583ffef4a72a08094db61f84464-5"><code data-line-number="5"></code></a></td><td class="code"><code><a id="rest_code_2c416583ffef4a72a08094db61f84464-5" name="rest_code_2c416583ffef4a72a08094db61f84464-5"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_2c416583ffef4a72a08094db61f84464-6"><code data-line-number="6"></code></a></td><td class="code"><code><a id="rest_code_2c416583ffef4a72a08094db61f84464-6" name="rest_code_2c416583ffef4a72a08094db61f84464-6"></a><span class="kn">import</span><span class="w"> </span><span class="nn">mission11</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2017/08/03/gynvaels-mission-11-en-python-bytecode-reverse-engineering/#rest_code_2c416583ffef4a72a08094db61f84464-7"><code data-line-number="7"></code></a></td><td class="code"><code><a id="rest_code_2c416583ffef4a72a08094db61f84464-7" name="rest_code_2c416583ffef4a72a08094db61f84464-7"></a><span class="nb">print</span> <span class="s2">&quot;Result:&quot;</span><span class="p">,</span> <span class="n">mission11</span><span class="o">.</span><span class="n">check_password</span><span class="p">(</span><span class="s1">&#39;huh, that actually worked!&#39;</span><span class="p">)</span>
</code></td></tr></table></div><p>And we get this:</p>
<img alt="/images/gynvaels-mission-11-en/running-bmp.png" class="align-center" src="https://chriswarrick.com/images/gynvaels-mission-11-en/running-bmp.png">
</section>
<section id="resources">
<h1>Resources</h1>
<ul class="simple">
<li><p><a class="reference external" href="https://chriswarrick.com/listings/gynvaels-mission-11-en/mission11-solver.py.html">mission11-solver.py (full solver code)</a></p></li>
<li><p><a class="reference external" href="https://chriswarrick.com/listings/gynvaels-mission-11-en/mission11-genexpr.py.html">mission11-genexpr.py</a>, <a class="reference external" href="https://chriswarrick.com/listings/gynvaels-mission-11-en/mission11-genexpr.txt.html">mission11-genexpr.txt</a> (used for side note regarding generator expressions vs. list comprehensions)</p></li>
<li><p><a class="reference external" href="https://chriswarrick.com/listings/gynvaels-mission-11-en/mission11.py.html">mission11.py code, used in BMP file</a></p></li>
<li><p><a class="reference external" href="https://chriswarrick.com/listings/gynvaels-mission-11-en/ziprunner.py.html">ziprunner.py, file that runs the BMP/ZIP module</a> (adapted from Gynvael’s)</p></li>
<li><p><a class="reference external" href="https://chriswarrick.com/pub/gynvaels-mission-11-en/gynmod.bmp">gynmod.bmp</a></p></li>
<li><p><a class="reference external" href="https://chriswarrick.com/pub/gynvaels-mission-11-en/mission11.bmp">mission11.bmp</a></p></li>
<li><p><a class="reference external" href="https://docs.python.org/2/library/dis.html#python-bytecode-instructions">dis module documentation</a>.</p></li>
</ul>
<p>Thanks for the mission (and BMP idea), Gynvael!</p>
</section>
]]></content:encoded><category>Python</category><category>BMP</category><category>Gynvael Coldwind</category><category>hacking</category><category>Paint</category><category>Python</category><category>Python hackery</category><category>Python internals</category><category>reverse engineering</category><category>writeup</category></item></channel></rss>