<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="/feeds.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="https://chameth.com/">
    <title>Chameth.com - posts like break-everything-fuzz-testing, obfuscating-kotlin-proguard but not debugging-beyond-the-debugger, finding-an-awkward-bug-with-claude-code, why-you-should-be-using-https</title>
    <subtitle>Personal homepage of Chris Smith</subtitle>
    <link href="https://chameth.com/feeds/posts/like/break-everything-fuzz-testing,obfuscating-kotlin-proguard/unlike/debugging-beyond-the-debugger,finding-an-awkward-bug-with-claude-code,why-you-should-be-using-https/" rel="self"/>
    <link href="https://chameth.com/"/>
    <icon>https://chameth.com/favicon.png</icon>
    <updated>2020-04-26T00:00:00Z</updated>
    <id>https://chameth.com/</id>
    <author>
        <name>Chris Smith</name>
    </author>
    <entry>
        <title>How to break everything by fuzz testing</title>
        <link href="https://chameth.com/break-everything-fuzz-testing/"/>
        <updated>2020-04-26T00:00:00Z</updated>
        <id>https://chameth.com/break-everything-fuzz-testing/</id>
        <content xml:lang="en" type="html">&lt;figure class=&#34;image left&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/break-everything-fuzz-testing/chimp.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/break-everything-fuzz-testing/chimp.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/break-everything-fuzz-testing/chimp.jpg&#34; alt=&#34;Chimp sat at a typewriter&#34; loading=&#34;lazy&#34; width=&#34;300&#34; height=&#34;239&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;Fuzz testing is a bit like the infinite monkey theorem, but instead of Shakespeare you get crashes.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Fuzz testing, if you’re not aware, is a form of testing that uses procedurally generated random
