<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: xVE</title>
    <description>The latest articles on DEV Community by xVE (@xve-e).</description>
    <link>https://dev.to/xve-e</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3837920%2F9b2cc731-64ab-490a-9ced-d78237a2be00.png</url>
      <title>DEV Community: xVE</title>
      <link>https://dev.to/xve-e</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/xve-e"/>
    <language>en</language>
    <item>
      <title>Analyzing Akamai BMP 4.1.3 - Part 2</title>
      <dc:creator>xVE</dc:creator>
      <pubDate>Tue, 24 Mar 2026 00:49:06 +0000</pubDate>
      <link>https://dev.to/xve-e/analyzing-akamai-bmp-413-part-2-31k3</link>
      <guid>https://dev.to/xve-e/analyzing-akamai-bmp-413-part-2-31k3</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.to/xve-e/analyzing-akamai-bmp-413-part-1-for-noobs-learn-4pmm"&gt;PART 1&lt;/a&gt;&lt;br&gt;
This article was uploaded to a self-published website because the engine here doesn't support KAPEX or LATEX. If you want to see a cleaner and more readable article, go to &lt;a href="https://xve-e.github.io/2026/03/23/analyzing-akamai-bmp-part-2.html" rel="noopener noreferrer"&gt;https://xve-e.github.io/2026/03/23/analyzing-akamai-bmp-part-2.html&lt;/a&gt; .&lt;br&gt;
App showcase: Iberia 14.81.0&lt;br&gt;
IDA Pro: 9.3&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Analyzing the post-decompress lib
&lt;/h3&gt;

&lt;p&gt;The decompiler often misidentified the number of arguments and return values for the polymorphic dispatcher, i used a secret technique to get around this using asm.&lt;/p&gt;

&lt;p&gt;As we saw earlier, sub_25E0AC is a large polymorphic dispatcher.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sub_25E0AC(string_ptr)                    → strlen or string copy
sub_25E0AC(string_ptr, 0x8641, 0xFFFFFFFF) → string deobfuscation
sub_25E0AC(plaintext, output, len, key, iv) → AES-128-CBC encrypt
sub_25E0AC(qword_2466A8)                  → MT19937 extract
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fltslpy9ahjbh28sen0fx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fltslpy9ahjbh28sen0fx.png" alt="graphsub_25E0AC" width="458" height="812"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JNI Entry Points&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;VA&lt;/th&gt;
&lt;th&gt;Java Name&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0x9D394&lt;/td&gt;
&lt;td&gt;SensorDataBuilder.buildN&lt;/td&gt;
&lt;td&gt;Main entry: serialize + encrypt sensor data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x9D074&lt;/td&gt;
&lt;td&gt;SensorDataBuilder.encryptKeyN&lt;/td&gt;
&lt;td&gt;Generate session ID (20-char base62 → base64)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0xA0144&lt;/td&gt;
&lt;td&gt;addOne&lt;/td&gt;
&lt;td&gt;Set MT flag dword_247A38&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0xA0150&lt;/td&gt;
&lt;td&gt;sampleTest&lt;/td&gt;
&lt;td&gt;Set MT flag dword_247A3C&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0xA015C&lt;/td&gt;
&lt;td&gt;presentData&lt;/td&gt;
&lt;td&gt;Set MT flag dword_247A40&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0xA0168&lt;/td&gt;
&lt;td&gt;testOne&lt;/td&gt;
&lt;td&gt;Set MT flag dword_247A44&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Internal Functions (Called by buildN)&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;VA&lt;/th&gt;
&lt;th&gt;Size&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x9ED74&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0xAFC&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sub_9ED74&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Core encrypt+format: MT → AES → HMAC → b64 → header assembly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x9EAF0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0x34&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sub_9EAF0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Crypto context singleton getter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x9EB24&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0x250&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sub_9EB24&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;One-time key initialization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x9E840&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0x1D0&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sub_9E840&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;LCG-based string deobfuscation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x9E660&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0xF8&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sub_9E660&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;RSA_public_encrypt wrapper&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x9E594&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0x90&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sub_9E594&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;HMAC-SHA256 wrapper&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x9E620&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0x24&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sub_9E620&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;RAND_bytes wrapper&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x9E75C&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0xE0&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sub_9E75C&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Base64 encode (OpenSSL BIO)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x9FAD0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0x130&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sub_9FAD0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;MT19937 bounded random&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x9F91C&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0xFC&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sub_9F91C&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;C++ stringstream initialization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x9FDF8&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0xD0&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sub_9FDF8&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stringstream write (string)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x1CFD2C&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0x158&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sub_1CFD2C&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stringstream write (integer)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x9DBD0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0x98&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sub_9DBD0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;JNI CallIntMethodV wrapper&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  1.1. Serialization Pipeline
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Function: &lt;code&gt;Java_com_cyberfend_cyfsecurity_SensorDataBuilder_buildN&lt;/code&gt; @ 0x9D394&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Size&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;0x83C&lt;/code&gt; (2108 bytes)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Input&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ArrayList&amp;lt;Pair&amp;lt;String, String&amp;gt;&amp;gt;&lt;/code&gt; — 28 entries from Java&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output&lt;/td&gt;
&lt;td&gt;Encrypted header string &lt;code&gt;"6,a,{rsa1},{rsa2}${b64}${timing}"&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsmfk7qjzeb28fsi59s5k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsmfk7qjzeb28fsi59s5k.png" alt="sub_9D394graph" width="362" height="707"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step-by-step from Assembly&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Phase 1&lt;/strong&gt;: JNI Environment Setup (0x9D3CC–0x9D54C)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The function begins by resolving all required JNI references prior to data extraction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;FindClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"android/os/Build$VERSION"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;GetStaticFieldID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SDK_INT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"I"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;GetStaticIntField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                         &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;must&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sanity&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;FindClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"java/util/ArrayList"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;GetMethodID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"size"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="s"&gt;"()I"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                 &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;pair_count&lt;/span&gt;
&lt;span class="n"&gt;GetMethodID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"get"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="s"&gt;"(I)Ljava/lang/Object;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;FindClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"android/util/Pair"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;GetFieldID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"first"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="s"&gt;"Ljava/lang/Object;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;GetFieldID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"second"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Ljava/lang/Object;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Phase 2&lt;/strong&gt;: Pair Vector Extraction (0x9D554–0x9D6A8)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each element of the input &lt;code&gt;ArrayList&lt;/code&gt; is extracted via a JNI iteration loop over indices $i \in [0,\ \text{pair_count} - 1]$:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;pair&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;key&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GetStringUTFChars&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;first&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GetStringUTFChars&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;second&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pairs are stored in a C++ vector as 48-byte structs with the layout:&lt;/p&gt;

