<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>msm's home</title><link>https://msm.lt/</link><description>Recent content on msm's home</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Sat, 25 Oct 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://msm.lt/index.xml" rel="self" type="application/rss+xml"/><item><title>RULECOMPILE - Undocumented Ghidra decompiler rule language</title><link>https://msm.lt/re/ghidra/rulecompile/</link><pubDate>Mon, 30 Dec 2024 00:00:00 +0000</pubDate><guid>https://msm.lt/re/ghidra/rulecompile/</guid><description>&lt;p>Or &amp;ldquo;How I got annoyed by a poor decompilation so I unearthed a hidden Ghidra feature&amp;rdquo;&lt;/p>
&lt;p>&lt;em>TLDR: there is a (undocumented and disabled by default) feature in the Ghidra decompiler that
lets you create your own decompiler passes, using a custom DSL. I leverage it to write a
deobfuscation rule for a simple obfuscation technique.&lt;/em>&lt;/p>
&lt;ul>
&lt;li>&lt;a href="#story-setup">Story Setup&lt;/a> - introduction and problem statement&lt;/li>
&lt;li>&lt;a href="#decompiler-101">Decompiler 101&lt;/a> - building and using Ghidra decompiler directly&lt;/li>
&lt;li>&lt;a href="#rulecompile">RULECOMPILE&lt;/a> - a curious #define flag from the decompiler source&lt;/li>
&lt;li>&lt;a href="#a-forgotten-language-of-dragons">A forgotten language of dragons&lt;/a> - reverse-engineering a forgotten code pattern matching DSL&lt;/li>
&lt;li>&lt;a href="#how-to-train-your-dragon">How to train your dragon&lt;/a> - how to write a rule that is actually useful&lt;/li>
&lt;li>&lt;a href="#conclusion">Conclusion&lt;/a> - parting thoughts&lt;/li>
&lt;/ul>
&lt;h2 id="story-setup">Story setup&lt;/h2>
&lt;p>It all started with this one missed deobfuscation:&lt;/p>
&lt;p>
&lt;img src="https://msm.lt/re/ghidra/rulecompile/start.png" alt="" >
&lt;/p>
&lt;p>Do you know what this function does? Take a few seconds to think about it, if you want.&lt;/p>
&lt;p>&amp;hellip;&lt;/p>
&lt;p>&amp;hellip;&lt;/p>
&lt;p>Yes, this is just a simple incrementation. Consider the lowest bit of &lt;code>param_1&lt;/code>:&lt;/p>
&lt;ul>
&lt;li>if &lt;code>param1 &amp;amp; 1&lt;/code> is 0, then &lt;code>(param1 &amp;amp; 1) * 2&lt;/code> is zero too, and &lt;code>param1 ^ 1&lt;/code> is just &lt;code>param1 + 1&lt;/code>.&lt;/li>
&lt;li>if &lt;code>param1 &amp;amp; 1&lt;/code> is 1, then &lt;code>(param1 &amp;amp; 1) * 2&lt;/code> equals 2, but &lt;code>param1 ^ 1&lt;/code> is now &lt;code>param1 - 1&lt;/code>, so the result is &lt;code>param1 + 1&lt;/code> again.&lt;/li>
&lt;/ul>
&lt;p>What can we do to clean this up? There are several possible courses of action. Let&amp;rsquo;s consider them one by one:&lt;/p>
&lt;h4 id="ignore-the-problem">Ignore the problem&lt;/h4>
&lt;p>We can &lt;strong>ignore the problem&lt;/strong> entirely and live with it - the pattern is easy to spot,
and we already recognise it. This is probably the sanest option. As you may guess, I didn&amp;rsquo;t pursue it, though maybe I should.&lt;/p>
&lt;h4 id="fix-it-with-a-script">Fix it with a script&lt;/h4>
&lt;p>Maybe we can write a Ghidra script that will fix the decompilation?&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> Well, no.
Unfortunately, &lt;strong>Ghidra is not very flexible when one wants to influence the decompiler&lt;/strong>.
The decompiler is almost a blackbox that we can just
nudge in the right directions. Almost all analysis happen in there:&lt;/p>
&lt;ul>
&lt;li>Raw bytes are disassembled and translated to Pcode using SLEIGH&lt;/li>
&lt;li>Pcode is optimized and lifted to high Pcode&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup>&lt;/li>
&lt;li>High-level programing language structures - loops, conditionals, control flow - are recovered&lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup>&lt;/li>
&lt;li>A tokenized version of decompiled source code is generated and sent back to Ghidra.&lt;/li>
&lt;/ul>
&lt;p>With &lt;a href="https://raw.githubusercontent.com/NationalSecurityAgency/ghidra/refs/heads/master/Ghidra/Features/Decompiler/src/main/help/help/topics/DecompilePlugin/DecompilerAnnotations.html">few exceptions&lt;/a>,
none of these steps can be influenced by a script/extension/program annotations.&lt;/p>
&lt;h4 id="patch-the-assembly-code">Patch the assembly code&lt;/h4>
&lt;p>This one is actually doable - we can patch the binary assembly code and replace it that whols
section with incrementation. But that has &lt;strong>a lot of downsides&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>Our code is now architecture dependent - even though the rule is very generic, and Ghidra works with dozens of architectures thanks to PCode.&lt;/li>
&lt;li>It may be very hard to match the obfuscation pattern - especially if the code we see is already a simplified version of the original, much more obfuscated code.&lt;/li>
&lt;li>We have to patch the binary, which is invasive and may make the binary unrunnable.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>In practice this is what I do&lt;/strong> when I have to, but I wish there was a better way.&lt;/p>
&lt;h4 id="improve-the-decompiler-and-submit-a-pull-request">Improve the decompiler and submit a pull request&lt;/h4>
&lt;p>In principle, this is the best option. Ghidra is &lt;a href="https://github.com/NationalSecurityAgency/ghidra/">open-source&lt;/a>,
so we can grab the source code, make our changes, and maybe submit a pull request.&lt;/p>
&lt;p>The problem is that decompiler is a
&lt;a href="https://github.com/NationalSecurityAgency/ghidra/tree/master/Ghidra/Features/Decompiler/src/decompile/cpp">complex&lt;/a>
piece of software, so that&amp;rsquo;s a non-trivial task. A large upside is that we can submit
our changes to the official Ghidra repository as a pull request, so that &lt;strong>everyone can benefit&lt;/strong> from them.
Unfortunately, there&amp;rsquo;s not many people who can review such a pull request, so they
tend to &lt;a href="https://github.com/NationalSecurityAgency/ghidra/pull/6070">wait forever&lt;/a> for merging.
So, unless you&amp;rsquo;re very dedicated, there is &lt;strong>no way to share your improvements with the community&lt;/strong>.&lt;/p>
&lt;p>What if there was an easier way?&lt;/p>
&lt;h2 id="decompiler-101">Decompiler 101&lt;/h2>
&lt;p>Let&amp;rsquo;s take a closer look at the decompiler. I didn&amp;rsquo;t get around to post about it yet&lt;sup id="fnref:4">&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref">4&lt;/a>&lt;/sup>,
but long story short: there is a internal debugger tool, not build
by default, that you can use to peek into the decompiler internals. It&amp;rsquo;s called
&lt;code>decomp_dbg&lt;/code>, and the best public source of information about it right now is
&lt;a href="https://www.nccgroup.com/us/research-blog/earlyremoval-in-the-conservatory-with-the-wrench-exploring-ghidra-s-decompiler-internals-to-make-automatic-p-code-analysis-scripts/">this nccgroup blog post&lt;/a>.
and &lt;a href="https://github.com/NationalSecurityAgency/ghidra/issues/720">this Github issue&lt;/a>.&lt;/p>
&lt;p>I&amp;rsquo;ll update this section with a link to a more detailed post when/if I write it,
but for now the point is that you can go to &lt;code>Ghidra/Features/Decompiler/src/decompile/cpp&lt;/code>,
run &lt;code>make decomp_dbg&lt;/code>, and get a &lt;code>decomp_dbg&lt;/code> binary. For this blog post, I will use the
&lt;a href="https://github.com/NationalSecurityAgency/ghidra/releases/tag/Ghidra_11.2.1_build">ghidra 11.2.1 release&lt;/a>
(Ghidra_11.1.2_build tag in the git repository).&lt;/p>
&lt;p>Let&amp;rsquo;s try it. First, download this &lt;a href="./obfuscated">obfuscated binary&lt;/a>.
You can check it in Ghidra - the main function is just &lt;code>return argc&lt;/code>,
but obfuscated with the technique I mentioned above. There is an option
to &amp;ldquo;debug function decompilation&amp;rdquo; in Ghidra, which we can use to analyse
the decompilation process:&lt;/p>
&lt;p>
&lt;img src="https://msm.lt/re/ghidra/rulecompile/export.png" alt="" >
&lt;/p>
&lt;p>But we won&amp;rsquo;t actually use it in this blog post&lt;sup id="fnref:5">&lt;a href="#fn:5" class="footnote-ref" role="doc-noteref">5&lt;/a>&lt;/sup>. So let&amp;rsquo;s run &lt;code>decomp_dbg&lt;/code> on the binary directly:&lt;/p>
&lt;pre tabindex="0">&lt;code>$ set -x SLEIGHHOME ~/opt/ghidra # export SLEIGHHOME=... for bash users
$ ./decomp_dbg
[decomp]&amp;gt; load file /home/you/xyz/obfuscated
[decomp]&amp;gt; load addr 0x0101129
Low-level ERROR: Unable to load 512 bytes at r0x00101129
Unable to proceed with function: func_0x00101129
&lt;/code>&lt;/pre>&lt;p>Wait, what? This worked for me before. After a quick look at the source code
and a lucky guess, another try:&lt;/p>
&lt;pre tabindex="0">&lt;code>$ set -x SLEIGHHOME ~/opt/ghidra # export SLEIGHHOME=... for bash users
$ ./decomp_dbg
[decomp]&amp;gt; load file /home/you/xyz/obfuscated
[decomp]&amp;gt; adjust vma 0x100000
[decomp]&amp;gt; load addr 0x0101129
Function func_0x00101129: 0x00101129
&lt;/code>&lt;/pre>&lt;p>Now we are free to decompile to our heart&amp;rsquo;s content:&lt;/p>
&lt;pre tabindex="0">&lt;code>[decomp]&amp;gt; decompile
Decompiling func_0x00101129
Decompilation complete
[decomp]&amp;gt; print C
int4 func_0x00101129(uint4 param_1)
{
return (param_1 &amp;amp; 1) * 2 + (param_1 ^ 1);
}
&lt;/code>&lt;/pre>&lt;h2 id="rulecompile">RULECOMPILE&lt;/h2>
&lt;p>This begs the question&lt;sup id="fnref:6">&lt;a href="#fn:6" class="footnote-ref" role="doc-noteref">6&lt;/a>&lt;/sup>, what other features are possible? The list is in the
&lt;a href="https://github.com/NationalSecurityAgency/ghidra/blob/master/Ghidra/Features/Decompiler/src/decompile/cpp/ifacedecomp.cc">ifacedecomp.cc&lt;/a>
file. But wait, what is this?&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cpp" data-lang="cpp">&lt;span style="display:flex;">&lt;span> status&lt;span style="color:#f92672">-&amp;gt;&lt;/span>registerCom(&lt;span style="color:#66d9ef">new&lt;/span> IfcLoadTestFile(), &lt;span style="color:#e6db74">&amp;#34;load&amp;#34;&lt;/span>,&lt;span style="color:#e6db74">&amp;#34;test&amp;#34;&lt;/span>,&lt;span style="color:#e6db74">&amp;#34;file&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> status&lt;span style="color:#f92672">-&amp;gt;&lt;/span>registerCom(&lt;span style="color:#66d9ef">new&lt;/span> IfcListTestCommands(), &lt;span style="color:#e6db74">&amp;#34;list&amp;#34;&lt;/span>,&lt;span style="color:#e6db74">&amp;#34;test&amp;#34;&lt;/span>,&lt;span style="color:#e6db74">&amp;#34;commands&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> status&lt;span style="color:#f92672">-&amp;gt;&lt;/span>registerCom(&lt;span style="color:#66d9ef">new&lt;/span> IfcExecuteTestCommand(), &lt;span style="color:#e6db74">&amp;#34;execute&amp;#34;&lt;/span>,&lt;span style="color:#e6db74">&amp;#34;test&amp;#34;&lt;/span>,&lt;span style="color:#e6db74">&amp;#34;command&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#ifdef CPUI_RULECOMPILE
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> status&lt;span style="color:#f92672">-&amp;gt;&lt;/span>registerCom(&lt;span style="color:#66d9ef">new&lt;/span> IfcParseRule(),&lt;span style="color:#e6db74">&amp;#34;parse&amp;#34;&lt;/span>,&lt;span style="color:#e6db74">&amp;#34;rule&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> status&lt;span style="color:#f92672">-&amp;gt;&lt;/span>registerCom(&lt;span style="color:#66d9ef">new&lt;/span> IfcExperimentalRules(),&lt;span style="color:#e6db74">&amp;#34;experimental&amp;#34;&lt;/span>,&lt;span style="color:#e6db74">&amp;#34;rules&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#endif
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> status&lt;span style="color:#f92672">-&amp;gt;&lt;/span>registerCom(&lt;span style="color:#66d9ef">new&lt;/span> IfcContinue(),&lt;span style="color:#e6db74">&amp;#34;continue&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Two commands are fenced behind a feature flag - undocumented and not enabled by default&lt;/strong>.
As of today, googling &lt;code>CPUI_RULECOMPILE&lt;/code> returns only three results,
two of them are source code from the official Github and the last one from a source code mirror.&lt;sup id="fnref:7">&lt;a href="#fn:7" class="footnote-ref" role="doc-noteref">7&lt;/a>&lt;/sup>&lt;/p>
&lt;p>Let&amp;rsquo;s try to enable it! Just add the flag to the makefile and build:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-diff" data-lang="diff">&lt;span style="display:flex;">&lt;span>$ git diff
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/Makefile b/Ghidra/Features/Decompiler/src/decompile/cpp/Makefile
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>index ead17e0..3946e17 100755
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">--- a/Ghidra/Features/Decompiler/src/decompile/cpp/Makefile
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">&lt;/span>&lt;span style="color:#a6e22e">+++ b/Ghidra/Features/Decompiler/src/decompile/cpp/Makefile
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">&lt;/span>&lt;span style="color:#75715e">@@ -38,7 +38,7 @@ endif
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> CXX=g++ -std=c++11
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> # Debug flags
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">-DBG_CXXFLAGS=-g -Wall -Wno-sign-compare
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">&lt;/span>&lt;span style="color:#a6e22e">+DBG_CXXFLAGS=-g -Wall -Wno-sign-compare -DCPUI_RULECOMPILE
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">&lt;/span> #DBG_CXXFLAGS=-g -pg -Wall -Wno-sign-compare
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> #DBG_CXXFLAGS=-g -fprofile-arcs -ftest-coverage -Wall -Wno-sign-compare
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ make decomp_dbg -j 8
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Annnnd it doesn&amp;rsquo;t work - we get tons of compiler errors:&lt;/p>
&lt;pre tabindex="0">&lt;code>architecture.cc: In member function ‘void ghidra::Architecture::decodeDynamicRule(ghidra::Decoder&amp;amp;)’:
architecture.cc:729:57: error: ‘el’ was not declared in this scope
729 | Rule *dynrule = RuleGeneric::build(rulename,groupname,el-&amp;gt;getContent());
In copy constructor ‘ghidra::Address::Address(const ghidra::Address&amp;amp;)’,
inlined from ‘ghidra::rangemap&amp;lt;ghidra::ScopeMapper&amp;gt;::AddrRange::AddrRange(ghidra::rangemap&amp;lt;ghidra::ScopeMapper&amp;gt;::AddrRange&amp;amp;&amp;amp;)’ at rangemap.hh:76:9,
inlined from ‘void std::__new_allocator&amp;lt;_Tp&amp;gt;::construct(_Up*, _Args&amp;amp;&amp;amp; ...) [with _Up = ghidra::rangemap&amp;lt;ghidra::ScopeMapper&amp;gt;::AddrRange; _Args = {ghidra::rangemap&amp;lt;ghidra::ScopeMapper&amp;gt;::AddrRange}; _Tp = std::_Rb_tree_node&amp;lt;ghidra::rangem
ap&amp;lt;ghidra::ScopeMapper&amp;gt;::AddrRange&amp;gt;]’ at /nix/store/4krab2h0hd4wvxxmscxrw21pl77j4i7j-gcc-13.3.0/include/c++/13.3.0/bits/new_allocator.h:191:4,
inlined from ‘static void std::allocator_traits&amp;lt;std::allocator&amp;lt;_CharT&amp;gt; &amp;gt;::construct(allocator_type&amp;amp;, _Up*, _Args&amp;amp;&amp;amp; ...) [with _Up = ghidra::rangemap&amp;lt;ghidra::ScopeMapper&amp;gt;::AddrRange; _Args = {ghidra::rangemap&amp;lt;ghidra::ScopeMapper&amp;gt;::AddrRa
nge}; _Tp = std::_Rb_tree_node&amp;lt;ghidra::rangemap&amp;lt;ghidra::ScopeMapper&amp;gt;::AddrRange&amp;gt;]’ at /nix/store/4krab2h0hd4wvxxmscxrw21pl77j4i7j-gcc-13.3.0/include/c++/13.3.0/bits/alloc_traits.h:538:17,
&lt;/code>&lt;/pre>&lt;p>Apparently nobody tried to compile with this feature enabled in a long time. Let&amp;rsquo;s try to fix it.&lt;/p>
&lt;p>First of all, we don&amp;rsquo;t have &lt;code>ruleparse.cc&lt;/code> nor &lt;code>ruleparse.hh&lt;/code> files, but we have &lt;code>ruleparse.y&lt;/code>.
For those of you who attended a compiler course, this is a YACC file and we can build it with bison:&lt;/p>
&lt;pre tabindex="0">&lt;code>$ make ruleparse.cc ruleparse.hh
bison -p ruleparse -d -o ruleparse.cc ruleparse.y
&lt;/code>&lt;/pre>&lt;p>Then let&amp;rsquo;s hunt copilation errors one by one. I&amp;rsquo;ll spare you the boring details, and
just show my ugly patch:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-diff" data-lang="diff">&lt;span style="display:flex;">&lt;span>diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>index 494d160..8ac2725 100755
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">--- a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">&lt;/span>&lt;span style="color:#a6e22e">+++ b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">&lt;/span>&lt;span style="color:#75715e">@@ -726,7 +726,7 @@ void Architecture::decodeDynamicRule(Decoder &amp;amp;decoder)
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> throw LowlevelError(&amp;#34;Dynamic rule has no group&amp;#34;);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> if (!enabled) return;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> #ifdef CPUI_RULECOMPILE
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">- Rule *dynrule = RuleGeneric::build(rulename,groupname,el-&amp;gt;getContent());
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">&lt;/span>&lt;span style="color:#a6e22e">+ Rule *dynrule = RuleGeneric::build(rulename,groupname, (reinterpret_cast&amp;lt;XmlDecode*&amp;gt;(&amp;amp;decoder))-&amp;gt;getCurrentXmlElement()-&amp;gt;getContent());
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">&lt;/span> extra_pool_rules.push_back(dynrule);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> #else
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> throw LowlevelError(&amp;#34;Dynamic rules have not been enabled for this decompiler&amp;#34;);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/rulecompile.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/rulecompile.cc
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>index fe8a413..f346ce9 100755
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">--- a/Ghidra/Features/Decompiler/src/decompile/cpp/rulecompile.cc
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">&lt;/span>&lt;span style="color:#a6e22e">+++ b/Ghidra/Features/Decompiler/src/decompile/cpp/rulecompile.cc
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">&lt;/span>&lt;span style="color:#75715e">@@ -14,14 +14,19 @@
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> * limitations under the License.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> */
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> #ifdef CPUI_RULECOMPILE
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">-#include &amp;#34;rulecompile.hh&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">-#include &amp;#34;ruleparse.hh&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">&lt;/span>&lt;span style="color:#a6e22e">+
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">+#include &amp;#34;types.h&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">+#include &amp;lt;string&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">+using std::string;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">+using namespace ghidra;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">+
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">+
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">+int4 ruleparsedebug;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">+extern int4 ruleparseparse(void);
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> namespace ghidra {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> RuleCompile *rulecompile;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">-extern int4 ruleparsedebug;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">-extern int4 ruleparseparse(void);
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> class MyLoadImage : public LoadImage { // Dummy loadimage
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> public:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleparse.y b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleparse.y
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>index 3d3ced6..32f42ff 100755
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">--- a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleparse.y
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">&lt;/span>&lt;span style="color:#a6e22e">+++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleparse.y
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">&lt;/span>&lt;span style="color:#75715e">@@ -15,11 +15,19 @@
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> */
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> %{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> #ifdef CPUI_RULECOMPILE
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">+
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">+#include &amp;#34;types.h&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">+#include &amp;lt;string&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">+using std::string;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">+
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">&lt;/span> #include &amp;#34;rulecompile.hh&amp;#34;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> #define YYERROR_VERBOSE
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">+using namespace ghidra;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">+namespace ghidra {
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">&lt;/span> extern RuleCompile *rulecompile;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">+}
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">&lt;/span> extern int ruleparselex(void);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> extern int ruleparseerror(const char *str);
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>NB: these are just hacks to make it compile, not a proper fix.&lt;/p>
&lt;p>Anyway, with these fixes we can compile &lt;code>decomp_dbg&lt;/code> and run it:&lt;/p>
&lt;pre tabindex="0">&lt;code>$ set -x SLEIGHHOME ~/opt/ghidra # export SLEIGHHOME=... for bash users
$ ./decomp_dbg
[decomp]&amp;gt; experimental rules
Command parsing error: Missing name of file containing experimental rules
&lt;/code>&lt;/pre>&lt;p>Ok&amp;hellip; now what?&lt;/p>
&lt;h4 id="into-the-xml-hell">Into the XML hell&lt;/h4>
&lt;p>Since there&amp;rsquo;s no documentation, we have to figure out how to use this by reading
the source code. I&amp;rsquo;ll focus on the &lt;code>experimental rules&lt;/code> command (it is used
to load and enable the decompiler rules). If we try to load a random file, we get a syntax error:&lt;/p>
&lt;pre tabindex="0">&lt;code>[decomp]&amp;gt; experimental rules /etc/passwd
Successfully registered experimental file /etc/passwd
[decomp]&amp;gt; [decomp]&amp;gt; load file /home/you/xyz/obfuscated
ERROR: Invalid command
[decomp]&amp;gt; load file /home/you/xyz/obfuscated
Trying to parse /etc/passwd for experimental rules
syntax error
Skipping experimental rules
/home/you/xyz/obfuscated successfully loaded: Intel/AMD 64-bit x86
&lt;/code>&lt;/pre>&lt;p>Let&amp;rsquo;s dig into a source code:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cpp" data-lang="cpp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">*&lt;/span>status&lt;span style="color:#f92672">-&amp;gt;&lt;/span>optr &lt;span style="color:#f92672">&amp;lt;&amp;lt;&lt;/span> &lt;span style="color:#e6db74">&amp;#34;Trying to parse &amp;#34;&lt;/span> &lt;span style="color:#f92672">&amp;lt;&amp;lt;&lt;/span> dcp&lt;span style="color:#f92672">-&amp;gt;&lt;/span>experimental_file &lt;span style="color:#f92672">&amp;lt;&amp;lt;&lt;/span> &lt;span style="color:#e6db74">&amp;#34; for experimental rules&amp;#34;&lt;/span> &lt;span style="color:#f92672">&amp;lt;&amp;lt;&lt;/span> endl;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">try&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Element &lt;span style="color:#f92672">*&lt;/span>root &lt;span style="color:#f92672">=&lt;/span> store.openDocument(dcp&lt;span style="color:#f92672">-&amp;gt;&lt;/span>experimental_file)&lt;span style="color:#f92672">-&amp;gt;&lt;/span>getRoot();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> (root&lt;span style="color:#f92672">-&amp;gt;&lt;/span>getName() &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#e6db74">&amp;#34;experimental_rules&amp;#34;&lt;/span>) store.registerTag(root);
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>OK, so we need XML. By digging further, we deduce that the file should look like this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">&amp;lt;experimental_rules&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;rule&lt;/span> &lt;span style="color:#a6e22e">name=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;rule_name&amp;#34;&lt;/span> &lt;span style="color:#a6e22e">group=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;group_name&amp;#34;&lt;/span> &lt;span style="color:#a6e22e">enable=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;true&amp;#34;&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ???
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/rule&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">&amp;lt;/experimental_rules&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Rule name is arbitrary, and group may be &lt;code>analysis&lt;/code> for example (this determines when
our rule gets to execute). But what do we put inside? We have to read the YACC grammar to understand the syntax. The grammar,
untouched since the initial Ghidra release, is
&lt;a href="https://github.com/NationalSecurityAgency/ghidra/blob/master/Ghidra/Features/Decompiler/src/decompile/cpp/ruleparse.y">here&lt;/a>.
It should look familiar if you ever wrote a BNF parser. For example,&lt;/p>
&lt;pre tabindex="0">&lt;code>fullrule: &amp;#39;{&amp;#39; statementlist actionlist &amp;#39;}&amp;#39;
&lt;/code>&lt;/pre>&lt;p>Means that the full rule consists of a literal &lt;code>{&lt;/code> followed by a &lt;code>statementlist&lt;/code> followed by an &lt;code>actionlist&lt;/code>
followed by a literal &lt;code>}&lt;/code>. Similarly, we can investigate &lt;code>statementlist&lt;/code> and &lt;code>actionlist&lt;/code>, and so on.&lt;/p>
&lt;p>There is one thing that can help us - &lt;strong>a comment left in rulecompile.hh&lt;/strong>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cpp" data-lang="cpp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">/*
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> Definition of the language
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> Identifiers start with &amp;#39;o&amp;#39; for named pcodeops
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> &amp;#39;v&amp;#39; for named varnodes
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> &amp;#39;#&amp;#39; for named constants
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> A &amp;#34;statement&amp;#34; is a sequence of &amp;#34;steps&amp;#34;, ending in a semicolon
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> Steps are sequential, proceeding left to right. Each step is either a
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> building step (which defines a new entity in terms of an existing entity), or a
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> constraint (which forces a condition to be true)
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> Building steps:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> o -&amp;gt; v v is the output of o
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> o1 -&amp;gt; o2 o2 is a (named) copy of o1
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> o &amp;lt;- v v is ANY input of o
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> o &amp;lt;-(0) v v is input 0 of o
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> o &amp;lt;-(1) #c input 1 to o is a constant (now named c)
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> o &amp;lt;-(1) #0 input 1 to o is a constant with value 0
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> v &amp;lt;- o o is the defining op of v
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> v -&amp;gt; o o is ANY of the ops taking v as an input (may be inefficient)
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> v -&amp;gt;! o o is the one and only op taking v as input
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> v1 -&amp;gt; v2 v2 is a (named) copy of v1
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> Constraints:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> o(+) o must have an opcode equal &amp;#39;+&amp;#39;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> o1(== o2) o1 and o2 must be the same pcode op
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> o1(!= o2) o1 and o2 must not be the same pcode op
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> v1(== v2) v1 and v2 must be the same varnode
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> v1(!= v2) v1 and v2 must not be the same varnode
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> Statements can be grouped (into &amp;#34;statementlist&amp;#34;) with parentheses &amp;#39;(&amp;#39; and &amp;#39;)&amp;#39;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> There is an OR operator
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> &amp;#39;[&amp;#39; statementlist
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> | statementlist
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> ...
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> &amp;#39;]&amp;#39;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> */&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>That comment is not wrong, but it&amp;rsquo;s also incomplete. How do we actually create a complete rule? Let&amp;rsquo;s dig in deeper.&lt;/p>
&lt;h2 id="a-forgotten-language-of-dragons">A forgotten language of dragons&lt;/h2>
&lt;p>First things first. We already know that&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-yacc" data-lang="yacc">fullrule: &amp;#39;{&amp;#39; statementlist actionlist &amp;#39;}&amp;#39;
&lt;/code>&lt;/pre>&lt;p>An abridged version of other important parts of the grammar (with C++ snippets removed) is:&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-yacc" data-lang="yacc">statement: opnode &amp;#39;;&amp;#39; { ... }
| varnode &amp;#39;;&amp;#39; { ... }
| deadnode &amp;#39;;&amp;#39; { ... }
| &amp;#39;[&amp;#39; orgroupmid &amp;#39;]&amp;#39; { ... }
| &amp;#39;(&amp;#39; statementlist &amp;#39;)&amp;#39; { ... }
opnode: op_ident { ... }
| opnode &amp;#39;(&amp;#39; op_list &amp;#39;)&amp;#39; { ... }
...;
varnode: var_ident { ... }
| opnode LEFT_ARROW &amp;#39;(&amp;#39; INTB &amp;#39;)&amp;#39; var_ident { ... }
| opnode LEFT_ARROW var_ident { ... }
| opnode RIGHT_ARROW var_ident { ... }
| varnode &amp;#39;(&amp;#39; OP_INT_EQUAL var_ident &amp;#39;)&amp;#39; { ... }
...;
deadnode: opnode LEFT_ARROW &amp;#39;(&amp;#39; INTB &amp;#39;)&amp;#39; rhs_const { ... }
| opnode &amp;#39;=&amp;#39; op_ident { ... }
...;
actionlist: ACTION_TICK { ... }
| actionlist action { ... };
action: opnewnode &amp;#39;;&amp;#39; { ... }
| varnewnode &amp;#39;;&amp;#39; { ... }
| deadnewnode &amp;#39;;&amp;#39; { ... };
varnewnode: opnewnode DOUBLE_LEFT_ARROW &amp;#39;(&amp;#39; rhs_const &amp;#39;)&amp;#39; var_ident { ... }
...;
deadnewnode: opnewnode DOUBLE_LEFT_ARROW &amp;#39;(&amp;#39; rhs_const &amp;#39;)&amp;#39; rhs_const var_size { ... }
...;
&lt;/code>&lt;/pre>&lt;p>So we have statements followed by ACTION_TICK followed by actions, and they both consist of
&amp;ldquo;opnodes&amp;rdquo;, &amp;ldquo;varnodes&amp;rdquo; and &amp;ldquo;deadnodes&amp;rdquo;. The high-level structure of the experimental rule file is therefore:&lt;/p>
&lt;pre tabindex="0">&lt;code>{
statements
--
actions
}
&lt;/code>&lt;/pre>&lt;p>And the possible statements are (among many others)&lt;/p>
&lt;ul>
&lt;li>Opnodes: &lt;code>o1&lt;/code>, &lt;code>o1(+)&lt;/code>, &amp;hellip;&lt;/li>
&lt;li>Varnodes: &lt;code>o1 &amp;lt;- v1&lt;/code>, &lt;code>o1 &amp;lt;-(1) v1&lt;/code>, &lt;code>o1 -&amp;gt; v1&lt;/code>, &lt;code>v1(== v2)&lt;/code>&lt;/li>
&lt;li>Deadnodes: &lt;code>o1 &amp;lt;-(1) 123&lt;/code>, &lt;code>o1 = o2&lt;/code>, &amp;hellip;&lt;/li>
&lt;/ul>
&lt;p>And for the actions (among many others):&lt;/p>
&lt;ul>
&lt;li>Opnewnodes: &lt;code>o1&lt;/code>&lt;/li>
&lt;li>Varnewnodes: &lt;code>o1 &amp;lt;--(1) v1&lt;/code>&lt;/li>
&lt;li>Deadnewnodes: &lt;code>o1 &amp;lt;--(1) 123 4&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>Now that &lt;em>still&lt;/em> doesn&amp;rsquo;t explain how to use it, but at least we can make &lt;strong>a file that we can parse&lt;/strong>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">&amp;lt;experimental_rules&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;rule&lt;/span> &lt;span style="color:#a6e22e">name=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;rule_name&amp;#34;&lt;/span> &lt;span style="color:#a6e22e">group=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;group_name&amp;#34;&lt;/span> &lt;span style="color:#a6e22e">enable=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;true&amp;#34;&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> o1(+) -&amp;gt; v1;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> o2;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> o3;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> o2 &amp;amp;lt; v1;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/rule&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">&amp;lt;/experimental_rules&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And it does parse:&lt;sup id="fnref:8">&lt;a href="#fn:8" class="footnote-ref" role="doc-noteref">8&lt;/a>&lt;/sup>&lt;/p>
&lt;pre tabindex="0">&lt;code>[decomp]&amp;gt; experimental rules /home/you/xyz/test.xml
Successfully registered experimental file /home/you/xyz/test.xml
[decomp]&amp;gt; load file /home/you/xyz/obfuscated
Trying to parse /home/you/xyz/test.xml for experimental rules
Unable to parse dynamic rule: rule_name
Could not create architecture
[decomp]&amp;gt; adjust vma 0x100000
Execution error: No load image present
[decomp]&amp;gt; load addr 0x0101129
fish: Process 914812, &amp;#39;./decomp_dbg&amp;#39; from job 1, &amp;#39;./decomp_dbg&amp;#39; terminated by signal SIGSEGV (Address boundary error)
&lt;/code>&lt;/pre>&lt;p>Well, it&amp;rsquo;s not perfect yet, but we&amp;rsquo;re getting there.&lt;/p>
&lt;h2 id="how-to-train-your-dragon">How to train your dragon&lt;/h2>
&lt;p>Now the fun part. After reading the code and debugging segfaults (lots of segfaults&lt;sup id="fnref:9">&lt;a href="#fn:9" class="footnote-ref" role="doc-noteref">9&lt;/a>&lt;/sup>) with gdb, I
figured out the rules:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Statements&lt;/strong> describe what we want to match&lt;/li>
&lt;li>&lt;strong>Actions&lt;/strong> describe how we want to transform the matched AST.&lt;/li>
&lt;li>&lt;strong>Opnodes&lt;/strong> are the (pcode) operations we want to optimize&lt;/li>
&lt;li>&lt;strong>Varnodes&lt;/strong> are, well, varnodes - the operands pcode operations take&lt;/li>
&lt;li>&lt;strong>Deadnodes&lt;/strong> are not actually dead operations, they perform operations on defined varnodes and opnodes.&lt;/li>
&lt;/ul>
&lt;p>So in the &lt;strong>statement section&lt;/strong>, we can write for example:&lt;/p>
&lt;ul>
&lt;li>&lt;code>o1&lt;/code> - match any operation (and name it &lt;code>o1&lt;/code>).&lt;/li>
&lt;li>&lt;code>o1(+)&lt;/code> - match any addition operation (and name it &lt;code>o1&lt;/code>).&lt;/li>
&lt;li>&lt;code>v1&lt;/code> - match any varnode (value) (and name it &lt;code>v1&lt;/code>).&lt;/li>
&lt;li>&lt;code>v1(==v2)&lt;/code> - match any varnode &lt;code>v1&lt;/code>, as long as it&amp;rsquo;s equal to &lt;code>v2&lt;/code>.&lt;/li>
&lt;li>&lt;code>o1 &amp;lt;- v1&lt;/code> - match any operation &lt;code>o1&lt;/code>, with &lt;code>v1&lt;/code> being any of its operands.&lt;/li>
&lt;li>&lt;code>o1 &amp;lt;-(0) v1&lt;/code> - match any operation &lt;code>o1&lt;/code>, with &lt;code>v1&lt;/code> being the first operand.&lt;/li>
&lt;li>&lt;code>o1(+) &amp;lt;- v1&lt;/code> - match any addition operation &lt;code>o1&lt;/code>, with &lt;code>v1&lt;/code> being any of the oprands.&lt;/li>
&lt;li>&lt;code>o1 &amp;lt;-(1) 123&lt;/code> - match any addition operation &lt;code>o1&lt;/code>, with 123 being the second operand.&lt;/li>
&lt;li>&lt;code>o1 &amp;lt;- v2 &amp;lt;- o3&lt;/code> - match any operation &lt;code>o1&lt;/code>, with &lt;code>v1&lt;/code> being any of its operands, and &lt;code>o3&lt;/code> using &lt;code>v1&lt;/code>.&lt;/li>
&lt;/ul>
&lt;p>And so on. In the &lt;strong>action section&lt;/strong> we define how we want to transform the AST, so for example:&lt;/p>
&lt;ul>
&lt;li>&lt;code>o1 &amp;lt;--(0) v1&lt;/code> - make &lt;code>v1&lt;/code> the first operand of &lt;code>o1&lt;/code>.&lt;/li>
&lt;li>&lt;code>o1 &amp;lt;--(1) 42&lt;/code> - make &lt;code>42&lt;/code> the second operand of &lt;code>o1&lt;/code>.&lt;/li>
&lt;/ul>
&lt;p>There&amp;rsquo;s more, for example we can match on more complex conditions or create new nodes in the action section,
but we won&amp;rsquo;t need that for this blog post. So &lt;strong>a very simple rule&lt;/strong> that is not a NOP is:&lt;/p>
&lt;pre tabindex="0">&lt;code>{
o1(+);
--
o1 &amp;lt;-- (0) 0;
o1 &amp;lt;-- (1) 0;
}
&lt;/code>&lt;/pre>&lt;p>Literally: &amp;ldquo;match any addition operation &lt;code>o1&lt;/code>, and replace both operands with 0&amp;rdquo;. Let&amp;rsquo;s try it on our program:&lt;/p>
&lt;pre tabindex="0">&lt;code>$ decomp_dbg
...
[decomp]&amp;gt; decompile
Decompiling func_0x00101129
Decompilation complete
[decomp]&amp;gt; print C
xunknown8 func_0x00101129(void)
{
xRam0000000000000000 = 0;
return 0;
}
&lt;/code>&lt;/pre>&lt;p>Great! As expected, the code simplified greatly (since we just removed all additions from our program).
Getting to that point was tough, but now that we understand what&amp;rsquo;s going on it&amp;rsquo;s getting much easier.&lt;/p>
&lt;p>Let&amp;rsquo;s go back to the original obfuscation and try to match the whole operation:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cpp" data-lang="cpp">&lt;span style="display:flex;">&lt;span>int4 &lt;span style="color:#a6e22e">main&lt;/span>(uint4 param_1) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> (param_1 &lt;span style="color:#f92672">&amp;amp;&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>) &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span> &lt;span style="color:#f92672">+&lt;/span> (param_1 &lt;span style="color:#f92672">^&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>We have several constraints:&lt;/p>
&lt;ul>
&lt;li>The root of the AST tree that we want to match is a &lt;code>+&lt;/code> operation.&lt;/li>
&lt;li>One of &lt;code>+&lt;/code> operands should be &lt;code>^&lt;/code>&lt;/li>
&lt;li>The other operand of &lt;code>+&lt;/code> must be &lt;code>*&lt;/code>&lt;/li>
&lt;li>And the other operand of &lt;code>+&lt;/code> must be &lt;code>&amp;amp;&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>Let&amp;rsquo;s try to model this using our grammar knowledge:&lt;/p>
&lt;pre tabindex="0">&lt;code>{
o_plus(+) &amp;lt;- v1 &amp;lt;- o_mul(*) &amp;lt;- v2 &amp;lt;- o_and(&amp;amp;);
o_plus(+) &amp;lt;- v4 &amp;lt;- o_xor(^);
--
o_plus &amp;lt;-- (0) 0;
o_plus &amp;lt;-- (1) 0;
}
&lt;/code>&lt;/pre>&lt;p>For the action I still use the &amp;ldquo;zero everything rule&amp;rdquo;, to make sure the rule still matches. And it does:&lt;/p>
&lt;pre tabindex="0">&lt;code>$ decomp_dbg
...
[decomp]&amp;gt; print C
xunknown8 func_0x00101129(void)
{
xRam0000000000000000 = 0;
return 0;
}
&lt;/code>&lt;/pre>&lt;p>We&amp;rsquo;re not done yet - we don&amp;rsquo;t check the constants or variables anywhere, so our rule will also match &lt;code>(a &amp;amp; 123) * 13 + (b ^ 123)&lt;/code> for example.
That&amp;rsquo;s not what we want. Let&amp;rsquo;s fix it. There are probably more elegant ways to achieve this, but I did this in the simplest way I could think of:&lt;/p>
&lt;pre tabindex="0">&lt;code>{
o_plus(+) &amp;lt;- v1 &amp;lt;- o_mul(*) &amp;lt;- v2 &amp;lt;- o_and(&amp;amp;);
o_plus(+) &amp;lt;- v4 &amp;lt;- o_xor(^);
[ o_xor &amp;lt;-(0) 1; o_xor &amp;lt;-(1) vin; | o_xor &amp;lt;-(1) 1; o_xor &amp;lt;-(0) vin; ]
[ o_and &amp;lt;-(0) 1; o_and &amp;lt;-(1) vin; | o_and &amp;lt;-(1) 1; o_and &amp;lt;-(0) vin; ]
[ o_mul &amp;lt;-(0) 2; | o_mul &amp;lt;-(1) 2; ]
--
o_plus &amp;lt;-- (0) 0;
o_plus &amp;lt;-- (1) 0;
}
&lt;/code>&lt;/pre>&lt;p>This uses the &amp;ldquo;or&amp;rdquo; syntax that I didn&amp;rsquo;t mention before - &lt;code>[ ... | ... ]&lt;/code>. This means that either the first or the second
statement must match. This rule checks our constraints case by case. For example, &lt;code>[ o_xor &amp;lt;-(0) 1; o_xor &amp;lt;-(1) vin; | o_xor &amp;lt;-(1) 1; o_xor &amp;lt;-(0) vin; ]&lt;/code>
means that either first parameter to &lt;code>o_xor&lt;/code> is &lt;code>1&lt;/code>, and the second parameter is &lt;code>vin&lt;/code>, or the first parameter is &lt;code>vin&lt;/code> and the second is &lt;code>1&lt;/code>.&lt;/p>
&lt;p>After verifying that this still matches our code, we can replace the &amp;ldquo;zero everything&amp;rdquo; action: We want to change the operation to
incrementation, i.e. &lt;code>x + 1&lt;/code>. So we want a &lt;code>+&lt;/code> operating with one parameter equal to 1, and the other equal to the matched varnode.
Fortunately our top-level opration is already addition, so we just need to replace operands:&lt;/p>
&lt;pre tabindex="0">&lt;code>{
o_plus(+) &amp;lt;- v1 &amp;lt;- o_mul(*) &amp;lt;- v2 &amp;lt;- o_and(&amp;amp;);
o_plus(+) &amp;lt;- v4 &amp;lt;- o_xor(^);
[ o_xor &amp;lt;-(0) 1; o_xor &amp;lt;-(1) vin; | o_xor &amp;lt;-(1) 1; o_xor &amp;lt;-(0) vin; ]
[ o_and &amp;lt;-(0) 1; o_and &amp;lt;-(1) vin; | o_and &amp;lt;-(1) 1; o_and &amp;lt;-(0) vin; ]
[ o_mul &amp;lt;-(0) 2; | o_mul &amp;lt;-(1) 2; ]
--
o_plus &amp;lt;-- (0) vin;
o_plus &amp;lt;-- (1) 1;
}
&lt;/code>&lt;/pre>&lt;p>A hand-painted artisanal version of the final rule:&lt;/p>
&lt;p>
&lt;img src="https://msm.lt/re/ghidra/rulecompile/cpui_colored.png" alt="" >
&lt;/p>
&lt;p>And&amp;hellip; that&amp;rsquo;s it! We can verify that our works correctly now:&lt;/p>
&lt;pre tabindex="0">&lt;code>[decomp]&amp;gt; print C
int4 func_0x00101129(int4 param_1) {
return (int4)(param_1 + 1);
}
&lt;/code>&lt;/pre>&lt;p>The full rule is, including the XML boilerplate is&lt;sup id="fnref:10">&lt;a href="#fn:10" class="footnote-ref" role="doc-noteref">10&lt;/a>&lt;/sup>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">&amp;lt;experimental_rules&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;rule&lt;/span> &lt;span style="color:#a6e22e">name=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;obfuscated_increment&amp;#34;&lt;/span> &lt;span style="color:#a6e22e">group=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;analysis&amp;#34;&lt;/span> &lt;span style="color:#a6e22e">enable=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;true&amp;#34;&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>&lt;span style="color:#75715e">&amp;lt;![CDATA[
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> {
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> o_plus(+) &amp;lt;- v1 &amp;lt;- o_mul(*) &amp;lt;- v2 &amp;lt;- o_and(&amp;amp;);
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> o_plus(+) &amp;lt;- v4 &amp;lt;- o_xor(^) &amp;lt;- vin0;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> [ o_xor &amp;lt;-(0) 1; o_xor &amp;lt;-(1) vin(==vin0); | o_xor &amp;lt;-(1) 1; o_xor &amp;lt;-(0) vin(==vin0); ]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> [ o_and &amp;lt;-(0) 1; o_and &amp;lt;-(1) vin(==vin0); | o_and &amp;lt;-(1) 1; o_and &amp;lt;-(0) vin(==vin0); ]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> [ o_mul &amp;lt;-(0) 2; | o_mul &amp;lt;-(1) 2; ]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> --
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> o_plus &amp;lt;-- (0) vin;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> o_plus &amp;lt;-- (1) 1;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> }
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> ]]&amp;gt;&lt;/span>&lt;span style="color:#f92672">&amp;lt;/rule&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">&amp;lt;/experimental_rules&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And the commands to use it:&lt;/p>
&lt;pre tabindex="0">&lt;code>experimental rules /home/you/xyz/rules.xml
load file /home/you/xyz/obfuscated
adjust vma 0x100000
load addr 0x0101129
decompile
print C
&lt;/code>&lt;/pre>&lt;p>Procedure to apply our rules to the Ghidra UI is slightly different (we need to patch ghidra_process.cc and build.gradle
instead of consolemain.cc and Makefile), but the idea is the same. You can get the patch which makes decompiler use
&lt;code>/etc/ghidra-rules.xml&lt;/code> &lt;a href="./ghidra.patch">here&lt;/a>. Happy hacking.&lt;/p>
&lt;p>
&lt;img src="https://msm.lt/re/ghidra/rulecompile/after.png" alt="" >
&lt;/p>
&lt;h2 id="conclusion">Conclusion&lt;/h2>
&lt;p>So that&amp;rsquo;s it, &lt;strong>we created a simple deobfuscation rule for Ghidra decompiler&lt;/strong>. Since it&amp;rsquo;s
an independent file, you can easily share it with your friends and family - just
send them an XML file and they can use it.&lt;/p>
&lt;p>As long as they also use your modified version of Ghidra with rules compiled in, of course.&lt;/p>
&lt;p>What are the next steps? Frankly, I don&amp;rsquo;t think there are any. Clearly a lot of work was put into this rule engine,
including a custom DSL and AST matcher. But this feature sits in the current
state for at least 5 years, and I don&amp;rsquo;t think Ghidra devs will agree to enable it by default - even if I submitted a PR.
It was disabled for a reason.&lt;/p>
&lt;p>That would be nice of course - I work with obfuscated code often, and I would love an &lt;a href="https://github.com/NationalSecurityAgency/ghidra/discussions/5227#discussioncomment-5635776">easier way to extend Ghidra decompiler&lt;/a>&lt;sup id="fnref:11">&lt;a href="#fn:11" class="footnote-ref" role="doc-noteref">11&lt;/a>&lt;/sup>.
But nowadays I think I would just &lt;strong>let plugins register their own hooks&lt;/strong> and do arbitrary transformations on PCode with Java or Python code. I&amp;rsquo;m not sure if that&amp;rsquo;s doable, but one can dream.&lt;/p>
&lt;br>
&lt;br>
&lt;br>
&lt;p>&lt;em>Btw: if you use Ghidra, check out my related open-source projects: &lt;a href="https://github.com/msm-code/ghidralib">ghidralib&lt;/a>,
a Pythonic standard library for Ghidra, and &lt;a href="https://github.com/msm-code/GhidraCtrlP">CtrlP&lt;/a>, a quick search and
command palette plugin.&lt;/em>&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>Or can we? If there is a way, please let me know. It doesn&amp;rsquo;t invalidate the journey I&amp;rsquo;ve described in the rest of the post.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>This is not the official term, but it&amp;rsquo;s a good name for transformed Pcode.
The samentics and amount of available information chanes drastically.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>One day I will figure out how to force Ghidra to generate proper switches.&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:4">
&lt;p>I plan to document more obscure/obscurish Ghidra features in the future, though.&amp;#160;&lt;a href="#fnref:4" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:5">
&lt;p>But if you want to load the exported XML, the commands are &lt;code>restore /path/to/file.xml&lt;/code> and &lt;code>load function yourfunction&lt;/code>.&amp;#160;&lt;a href="#fnref:5" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:6">
&lt;p>Someone told me this usage is incorrect, but &lt;a href="https://dictionary.cambridge.org/dictionary/english/beg-the-question">cambridge dictionary&lt;/a> disagrees.&amp;#160;&lt;a href="#fnref:6" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:7">
&lt;p>To be fair, I recall that one user on Github mentioned in discussion that this
feature exist, and that they managed to compile it but had no success with it. That
still doesn&amp;rsquo;t count as an official documentation.&amp;#160;&lt;a href="#fnref:7" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:8">
&lt;p>I&amp;rsquo;ve wasted SO MUCH time on that &lt;code>&amp;amp;lt;&lt;/code>. The decompiler is not very talkative, so I was just getting random syntax errors on a few varnode types.&amp;#160;&lt;a href="#fnref:8" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:9">
&lt;p>I wonder if the instability is the reason why this feature was never enabled or officially documented.&amp;#160;&lt;a href="#fnref:9" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:10">
&lt;p>You may notice there is a small difference to the previous version - &lt;code>&amp;lt;- vin0&lt;/code> and &lt;code>(==vin0)&lt;/code>. I decided to play it safe, because I&amp;rsquo;m not 100%
sure how term unification works in this language.&amp;#160;&lt;a href="#fnref:10" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:11">
&lt;p>Also a low-level p-code in SSA form &lt;a href="https://github.com/NationalSecurityAgency/ghidra/discussions/5573#discussioncomment-6520456">link&lt;/a>
&lt;a href="https://github.com/NationalSecurityAgency/ghidra/discussions/5137">link&lt;/a>. And a C AST exposed to scripts
&lt;a href="https://github.com/NationalSecurityAgency/ghidra/discussions/4086">link&lt;/a>. And a pony.&amp;#160;&lt;a href="#fnref:11" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Collision attack for StreamHash5</title><link>https://msm.lt/posts/streamhash5/</link><pubDate>Thu, 27 Jan 2022 00:00:00 +0000</pubDate><guid>https://msm.lt/posts/streamhash5/</guid><description>&lt;p>StreamHash is an alternative family of cryptographic hash functions, designed
for maximum speed, while being reasonably secure at the same time.&lt;/p>
&lt;p>As far as I know, it&amp;rsquo;s not used in any production software, but is not completely
fringe too - it was submitted to the SHA-3 competition and prompted a few
academic publications.&lt;/p>
&lt;p>&lt;a href="https://github.com/mtrojnar/StreamHash5">StreamHash5&lt;/a> is the newest member of
the family. It was created as an improved
version of StreamHash4, after I implemented a practical collision attack for
it &lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>.&lt;/p>
&lt;p>In this blog post, I will describe my &lt;strong>impractical&lt;/strong> collision attack on
StreamHash5 (and a practical partial attack). I stress that to manage
expectations, but it&amp;rsquo;s enough to consider StreamHash5 broken cryptographically:&lt;/p>
&lt;ul>
&lt;li>Hash size is 512 bits. Hence, the generic birthday attack complexity is &lt;code>2**256&lt;/code>.&lt;/li>
&lt;li>My attack complexity is roughly &lt;code>2**128 * 2**38 = 2**166&lt;/code>.&lt;/li>
&lt;/ul>
&lt;p>While the project&amp;rsquo;s readme clearly states that &lt;code>There are currently no known collision attacks easier than the generic birthday attack&lt;/code> &lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup>.&lt;/p>
&lt;p>I&amp;rsquo;m also confident the attack complexity can be improved. But this research
spent the last 2 years in my drawer and I think it&amp;rsquo;s time to finally publish it.&lt;/p>
&lt;p>Partial collision example (line breaks added for clarity):&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>$ cat data.&lt;span style="color:#f92672">{&lt;/span>0,1&lt;span style="color:#f92672">}&lt;/span>.hex
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>626974636820646f20317420616c6f6ec0402c500c6570577b3c09fb4e966d2215ea0bb4a024bab440e907c9cc7e3bd0
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>696620796f752077616e6e61206372794b6dfb042aed03d14e8dbd4936536c3500000000000000000000000000000000
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ streamhash5sum data.0.bin
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>65bf759586d6b23e3ba7b36b9150920b &lt;span style="color:#75715e"># collision&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>6f1daa35f658c4181fc25960d2b0ac61 &lt;span style="color:#75715e"># collision&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>71df8e636e38beecbf1d36ae7f9c26e4 &lt;span style="color:#75715e"># collision&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>e4121fda76468f48ae542cb70a31875e
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ streamhash5sum data.1.bin
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>65bf759586d6b23e3ba7b36b9150920b &lt;span style="color:#75715e"># collision&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>6f1daa35f658c4181fc25960d2b0ac61 &lt;span style="color:#75715e"># collision&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>71df8e636e38beecbf1d36ae7f9c26e4 &lt;span style="color:#75715e"># collision&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>82ef6e3e544e910fc99b69c77ca58ceb
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="streamhash5">StreamHash5&lt;/h2>
&lt;p>Like one wise man with anger issues once said, &amp;ldquo;talk is cheap, show me
the code&amp;rdquo;. StreamHash5 processes data in 16-byte blocks. The internal state
has 4*16 bytes. After every round, the state is xor-ed with the number of
bits processed so far. Simplified version (works when &lt;code>len(data)&lt;/code> is
divisible by 16) below:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">sh5&lt;/span>(data):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> offset &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> state &lt;span style="color:#f92672">=&lt;/span> list(consts)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">while&lt;/span> offset &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#ae81ff">16&lt;/span> &lt;span style="color:#f92672">&amp;lt;=&lt;/span> len(data):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> offset &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">16&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> magic &lt;span style="color:#f92672">=&lt;/span> struct&lt;span style="color:#f92672">.&lt;/span>pack(&lt;span style="color:#e6db74">&amp;#34;&amp;lt;I&amp;#34;&lt;/span>, offset &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#ae81ff">8&lt;/span>)&lt;span style="color:#f92672">.&lt;/span>rjust(&lt;span style="color:#ae81ff">8&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;&lt;/span>&lt;span style="color:#ae81ff">\x00&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> state[&lt;span style="color:#ae81ff">3&lt;/span>] &lt;span style="color:#f92672">=&lt;/span> xor(state[&lt;span style="color:#ae81ff">3&lt;/span>], magic &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> block(data[offset&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">16&lt;/span>:offset], state)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> state[&lt;span style="color:#ae81ff">0&lt;/span>] &lt;span style="color:#f92672">+&lt;/span> state[&lt;span style="color:#ae81ff">1&lt;/span>] &lt;span style="color:#f92672">+&lt;/span> state[&lt;span style="color:#ae81ff">2&lt;/span>] &lt;span style="color:#f92672">+&lt;/span> state[&lt;span style="color:#ae81ff">3&lt;/span>]
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Of course, the real magic is in the &lt;code>block&lt;/code> compression function.
StreamHash can be described as four &amp;ldquo;almost-AES-CBC&amp;rdquo; encryptions
going on in parallel.&lt;/p>
&lt;p>The state is divided into four 16 byte chunks. First, every chunk is
xored with a new block of hashed data. After that, every block
is encrypted with two rounds of AES (every block uses a different
but constant key). In Python:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">xorstate&lt;/span>(data, state):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> state[&lt;span style="color:#ae81ff">0&lt;/span>] &lt;span style="color:#f92672">=&lt;/span> xor(data, state[&lt;span style="color:#ae81ff">0&lt;/span>])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> state[&lt;span style="color:#ae81ff">1&lt;/span>] &lt;span style="color:#f92672">=&lt;/span> xor(data, state[&lt;span style="color:#ae81ff">1&lt;/span>])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> state[&lt;span style="color:#ae81ff">2&lt;/span>] &lt;span style="color:#f92672">=&lt;/span> xor(data, state[&lt;span style="color:#ae81ff">2&lt;/span>])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> state[&lt;span style="color:#ae81ff">3&lt;/span>] &lt;span style="color:#f92672">=&lt;/span> xor(data, state[&lt;span style="color:#ae81ff">3&lt;/span>])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">halfblock&lt;/span>(state):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> state[&lt;span style="color:#ae81ff">0&lt;/span>] &lt;span style="color:#f92672">=&lt;/span> aes_round(state[&lt;span style="color:#ae81ff">0&lt;/span>], consts[&lt;span style="color:#ae81ff">0&lt;/span>])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> state[&lt;span style="color:#ae81ff">1&lt;/span>] &lt;span style="color:#f92672">=&lt;/span> aes_round(state[&lt;span style="color:#ae81ff">1&lt;/span>], consts[&lt;span style="color:#ae81ff">1&lt;/span>])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> state[&lt;span style="color:#ae81ff">2&lt;/span>] &lt;span style="color:#f92672">=&lt;/span> aes_round(state[&lt;span style="color:#ae81ff">2&lt;/span>], consts[&lt;span style="color:#ae81ff">2&lt;/span>])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> state[&lt;span style="color:#ae81ff">3&lt;/span>] &lt;span style="color:#f92672">=&lt;/span> aes_round(state[&lt;span style="color:#ae81ff">3&lt;/span>], consts[&lt;span style="color:#ae81ff">3&lt;/span>])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">block&lt;/span>(data, state):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> xorstate(data, state)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> halfblock(state)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> halfblock(state)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>In StreamHash5, the halfblock function is called twice per block - this is the
improvement over StreamHash4 introduced in the new version.&lt;/p>
&lt;p>This can also be described with the following ASCII-art:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span> data bits
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#f92672">|&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> v &lt;span style="color:#f92672">|&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>S0 &lt;span style="color:#f92672">-&amp;gt;&lt;/span> xor &lt;span style="color:#f92672">-&amp;gt;&lt;/span> aes_round(C0) &lt;span style="color:#f92672">-&amp;gt;&lt;/span> aes_round(C0) &lt;span style="color:#f92672">---&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#f92672">--&amp;gt;&lt;/span> S0
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>S1 &lt;span style="color:#f92672">-&amp;gt;&lt;/span> xor &lt;span style="color:#f92672">-&amp;gt;&lt;/span> aes_round(C1) &lt;span style="color:#f92672">-&amp;gt;&lt;/span> aes_round(C1) &lt;span style="color:#f92672">---&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#f92672">--&amp;gt;&lt;/span> S1
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>S2 &lt;span style="color:#f92672">-&amp;gt;&lt;/span> xor &lt;span style="color:#f92672">-&amp;gt;&lt;/span> aes_round(C2) &lt;span style="color:#f92672">-&amp;gt;&lt;/span> aes_round(C2) &lt;span style="color:#f92672">---&lt;/span> v &lt;span style="color:#f92672">--&amp;gt;&lt;/span> S2
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>S3 &lt;span style="color:#f92672">-&amp;gt;&lt;/span> xor &lt;span style="color:#f92672">-&amp;gt;&lt;/span> aes_round(C3) &lt;span style="color:#f92672">-&amp;gt;&lt;/span> aes_round(C3) &lt;span style="color:#f92672">-&amp;gt;&lt;/span> xor &lt;span style="color:#f92672">-&amp;gt;&lt;/span> S3
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="attack-description">Attack description&lt;/h2>
&lt;p>The attack itself is just a smart brute-force with a lot of precomputing.&lt;/p>
&lt;p>The problem we&amp;rsquo;re trying to solve can be stated as follows:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>AES(AES(A00 &lt;span style="color:#f92672">^&lt;/span> A1D, C0), C0) &lt;span style="color:#f92672">=&lt;/span> AES(AES(B00 &lt;span style="color:#f92672">^&lt;/span> B1D, C0), C0)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>AES(AES(A01 &lt;span style="color:#f92672">^&lt;/span> A1D, C1), C1) &lt;span style="color:#f92672">=&lt;/span> AES(AES(B01 &lt;span style="color:#f92672">^&lt;/span> B1D, C1), C1)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>AES(AES(A02 &lt;span style="color:#f92672">^&lt;/span> A1D, C2), C2) &lt;span style="color:#f92672">=&lt;/span> AES(AES(B02 &lt;span style="color:#f92672">^&lt;/span> B1D, C2), C2)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>AES(AES(A03 &lt;span style="color:#f92672">^&lt;/span> A1D, C3), C3) &lt;span style="color:#f92672">=&lt;/span> AES(AES(B03 &lt;span style="color:#f92672">^&lt;/span> B1D, C3), C3)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Excuse my notation. &lt;code>C0&lt;/code>, &lt;code>C1&lt;/code>, &lt;code>C2&lt;/code> and &lt;code>C3&lt;/code>. Are algorithm constants.
&lt;code>AES&lt;/code> is a single round of AES encryption. &lt;code>AnD&lt;/code> and &lt;code>BnD&lt;/code> describe &lt;code>n&lt;/code>th data blocks (in message &lt;code>A&lt;/code> and &lt;code>B&lt;/code> respectively). And finally, &lt;code>Anm&lt;/code>/&lt;code>Bnm&lt;/code> describe &lt;code>m&lt;/code>th state after processing &lt;code>n&lt;/code>th block
(remember, there are four states).&lt;/p>
&lt;p>In other words, the relationship between the state variables is:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># state 0 in message A&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>A10 &lt;span style="color:#f92672">=&lt;/span> AES(A00 &lt;span style="color:#f92672">^&lt;/span> A1D, C0)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>A20 &lt;span style="color:#f92672">=&lt;/span> AES(A10 &lt;span style="color:#f92672">^&lt;/span> A2D, C0)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>A30 &lt;span style="color:#f92672">=&lt;/span> AES(A20 &lt;span style="color:#f92672">^&lt;/span> A3D, C0)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># state 1 in message B&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>B11 &lt;span style="color:#f92672">=&lt;/span> AES(B00 &lt;span style="color:#f92672">^&lt;/span> B1D, C1)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>B21 &lt;span style="color:#f92672">=&lt;/span> AES(B10 &lt;span style="color:#f92672">^&lt;/span> B2D, C1)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>B31 &lt;span style="color:#f92672">=&lt;/span> AES(B20 &lt;span style="color:#f92672">^&lt;/span> B3D, C1)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># etc&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Finally, an example with ASCII art again:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span> A1D bits
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#f92672">|&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> v &lt;span style="color:#f92672">|&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>A00 &lt;span style="color:#f92672">-&amp;gt;&lt;/span> xor &lt;span style="color:#f92672">-&amp;gt;&lt;/span> aes_round(C0) &lt;span style="color:#f92672">-&amp;gt;&lt;/span> aes_round(C0) &lt;span style="color:#f92672">---&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#f92672">--&amp;gt;&lt;/span> A10
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>A01 &lt;span style="color:#f92672">-&amp;gt;&lt;/span> xor &lt;span style="color:#f92672">-&amp;gt;&lt;/span> aes_round(C1) &lt;span style="color:#f92672">-&amp;gt;&lt;/span> aes_round(C1) &lt;span style="color:#f92672">---&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#f92672">--&amp;gt;&lt;/span> A11
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>A02 &lt;span style="color:#f92672">-&amp;gt;&lt;/span> xor &lt;span style="color:#f92672">-&amp;gt;&lt;/span> aes_round(C2) &lt;span style="color:#f92672">-&amp;gt;&lt;/span> aes_round(C2) &lt;span style="color:#f92672">---&lt;/span> v &lt;span style="color:#f92672">--&amp;gt;&lt;/span> A12
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>A03 &lt;span style="color:#f92672">-&amp;gt;&lt;/span> xor &lt;span style="color:#f92672">-&amp;gt;&lt;/span> aes_round(C3) &lt;span style="color:#f92672">-&amp;gt;&lt;/span> aes_round(C3) &lt;span style="color:#f92672">-&amp;gt;&lt;/span> xor &lt;span style="color:#f92672">-&amp;gt;&lt;/span> A13
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>So, back to the problem again. I won&amp;rsquo;t try to solve all four equations.
We&amp;rsquo;ll create a collision for three equations in &lt;code>2**38&lt;/code> and observe that we can
repeat this &lt;code>2**128&lt;/code> times to get a collision for the fourth block &lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup>.
So we start with:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>AES(AES(A00 &lt;span style="color:#f92672">^&lt;/span> A1D, C0), C0) &lt;span style="color:#f92672">=&lt;/span> AES(AES(B00 &lt;span style="color:#f92672">^&lt;/span> B1D, C0), C0)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>AES(AES(A01 &lt;span style="color:#f92672">^&lt;/span> A1D, C1), C1) &lt;span style="color:#f92672">=&lt;/span> AES(AES(B01 &lt;span style="color:#f92672">^&lt;/span> B1D, C1), C1)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>AES(AES(A02 &lt;span style="color:#f92672">^&lt;/span> A1D, C2), C2) &lt;span style="color:#f92672">=&lt;/span> AES(AES(B02 &lt;span style="color:#f92672">^&lt;/span> B1D, C2), C2)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>We expand &lt;code>AES&lt;/code> round into suboperations - &lt;code>SubBytes&lt;/code>, &lt;code>AddRoundKey&lt;/code>,
&lt;code>MixColumns&lt;/code> and &lt;code>ShiftRows&lt;/code>, and simplify:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>SB(AR(MX(SR(SB(A00 &lt;span style="color:#f92672">^&lt;/span> A1D))), C0)) &lt;span style="color:#f92672">^&lt;/span> A2D &lt;span style="color:#f92672">=&lt;/span> SB(AR(MX(SR(SB(B00 &lt;span style="color:#f92672">^&lt;/span> B1D))), C0)) &lt;span style="color:#f92672">^&lt;/span> B2D
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>SB(AR(MX(SR(SB(A01 &lt;span style="color:#f92672">^&lt;/span> A1D))), C1)) &lt;span style="color:#f92672">^&lt;/span> A2D &lt;span style="color:#f92672">=&lt;/span> SB(AR(MX(SR(SB(B01 &lt;span style="color:#f92672">^&lt;/span> B1D))), C1)) &lt;span style="color:#f92672">^&lt;/span> B2D
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>SB(AR(MX(SR(SB(A02 &lt;span style="color:#f92672">^&lt;/span> A1D))), C2)) &lt;span style="color:#f92672">^&lt;/span> A2D &lt;span style="color:#f92672">=&lt;/span> SB(AR(MX(SR(SB(B02 &lt;span style="color:#f92672">^&lt;/span> B1D))), C2)) &lt;span style="color:#f92672">^&lt;/span> B2D
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Observe that &lt;code>SR(SB(A00 ^ A1D))&lt;/code> don&amp;rsquo;t mix bytes in any way. In fact, it&amp;rsquo;s
equivalent to &lt;code>SR(SB(A00)) ^ SR(SB(A1D))&lt;/code>. Use this trick to simplify equatoin
again (Let &lt;code>A00sr = SR(SB(A00))&lt;/code> etc):&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>SB(AR(MX(A00sr &lt;span style="color:#f92672">^&lt;/span> A1Dsr), C0)) &lt;span style="color:#f92672">^&lt;/span> A2D &lt;span style="color:#f92672">=&lt;/span> SB(AR(MX(B00sr &lt;span style="color:#f92672">^&lt;/span> B1Dsr), C0)) &lt;span style="color:#f92672">^&lt;/span> B2D
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>SB(AR(MX(A01sr &lt;span style="color:#f92672">^&lt;/span> A1Dsr), C1)) &lt;span style="color:#f92672">^&lt;/span> A2D &lt;span style="color:#f92672">=&lt;/span> SB(AR(MX(B01sr &lt;span style="color:#f92672">^&lt;/span> B1Dsr), C1)) &lt;span style="color:#f92672">^&lt;/span> B2D
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>SB(AR(MX(A02sr &lt;span style="color:#f92672">^&lt;/span> A1Dsr), C2)) &lt;span style="color:#f92672">^&lt;/span> A2D &lt;span style="color:#f92672">=&lt;/span> SB(AR(MX(B02sr &lt;span style="color:#f92672">^&lt;/span> B1Dsr), C2)) &lt;span style="color:#f92672">^&lt;/span> B2D
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Move variables around, and let &lt;code>d = A2D ^ B2D&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>d &lt;span style="color:#f92672">^&lt;/span> SB(AR(MX(A00sr &lt;span style="color:#f92672">^&lt;/span> A1Dsr), C0))&lt;span style="color:#f92672">=&lt;/span> SB(AR(MX(B00sr &lt;span style="color:#f92672">^&lt;/span> B1Dsr), C0))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>d &lt;span style="color:#f92672">^&lt;/span> SB(AR(MX(A01sr &lt;span style="color:#f92672">^&lt;/span> A1Dsr), C1))&lt;span style="color:#f92672">=&lt;/span> SB(AR(MX(B01sr &lt;span style="color:#f92672">^&lt;/span> B1Dsr), C1))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>d &lt;span style="color:#f92672">^&lt;/span> SB(AR(MX(A02sr &lt;span style="color:#f92672">^&lt;/span> A1Dsr), C2))&lt;span style="color:#f92672">=&lt;/span> SB(AR(MX(B02sr &lt;span style="color:#f92672">^&lt;/span> B1Dsr), C2))
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now, introduce helper functions for four constant:
&lt;code>let SSB_C0(x) = SB(AR(MX(x), C0))&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>d &lt;span style="color:#f92672">^&lt;/span> SSB_C0(A00sr &lt;span style="color:#f92672">^&lt;/span> A1Dsr) &lt;span style="color:#f92672">=&lt;/span> SSB_C0(B00sr &lt;span style="color:#f92672">^&lt;/span> B1Dsr)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>d &lt;span style="color:#f92672">^&lt;/span> SSB_C1(A01sr &lt;span style="color:#f92672">^&lt;/span> A1Dsr) &lt;span style="color:#f92672">=&lt;/span> SSB_C1(B01sr &lt;span style="color:#f92672">^&lt;/span> B1Dsr)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>d &lt;span style="color:#f92672">^&lt;/span> SSB_C2(A02sr &lt;span style="color:#f92672">^&lt;/span> A1Dsr) &lt;span style="color:#f92672">=&lt;/span> SSB_C2(B02sr &lt;span style="color:#f92672">^&lt;/span> B1Dsr)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Why? Because &lt;code>SB(AR(MX(x), C0))&lt;/code> is in a sweet spot, where it&amp;rsquo;s already hard to
analyse mathematically, but there is still only a single MixColumns step - so we
can operate on message dwords (32bit chunks) separately. This means we can
precompute inverse functions like:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>SSB_C0&lt;span style="color:#f92672">(&lt;/span>x&lt;span style="color:#f92672">)&lt;/span> &lt;span style="color:#f92672">=&lt;/span> y
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;&lt;span style="color:#f92672">=&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>x ∈ INVSSB_C0&lt;span style="color:#f92672">(&lt;/span>y&lt;span style="color:#f92672">)&lt;/span> &lt;span style="color:#75715e"># many inputs may give the same result&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This will come in handy.&lt;/p>
&lt;p>Now we can just brute-force &lt;code>A1Dsr&lt;/code> quickly. After plugging in a specific
value for &lt;code>A1D&lt;/code> (remember, the first data block) we get:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>d0 &lt;span style="color:#f92672">=&lt;/span> SB_C0&lt;span style="color:#f92672">(&lt;/span>B00sr ^ B1Dsr&lt;span style="color:#f92672">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>d1 &lt;span style="color:#f92672">=&lt;/span> SB_C1&lt;span style="color:#f92672">(&lt;/span>B01sr ^ B1Dsr&lt;span style="color:#f92672">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>d2 &lt;span style="color:#f92672">=&lt;/span> SB_C2&lt;span style="color:#f92672">(&lt;/span>B02sr ^ B1Dsr&lt;span style="color:#f92672">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This means that:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>d0 ^ d1 &lt;span style="color:#f92672">=&lt;/span> SB_C0&lt;span style="color:#f92672">(&lt;/span>B00sr ^ B1Dsr&lt;span style="color:#f92672">)&lt;/span> ^ SB_C1&lt;span style="color:#f92672">(&lt;/span>B01sr ^ B1Dsr&lt;span style="color:#f92672">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Observe that &lt;code>B00sr&lt;/code> and &lt;code>B01sr&lt;/code> don&amp;rsquo;t depend on &lt;code>A1D&lt;/code> (or even &lt;code>B1D&lt;/code>) . This means
that we can define a function:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>SB_C0xC1&lt;span style="color:#f92672">(&lt;/span>x&lt;span style="color:#f92672">)&lt;/span> &lt;span style="color:#f92672">=&lt;/span> SB_C0&lt;span style="color:#f92672">(&lt;/span>B00sr ^ x&lt;span style="color:#f92672">)&lt;/span> ^ SB_C1&lt;span style="color:#f92672">(&lt;/span>B01sr ^ x&lt;span style="color:#f92672">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And precompute its inverse:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>SB_C0xC1&lt;span style="color:#f92672">(&lt;/span>x&lt;span style="color:#f92672">)&lt;/span> &lt;span style="color:#f92672">=&lt;/span> y
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;&lt;span style="color:#f92672">=&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>x ∈ INVSB_C0xC1&lt;span style="color:#f92672">(&lt;/span>y&lt;span style="color:#f92672">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Going back to our equation, we can find solutions immediately. Pseudo-code:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># solve d0 ^ d1 = SB_C0(B00sr ^ B1Dsr) ^ SB_C1(B01sr ^ B1Dsr)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">for&lt;/span> B1Dsr &lt;span style="color:#f92672">in&lt;/span> INVSB_C0xC1(d0 &lt;span style="color:#f92672">^&lt;/span> d1):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">...&lt;/span> &lt;span style="color:#75715e"># do more crypto magic&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This takes care of the first two equations. But remember, we need to solve
three of them at once:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>d0 &lt;span style="color:#f92672">=&lt;/span> SB_C0&lt;span style="color:#f92672">(&lt;/span>B00sr ^ B1Dsr&lt;span style="color:#f92672">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>d1 &lt;span style="color:#f92672">=&lt;/span> SB_C1&lt;span style="color:#f92672">(&lt;/span>B01sr ^ B1Dsr&lt;span style="color:#f92672">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>d2 &lt;span style="color:#f92672">=&lt;/span> SB_C2&lt;span style="color:#f92672">(&lt;/span>B02sr ^ B1Dsr&lt;span style="color:#f92672">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Sadly, this is as far as clever precomputing gets us. But the good thing is
that we can work on 32bit input fragments independently. By picking a
random &lt;code>A1D&lt;/code> we have &lt;code>1 / 2*32&lt;/code> chance of satisfying the third equation by pure
chance. And when we do it&amp;rsquo;s over - the attack succeeded.&lt;/p>
&lt;p>So the idea is to split a message block into four 32bit parts, find a collision
for each part separately, and then combine them into a 128bit block.&lt;/p>
&lt;p>The only bad news is that sometimes we won&amp;rsquo;t find any &lt;code>A1D&lt;/code> that works, even
after exhaustive checking of all &lt;code>2**32&lt;/code> uint32 values. In this case, we have to
pick other initial states and redo the attack.&lt;/p>
&lt;p>That&amp;rsquo;s really it. I&amp;rsquo;ve glossed over a few details, but the gist of the attack
and the most interesting part is just that - a big precomputed inverse for xor
of two AES supersboxes.&lt;/p>
&lt;h2 id="conclusions">Conclusions&lt;/h2>
&lt;p>Even though I didn&amp;rsquo;t present a full practical collision, I&amp;rsquo;m confident &lt;strong>StreamHash5 shouldn&amp;rsquo;t be used&lt;/strong> in its current form. I see a few ways to improve my attack, and certainly focused work by experts and three-letter agencies would improve it even more.&lt;/p>
&lt;p>The usual takeaway is: &lt;strong>cryptography is hard&lt;/strong> - even when you&amp;rsquo;re a professional cryptographer, rolling your own crypto is risky.&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>You can read my &lt;a href="https://tailcall.net/static/talks/sbs2017/#1">slides&lt;/a> or
watch the &lt;a href="https://www.youtube.com/watch?v=IecyzkZWOR4">video&lt;/a>. Both are PL-only.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>&lt;a href="https://github.com/mtrojnar/StreamHash5">https://github.com/mtrojnar/StreamHash5&lt;/a>&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>Can we use the birthday paradox to bring it down to &lt;code>2**64&lt;/code> somehow?
I Don&amp;rsquo;t know. Maybe? But we don&amp;rsquo;t control the first three blocks, so it&amp;rsquo;s not obvious how.&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>A simple bluetooth keyboard with Raspberry PI</title><link>https://msm.lt/posts/bluetooth-keyboard/</link><pubDate>Fri, 19 Nov 2021 00:00:00 +0000</pubDate><guid>https://msm.lt/posts/bluetooth-keyboard/</guid><description>&lt;p>My laptop only has one USB port.&lt;/p>
&lt;p>I understand that the times are changing. Wireless devices are more and more popular,
wi-fi and Bluetooth takes over that pesky cables and bulky physical connectors.
We&amp;rsquo;re entering a new cable-less era.&lt;/p>
&lt;p>This doesn&amp;rsquo;t change the fact, that my mouse and my keyboard connect over USB.
That&amp;rsquo;s two devices. And I want both.&lt;/p>
&lt;p>So of course I&amp;rsquo;ve decided to write a Bluetooth keyboard proxy using my Raspberry
Pi as a gateway. I couldn&amp;rsquo;t find any working tutorials, and after a night of
cursing at the screen, I&amp;rsquo;ve decided to share my findings with future generations.&lt;/p>
&lt;p>The code should work with any Bluetooth-enabled Linux device. I&amp;rsquo;ve tested the code on
Raspberry Pi and Ubuntu, non-Debian distributions may require a bit different steps.&lt;/p>
&lt;h2 id="d-bus-how-does-it-work">D-Bus, how does it work?&lt;/h2>
&lt;p>D-Bus is a IPC framework designed to facilitate communication between multiple
processes in a composable and extensible way. It&amp;rsquo;s a shared channel used by
applications to communicate. For example, I can ask Spotify to change song using &lt;code>dbus-send&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ dbus-send --print-reply --dest&lt;span style="color:#f92672">=&lt;/span>org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Next
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>What just happened is I&amp;rsquo;ve called a &lt;code>org.mpris.MediaPlayer2.Player.Next&lt;/code> &amp;ldquo;method&amp;rdquo;
on the &lt;code>/org/mpris/MediaPlayer2&lt;/code> object using &lt;code>org.mpris.MediaPlayer2.spotify&lt;/code>
connection.&lt;/p>
&lt;p>&lt;code>Bluez&lt;/code> is a Linux implementation of Bluetooth, and it has a D-Bus API &lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>.
It implements the &lt;code>org.freedesktop.DBus.Introspectable&lt;/code> interface, so we can look
take a look at it via cli:&lt;/p>
&lt;pre tabindex="0">&lt;code>pi@tmicro:~ $ sudo gdbus introspect --system --dest org.bluez --object-path /org/bluez
node /org/bluez {
interface org.freedesktop.DBus.Introspectable {
methods:
Introspect(out s xml);
signals:
properties:
};
interface org.bluez.AgentManager1 {
methods:
RegisterAgent(in o agent,
in s capability);
UnregisterAgent(in o agent);
RequestDefaultAgent(in o agent);
signals:
properties:
};
interface org.bluez.ProfileManager1 {
methods:
RegisterProfile(in o profile,
in s UUID,
in a{sv} options);
UnregisterProfile(in o profile);
signals:
properties:
};
interface org.bluez.HealthManager1 {
methods:
CreateApplication(in a{sv} config,
out o application);
DestroyApplication(in o application);
signals:
properties:
};
node hci0 {
};
};
&lt;/code>&lt;/pre>&lt;p>We see three interfaces and one node.&lt;/p>
&lt;p>We can call methods the interfaces&lt;/p>
&lt;p>which we can introspect further with&lt;/p>
&lt;pre tabindex="0">&lt;code>sudo gdbus introspect --system --dest org.bluez --object-path /org/bluez/hci0
# (...)
&lt;/code>&lt;/pre>&lt;p>Other useful debugging commands are:&lt;/p>
&lt;ul>
&lt;li>&lt;code>sudo btmon&lt;/code> (monitor Bluetooth activity on the device)&lt;/li>
&lt;li>&lt;code>sudo busctl monitor [service]&lt;/code> (introspect selected bus)&lt;/li>
&lt;/ul>
&lt;h2 id="keyboard-service">Keyboard service&lt;/h2>
&lt;p>To serve as a keyboard we only need to do two things: register our service
and wait for connection.&lt;/p>
&lt;p>Registration is done by calling the &lt;code>org.bluez.ProfileManager1.RegisterProfile&lt;/code>
method with appropriate parameters.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># UUID for HID service (1124)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># https://www.bluetooth.com/specifications/assigned-numbers/service-discovery&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>UUID &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#34;00001124-0000-1000-8000-00805f9b34fb&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>PROFILE_DBUS_PATH &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#34;/bluez/msm/bluekeyboard&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>print(&lt;span style="color:#e6db74">&amp;#34;Registering the profile...&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>opts &lt;span style="color:#f92672">=&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;Role&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;server&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;RequireAuthentication&amp;#34;&lt;/span>: &lt;span style="color:#66d9ef">False&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;RequireAuthorization&amp;#34;&lt;/span>: &lt;span style="color:#66d9ef">False&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;AutoConnect&amp;#34;&lt;/span>: &lt;span style="color:#66d9ef">True&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;ServiceRecord&amp;#34;&lt;/span>: (Path(__file__)&lt;span style="color:#f92672">.&lt;/span>parent &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#e6db74">&amp;#34;service.xml&amp;#34;&lt;/span>)&lt;span style="color:#f92672">.&lt;/span>read_text(),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>bluez &lt;span style="color:#f92672">=&lt;/span> bus&lt;span style="color:#f92672">.&lt;/span>get_object(&lt;span style="color:#e6db74">&amp;#34;org.bluez&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;/org/bluez&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>manager &lt;span style="color:#f92672">=&lt;/span> dbus&lt;span style="color:#f92672">.&lt;/span>Interface(bluez, &lt;span style="color:#e6db74">&amp;#34;org.bluez.ProfileManager1&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>manager&lt;span style="color:#f92672">.&lt;/span>RegisterProfile(PROFILE_DBUS_PATH, UUID, opts)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Looks pretty straightforward, right? Wait, what is &lt;code>service.xml&lt;/code>? Glad you&amp;rsquo;ve asked
(&lt;a href="https://github.com/msm-code/RandomCodes/blob/master/bluetooth-keyboard/service.xml">service.xml&lt;/a>):&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;UTF-8&amp;#34; ?&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">&amp;lt;record&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;attribute&lt;/span> &lt;span style="color:#a6e22e">id=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0001&amp;#34;&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;uuid&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x1124&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;attribute&lt;/span> &lt;span style="color:#a6e22e">id=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0004&amp;#34;&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;uuid&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0100&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;uint16&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0011&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;uuid&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0011&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;attribute&lt;/span> &lt;span style="color:#a6e22e">id=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0005&amp;#34;&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;uuid&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x1002&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;attribute&lt;/span> &lt;span style="color:#a6e22e">id=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0006&amp;#34;&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;uint16&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x656e&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;uint16&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x006a&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;uint16&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0100&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;attribute&lt;/span> &lt;span style="color:#a6e22e">id=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0009&amp;#34;&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;uuid&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x1124&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;uint16&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0100&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;attribute&lt;/span> &lt;span style="color:#a6e22e">id=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x000d&amp;#34;&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;uuid&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0100&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;uint16&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0013&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;uuid&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0011&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;attribute&lt;/span> &lt;span style="color:#a6e22e">id=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0100&amp;#34;&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;text&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;Raspberry Pi Virtual Keyboard&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;attribute&lt;/span> &lt;span style="color:#a6e22e">id=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0101&amp;#34;&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;text&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;USB &amp;gt; BT Keyboard&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;attribute&lt;/span> &lt;span style="color:#a6e22e">id=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0102&amp;#34;&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;text&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;Raspberry Pi&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;attribute&lt;/span> &lt;span style="color:#a6e22e">id=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0200&amp;#34;&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;uint16&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0100&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;attribute&lt;/span> &lt;span style="color:#a6e22e">id=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0201&amp;#34;&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;uint16&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0111&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;attribute&lt;/span> &lt;span style="color:#a6e22e">id=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0202&amp;#34;&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;uint8&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x40&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;attribute&lt;/span> &lt;span style="color:#a6e22e">id=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0203&amp;#34;&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;uint8&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x00&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;attribute&lt;/span> &lt;span style="color:#a6e22e">id=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0204&amp;#34;&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;boolean&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;false&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;attribute&lt;/span> &lt;span style="color:#a6e22e">id=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0205&amp;#34;&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;boolean&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;false&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;attribute&lt;/span> &lt;span style="color:#a6e22e">id=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0206&amp;#34;&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;uint8&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x22&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;text&lt;/span> &lt;span style="color:#a6e22e">encoding=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;hex&amp;#34;&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;05010906a101850175019508050719e029e715002501810295017508810395057501050819012905910295017503910395067508150026ff000507190029ff8100c0050c0901a1018503150025017501950b0a23020a21020ab10109b809b609cd09b509e209ea09e9093081029501750d8103c0&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;attribute&lt;/span> &lt;span style="color:#a6e22e">id=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0207&amp;#34;&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;uint16&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0409&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;uint16&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0100&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/sequence&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;attribute&lt;/span> &lt;span style="color:#a6e22e">id=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x020b&amp;#34;&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;uint16&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0100&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;attribute&lt;/span> &lt;span style="color:#a6e22e">id=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x020c&amp;#34;&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;uint16&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0c80&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;attribute&lt;/span> &lt;span style="color:#a6e22e">id=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x020d&amp;#34;&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;boolean&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;true&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;attribute&lt;/span> &lt;span style="color:#a6e22e">id=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x020e&amp;#34;&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;boolean&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;false&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;attribute&lt;/span> &lt;span style="color:#a6e22e">id=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x020f&amp;#34;&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;uint16&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0640&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;attribute&lt;/span> &lt;span style="color:#a6e22e">id=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0210&amp;#34;&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;uint16&lt;/span> &lt;span style="color:#a6e22e">value=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0x0320&amp;#34;&lt;/span> &lt;span style="color:#f92672">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">&amp;lt;/record&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Ok, what is &lt;strong>that&lt;/strong>? It&amp;rsquo;s an SDP record. SDP (Service Discovery Protocol) records
describe characteristics of the device that may be used by remote devices. I won&amp;rsquo;t
explain how it works: partly because it&amp;rsquo;s out of scope of this post, and partly
because I have no idea myself. But it works.&lt;/p>
&lt;p>The second part of the puzzle is waiting for a connection. Fortunately Python3
natively supports Bluetooth sockets, so no external dependencies are required:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>scontrol &lt;span style="color:#f92672">=&lt;/span> socket&lt;span style="color:#f92672">.&lt;/span>socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>scontrol&lt;span style="color:#f92672">.&lt;/span>setsockopt(socket&lt;span style="color:#f92672">.&lt;/span>SOL_SOCKET, socket&lt;span style="color:#f92672">.&lt;/span>SO_REUSEADDR, &lt;span style="color:#ae81ff">1&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>scontrol&lt;span style="color:#f92672">.&lt;/span>bind((address, P_CTRL))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>scontrol&lt;span style="color:#f92672">.&lt;/span>listen(&lt;span style="color:#ae81ff">1&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sinterrupt &lt;span style="color:#f92672">=&lt;/span> socket&lt;span style="color:#f92672">.&lt;/span>socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sinterrupt&lt;span style="color:#f92672">.&lt;/span>setsockopt(socket&lt;span style="color:#f92672">.&lt;/span>SOL_SOCKET, socket&lt;span style="color:#f92672">.&lt;/span>SO_REUSEADDR, &lt;span style="color:#ae81ff">1&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sinterrupt&lt;span style="color:#f92672">.&lt;/span>bind((address, P_INTR))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sinterrupt&lt;span style="color:#f92672">.&lt;/span>listen(&lt;span style="color:#ae81ff">1&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>scontrol, sinfo &lt;span style="color:#f92672">=&lt;/span> scontrol&lt;span style="color:#f92672">.&lt;/span>accept()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>print(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;Connected on the control socket &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>sinfo[&lt;span style="color:#ae81ff">0&lt;/span>]&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cinterrupt, cinfo &lt;span style="color:#f92672">=&lt;/span> sinterrupt&lt;span style="color:#f92672">.&lt;/span>accept()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>print(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;Connected on the interrupt channel &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>cinfo[&lt;span style="color:#ae81ff">0&lt;/span>]&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="scan-codes">Scan codes&lt;/h2>
&lt;p>Only one thing left to code - we want to send keystrokes to the connected device.
This is done by sending a command packet to the socket. The format is:&lt;/p>
&lt;pre tabindex="0">&lt;code>[0xA1, 0x01, modifier, 0, key0, key1, key2, key3, key4, key5]
&lt;/code>&lt;/pre>&lt;p>But remember that you always have to notify the remote that the keys were
released, by zeroing out the keys in the next packet. So let&amp;rsquo;s implement that:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">send_char&lt;/span>(char, cinterrupt):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> keycode, shift &lt;span style="color:#f92672">=&lt;/span> char_to_keycode(char)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> modkey &lt;span style="color:#f92672">=&lt;/span> (&lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#f92672">&amp;lt;&amp;lt;&lt;/span> &lt;span style="color:#ae81ff">6&lt;/span>) &lt;span style="color:#66d9ef">if&lt;/span> shift &lt;span style="color:#66d9ef">else&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cinterrupt&lt;span style="color:#f92672">.&lt;/span>send(bytes([&lt;span style="color:#ae81ff">0xA1&lt;/span>, &lt;span style="color:#ae81ff">1&lt;/span>, modkey, &lt;span style="color:#ae81ff">0&lt;/span>, keycode, &lt;span style="color:#ae81ff">0&lt;/span>, &lt;span style="color:#ae81ff">0&lt;/span>, &lt;span style="color:#ae81ff">0&lt;/span>, &lt;span style="color:#ae81ff">0&lt;/span>, &lt;span style="color:#ae81ff">0&lt;/span>]))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> time&lt;span style="color:#f92672">.&lt;/span>sleep(&lt;span style="color:#ae81ff">0.01&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cinterrupt&lt;span style="color:#f92672">.&lt;/span>send(bytes([&lt;span style="color:#ae81ff">0xA1&lt;/span>, &lt;span style="color:#ae81ff">1&lt;/span>, &lt;span style="color:#ae81ff">0&lt;/span>, &lt;span style="color:#ae81ff">0&lt;/span>, &lt;span style="color:#ae81ff">0&lt;/span>, &lt;span style="color:#ae81ff">0&lt;/span>, &lt;span style="color:#ae81ff">0&lt;/span>, &lt;span style="color:#ae81ff">0&lt;/span>, &lt;span style="color:#ae81ff">0&lt;/span>, &lt;span style="color:#ae81ff">0&lt;/span>]))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> time&lt;span style="color:#f92672">.&lt;/span>sleep(&lt;span style="color:#ae81ff">0.01&lt;/span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The trick is that we&amp;rsquo;re sending keycodes, not chars. You can observe keycodes with
many utilities, for example, &lt;code>xev&lt;/code>. I couldn&amp;rsquo;t find an easy way to convert char
to keycode in python, so I went the easy way and just hardcoded the ones I needed
(&lt;a href="https://github.com/msm-code/RandomCodes/blob/master/bluetooth-keyboard/keycodes.py">keycodes.py&lt;/a>):&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">char_to_keycode&lt;/span>(char):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> keymap &lt;span style="color:#f92672">=&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;1&amp;#34;&lt;/span>: (&lt;span style="color:#ae81ff">30&lt;/span>, &lt;span style="color:#66d9ef">False&lt;/span>),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;2&amp;#34;&lt;/span>: (&lt;span style="color:#ae81ff">31&lt;/span>, &lt;span style="color:#66d9ef">False&lt;/span>),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;3&amp;#34;&lt;/span>: (&lt;span style="color:#ae81ff">32&lt;/span>, &lt;span style="color:#66d9ef">False&lt;/span>),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;!&amp;#34;&lt;/span>: (&lt;span style="color:#ae81ff">30&lt;/span>, &lt;span style="color:#66d9ef">True&lt;/span>),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> keymap[char]
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>For the demo we&amp;rsquo;ll just read user input in a loop and send it char by char to the remote:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">while&lt;/span> &lt;span style="color:#66d9ef">True&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> text &lt;span style="color:#f92672">=&lt;/span> input()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">for&lt;/span> c &lt;span style="color:#f92672">in&lt;/span> text &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#e6db74">&amp;#34;&lt;/span>&lt;span style="color:#ae81ff">\n&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> send_char(c, cinterrupt)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>That&amp;rsquo;s all! Put all the pieces together in &lt;a href="https://github.com/msm-code/RandomCodes/blob/master/bluetooth-keyboard/bluetooth_server.py">bluetooth_server.py&lt;/a>.&lt;/p>
&lt;h2 id="connect-the-victim">Connect the victim&lt;/h2>
&lt;p>We&amp;rsquo;re almost done! Now we must disable &lt;code>input&lt;/code> plugin in Bluetooth,
otherwise the keyboard code will not work:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo vim /etc/systemd/system/bluetooth.target.wants/bluetooth.service
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Add the &lt;code>-P input&lt;/code> parameter:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-diff" data-lang="diff">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">9c9
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;lt; ExecStart=/usr/lib/bluetooth/bluetoothd
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">&lt;/span>&lt;span style="font-weight:bold">---
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="font-weight:bold">&lt;/span>&lt;span style="color:#a6e22e">&amp;gt; ExecStart=/usr/lib/bluetooth/bluetoothd -P input
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And restart the service:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo systemctl daemon-reload
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo systemctl restart Bluetooth
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Make sure that the service runs on your machine and has the expected parameter:&lt;/p>
&lt;pre tabindex="0">&lt;code>$ ps aux | grep bluetoothd
root 230 0.0 0.0 8628 5108 ? Ss 02:08 0:00 /usr/lib/bluetooth/bluetoothd -P
&lt;/code>&lt;/pre>&lt;p>Time to start our program:&lt;/p>
&lt;pre tabindex="0">&lt;code>$ sudo python3 bluetooth_server.py
Registering the profile...
Waiting for connections...
&lt;/code>&lt;/pre>&lt;p>Now let&amp;rsquo;s connect the victim to your new &amp;ldquo;keyboard&amp;rdquo;. Start the agent with bluetoothctl:&lt;/p>
&lt;pre tabindex="0">&lt;code>$ sudo bluetoothctl
Agent registered
[bluetooth]# power on
Changing power on succeeded
[bluetooth]# discoverable on
Changing discoverable on succeeded
[CHG] Controller 00:21:5C:B0:89:56 Discoverable: yes
[bluetooth]# default-agent
Default agent request successful
&lt;/code>&lt;/pre>&lt;p>Your machine should now be discoverable. You&amp;rsquo;ll need to confirm pin in the
terminal (and optionally authorize some services):&lt;/p>
&lt;pre tabindex="0">&lt;code>[NEW] Device 23:1D:C1:F4:10:1D Z2K21E1
Request confirmation
[agent] Confirm passkey 216956 (yes/no): yes
&lt;/code>&lt;/pre>&lt;p>If everything went right, the remote machine should now connect to your &amp;ldquo;keyboard&amp;rdquo;
and you can send your keystrokes. And without any USB cables. The future is now.&lt;/p>
&lt;h2 id="closing-thoughts">Closing thoughts&lt;/h2>
&lt;p>The (second) real reason for this post was that I&amp;rsquo;ve wanted to play with dbus
and bluetooth for a long time. Now I had a good reason to do both.&lt;/p>
&lt;p>My day job and main interest is security, so obviously I immediately thought
how to abuse this. And I&amp;rsquo;m not impressed - I can easily masquerade my
keyboard-wannabe Raspberry Pi as an audio player device. It&amp;rsquo;s easy to imagine
an attack scenario where someone pairs with innocent looking speakers, only
to be hacked by injected keystrokes. Nevertheless, I&amp;rsquo;m glad the USB flaws
are not going away, and we can port Rubber Ducky to Bluetooth.&lt;/p>
&lt;p>All the code for this post is &lt;a href="https://github.com/msm-code/RandomCodes/tree/master/bluetooth-keyboard">on Github&lt;/a>:
&lt;a href="https://github.com/msm-code/RandomCodes/tree/master/bluetooth-keyboard">https://github.com/msm-code/RandomCodes/tree/master/bluetooth-keyboard&lt;/a>.&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>In fact, the API changed completely a few years ago, and that&amp;rsquo;s the
reason why old code doesn&amp;rsquo;t work anymore.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Cracking RNGs: Linear Congruential Generators</title><link>https://msm.lt/posts/cracking-rngs-lcgs/</link><pubDate>Mon, 10 Jul 2017 00:00:00 +0000</pubDate><guid>https://msm.lt/posts/cracking-rngs-lcgs/</guid><description>&lt;p>Random numbers are often useful during programming - they can be used for rendering pretty animations, generating interesting content in computer games, load balancing, executing a randomized algorithm, etc. Unfortunately, CPUs are deterministic machines, and (controversial RDRAND instruction aside) cannot just generate random numbers out of thin air. This left programmers and computer designers with few options:&lt;/p>
&lt;ul>
&lt;li>Invest in additional devices (&lt;a href="https://en.wikipedia.org/wiki/Hardware_random_number_generator">Hardware Random Number Generators&lt;/a>).&lt;/li>
&lt;li>Use existing hardware in an unintended way (for example, by collecting lowest bits of audio input from a microphone, measuring hard disk seek times or timing keystrokes).&lt;/li>
&lt;li>Fake it - generate numbers that &amp;ldquo;look&amp;rdquo; random, but aren&amp;rsquo;t.&lt;/li>
&lt;/ul>
&lt;p>All these options were explored, but dedicated devices never went mainstream, and other ways of gathering entropy have too small throughput to be used exclusively. This left programmers with the third option - numbers that look random but are in fact generated by a completely deterministic algorithm. These algorithms are called &amp;ldquo;&lt;a href="https://en.wikipedia.org/wiki/Pseudorandom_number_generator">Pseudo Random Number Generators&lt;/a>&amp;rdquo;, or PRNGs in short.&lt;/p>
&lt;p>PRNGs are usually really good at generating statistically random numbers. A quality of generator can be measured by one of few standardized tests, like &lt;a href="https://en.wikipedia.org/wiki/TestU01">TestU01&lt;/a> or &lt;a href="https://en.wikipedia.org/wiki/Diehard_tests">DIEHARD test suite&lt;/a> - and good PRNGs are often as good as true random number generators (TRNG).&lt;/p>
&lt;p>Unfortunately, there is one problem with PRNGs that cannot be fixed - they are still deterministic &amp;ldquo;in heart&amp;rdquo;, and knowing a full internal state of PRNG allows an attacker to predict all future (and, usually, previous) values. This usually isn&amp;rsquo;t a problem, unless PRNGs are used for security sensitive things - like generating certificates, encryption keys, secrets, etc &lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>. In this post, I&amp;rsquo;ll show how easily PRNGs can be cracked (cracking PRNG means recovering its internal state and predicting future values).&lt;/p>
&lt;p>This time I&amp;rsquo;ll focus on one specific kind of PRNGs - &lt;a href="https://en.wikipedia.org/wiki/Linear_congruential_generator">Linear Congruential Generators&lt;/a>. They are defined by three integers, &amp;ldquo;multiplier&amp;rdquo;, &amp;ldquo;increment&amp;rdquo; and &amp;ldquo;modulus&amp;rdquo;, and can be implemented in three lines of Python code:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">prng_lcg&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> m &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">672257317069504227&lt;/span> &lt;span style="color:#75715e"># the &amp;#34;multiplier&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> c &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">7382843889490547368&lt;/span> &lt;span style="color:#75715e"># the &amp;#34;increment&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> n &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">9223372036854775783&lt;/span> &lt;span style="color:#75715e"># the &amp;#34;modulus&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> __init__(self, seed):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>state &lt;span style="color:#f92672">=&lt;/span> seed &lt;span style="color:#75715e"># the &amp;#34;seed&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">next&lt;/span>(self):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>state &lt;span style="color:#f92672">=&lt;/span> (self&lt;span style="color:#f92672">.&lt;/span>state &lt;span style="color:#f92672">*&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>m &lt;span style="color:#f92672">+&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>c) &lt;span style="color:#f92672">%&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>n
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>state
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">test&lt;/span>():
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> gen &lt;span style="color:#f92672">=&lt;/span> prng_lcg(&lt;span style="color:#ae81ff">123&lt;/span>) &lt;span style="color:#75715e"># seed = 123&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print gen&lt;span style="color:#f92672">.&lt;/span>next() &lt;span style="color:#75715e"># generate first value&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print gen&lt;span style="color:#f92672">.&lt;/span>next() &lt;span style="color:#75715e"># generate second value&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print gen&lt;span style="color:#f92672">.&lt;/span>next() &lt;span style="color:#75715e"># generate third value&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>LCGs are one of the most popular pseudo-random number generators. There are reasons for that: they&amp;rsquo;re mathematically elegant, very easy to understand/implement and very fast, especially when a modulus is a power of two (because slow modular division can be replaced with binary AND in this case). Unfortunately, they&amp;rsquo;re not perfect at being statistically random (depending on chosen constants, resulting bits often have varying level of &amp;ldquo;randomness&amp;rdquo;) and, as we&amp;rsquo;ll see soon, are dramatically weak at being cryptographically secure.&lt;/p>
&lt;h3 id="challenge-0-everything-known">Challenge 0: everything known&lt;/h3>
&lt;p>After a short theoretical introduction, let&amp;rsquo;s focus on the attacks. This is not actually a challenge yet, just explanation of what we&amp;rsquo;re trying to achieve. Let&amp;rsquo;s say that we are observing one LCG, and it generated three consecutive values:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>s0 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">2300417199649672133&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>s1 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">2071270403368304644&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>s2 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">5907618127072939765&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And we want to learn the next value that will be generated, without actually calling PRNG again. In this case, we have all necessary information (state, m, c, n) so the problem is trivial - we just plug the values into the formula. Let&amp;rsquo;s check:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>In [&lt;span style="color:#ae81ff">929&lt;/span>]: m &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">672257317069504227&lt;/span> &lt;span style="color:#75715e"># the &amp;#34;multiplier&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">...&lt;/span>: c &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">7382843889490547368&lt;/span> &lt;span style="color:#75715e"># the &amp;#34;increment&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">...&lt;/span>: n &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">9223372036854775783&lt;/span> &lt;span style="color:#75715e"># the &amp;#34;modulus&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">...&lt;/span>: s0 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">2300417199649672133&lt;/span> &lt;span style="color:#75715e"># seed&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>In [&lt;span style="color:#ae81ff">931&lt;/span>]: s1 &lt;span style="color:#f92672">=&lt;/span> (s0&lt;span style="color:#f92672">*&lt;/span>m &lt;span style="color:#f92672">+&lt;/span> c) &lt;span style="color:#f92672">%&lt;/span> n
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>In [&lt;span style="color:#ae81ff">931&lt;/span>]: s2 &lt;span style="color:#f92672">=&lt;/span> (s1&lt;span style="color:#f92672">*&lt;/span>m &lt;span style="color:#f92672">+&lt;/span> c) &lt;span style="color:#f92672">%&lt;/span> n
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>In [&lt;span style="color:#ae81ff">932&lt;/span>]: s3 &lt;span style="color:#f92672">=&lt;/span> (s2&lt;span style="color:#f92672">*&lt;/span>m &lt;span style="color:#f92672">+&lt;/span> c) &lt;span style="color:#f92672">%&lt;/span> n
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>In [&lt;span style="color:#ae81ff">933&lt;/span>]: s4 &lt;span style="color:#f92672">=&lt;/span> (s3&lt;span style="color:#f92672">*&lt;/span>m &lt;span style="color:#f92672">+&lt;/span> c) &lt;span style="color:#f92672">%&lt;/span> n
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>In [&lt;span style="color:#ae81ff">934&lt;/span>]: s1
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Out[&lt;span style="color:#ae81ff">934&lt;/span>]: &lt;span style="color:#ae81ff">2071270403368304644&lt;/span>L &lt;span style="color:#75715e"># correct&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>In [&lt;span style="color:#ae81ff">935&lt;/span>]: s2
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Out[&lt;span style="color:#ae81ff">935&lt;/span>]: &lt;span style="color:#ae81ff">5907618127072939765&lt;/span>L &lt;span style="color:#75715e"># correct&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>In [&lt;span style="color:#ae81ff">936&lt;/span>]: s3
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Out[&lt;span style="color:#ae81ff">936&lt;/span>]: &lt;span style="color:#ae81ff">5457707446309988294&lt;/span>L &lt;span style="color:#75715e"># predicted!&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>We know a full internal state of our LCG, and we can easily generate all future values. In fact, we can even go back and get all previously generated values, which is a security problem too.&lt;/p>
&lt;h3 id="challenge-1-unknown-increment">Challenge 1: unknown increment&lt;/h3>
&lt;p>Ok, let&amp;rsquo;s move to the first challenge. What if we don&amp;rsquo;t know &amp;ldquo;increment&amp;rdquo;? i.e:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>m &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">81853448938945944&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>c &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#75715e"># unknown&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>n &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">9223372036854775783&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And let&amp;rsquo;s say that we know two consecutive values generated by this LCG:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>s0 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">4501678582054734753&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>s1 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">4371244338968431602&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Can we still attack this? Again, in this case, all values are 64bit, too much to bruteforce it. Let&amp;rsquo;s use some basic math instead.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>s1 &lt;span style="color:#f92672">=&lt;/span> s0&lt;span style="color:#f92672">*&lt;/span>m &lt;span style="color:#f92672">+&lt;/span> c (mod n)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>c &lt;span style="color:#f92672">=&lt;/span> s1 &lt;span style="color:#f92672">-&lt;/span> s0&lt;span style="color:#f92672">*&lt;/span>m (mod n)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Easy. Now we can implement our attack in Python and plug concrete values in:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">crack_unknown_increment&lt;/span>(states, modulus, multiplier):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> increment &lt;span style="color:#f92672">=&lt;/span> (states[&lt;span style="color:#ae81ff">1&lt;/span>] &lt;span style="color:#f92672">-&lt;/span> states[&lt;span style="color:#ae81ff">0&lt;/span>]&lt;span style="color:#f92672">*&lt;/span>multiplier) &lt;span style="color:#f92672">%&lt;/span> modulus
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> modulus, multiplier, increment
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>print crack_unknown_increment([&lt;span style="color:#ae81ff">4501678582054734753&lt;/span>, &lt;span style="color:#ae81ff">4371244338968431602&lt;/span>], &lt;span style="color:#ae81ff">9223372036854775783&lt;/span>, &lt;span style="color:#ae81ff">81853448938945944&lt;/span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>That&amp;rsquo;s it - challenge solved.&lt;/p>
&lt;h3 id="challenge-2-unknown-increment-and-multiplier">Challenge 2: unknown increment and multiplier&lt;/h3>
&lt;p>Previous two levels were rather trivial, time for something more interesting. Now we know neither multiplier nor increment:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>m &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#75715e"># unknown&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>c &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#75715e"># unknown&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>n &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">9223372036854775783&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now we don&amp;rsquo;t know increment and multiplier. At least we get to know three consecutive values from LCG:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>s0 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">6473702802409947663&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>s1 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">6562621845583276653&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>s2 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">4483807506768649573&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This looks much harder, but really isn&amp;rsquo;t - we still have two linear equations, and two unknowns, so everything should go smoothly:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>s_1 &lt;span style="color:#f92672">=&lt;/span> s0&lt;span style="color:#f92672">*&lt;/span>m &lt;span style="color:#f92672">+&lt;/span> c (mod n)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>s_2 &lt;span style="color:#f92672">=&lt;/span> s1&lt;span style="color:#f92672">*&lt;/span>m &lt;span style="color:#f92672">+&lt;/span> c (mod n)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>s_2 &lt;span style="color:#f92672">-&lt;/span> s_1 &lt;span style="color:#f92672">=&lt;/span> s1&lt;span style="color:#f92672">*&lt;/span>m &lt;span style="color:#f92672">-&lt;/span> s0&lt;span style="color:#f92672">*&lt;/span>m (mod n)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>s_2 &lt;span style="color:#f92672">-&lt;/span> s_1 &lt;span style="color:#f92672">=&lt;/span> m&lt;span style="color:#f92672">*&lt;/span>(s1 &lt;span style="color:#f92672">-&lt;/span> s0) (mod n)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>m &lt;span style="color:#f92672">=&lt;/span> (s_2 &lt;span style="color:#f92672">-&lt;/span> s_1)&lt;span style="color:#f92672">/&lt;/span>(s_1 &lt;span style="color:#f92672">-&lt;/span> s_0) (mod n)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And when we know multiplier, problem is reduced to the one we already solved in chellenge 1. Let&amp;rsquo;s implement this in Python:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">crack_unknown_multiplier&lt;/span>(states, modulus):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> multiplier &lt;span style="color:#f92672">=&lt;/span> (states[&lt;span style="color:#ae81ff">2&lt;/span>] &lt;span style="color:#f92672">-&lt;/span> states[&lt;span style="color:#ae81ff">1&lt;/span>]) &lt;span style="color:#f92672">*&lt;/span> modinv(states[&lt;span style="color:#ae81ff">1&lt;/span>] &lt;span style="color:#f92672">-&lt;/span> states[&lt;span style="color:#ae81ff">0&lt;/span>], modulus) &lt;span style="color:#f92672">%&lt;/span> modulus
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> crack_unknown_increment(states, modulus, multiplier)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>print crack_unknown_multiplier([&lt;span style="color:#ae81ff">6473702802409947663&lt;/span>, &lt;span style="color:#ae81ff">6562621845583276653&lt;/span>, &lt;span style="color:#ae81ff">4483807506768649573&lt;/span>], &lt;span style="color:#ae81ff">9223372036854775783&lt;/span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This algorithm uses modular division, so we&amp;rsquo;ll need modular inverse too. We can use &lt;a href="https://en.wikibooks.org/wiki/Algorithm_Implementation/Mathematics/Extended_Euclidean_algorithm">this one&lt;/a>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">egcd&lt;/span>(a, b):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> a &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> (b, &lt;span style="color:#ae81ff">0&lt;/span>, &lt;span style="color:#ae81ff">1&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">else&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> g, x, y &lt;span style="color:#f92672">=&lt;/span> egcd(b &lt;span style="color:#f92672">%&lt;/span> a, a)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> (g, y &lt;span style="color:#f92672">-&lt;/span> (b &lt;span style="color:#f92672">//&lt;/span> a) &lt;span style="color:#f92672">*&lt;/span> x, x)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">modinv&lt;/span>(b, n):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> g, x, _ &lt;span style="color:#f92672">=&lt;/span> egcd(b, n)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> g &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> x &lt;span style="color:#f92672">%&lt;/span> n
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="challenge-3-unknown-increment-multiplier-and-modulus">Challenge 3: unknown increment, multiplier and modulus&lt;/h3>
&lt;p>Now a list of values that we know doesn&amp;rsquo;t look very interesting:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>m &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#75715e"># unknown&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>c &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#75715e"># unknown&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>n &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#75715e"># unknown&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>But we have a lot of generated integers:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>s0 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">2818206783446335158&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>s1 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">3026581076925130250&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>s2 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">136214319011561377&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>s3 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">359019108775045580&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>s4 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">2386075359657550866&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>s5 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">1705259547463444505&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>s6 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">2102452637059633432&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Unfortunatelly, this time we can&amp;rsquo;t solve this with simple linear equations - we don&amp;rsquo;t know modulus, so every equation we&amp;rsquo;ll form will introduce new unknown:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>s1 &lt;span style="color:#f92672">=&lt;/span> s0&lt;span style="color:#f92672">*&lt;/span>m &lt;span style="color:#f92672">+&lt;/span> c (mod n)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>s2 &lt;span style="color:#f92672">=&lt;/span> s1&lt;span style="color:#f92672">*&lt;/span>m &lt;span style="color:#f92672">+&lt;/span> c (mod n)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>s3 &lt;span style="color:#f92672">=&lt;/span> s2&lt;span style="color:#f92672">*&lt;/span>m &lt;span style="color:#f92672">+&lt;/span> c (mod n)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This doesn&amp;rsquo;t look bad - three equations and three unknowns. At least until we remember, that by definition this really is equivalent to:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>s1 &lt;span style="color:#f92672">-&lt;/span> (s0&lt;span style="color:#f92672">*&lt;/span>m &lt;span style="color:#f92672">+&lt;/span> c) &lt;span style="color:#f92672">=&lt;/span> k_1 &lt;span style="color:#f92672">*&lt;/span> n
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>s2 &lt;span style="color:#f92672">-&lt;/span> (s1&lt;span style="color:#f92672">*&lt;/span>m &lt;span style="color:#f92672">+&lt;/span> c) &lt;span style="color:#f92672">=&lt;/span> k_2 &lt;span style="color:#f92672">*&lt;/span> n
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>s3 &lt;span style="color:#f92672">-&lt;/span> (s2&lt;span style="color:#f92672">*&lt;/span>m &lt;span style="color:#f92672">+&lt;/span> c) &lt;span style="color:#f92672">=&lt;/span> k_3 &lt;span style="color:#f92672">*&lt;/span> n
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Six unknowns and three equations. And it&amp;rsquo;s clear that no number of equations will help us because every new equation introduces new unknown. Fortunately, there is a mathematical trick that usually comes in handy in situations like this. Namely, interesting number theory fact: if we have few random multiples of n, with large probability their gcd will be equal to n. For example:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>In [&lt;span style="color:#ae81ff">944&lt;/span>]: n &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">123456789&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>In [&lt;span style="color:#ae81ff">945&lt;/span>]: reduce(gcd, [randint(&lt;span style="color:#ae81ff">1&lt;/span>, &lt;span style="color:#ae81ff">1000000&lt;/span>)&lt;span style="color:#f92672">*&lt;/span>n, randint(&lt;span style="color:#ae81ff">1&lt;/span>, &lt;span style="color:#ae81ff">1000000&lt;/span>)&lt;span style="color:#f92672">*&lt;/span>n, randint(&lt;span style="color:#ae81ff">1&lt;/span>, &lt;span style="color:#ae81ff">1000000&lt;/span>)&lt;span style="color:#f92672">*&lt;/span>n])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Out[&lt;span style="color:#ae81ff">945&lt;/span>]: &lt;span style="color:#ae81ff">123456789&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Why is this useful? Because if we can think of some modular operations that will give something congruent to zero, for example:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>X &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> (mod n)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Then, by definition, this is equivalent to:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>X &lt;span style="color:#f92672">=&lt;/span> k&lt;span style="color:#f92672">*&lt;/span>n
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This is only interesting if X != 0, but X = 0 (mod n). We just need to take a gcd from few such values, and we can recover n. This is a really generic method, that can often be used when modulus that we&amp;rsquo;re using is unknown.&lt;/p>
&lt;p>Ok, now how can we generate something like this for above LCG? We can introduce sequence T(n) = S(n+1) - S(n):&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>t0 &lt;span style="color:#f92672">=&lt;/span> s1 &lt;span style="color:#f92672">-&lt;/span> s0
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>t1 &lt;span style="color:#f92672">=&lt;/span> s2 &lt;span style="color:#f92672">-&lt;/span> s1 &lt;span style="color:#f92672">=&lt;/span> (s1&lt;span style="color:#f92672">*&lt;/span>m &lt;span style="color:#f92672">+&lt;/span> c) &lt;span style="color:#f92672">-&lt;/span> (s0&lt;span style="color:#f92672">*&lt;/span>m &lt;span style="color:#f92672">+&lt;/span> c) &lt;span style="color:#f92672">=&lt;/span> m&lt;span style="color:#f92672">*&lt;/span>(s1 &lt;span style="color:#f92672">-&lt;/span> s0) &lt;span style="color:#f92672">=&lt;/span> m&lt;span style="color:#f92672">*&lt;/span>t0 (mod n)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>t2 &lt;span style="color:#f92672">=&lt;/span> s3 &lt;span style="color:#f92672">-&lt;/span> s2 &lt;span style="color:#f92672">=&lt;/span> (s2&lt;span style="color:#f92672">*&lt;/span>m &lt;span style="color:#f92672">+&lt;/span> c) &lt;span style="color:#f92672">-&lt;/span> (s1&lt;span style="color:#f92672">*&lt;/span>m &lt;span style="color:#f92672">+&lt;/span> c) &lt;span style="color:#f92672">=&lt;/span> m&lt;span style="color:#f92672">*&lt;/span>(s2 &lt;span style="color:#f92672">-&lt;/span> s1) &lt;span style="color:#f92672">=&lt;/span> m&lt;span style="color:#f92672">*&lt;/span>t1 (mod n)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>t3 &lt;span style="color:#f92672">=&lt;/span> s4 &lt;span style="color:#f92672">-&lt;/span> s3 &lt;span style="color:#f92672">=&lt;/span> (s3&lt;span style="color:#f92672">*&lt;/span>m &lt;span style="color:#f92672">+&lt;/span> c) &lt;span style="color:#f92672">-&lt;/span> (s2&lt;span style="color:#f92672">*&lt;/span>m &lt;span style="color:#f92672">+&lt;/span> c) &lt;span style="color:#f92672">=&lt;/span> m&lt;span style="color:#f92672">*&lt;/span>(s3 &lt;span style="color:#f92672">-&lt;/span> s2) &lt;span style="color:#f92672">=&lt;/span> m&lt;span style="color:#f92672">*&lt;/span>t2 (mod n)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And now we can use this trick to generate our desired operation:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>t2&lt;span style="color:#f92672">*&lt;/span>t0 &lt;span style="color:#f92672">-&lt;/span> t1&lt;span style="color:#f92672">*&lt;/span>t1 &lt;span style="color:#f92672">=&lt;/span> (m&lt;span style="color:#f92672">*&lt;/span>m&lt;span style="color:#f92672">*&lt;/span>t0 &lt;span style="color:#f92672">*&lt;/span> t0) &lt;span style="color:#f92672">-&lt;/span> (m&lt;span style="color:#f92672">*&lt;/span>t0 &lt;span style="color:#f92672">*&lt;/span> m&lt;span style="color:#f92672">*&lt;/span>t0) &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> (mod n)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Using this method we can generate few values congruent to 0, and crack LCG with mentioned &amp;ldquo;trick&amp;rdquo;. Attack in Python, again:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">crack_unknown_modulus&lt;/span>(states):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> diffs &lt;span style="color:#f92672">=&lt;/span> [s1 &lt;span style="color:#f92672">-&lt;/span> s0 &lt;span style="color:#66d9ef">for&lt;/span> s0, s1 &lt;span style="color:#f92672">in&lt;/span> zip(states, states[&lt;span style="color:#ae81ff">1&lt;/span>:])]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> zeroes &lt;span style="color:#f92672">=&lt;/span> [t2&lt;span style="color:#f92672">*&lt;/span>t0 &lt;span style="color:#f92672">-&lt;/span> t1&lt;span style="color:#f92672">*&lt;/span>t1 &lt;span style="color:#66d9ef">for&lt;/span> t0, t1, t2 &lt;span style="color:#f92672">in&lt;/span> zip(diffs, diffs[&lt;span style="color:#ae81ff">1&lt;/span>:], diffs[&lt;span style="color:#ae81ff">2&lt;/span>:])]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> modulus &lt;span style="color:#f92672">=&lt;/span> abs(reduce(gcd, zeroes))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> crack_unknown_multiplier(states, modulus)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>print crack_unknown_modulus([&lt;span style="color:#ae81ff">2818206783446335158&lt;/span>, &lt;span style="color:#ae81ff">3026581076925130250&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ae81ff">136214319011561377&lt;/span>, &lt;span style="color:#ae81ff">359019108775045580&lt;/span>, &lt;span style="color:#ae81ff">2386075359657550866&lt;/span>, &lt;span style="color:#ae81ff">1705259547463444505&lt;/span>])
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Looks like it works!&lt;/p>
&lt;h3 id="the-end">The end?&lt;/h3>
&lt;p>So we have just cracked LCG, without bruteforcing, with basically zero knowledge - only by observing its output. So can we crack every LCG in the world now? Unfortunately, no. The reason we were able to mount the attacks so easily is that all the operations are linear, and we get a complete state of LCG every time. This is basically a cryptologist&amp;rsquo;s dream.&lt;/p>
&lt;p>Unfortunately, in a real world, things aren&amp;rsquo;t always that easy. Most importantly, all these attacks can be disrupted by truncating the output - for example, using 64bit integers for computation, but returning state % 2**32. This method is often used in practice (not for improved security, but because it&amp;rsquo;s improving number distribution). Alternatively, introducing nonlinear operations somewhere will complicate attacks greatly (for example xoring state with something).&lt;/p>
&lt;p>Of course, this doesn&amp;rsquo;t mean that simple truncation will ruin our chances of cracking LCG - we&amp;rsquo;ll just have to use more complicated math, like all-powerful &lt;a href="https://en.wikipedia.org/wiki/Lenstra%E2%80%93Lenstra%E2%80%93Lov%C3%A1sz_lattice_basis_reduction_algorithm">LLL Algorithm&lt;/a>. I&amp;rsquo;ll come back to these attacks sooner or later - but this blog post is getting long anyway, and I&amp;rsquo;ve heard that nobody reads more than few pages. For now, the main takeaway from this article is:&lt;/p>
&lt;ul>
&lt;li>If you need random numbers for anything crypto related, use secure random number generator, not just any PRNG.&lt;/li>
&lt;li>LCG is not a secure RNG.&lt;/li>
&lt;/ul>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>Although CSPRNGs (Cryptographically Secure Pseudo Random Number Generators) can be used in such case&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item></channel></rss>