inputs to see how a program behaves. For instance, if you were fuzz testing a web page renderer
you might generate a bunch of HTML - some valid, and some not - and make sure the rendering
process didn’t unexpectedly crash.&lt;/p&gt;
&lt;p&gt;Fuzz testing doesn’t readily lend itself to all types of software, but it particularly shines
in cases where some kind of complex user input is accepted and processed in some way - like
the aforementioned web page renderer. I was recently adding a library to parse EXIF data to
images to an Internet-facing service and realised it was a perfect opportunity to do some fuzz
testing. Even if I didn’t find any issues, I’d improve my confidence that the library was safe
enough to expose to the Internet.&lt;/p&gt;
&lt;h3 id=&#34;breaking-my-exif-library&#34;&gt;Breaking my EXIF library&lt;/h3&gt;
&lt;p&gt;I wrote a quick harness to run &lt;a href=&#34;https://github.com/dvyukov/go-fuzz&#34;&gt;go-fuzz&lt;/a&gt; on the library,
and gave it some pre-existing demo files as sample input. The way go-fuzz works is that it
instruments your code and then mutates the inputs to try to improve the coverage. For example,
if I had some sample data that had an EXIF tag with a value of 1 then go-fuzz might change it
to a 2 and see if the code follows a different path. In most cases it won’t but when it does,
they tend to be very interesting cases.&lt;/p&gt;
&lt;!--more--&gt;
&lt;p&gt;One of the first issues that go-fuzz found was that some values in a maker note field would cause
the library to panic (i.e., crash). This happened because there was a check to see if the first
six characters were “Nikon” and a null byte, without first checking to see if there were actually
six characters available. This is a kind of bug that doesn’t happen much with “real” data - as
the field is either not present or completed correctly - but could easily be exploited once this
code is exposed to the Internet.&lt;/p&gt;
&lt;p&gt;Another interesting bug that go-fuzz found was that if a tag had a particularly large count, the
library would try to allocate an obscene amount of memory and die. There was already a check in
the code that was meant to avoid this exact scenario, but go-fuzz managed to find a way around
it. Each tag has a size (for example an integer tag takes a fixed number of bytes) and a count;
the existing check multiplied the two together and made sure that the result wasn’t too large.
For most cases this was fine but go-fuzz found a case where the count was so large that when
multiplied by the size of the tag it overflowed the integer and became negative, thus passing
the sanity check but then subsequently failing when it came around to actually allocating the
memory.&lt;/p&gt;
&lt;p&gt;The final bug of note that go-fuzz found was the most interesting. EXIF data is stored in IFDs
(“Image File Directories”), and each IFD provides what is effectively a pointer (a byte offset)
to the next one. The EXIF library already had a check to make sure that these didn’t loop, but
it only checked the immediately preceding IFD - so if IFD 1 linked to IFD 2, it would catch IFD 2
linking back to IFD 1 and break the loop with an error. Go-fuzz found that having three interlinked
IFDs had the same issue, though, and the guard code wasn’t triggered. This created an infinite
loop, maxing out a CPU core until the process was eventually killed - one of the worst kind of
bugs you could have in an Internet-facing service which doesn’t deal with private data! The fix
for this was fairly straightforward - I just made the library keep a record of the previously
visited IFDs and bail out if it found a loop.&lt;/p&gt;
&lt;h3 id=&#34;breaking-my-ide&#34;&gt;Breaking my IDE&lt;/h3&gt;
&lt;p&gt;When go-fuzz detects an issue it outputs not only the details of the problem (the stack trace,
error message, and so forth) but also the input that generated the problem. This is useful for
reproducing and making sure the issue is fixed, but it also makes it really easy to write
a test to ensure that the behaviour never regresses in the future.&lt;/p&gt;
&lt;p&gt;As I was working through fixing the bugs that go-fuzz found, I dutifully added new tests where
needed. After adding the sample input with looping IFDs to the project, I switched to IDEA to
write a test to use it. I clicked on the input file to copy the file name, and then the entire
IDE hung and had to be restarted. Uh oh! When I restarted IDEA, it immediately began indexing
the project and again hung. It turns out IDEA parses EXIF data (presumably, even if it does
nothing else with the data, to get the rotation property for images), and the library they use -
an independent one written on Java - had the same bug as the Go library I was using.&lt;/p&gt;
&lt;p&gt;In order to stop IDEA from indexing the file and becoming unusable I renamed it from a ‘.tif’
extension to ‘.dat’, and everything went back to normal. I thought I’d best report the bug to
JetBrains, though, so they could put a proper fix in.&lt;/p&gt;
&lt;h3 id=&#34;breaking-youtrack&#34;&gt;Breaking YouTrack&lt;/h3&gt;
&lt;p&gt;JetBrains use their own issue tracker called YouTrack for reporting bugs in IDEA. I dutifully
went over and described the problem, attaching the log files from the IDE, a description of how
the file was malformed, and carefully selected the .dat version of the file to upload so that it
wouldn’t cause anyone else the same immediate problem.&lt;/p&gt;
&lt;p&gt;After trying to upload the file I got a strange error back. Uh oh! I submitted the IDEA issue as
it stood, unable to see if the attachments had even uploaded, and went and wrote up an issue for
YouTrack itself about the error message. While I was doing that, YouTrack seemed to slow down and
become really annoying to use. I had a sinking feeling the exact same thing was probably
happening as with IDEA and my library - but this time YouTrack had content-sniffed the file
instead of relying on the file extension. In hindsight, I should’ve put the file in a passworded
archive to ensure no automated tools got hold of it. I marked the issue as a security problem as in
a service like YouTrack it presents a denial-of-service opportunity&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:1&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; (remember when I said it was
one of the worst kinds of bugs you could have in an Internet-facing service?…)&lt;/p&gt;
&lt;p&gt;Shortly after I raised my YouTrack ticket, a notice appeared at the top of the page saying they
were investigating the current performance issues. Uh oh! I was holding out hope that this was
unrelated to me uploading the buggy dat file, but the timing all seemed a bit suspect. I shot
support an e-mail saying I think I might be the root cause for their performance issues and
linked to the ticket. In the time it took me to e-mail them, the entire site had been
put into maintenance mode. I got an e-mail back a few hours later confirming the outage
was in fact all my fault, as I’d feared. Within the space of days the JetBrains security team
had fixed the issue in YouTrack, which was a pretty nice turnaround.&lt;/p&gt;
&lt;p&gt;So if you were trying to access YouTrack at the start of March and couldn’t - I’m sorry, I didn’t
mean to! Also, if you’re building an Internet-facing service that takes user input you should
really consider running a fuzz tester against it!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;“We have a problem”. “Remember, there are no such things as problems,
only opportunities”. “Well then we have a DDoS opportunity.”
– &lt;a href=&#34;https://twitter.com/J4vv4D/status/671090709588496384&#34;&gt;@J4vv4d&lt;/a&gt; &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:1&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    <entry>
        <title>Obfuscating Kotlin code with ProGuard</title>
        <link href="https://chameth.com/obfuscating-kotlin-proguard/"/>
        <updated>2019-10-21T00:00:00Z</updated>
        <id>https://chameth.com/obfuscating-kotlin-proguard/</id>
        <content xml:lang="en" type="html">&lt;figure class=&#34;image left&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/obfuscating-kotlin-proguard/kotlin-proguard.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/obfuscating-kotlin-proguard/kotlin-proguard.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/obfuscating-kotlin-proguard/kotlin-proguard.png&#34; alt=&#34;Kotlin and Proguard logos&#34; loading=&#34;lazy&#34; width=&#34;343&#34; height=&#34;207&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;Kotlin + Proguard = fun&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Obfuscating code is the process of modifying source code or build output in