&lt;p&gt;$$\text{struct PairEntry} = \underbrace{\text{key}}&lt;em&gt;{\text{std::string, 24 B}} \;|\; \underbrace{\text{value}}&lt;/em&gt;{\text{std::string, 24 B}}$$&lt;/p&gt;

&lt;p&gt;The 24-byte &lt;code&gt;std::string&lt;/code&gt; layout corresponds to the standard libc++ small-string-optimized (SSO) representation on AArch64.&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Phase 3&lt;/strong&gt;: Output Initialization from First Pair (0x9D6F8–0x9D724)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;strong&gt;value field of the first pair&lt;/strong&gt; (index 0) is used as the initial content of the serialized output buffer; its key is discarded. In the observed execution context, this value is the SDK version string &lt;code&gt;"4.1.3"&lt;/code&gt;.&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Phase 4&lt;/strong&gt;: Separator String Deobfuscation (0x9D728–0x9D768)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The separator literal is stored obfuscated in &lt;code&gt;.rodata&lt;/code&gt; and decoded at runtime. The encoded form &lt;code&gt;"WUfOL#f}+"&lt;/code&gt; is passed to a &lt;code&gt;.pb&lt;/code&gt; dispatcher alongside the constant &lt;code&gt;0x8641&lt;/code&gt;, which drives a substitution-based decode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;9d728  ADRL  X9, aWufolF         ; load encoded string "WUfOL#f}+"
9d738  STRB  W8, [SP, #var_90]   ; SSO length field = 9
9d744  STUR  X9, [SP, #var_90+1] ; copy encoded bytes onto stack
9d748  ADD   X8, SP, #var_78     ; destination buffer = var_78
9d750  MOV   W1, #0x8641         ; deobfuscation constant
9d754  MOV   W2, #0xFFFFFFFF     ; flag
9d758  BL    sub_25E0AC          ; decode → "-1,2,-94," stored in var_78
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The decode mechanism and constant &lt;code&gt;0x8641&lt;/code&gt; are identical to those observed in &lt;code&gt;buildVerification()&lt;/code&gt; , indicating a shared obfuscation scheme across the serialization pipeline.&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Phase 5&lt;/strong&gt;: Pair Serialization Loop (0x9D76C–0x9D84C)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pairs at indices $i \in [1,\ \text{pair_count} - 1]$ are serialized in order. Each iteration appends to the output buffer with the pattern:&lt;/p&gt;

&lt;p&gt;$$\text{output} \mathrel{+}= \text{separator} \;|\; \text{key}_i \;|\; \texttt{","} \;|\; \text{value}_i$$&lt;/p&gt;

&lt;p&gt;The struct stride is 48 bytes (&lt;code&gt;ADD X22, X22, #0x30&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;9d7b0  ADD   X0, SP, #var_60    ; output string ptr
9d7b4  BL    sub_25E0AC         ; append(output, separator)
9d7d4  LDRB  W9, [X8]           ; load key SSO flag (offset +0)
9d7f0  BL    sub_1CDC48         ; append(output, key)
9d7f8  MOV   X1, X20            ; X20 = "," literal @ 0x51163
9d7fc  BL    sub_1CE08C         ; append(output, ",")
9d81c  LDRB  W9, [X8, #0x18]    ; load value SSO flag (offset +24)
9d83c  BL    sub_1CDC48         ; append(output, value)
9d840  ADD   X22, X22, #0x30    ; advance to next struct (stride = 48)
9d844  ADD   X24, X24, #1       ; i++
9d84c  B.NE  loop_start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Phase 6&lt;/strong&gt;: &lt;code&gt;SECURITY_PATCH&lt;/code&gt; Field Appended via JNI (0x9D850–0x9D92C)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After exhausting the input vector, the function retrieves &lt;code&gt;Build.VERSION.SECURITY_PATCH&lt;/code&gt; directly from the Android runtime via JNI reflection, bypassing the Java-side pair list entirely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;9d888  ADRL  X2, aSecurityPatch    ; field name "SECURITY_PATCH"
9d890  ADRL  X3, aLjavaLangStrin   ; descriptor "Ljava/lang/String;"
9d8a4  BLR   X8                    ; GetStaticFieldID
9d8bc  BLR   X8                    ; GetStaticObjectField
9d8d4  BLR   X8                    ; GetStringUTFChars → X20 = e.g. "2025-04-01"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The value is appended with a dedicated tag identifier &lt;code&gt;-164&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$$\text{output} \mathrel{+}= \texttt{"-1,2,-94,"} \;\|\; \texttt{"-164,"} \;\|\; \text{SECURITY\_PATCH}$$&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;9d900  BL    sub_25E0AC            ; append(output, "-1,2,-94,")
9d904  ADRL  X1, a164              ; literal "-164"
9d910  BL    sub_25E0AC            ; append(output, "-164")
9d914  ADRL  X1, asc_51163         ; ","
9d920  BL    sub_25E0AC            ; append(output, ",")
9d928  MOV   X1, X20               ; SECURITY_PATCH string
9d92c  BL    sub_1CE08C            ; append(output, security_patch)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The native-side injection of &lt;code&gt;SECURITY_PATCH&lt;/code&gt; — absent from the Java-supplied pair list — constitutes an integrity signal that cannot be trivially spoofed by intercepting the Java layer alone.&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Phase 7&lt;/strong&gt;: Encryption and Formatting (0x9D930–0x9D96C)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The assembled plaintext is passed to the shared cryptographic context singleton and encrypted via &lt;code&gt;sub_9ED74&lt;/code&gt;, which implements the same AES-128-CBC + HMAC-SHA256 pipeline.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;9d930  BL    sub_9EAF0     ; acquire crypto context singleton
9d964  ADD   X8, SP, #var_90   ; output buffer
9d968  ADD   X1, SP, #var_B0   ; plaintext string
9d96c  BL    sub_9ED74     ; encrypt + assemble → "6,a,{rsa1},{rsa2}${b64}${timing}"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Phase 8&lt;/strong&gt;: Return to Java (0x9D99C–0x9D9AC)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The formatted output string is converted to a managed Java string and returned to the caller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;9d99c  BLR   X8           ; NewStringUTF(output_cstr)
9d9ac  ; return jstring
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Serialization Format&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;4.1.3-1,2,-94,-90,{val}-1,2,-94,-91,{val}-1,2,-94,-70,-1,2,-94,-80,...-1,2,-94,-164,{SECURITY_PATCH}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;First: SDK version (pair 0 value only)&lt;/li&gt;
&lt;li&gt;Then: &lt;code&gt;{separator}{key},{value}&lt;/code&gt; for each remaining pair&lt;/li&gt;
&lt;li&gt;Last: &lt;code&gt;{separator}-164,{SECURITY_PATCH}&lt;/code&gt; (from JNI)&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2. Cryptographic Pipeline — &lt;code&gt;sub_9ED74&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Function: &lt;code&gt;sub_9ED74&lt;/code&gt; @ 0x9ED74&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Size&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;0xAFC&lt;/code&gt; (2812 bytes)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Calling convention&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;__usercall&lt;/code&gt; — X8 = output ptr, X0 = crypto context, X1 = plaintext&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Input&lt;/td&gt;
&lt;td&gt;Crypto context (from &lt;code&gt;sub_9EAF0&lt;/code&gt;), serialized sensor plaintext&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output&lt;/td&gt;
&lt;td&gt;&lt;code&gt;"6,a,{rsa1},{rsa2}${base64(IV+cipher+HMAC)}${timing}"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Phase 1&lt;/strong&gt;: Separator Decode (0x9EDC8–0x9EE50)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Employs the same deobfuscation routine as &lt;code&gt;buildN&lt;/code&gt; : the encoded string &lt;code&gt;"WUfOL#f}+"&lt;/code&gt; is decoded with constant &lt;code&gt;0x8641&lt;/code&gt;, yielding the separator &lt;code&gt;"-1,2,-94,"&lt;/code&gt;. The result is stored in &lt;code&gt;var_180&lt;/code&gt; for later concatenation with the suffix &lt;code&gt;"-170"&lt;/code&gt; during payload assembly.&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Phase 2&lt;/strong&gt;: MT19937 PRNG Initialization (0x9EE64–0x9EE80)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two atomic guard flags gate one-time initialization of the Mersenne Twister state:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;byte_2466A0&lt;/code&gt; — controls MT state array initialization&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;byte_247A30&lt;/code&gt; — controls seeding from &lt;code&gt;clock_gettime(CLOCK_REALTIME)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The seeding routine at &lt;code&gt;0x9F698–0x9F6E4&lt;/code&gt; implements the standard MT19937 initialization recurrence:&lt;/p&gt;

&lt;p&gt;$$\text{state}[i] = i + 1812433253 \cdot \left(\text{state}[i-1] \oplus \left(\text{state}[i-1] \gg 30\right)\right), \quad i \in [1, 623]$$&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;; state[0] = seed (from clock_gettime)
9f6ac  STR   X9,  [qword_2466A8]
9f6b0  MOV   X10, #1                  ; i = 1
loop:
9f6c0  MUL+ADD  X9 = i + 1812433253 * (state[i-1] ^ (state[i-1] &amp;gt;&amp;gt; 30))
9f6c4  STR   X9,  [qword_2466A8 + i*8]
9f6cc  ADD   X10, X10, #1
9f6d0  CMP   X10, #624
9f6d4  B.NE  loop
9f6e0  STR   XZR, [qword_247A28]      ; index = 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Phase 3&lt;/strong&gt;: Verification Value Generation (0x9EE84–0x9F060)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Five sampling ranges are loaded from &lt;code&gt;.rodata&lt;/code&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variable&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Conditional Flag&lt;/th&gt;
&lt;th&gt;Semantic&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;var_188&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;[1, 1000]&lt;/td&gt;
&lt;td&gt;— (unconditional)&lt;/td&gt;
&lt;td&gt;base values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;var_190&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;[1, 6]&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;dword_247A38&lt;/code&gt; (&lt;code&gt;addOne&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;optional&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;var_198&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;[1, 7]&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;dword_247A3C&lt;/code&gt; (&lt;code&gt;sampleTest&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;optional&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;var_1A0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;[1, 8]&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;dword_247A40&lt;/code&gt; (&lt;code&gt;presentData&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;optional&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;var_1A8&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;[1, 4]&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;dword_247A44&lt;/code&gt; (&lt;code&gt;testOne&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;optional&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Sampling sequence (registers mapped from assembly):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;v13&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MT_rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v14&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MT_rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;dword_247A38&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="n"&gt;v15&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MT_rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v16&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MT_rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;dword_247A3C&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="n"&gt;v17&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MT_rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v18&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MT_rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;dword_247A40&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="n"&gt;v19&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MT_rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v20&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MT_rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;dword_247A44&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Four verification values are derived through a chained XOR construction:&lt;/p&gt;

&lt;p&gt;$$\text{val}&lt;em&gt;1 = v&lt;/em&gt;{14} + 7 \cdot v_{13}$$&lt;/p&gt;

&lt;p&gt;$$\text{val}&lt;em&gt;2 = \left(v&lt;/em&gt;{16} + 8 \cdot v_{15}\right) \oplus \text{val}_1$$&lt;/p&gt;

&lt;p&gt;$$\text{val}&lt;em&gt;3 = \left(v&lt;/em&gt;{18} + 9 \cdot v_{17}\right) \oplus \text{val}_2$$&lt;/p&gt;

&lt;p&gt;$$\text{val}&lt;em&gt;4 = \left(v&lt;/em&gt;{20} + 5 \cdot v_{19}\right) \oplus \text{val}_3$$&lt;/p&gt;

&lt;p&gt;The AArch64 encoding uses shift-and-subtract/add idioms for constant multiplication:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;; val1 = v14 + 7*v13
9efe4  LSL   W8, W22, #3         ; W8 = v13 * 8
9efe8  SUB   W8, W8,  W22        ; W8 = v13*8 - v13 = v13*7
9efec  ADD   W22, W24, W8        ; W22 = v14 + 7*v13

; val2 = (v16 + 8*v15) ^ val1
9f00c  LSL   W8, W23, #3
9f010  ADD   W8, W26, W8
9f014  EOR   W22, W8,  W22

; val3 = (v18 + 9*v17) ^ val2
9f030  ADD   W8, W25, W25,LSL#3  ; W8 = v17 + v17*8 = v17*9
9f034  ADD   W8, W28, W8
9f038  EOR   W22, W8,  W22

; val4 = (v20 + 5*v19) ^ val3
9f054  ADD   W8, W27, W27,LSL#2  ; W8 = v19 + v19*4 = v19*5
9f058  ADD   W8, W19, W8
9f05c  EOR   W1,  W8,  W22
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final verification string is serialized via a &lt;code&gt;std::stringstream&lt;/code&gt;-equivalent dispatcher with the form &lt;code&gt;"val1,val2,val3,val4"&lt;/code&gt;.&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Phase 4&lt;/strong&gt;: Plaintext Payload Assembly (0x9F070–0x9F0E4)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The plaintext buffer is constructed by sequential concatenation:&lt;/p&gt;

&lt;p&gt;$$\text{plaintext} \mathrel{+}= \texttt{"-1,2,-94,"} \;|\; \texttt{"-170,"} \;|\; \text{val}_1\texttt{,val}_2\texttt{,val}_3\texttt{,val}_4$$&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;9f090  BL    sub_1CDC48         ; append(plaintext, "-1,2,-94,")
9f0a0  ADRL  X1, a170           ; literal "-170"
9f0ac  BL    sub_25E0AC         ; append(plaintext, "-170")
9f0b0  ADRL  X1, asc_51163      ; ","
9f0bc  BL    sub_1CE08C         ; append(plaintext, ",")
9f0e4  BL    sub_1CDC48         ; append(plaintext, "val1,val2,val3,val4")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Phase 5&lt;/strong&gt;: AES-128-CBC Encryption (0x9F110–0x9F16C)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A fresh 16-byte IV is generated per invocation via &lt;code&gt;RAND_bytes()&lt;/code&gt;. The AES key and IV are read from the crypto context at offsets &lt;code&gt;ctx[0]&lt;/code&gt; and &lt;code&gt;ctx[8]&lt;/code&gt; respectively. PKCS#7 padding is applied implicitly. The output layout is:&lt;/p&gt;

&lt;p&gt;$$\text{ciphertext_blob} = \text{IV}&lt;em&gt;{16} \;|\; \text{AES\text{-}128\text{-}CBC}(\text{plaintext},\; k&lt;/em&gt;{\text{AES}},\; \text{IV})$$&lt;/p&gt;

&lt;p&gt;The IV is prepended via a single 128-bit NEON store (&lt;code&gt;STR Q0&lt;/code&gt;), and the output buffer is allocated as &lt;code&gt;encrypted_len + 17&lt;/code&gt; bytes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;9f114  BL    sub_9E620          ; RAND_bytes(16) → ctx[8]
9f12c  LDP   X3, X4, [X20]     ; X3 = AES key ptr, X4 = IV ptr
9f160  LDR   Q0, [X8]          ; load IV (16 bytes, NEON Q-register)
9f168  STR   Q0, [X0], #0x10   ; prepend IV; advance pointer
9f16c  BL    sub_25E0AC        ; memcpy(buf+16, ciphertext, encrypted_len)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Phase 6&lt;/strong&gt;: HMAC-SHA256 Authentication (0x9F190–0x9F1A4)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The authentication tag is computed over the full &lt;code&gt;IV || ciphertext&lt;/code&gt; blob, using a 32-byte HMAC key at &lt;code&gt;ctx[16]&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;$$\text{tag} = \text{HMAC\text{-}SHA256}!\left(k_{\text{HMAC}},\; \text{IV} | \text{ciphertext}\right)$$&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;9f190  ADD   W26, W25, #0x10   ; input_len = encrypted_len + 16
9f194  LDR   X2,  [X20, #0x10] ; HMAC key ptr (32 bytes) from ctx[16]
9f198  MOV   X0,  X22          ; data = IV || ciphertext
9f19c  MOV   W1,  W26          ; data length
9f1a0  BL    sub_9E594         ; HMAC-SHA256 → X23 (32-byte tag)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Phase 7&lt;/strong&gt;: Final Binary Assembly and Base64 Encoding (0x9F1B8–0x9F204)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The authenticated ciphertext is assembled into a contiguous binary blob:&lt;/p&gt;

&lt;p&gt;$$\text{output_bin} = \text{IV}&lt;em&gt;{16} \;|\; \text{ciphertext}&lt;/em&gt;{n} \;|\; \text{HMAC}_{32}$$&lt;/p&gt;

&lt;p&gt;Total length: $n + 48$ bytes. The 32-byte HMAC is written atomically via two 128-bit NEON registers (&lt;code&gt;LDP Q0, Q1&lt;/code&gt; / &lt;code&gt;STP Q0, Q1&lt;/code&gt;). The blob is then Base64-encoded:&lt;/p&gt;

&lt;p&gt;$$\text{b64} = \text{Base64}!\left(\text{output_bin}\right)$$&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;9f1d8  LDP   Q0, Q1, [X23]     ; load 32-byte HMAC (two NEON Q-registers)
9f1dc  ADD   X8,  X24, X19     ; offset = base + (IV + ciphertext length)
9f1e0  STP   Q0, Q1, [X8]      ; store 32-byte HMAC
9f1f8  ADD   W1,  W25, #0x30   ; total_len = encrypted_len + 48
9f200  BL    sub_9E75C         ; base64_encode(output_bin, total_len) → X25
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Phase 8&lt;/strong&gt;: Final Header String Construction (0x9F21C–0x9F4F4)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The complete header value is assembled through three logical segments:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Segment A&lt;/strong&gt; — Key material header:&lt;/p&gt;

&lt;p&gt;$$\texttt{"6,a,{base64(RSA(}k_{\text{AES}}\texttt{))},{base64(RSA(}k_{\text{HMAC}}\texttt{))}"}$$&lt;/p&gt;

&lt;p&gt;where &lt;code&gt;ctx[24]&lt;/code&gt; and &lt;code&gt;ctx[32]&lt;/code&gt; hold the RSA-wrapped, Base64-encoded symmetric keys.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Segment B&lt;/strong&gt; — Timing telemetry:&lt;/p&gt;

&lt;p&gt;$$\texttt{"{}\Delta t_{\text{encrypt}}\texttt{µs},{}\Delta t_{\text{hmac}}\texttt{µs},{}\Delta t_{\text{b64}}\texttt{µs}"}$$&lt;/p&gt;

&lt;p&gt;Derived from three consecutive &lt;code&gt;clock_gettime&lt;/code&gt; delta measurements converted to microseconds via &lt;code&gt;FCVTMS&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final concatenation:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;$$\text{header} = \text{Segment_A} \;|\; \texttt{"\$"} \;|\; \text{b64} \;|\; \texttt{"\$"} \;|\; \text{Segment_B}$$&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;9f4a4  BL    sub_1CDC48        ; output = Segment_A
9f4ac  LDR   X1, [off_245020]  ; "$"
9f4b4  BL    sub_25E0AC        ; append "$"
9f4c0  BL    sub_1CE08C        ; append b64 (X25)
9f4c4  LDR   X1, [off_245020]  ; "$"
9f4cc  BL    sub_25E0AC        ; append "$"
9f4f4  BL    sub_25E0AC        ; append Segment_B (timing)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Mersenne Twister Verification
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3.1 MT19937 Implementation
&lt;/h3&gt;

&lt;p&gt;The native code employs a standard MT19937 PRNG, confirmed by three structural markers: a 624-element state array at &lt;code&gt;qword_2466A8&lt;/code&gt;, the initialization multiplier &lt;code&gt;1812433253&lt;/code&gt;, and a twist operation matching the reference implementation.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.2 &lt;code&gt;sub_9FAD0&lt;/code&gt;: Bounded Random Sampling
&lt;/h3&gt;

&lt;p&gt;This function implements rejection sampling for uniform distribution over the range &lt;code&gt;[lo, hi]&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;mt_rand_range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mt_extract&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// rejection to ensure uniformity&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3.3 Verification String Serialization
&lt;/h3&gt;

&lt;p&gt;The four values $\text{val}_{1..4}$ are written to a C++ &lt;code&gt;std::stringstream&lt;/code&gt; as comma-separated decimal integers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;sub_25E0AC(stream, value)&lt;/code&gt; — write integer&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sub_9FDF8(stream, ",", 1)&lt;/code&gt; — write separator&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sub_1CFD2C(stream, value)&lt;/code&gt; — write final integer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Output format: &lt;code&gt;"val1,val2,val3,val4"&lt;/code&gt; (e.g., &lt;code&gt;"427,1052,5765,4661"&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  3.4 Flag Behavior
&lt;/h3&gt;

&lt;p&gt;The four control flags (&lt;code&gt;dword_247A38&lt;/code&gt;, &lt;code&gt;dword_247A3C&lt;/code&gt;, &lt;code&gt;dword_247A40&lt;/code&gt;, &lt;code&gt;dword_247A44&lt;/code&gt;) are set by the JNI entry points &lt;code&gt;addOne&lt;/code&gt;, &lt;code&gt;sampleTest&lt;/code&gt;, &lt;code&gt;presentData&lt;/code&gt;, and &lt;code&gt;testOne&lt;/code&gt; respectively. Their static value in the binary is &lt;code&gt;0xFFFFFFFF&lt;/code&gt; (not equal to 1), rendering all conditional terms zero by default. At runtime, the Java layer may activate individual flags by calling the corresponding JNI setter with argument &lt;code&gt;1&lt;/code&gt;. When enabled, a bounded random offset is added to each accumulator term. For the initial sensor data generation these flags are typically inactive, yielding $v_{14} = v_{16} = v_{18} = v_{20} = 0$.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Key Initialization — &lt;code&gt;sub_9EB24&lt;/code&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Function: &lt;code&gt;sub_9EB24&lt;/code&gt; @ 0x9EB24
&lt;/h3&gt;

&lt;p&gt;Invoked when &lt;code&gt;ctx[40] == 0&lt;/code&gt; (uninitialized). Executes once per process lifetime.&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Phase 1&lt;/strong&gt;: Key Buffer Allocation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Three heap buffers are allocated from the crypto context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;9eb5c  BL    sub_25E0AC    ; ctx[0]  = malloc(17)  → AES key buffer  (16 B + null)
9ec54  BL    sub_20AF7C    ; ctx[8]  = malloc(17)  → IV buffer       (16 B + null)
9ec64  BL    sub_25E0AC    ; ctx[16] = malloc(33)  → HMAC key buffer (32 B + null)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Phase 2&lt;/strong&gt;: RSA Public Key Deobfuscation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;268 bytes of obfuscated key material are loaded from &lt;code&gt;off_245030&lt;/code&gt; and decoded via the LCG substitution cipher with seed &lt;code&gt;63&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;9eb7c  LDR   X3, [off_245030]   ; load 268-byte obfuscated PEM blob
9ebf4  BL    sub_9E840          ; deobfuscate(material, seed=63, flag=-1) → PEM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Phase 3&lt;/strong&gt;: Session Key Generation and RSA Encryption
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;; AES key: 16 random bytes, RSA-encrypted, Base64-encoded → ctx[24]
9ec38  BL    sub_9E660     ; RSA_public_encrypt(pem_key, rand_16)
9ec48  BL    sub_9E75C     ; base64(encrypted) → ctx[24]

; HMAC key: 32 random bytes, RSA-encrypted, Base64-encoded → ctx[32]
9ec9c  BL    sub_9E660     ; RSA_public_encrypt(pem_key, rand_32)
9eca8  BL    sub_9E75C     ; base64(encrypted) → ctx[32]

; Mark context as initialized
9ecd4  STRB  #1, [X2, #40] ; ctx[40] = 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. String Deobfuscation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  5.1 Native: LCG Substitution Cipher (&lt;code&gt;sub_9E840&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Used for RSA key deobfuscation (&lt;code&gt;off_245030&lt;/code&gt;) and separator decoding (&lt;code&gt;"WUfOL#f}+"&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The charset is constructed from 92 printable ASCII characters in the range [32, 126], excluding &lt;code&gt;"&lt;/code&gt; (0x22), &lt;code&gt;'&lt;/code&gt; (0x27), and &lt;code&gt;\&lt;/code&gt; (0x5C). For each input byte, a linear congruential generator advances the state and produces a reverse-lookup shift:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;build_charset&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;127&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;34&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;39&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;92&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lcg_decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;charset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;build_charset&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;charset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;lcg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt;
    &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;byte&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;idx&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;charset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;shift&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;lcg&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mh"&gt;0xFFFF&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
        &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;charset&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;shift&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;lcg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lcg&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;65793&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;4282663&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mh"&gt;0x7FFFFF&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5.2 Java: XOR Table Cipher (&lt;code&gt;C0018K.kpR&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Used for all Java-side string deobfuscation. A pseudo-random table of 32 768 entries is derived from a feedback recurrence seeded at 3, then applied as a positional XOR stream:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;build_table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;32768&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;val&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;
        &lt;span class="n"&gt;prev&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;88&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;63&lt;/span&gt;   &lt;span class="c1"&gt;# constant +88 in C0018K.kpR
&lt;/span&gt;        &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prev&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decode_kpR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoded&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;build_table&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;chr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoded&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: The method &lt;code&gt;CYFMonitor.KkI&lt;/code&gt; uses an additive constant of &lt;code&gt;+11&lt;/code&gt; with a distinct table. The two routines are not interchangeable.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  6. Java-Side Architecture
&lt;/h2&gt;

&lt;h3&gt;
  
  
  6.1 &lt;code&gt;CYFManager.buildSensorData()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The primary Java entry point orchestrates the full sensor data pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Evaluate event count thresholds to select fast path or full path&lt;/li&gt;
&lt;li&gt;Collect data from 12+ sensor subsystems&lt;/li&gt;
&lt;li&gt;Assemble a &lt;code&gt;LinkedHashMap&amp;lt;String, String&amp;gt;&lt;/code&gt; with ~25 entries&lt;/li&gt;
&lt;li&gt;Convert to &lt;code&gt;ArrayList&amp;lt;Pair&amp;lt;String, String&amp;gt;&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Invoke native &lt;code&gt;buildN(pairs)&lt;/code&gt; → encrypted header&lt;/li&gt;
&lt;li&gt;Append &lt;code&gt;$[3]..$[6]&lt;/code&gt; sections: Proof-of-Work, CCA token, signal, metadata&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  6.2 Fast Path (event count &amp;lt; 16)
&lt;/h3&gt;

&lt;p&gt;When both &lt;code&gt;GA&lt;/code&gt; and &lt;code&gt;IIT&lt;/code&gt; accumulators hold fewer than 16 events &lt;strong&gt;and&lt;/strong&gt; &lt;code&gt;EG.D.isValid()&lt;/code&gt; is true, the function returns cached sensor data from &lt;code&gt;EG.D.get()&lt;/code&gt;. Every fifth call triggers key rotation via &lt;code&gt;encryptString()&lt;/code&gt;. Cache access is serialized via &lt;code&gt;AtomicBoolean.compareAndSet()&lt;/code&gt; with a 5-second reentrance lock.&lt;/p&gt;

&lt;h3&gt;
  
  
  6.3 Full Path (event count ≥ 16)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Call &lt;code&gt;buildN()&lt;/code&gt; with suffix &lt;code&gt;,0&lt;/code&gt; → return this header&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;GA ≥ 16&lt;/code&gt; OR &lt;code&gt;IIT ≥ 16&lt;/code&gt;: call &lt;code&gt;buildN()&lt;/code&gt; again with suffix &lt;code&gt;,1&lt;/code&gt; → cache via &lt;code&gt;EG.D.put()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;GA ≥ 128&lt;/code&gt; OR &lt;code&gt;IIT ≥ 128&lt;/code&gt;: reset both accumulators&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  6.4 Sensor Collector Classes (java)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Class&lt;/th&gt;
&lt;th&gt;Alias&lt;/th&gt;
&lt;th&gt;Data Collected&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;C0005GA&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;EG.GA&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Accelerometer, gyroscope, magnetometer (orientation)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;C0009GN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;EG.GN/McP.IIT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Motion analysis, jerk derivatives (9 axes)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;C0022KG&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;EG.KG&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Touch events (DOWN/MOVE/UP with coordinates)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;C0018K&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;EG.K&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Text input events (keystroke timing)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;C0054Z&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;EG.Z&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;EditText field metadata&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;C0008GK&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;EG.GK&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Activity lifecycle (resume/pause events)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;C0006GE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;EG.GE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Device info (40+ fields)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;C0051Vw&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;EG.Vw/KWS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;System fingerprint, device ID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;C0001C&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;EG.C&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;DCI/JavaScript bridge (WebView challenges)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;C0002D&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;EG.D&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CPR signal cache&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;C0042U&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;EG.U&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Proof-of-Work responses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;C0038M&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;EG.M&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CCA challenge tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Last-minute update:&lt;/strong&gt; I wrote this article in a hurry due to lack of time, I ended up forgetting to provide something tangible and useful for you, here is the SensorData decryptor, make sure you are using &lt;strong&gt;Frida 17.8.2&lt;/strong&gt; and the correct version of Iberia.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2sv1nbhbvsro5d61qi0m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2sv1nbhbvsro5d61qi0m.png" alt=" " width="800" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to use:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Hook the app:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;frida -U -f com.iberia.android -l hook.js
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;After the app opens, trigger login or smth&lt;/li&gt;
&lt;li&gt;Look for these log lines:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[AKM] SESSION_KEY_16: 59bf28fde390277c14dff6247116a39e    ← this is SESSION_KEY
[AKM] HMAC_KEY_32:    a5ed42ba...f5af23fc                  ← this is HMAC_KEY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Paste the keys in &lt;code&gt;.py&lt;/code&gt;, run, be happy&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;a href="https://github.com/xVE-e/akamaibmpstrings/blob/main/decrypt_sensor.py" rel="noopener noreferrer"&gt;https://github.com/xVE-e/akamaibmpstrings/blob/main/decrypt_sensor.py&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/xVE-e/akamaibmpstrings/blob/main/hook.js" rel="noopener noreferrer"&gt;https://github.com/xVE-e/akamaibmpstrings/blob/main/hook.js&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm going to rest here, wait for part 3.&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>infosec</category>
      <category>programming</category>
      <category>security</category>
    </item>
    <item>
      <title>Analyzing Akamai BMP 4.1.3 - Part 1 - For Noobs Learn</title>
      <dc:creator>xVE</dc:creator>
      <pubDate>Sun, 22 Mar 2026 06:31:26 +0000</pubDate>
      <link>https://dev.to/xve-e/analyzing-akamai-bmp-413-part-1-for-noobs-learn-4pmm</link>
      <guid>https://dev.to/xve-e/analyzing-akamai-bmp-413-part-1-for-noobs-learn-4pmm</guid>
      <description>&lt;p&gt;App showcase: Iberia 14.81.0&lt;br&gt;
IDA Pro: 9.3&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1&lt;/strong&gt;. &lt;strong&gt;Initial analysis&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Well, I already had some prior knowledge of how Akamai worked, after loading the library in Ida, which I found very strange initially:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fghkjkuofqcenpwyzimhq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fghkjkuofqcenpwyzimhq.png" alt="firsts functions" width="384" height="241"&gt;&lt;/a&gt;&lt;br&gt;
The library is over 2MB, and the low number of functions made me realize something was wrong. So I went to check the exports:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fveyathi4v0w2fdby7vnn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fveyathi4v0w2fdby7vnn.png" alt=" " width="706" height="211"&gt;&lt;/a&gt;&lt;br&gt;
 I try disasm addresses of the exported functions:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;initializeKeyN @ 0x9d060&lt;/code&gt;&lt;br&gt;
&lt;code&gt;encryptKeyN @ 0x9d074&lt;/code&gt;&lt;br&gt;
&lt;code&gt;decryptN @ 0x9d18c&lt;/code&gt;&lt;br&gt;
&lt;code&gt;buildN @ 0x9d394 &amp;lt;-- prob generates the sensor data&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The decompilation failed because this isn't even a functional arm64 instruction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0x9d060: bytes=1094e857b4b328ef  -&amp;gt; NOT a valid ARM64 instruction                                                                                                                                                                   
0x9d394: bytes=a23908369f7bcc23  -&amp;gt; NOT a valid ARM64 instruction
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bytes appeared to be random data, not opcodes. The native code is encrypted on disk.&lt;/p&gt;

&lt;p&gt;strings before:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo4vs9sxpvrovjoq9lrsv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo4vs9sxpvrovjoq9lrsv.png" alt="before" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2&lt;/strong&gt;. &lt;strong&gt;Decompression using unicorn&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;IDA only recognized 8 functions in the entire binary (of ~1.5MB of .text!). Among them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;.init_proc @ 0x2cdc20 — function that runs automatically when the .so file is loaded by Android&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;sub_2CBF50 @ 0x2cbf50 — huge function (0x1CC8 bytes) called by .init_proc&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Decompiling .init_proc revealed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;init_proc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;                                        
      &lt;span class="n"&gt;sub_2CBF50&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// &amp;lt;-- the unpacker                                                                                                                                                                                         &lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.1&lt;/strong&gt;. &lt;strong&gt;Analyzing the unpacker (sub_2CBF50)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the centerpiece.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.spd&lt;/code&gt; (Section Protection Data) data structure&lt;/p&gt;

&lt;p&gt;The table is located at address VA &lt;code&gt;0x2CDCC0&lt;/code&gt; with this layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0x2CDCC0: checksum/magic (0x15043297f10b7863)
0x2CDCC8: outer_count = 2 (how many encrypted sections)
0x2CDCD0: start of entries
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each external entrance has:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;qword[0]: section offset (VA) e.g.: 0x000000 (.text+.rodata)
qword[1]: section size e.g.: 0x2116E0
qword[2]: flags (for mprotect) e.g.: 5 (RX)
qword[3]: number of subsections e.g.: 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each subsection has:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;14 qwords = 28 32-bit round keys (cipher keys)
1 checksum/sentinel qword
1 padding qword
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then: offset, size, and more keys for the next subsection&lt;/p&gt;

&lt;p&gt;The encrypted sections found:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;| Section                         | VA        | Size               | Subsections |
|---------------------------------|-----------|--------------------|-------------|
| Segment 1 (code + rodata)       | 0x000000  | 0x2116E0 (~2MB)    | 3           |
| Segment 2 (.pb + extras)        | 0x254000  | 0x079F68 (~490KB)  | 1           |

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The cipher: Speck-like block cipher&lt;/p&gt;

&lt;p&gt;The algorithm is a custom block cipher inspired by the &lt;a href="https://en.wikipedia.org/wiki/Speck_%28cipher%29" rel="noopener noreferrer"&gt;NSA's&lt;/a&gt; Speck, operating on 64-bit blocks (2×32 bits) with 28 rounds.&lt;/p&gt;

&lt;p&gt;Each round does:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;xor_val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt; &lt;span class="n"&gt;XOR&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt;
&lt;span class="n"&gt;rot3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ROR32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xor_val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// right rotation 3 bits&lt;/span&gt;

&lt;span class="n"&gt;sub_val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;round_key&lt;/span&gt; &lt;span class="n"&gt;XOR&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;rot3&lt;/span&gt; &lt;span class="c1"&gt;// subtraction mod 2^32&lt;/span&gt;
&lt;span class="n"&gt;rot24&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ROR32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sub_val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// = ROL8 (left rotation 8)&lt;/span&gt;
&lt;span class="n"&gt;hi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rot24&lt;/span&gt; &lt;span class="n"&gt;XOR&lt;/span&gt; &lt;span class="n"&gt;rot3&lt;/span&gt;
&lt;span class="n"&gt;lo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rot24&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It operates in CBC (&lt;a href="https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation" rel="noopener noreferrer"&gt;Cipher Block Chaining&lt;/a&gt;) mode: each decrypted block is XORed with the previous ciphertext, creating a chain dependency.&lt;/p&gt;

&lt;p&gt;The code has two paths:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;NEON path: uses ARM64 SIMD instructions to process 2 blocks at a time (128 bits) — performance optimization&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scalar path: processes 1 block of 64 bits at a time — fallback&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition, for some sections there is an XOR mode (when flags &amp;amp; 1 == 1) that uses the round keys as PRNG to generate a keystream, and applies byte-by-byte XOR (masking with &amp;amp; 0x7F).&lt;/p&gt;

&lt;p&gt;Auxiliary Functions&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sub_2540C0 → trampoline to sub_254314 → mprotect() wrapper to mark memory as RWX before writing  
sub_2540E0 → trampoline to loc_25429C → instruction cache flush (required on ARM after modifying code)  
sub_254148 → returns the base address (0, since it is PIE)  
sub_2CBF38 → returns a pointer to 0x2CDCC0 (.spd table)  
sub_2CBF44 → returns a pointer to 0x2CDCC8 (entry count)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.3&lt;/strong&gt;. &lt;strong&gt;Script to get the decompressed libakamaibmp.so&lt;/strong&gt;&lt;br&gt;
I used &lt;a href="https://github.com/unicorn-engine/unicorn" rel="noopener noreferrer"&gt;Unicorn Engine&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unicorn script &lt;a href="https://github.com/xVE-e/akamaibmpstrings/blob/main/dec.py" rel="noopener noreferrer"&gt;dec.py&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;root@xVE:$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sha256sum &lt;/span&gt;libakamaibmp.so
&lt;span class="go"&gt;ed963b92b7cb4b7859305102f04edd627ab5c60dd7622dccc4d926d5cfba78fd
&lt;/span&gt;&lt;span class="gp"&gt;root@xVE:$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;python3 dec.py
&lt;span class="go"&gt;[*] Akamai BMP 4.1.3
[*] Input:  libakamaibmp.so
[*] Output: libakamaibmp_dec.so
&lt;/span&gt;&lt;span class="gp"&gt;  Mapped LOAD: file 0x0 -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;VA 0x0 &lt;span class="o"&gt;(&lt;/span&gt;0x2116e0 bytes&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;  Mapped LOAD: file 0x2116e0 -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;VA 0x2156e0 &lt;span class="o"&gt;(&lt;/span&gt;0x2b928 bytes&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;  Mapped LOAD: file 0x23d008 -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;VA 0x245008 &lt;span class="o"&gt;(&lt;/span&gt;0x1678 bytes&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;  Mapped LOAD: file 0x248000 -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;VA 0x250000 &lt;span class="o"&gt;(&lt;/span&gt;0xa66 bytes&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;  Mapped LOAD: file 0x24c000 -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;VA 0x254000 &lt;span class="o"&gt;(&lt;/span&gt;0x79f68 bytes&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;[*] Emulating sub_2CBF50 @ 0x2CBF50...
[+] Emulation completed successfully!
  Patched segment VA 0x0 (0x2116e0 bytes)
  Patched segment VA 0x254000 (0x79f68 bytes)
[+] 2 segments patched
[+] Written: libakamaibmp_dec.so (2909936 bytes)
&lt;/span&gt;&lt;span class="gp"&gt;  initializeKeyN       @ VA 0x9d060 -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;file 0x9d060: VALID ARM64
&lt;span class="gp"&gt;  encryptKeyN          @ VA 0x9d074 -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;file 0x9d074: VALID ARM64
&lt;span class="gp"&gt;  decryptN             @ VA 0x9d18c -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;file 0x9d18c: VALID ARM64
&lt;span class="gp"&gt;  buildN               @ VA 0x9d394 -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;file 0x9d394: VALID ARM64
&lt;span class="gp"&gt;root@xVE:$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sha256sum &lt;/span&gt;libakamaibmp_dec.so
&lt;span class="go"&gt;416b1e5364cb735532fd3ef476dfa394b31206dd901a58e86a1cfac3f1f35b31
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3&lt;/strong&gt;. &lt;strong&gt;After-Decompression&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The changes are extreme; after decompression, all the strings in .rodata became visible, and hundreds of new functions became visible.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqqkd3ijkbm3d0fctrlb5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqqkd3ijkbm3d0fctrlb5.png" alt="after" width="800" height="336"&gt;&lt;/a&gt;&lt;br&gt;
With the readable strings in the .rodata file, it's already possible to identify that akamaibmp doesn't depend on the &lt;a href="https://source.android.com/docs/core/ota/apex" rel="noopener noreferrer"&gt;APEX´&lt;/a&gt; Android openssl, and has its own embedded openssl.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdgptdu4l61vwaonn9ef5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdgptdu4l61vwaonn9ef5.png" alt="functions after" width="386" height="701"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Well, great, it's improved significantly, but the .pb segment still has unreadable strings&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb6h8m3tnmnzkiqjrgovr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb6h8m3tnmnzkiqjrgovr.png" alt=" " width="547" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;.pb is much cooler than just strings, there's a gigantic polymorphic function &lt;code&gt;sub_25E0AC&lt;/code&gt; used for everything (11719 xrefs)&lt;br&gt;
The strings in the .pb are XORed using 0x55.&lt;/p&gt;

&lt;p&gt;.pb strings decoded (only 13, have more)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  /data/local/bin/su
  /data/local/xbin/su
  /sbin/su
  /su/bin/su
  /system/bin/su
  /system/bin/.ext/su
  /system/bin/failsafe/su
  /system/sd/xbin/su
  /system/usr/we-need-root/su
  /system/xbin/su
  /cache/su
  /data/su
  /proc/self/mounts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The .pb participates in some kind of root detection, which isn't very clear yet, but sounds trivial.&lt;/p&gt;

&lt;p&gt;.pb is certainly trivial, but during your search, I noticed a 680kb gap in .text, 680kb without functions, It seems that IDA is encountering some problems in this section; you will have to resolve the functions manually, as the auto-analysis didn't catch it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcq7kpqiru72xvezzubw3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcq7kpqiru72xvezzubw3.png" alt=" " width="800" height="62"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;+170 funcs solved manually&lt;/p&gt;

&lt;p&gt;Well, .pb is good, it has many functions, very useful, but there isn't much left to decrypt or decode.&lt;/p&gt;

&lt;p&gt;This saga will have 3 parts. The first part is the simplest; we are just cleaning up the library and making it a readable environment. In part two, we will address cryptography, and in the last part, we will have a functional sensor generator. Stay tuned!&lt;/p&gt;

&lt;p&gt;Analysis done in 37 minutes&lt;br&gt;
Telegram: @vxigl&lt;br&gt;
Discord: @vx7nyvek or @xve_e&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