order to make it harder for humans to understand. It’s often employed as a
tactic to deter reverse engineering of commercial applications or libraries
when you have no choice but to ship binaries or byte code. For Android apps,
&lt;a href=&#34;https://www.guardsquare.com/en/products/proguard&#34;&gt;ProGuard&lt;/a&gt; is part of the
default toolchain and obfuscation is usually only a config switch away.&lt;/p&gt;
&lt;p&gt;I was recently working on an Android library written in Kotlin that my client
wanted obfuscated to try and protect some of their trade secrets that were
included. Not a problem, I thought: it’s just a few lines of ProGuard config
and we’re away. Four hours and lots of hair pulling later I finally got it
working…&lt;/p&gt;
&lt;!--more--&gt;
&lt;h3 id=&#34;if-at-first-you-dont-succeed&#34;&gt;If at first you don’t succeed…&lt;/h3&gt;
&lt;p&gt;At first it seemed like ProGuard was refusing to obfuscate any class with a
&lt;code&gt;keep&lt;/code&gt; rule. With a simple test class:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;chroma-nc&#34;&gt;Test&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-k&#34;&gt;private&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;val&lt;/span&gt; &lt;span class=&#34;chroma-py&#34;&gt;secret&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;123&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-k&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;chroma-py&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;Chris&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-k&#34;&gt;fun&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;greet&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;        &lt;span class=&#34;chroma-n&#34;&gt;println&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;Hi &lt;/span&gt;&lt;span class=&#34;chroma-si&#34;&gt;$name&lt;/span&gt;&lt;span class=&#34;chroma-s2&#34;&gt;! Enter a number: &amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;        &lt;span class=&#34;chroma-n&#34;&gt;readLine&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;?.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;guess&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-k&#34;&gt;it&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;toInt&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-k&#34;&gt;private&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;fun&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;guess&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;attempt&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;Int&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;println&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;        &lt;span class=&#34;chroma-k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;attempt&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;secret&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;            &lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;Correct!&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;        &lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;            &lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;Nope!&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;        &lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And a ProGuard rule of:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;-keep public class Test {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    public void greet();
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I expected that the &lt;code&gt;Test&lt;/code&gt; class and the &lt;code&gt;greet&lt;/code&gt; method would remain, but both
fields and the &lt;code&gt;guess&lt;/code&gt; method would be obfuscated. When I built the project
and opened the class from Android Studio’s APK inspector I was disappointed:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;public&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;final&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;chroma-nc&#34;&gt;Test&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;public&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;constructor&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-k&#34;&gt;public&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;final&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;chroma-py&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;kotlin&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;String&lt;/span&gt; &lt;span class=&#34;chroma-cm&#34;&gt;/* compiled code */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-k&#34;&gt;private&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;final&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;val&lt;/span&gt; &lt;span class=&#34;chroma-py&#34;&gt;secret&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;kotlin&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;Int&lt;/span&gt; &lt;span class=&#34;chroma-cm&#34;&gt;/* compiled code */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-k&#34;&gt;public&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;final&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;fun&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;greet&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;():&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;kotlin&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;Unit&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;chroma-cm&#34;&gt;/* compiled code */&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-k&#34;&gt;private&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;final&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;fun&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;guess&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;attempt&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;kotlin&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;Int&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;):&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;kotlin&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;Unit&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;chroma-cm&#34;&gt;/* compiled code */&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Having your secret sauce in a field labelled “secret” isn’t exactly the level of
obfuscation I was hoping for. ProGuard has lots of knobs that you can twist to
affect what it keeps and what it renames, but all the incantations of &lt;code&gt;-keep&lt;/code&gt;,
&lt;code&gt;-keepmembernames&lt;/code&gt;, &lt;code&gt;-allowobfuscation&lt;/code&gt;, and so on, that I could come up with
either resulted in the class completely vanishing (because it wasn’t kept) or
showing up with all its symbols intact.&lt;/p&gt;
&lt;p&gt;There are lots of useful Stack Overflow posts describing how to obfuscate
a single method, or keep a single method and obfuscate the rest, but nothing
I tried seemed to make a difference. I’m not the biggest fan of ProGuard, but
I’ve used it enough before to know that it’s not usually that hard to make
it submit to your demands. Obviously something else was going on.&lt;/p&gt;
&lt;h3 id=&#34;-maybe-youre-solving-the-wrong-problem&#34;&gt;… Maybe you’re solving the wrong problem&lt;/h3&gt;
&lt;p&gt;My next thought was that perhaps Android Studio was doing something clever
like reading the ProGuard mapping file and automatically deobfuscating the
output for me. Looking at the mapping file it seems that ProGuard has
indeed decided to rename some things:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;Test -&amp;gt; Test:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    int secret -&amp;gt; a
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    java.lang.String name -&amp;gt; b
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    void greet() -&amp;gt; greet
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    void &amp;lt;init&amp;gt;() -&amp;gt; &amp;lt;init&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The obvious solution is to look at the class file in something less smart
than Android Studio. A couple of unzips later and I could do a quick test
to see if the original names were still present:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ strings Test.class | grep secret
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;secret
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The problem is evidently not with Android Studio, as &lt;code&gt;secret&lt;/code&gt; shouldn’t end
up in the class file at all: it should have been entirely replaced with &lt;code&gt;a&lt;/code&gt; like
the mapping file says. The output from &lt;code&gt;javap -p&lt;/code&gt; doesn’t show any hint of the
original names, however:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ javap -p Test
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;public final class Test {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;  private final int a;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;  private java.lang.String b;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;  public final void greet();
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;  public Test();
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But, given the names show up in &lt;code&gt;strings&lt;/code&gt;, they must be kicking around
somewhere. None of the various outputs from &lt;code&gt;javap&lt;/code&gt; helped until I hit
&lt;code&gt;-verbose&lt;/code&gt;. Right at the end of the class is:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;RuntimeVisibleAnnotations:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;  0: #58(#84=[I#2,I#2,I#4],#69=[I#2,I#1,I#3],#81=I#2,#70=[s#40],#71=[s#55,s#39,s#43,s#85,s#39,s#72,s#42,s#91,s#47,s#90,s#39,s#73,s#39,s#74,s#67,s#83])
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    kotlin.Metadata(
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;      mv=[1,1,15]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;      bv=[1,0,3]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;      k=1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;      d1=[&amp;#34;\u0000\&amp;#34;\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u000e\n\u0002\b\u0005\n\u0002\u0010\b\n\u0000\n\u0002\u0010\u0002\n\u0002\b\u0003\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002J\u0006\u0010\u000b\u001a\u00020\fJ\u0010\u0010\r\u001a\u00020\f2\u0006\u0010\u000e\u001a\u00020\nH\u0002R\u001a\u0010\u0003\u001a\u00020\u0004X\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b\u0005\u0010\u0006\&amp;#34;\u0004\b\u0007\u0010\bR\u000e\u0010\t\u001a\u00020\nX\u0082D¢\u0006\u0002\n\u0000¨\u0006\u000f&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;      d2=[&amp;#34;LTest;&amp;#34;,&amp;#34;&amp;#34;,&amp;#34;()V&amp;#34;,&amp;#34;name&amp;#34;,&amp;#34;&amp;#34;,&amp;#34;getName&amp;#34;,&amp;#34;()Ljava/lang/String;&amp;#34;,&amp;#34;setName&amp;#34;,&amp;#34;(Ljava/lang/String;)V&amp;#34;,&amp;#34;secret&amp;#34;,&amp;#34;&amp;#34;,&amp;#34;greet&amp;#34;,&amp;#34;&amp;#34;,&amp;#34;guess&amp;#34;,&amp;#34;attempt&amp;#34;,&amp;#34;lib_release&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    )
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There’s a Kotlin &lt;em&gt;annotation&lt;/em&gt; containing all of the symbols we were trying to
obfuscate away! Kotlin apparently uses this annotation for reflection and for
keeping track of various language features that don’t have a direct mapping in
Java bytecode (such as members with &lt;code&gt;internal&lt;/code&gt; access). Sure enough, switching
back to Android Studio and making it “decompile” the Kotlin code into Java
shows the annotation:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-nd&#34;&gt;@Metadata&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;mv&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;15&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;bv&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;k&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;d1&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;\u0000\&amp;#34;\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u000e\n\u0002\b\u0005\n\u0002\u0010\b\n\u0000\n\u0002\u0010\u0002\n\u0002\b\u0003\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002J\u0006\u0010\u000b\u001a\u00020\fJ\u0010\u0010\r\u001a\u00020\f2\u0006\u0010\u000e\u001a\u00020\nH\u0002R\u001a\u0010\u0003\u001a\u00020\u0004X\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b\u0005\u0010\u0006\&amp;#34;\u0004\b\u0007\u0010\bR\u000e\u0010\t\u001a\u00020\nX\u0082D¢\u0006\u0002\n\u0000¨\u0006\u000f&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;d2&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;LTest;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;()V&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;getName&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;()Ljava/lang/String;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;setName&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;(Ljava/lang/String;)V&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;secret&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;greet&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;guess&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;attempt&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;lib_release&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-kd&#34;&gt;public&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-kd&#34;&gt;final&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-kd&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;chroma-nc&#34;&gt;Test&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;solving-the-right-problem&#34;&gt;Solving the right problem&lt;/h3&gt;
&lt;p&gt;Now I had an idea of what was happening I was able to find a couple of other
reports of people having the same issue. There’s an open
&lt;a href=&#34;https://sourceforge.net/p/proguard/feature-requests/182/&#34;&gt;feature request for ProGuard to support Kotlin’s metadata annotation&lt;/a&gt;
but it’s not yet supported.&lt;/p&gt;
&lt;p&gt;As this was a library with a fairly straight forward interface I reasoned I
could probably get ProGuard to strip out the metadata annotation. If I stopped
Kotlin reflection working in the process then that would actually be a small
bonus. Unfortunately other people with the same idea had reported back that
they were unsuccessful: even when not using the default ProGuard config,
somehow the annotations are kept.&lt;/p&gt;
&lt;p&gt;Adding a &lt;code&gt;-printconfiguration&lt;/code&gt; instruction to my configuration lets me see
the full configuration being passed to ProGuard, and the reason for keeping
quickly becomes obvious:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;-keepattributes *Annotation*,*Annotation*
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This appears to be added by the Android build plugin before it invokes
ProGuard, and there’s no obvious way to disable it. ProGuard doesn’t offer
a way to reverse this instruction, either, but fortunately the build plugin
seems to concatenate all of the &lt;code&gt;-keepattribute&lt;/code&gt; values together and puts our
user-supplied ones first. Adding a negative filter:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;-keepattributes !*Annotation*
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Results in the following in the printed configuration:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;-keepattributes !*Annotation*,*Annotation*,*Annotation*
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The negative filter prevents any subsequent filters from matching. Recompiling
and looking at the class file again looks a lot more sensible:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-nn&#34;&gt;kotlin.io.ConsoleKt&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-kd&#34;&gt;public&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-kd&#34;&gt;final&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-kd&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;chroma-nc&#34;&gt;Test&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;chroma-kd&#34;&gt;private&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-kd&#34;&gt;final&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;123&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;chroma-kd&#34;&gt;private&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;Chris&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;chroma-kd&#34;&gt;public&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-kd&#34;&gt;final&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-nf&#34;&gt;greet&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;var1&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;Hi &amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-na&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;! Enter a number: &amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;System&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-na&#34;&gt;out&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-na&#34;&gt;println&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;var1&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;var10000&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;ConsoleKt&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-na&#34;&gt;readLine&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;();&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;chroma-k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;var10000&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;!=&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;         &lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;var1&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;var10000&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;         &lt;/span&gt;&lt;span class=&#34;chroma-kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;var3&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;Integer&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-na&#34;&gt;parseInt&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;var1&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;         &lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;var1&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;var3&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;==&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;123&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;Correct!&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;Nope!&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;         &lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;System&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-na&#34;&gt;out&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-na&#34;&gt;println&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;var1&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And that’s the story of how I spent half a day making a one line change.&lt;/p&gt;
</content>
    </entry>
</feed>
