<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Kernel on dere3046</title><link>https://dere3046.github.io/tags/kernel/</link><description>Recent content in Kernel on dere3046</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Thu, 02 Jul 2026 14:00:00 +0800</lastBuildDate><atom:link href="https://dere3046.github.io/tags/kernel/index.xml" rel="self" type="application/rss+xml"/><item><title>ksymless on older kernels</title><link>https://dere3046.github.io/posts/ksymless-older-kernels/</link><pubDate>Thu, 02 Jul 2026 14:00:00 +0800</pubDate><guid>https://dere3046.github.io/posts/ksymless-older-kernels/</guid><description>&lt;p&gt;v3 discovered kallsyms data by scanning for &lt;code&gt;token_index&lt;/code&gt; (256 x u16,
&lt;code&gt;ti[0]=0&lt;/code&gt;), then reading &lt;code&gt;kallsyms_offsets&lt;/code&gt; 512 bytes after it. works
on GKI 6.6 and 6.12. fails on 5.10, 5.15, and 6.1.&lt;/p&gt;
&lt;p&gt;the reason is simple. the binary output order of &lt;code&gt;write_src()&lt;/code&gt; in
&lt;code&gt;scripts/kallsyms.c&lt;/code&gt; changed between kernel versions.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;the layout shift happened somewhere between 6.1 and 6.6. android14-6.1
still uses the old order, android15-6.6 uses the new one.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;in the old layout (i call it v1), offsets come first. the entire block
looks like: offsets, then &lt;code&gt;kallsyms_relative_base&lt;/code&gt; (8 bytes, value is
&lt;code&gt;_text&lt;/code&gt;), then &lt;code&gt;kallsyms_num_syms&lt;/code&gt; (4 bytes, equals the symbol count N),
then names, markers, token table, and finally token_index at the end.
offsets are nowhere near token_index.&lt;/p&gt;
&lt;p&gt;in the new layout (v2, 6.6+), &lt;code&gt;token_index&lt;/code&gt; sits right before offsets.
token_index + 512 lands exactly on offsets. the v3 approach works
because of this.&lt;/p&gt;
&lt;p&gt;so for older kernels we need a different way to find offsets. without
token_index as a shortcut, we look for a sorted u32 array that ends
with the pattern: 8 bytes of &lt;code&gt;_text&lt;/code&gt; followed by 4 bytes matching the
array length. kind of like finding the signature of a packed struct.&lt;/p&gt;
&lt;p&gt;the scan works in two phases. first, we check if the current page is
entirely sorted:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; run &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, prev &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; max_i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; off) &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; max_i; i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; v &lt;span style="color:#f92672"&gt;=&lt;/span&gt; buf[(off &lt;span style="color:#f92672"&gt;+&lt;/span&gt; i &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;) &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ((&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;)v &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; prev) &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; prev &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;)v; run&lt;span style="color:#f92672"&gt;++&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (run &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; max_i) &lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;only if the sorted run reaches the page boundary do we cross into
safe_read territory. this filters out almost everything instantly.&lt;/p&gt;
&lt;p&gt;then we verify the pattern:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ((rb &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; &lt;span style="color:#f92672"&gt;~&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0x1FFFFFULL&lt;/span&gt;) &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; kernel_base) &lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (ns &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;)run) &lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;the mask comparison on &lt;code&gt;_text&lt;/code&gt; saves us from false negatives when the
value is not exactly 2MB aligned across different builds.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;code&gt;kallsyms_seqs_of_names&lt;/code&gt; was added in kernel 6.1. 5.10 and 5.15 don&amp;rsquo;t
have it. when it is missing, &lt;code&gt;get_sym_seq()&lt;/code&gt; falls back to using the
symbol index directly, which works because symbols are emitted in order.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;took me a moment to realize why the scan kept failing on real devices.
i had capped the sorted u32 run at the 4096 byte page boundary. one
page is 1024 u32 entries, the threshold was 10000. the fix was cross
page &lt;code&gt;safe_read&lt;/code&gt; for any candidate that survived the first phase.
simple.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kloffs @ ..., sorted=103903
layout v1, 103904 symbols
verify: addr-&amp;gt;name MATCH
verify: name-&amp;gt;addr MATCH
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;looks like it works on all three. 6.12 through v2, 6.6 through v2,
6.1 through v1. 5.10 and 5.15 builds pass CI.&lt;/p&gt;
&lt;p&gt;Thanks to &lt;a class="link" href="https://www.coolapk.com/u/1550124" target="_blank" rel="noopener"
 &gt;汐の月&lt;/a&gt; for providing
the device for GKI 6.6 testing, and to
&lt;a class="link" href="https://www.coolapk.com/u/41654149" target="_blank" rel="noopener"
 &gt;阿尔托莉雅·潘德拉贡&lt;/a&gt; for
providing the device for GKI 6.1 testing.&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://github.com/Dere3046/ksymless_Android" target="_blank" rel="noopener"
 &gt;https://github.com/Dere3046/ksymless_Android&lt;/a&gt;&lt;/p&gt;</description></item><item><title>finding kallsyms with token_index</title><link>https://dere3046.github.io/posts/ksymless-token-index/</link><pubDate>Thu, 02 Jul 2026 10:00:00 +0800</pubDate><guid>https://dere3046.github.io/posts/ksymless-token-index/</guid><description>&lt;p&gt;the first version relied on ADRP instruction scanning to find kallsyms
data. worked on android16-6.12, not on android15-6.6. the ADRP window
size depends on compiler inlining, which varies across kernel builds.
not something you can hardcode.&lt;/p&gt;
&lt;p&gt;the fix is simple. instead of chasing ADRP instructions, search for the
&lt;code&gt;token_index&lt;/code&gt; structure directly in kernel &lt;code&gt;.rodata&lt;/code&gt;. its layout is
determined by &lt;code&gt;write_src()&lt;/code&gt; in &lt;code&gt;scripts/kallsyms.c&lt;/code&gt;, identical in 6.6
and 6.12.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;output_label&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;kallsyms_token_index&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;256&lt;/span&gt;; i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\t&lt;/span&gt;&lt;span style="color:#e6db74"&gt;.short&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\t&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%d&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, best_idx[i]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// best_idx[i] = byte offset into token_table
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// token_index[0] = 0, strictly increasing, 256 x u16
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;output_label&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;kallsyms_offsets&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; table_cnt; i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; offset &lt;span style="color:#f92672"&gt;=&lt;/span&gt; table[i]&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;addr &lt;span style="color:#f92672"&gt;-&lt;/span&gt; relative_base;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\t&lt;/span&gt;&lt;span style="color:#e6db74"&gt;.long&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\t&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%#x&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, (&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;)offset);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;256 consecutive u16 values, strictly increasing, starting at 0. the
chance of random rodata matching that is essentially zero.&lt;/p&gt;
&lt;p&gt;once found, &lt;code&gt;kallsyms_offsets&lt;/code&gt; is exactly 512 bytes after &lt;code&gt;token_index&lt;/code&gt;
(plus &lt;code&gt;.balign 8&lt;/code&gt; padding). the search stops naturally when
&lt;code&gt;copy_from_kernel_nofault&lt;/code&gt; hits unmapped pages. we start scanning at
&lt;code&gt;kernel_base + 1MB&lt;/code&gt;, which is well inside &lt;code&gt;.text&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kernel_base &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt;)&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;sprint_symbol &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; &lt;span style="color:#f92672"&gt;~&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0x1FFFFFULL&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;no ADRP scanning, no BL chain, no window sizes to guess. simple.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sorted=126031
SCT MATCH, addr-&amp;gt;name MATCH, name-&amp;gt;addr MATCH
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;that is it.&lt;/p&gt;
&lt;p&gt;Thanks to &lt;a class="link" href="https://www.coolapk.com/u/1550124" target="_blank" rel="noopener"
 &gt;汐の月&lt;/a&gt; for providing
the device for GKI 6.6 testing.&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://github.com/Dere3046/ksymless_Android" target="_blank" rel="noopener"
 &gt;https://github.com/Dere3046/ksymless_Android&lt;/a&gt;&lt;/p&gt;</description></item><item><title>ksymless Android</title><link>https://dere3046.github.io/posts/ksymless-android/</link><pubDate>Fri, 19 Jun 2026 00:00:00 +0000</pubDate><guid>https://dere3046.github.io/posts/ksymless-android/</guid><description>&lt;p&gt;ARM64 port of &lt;a class="link" href="https://github.com/rota1001/ksymless" target="_blank" rel="noopener"
 &gt;ksymless&lt;/a&gt;. finds
&lt;code&gt;sys_call_table&lt;/code&gt; and reconstructs &lt;code&gt;kallsyms_lookup_name&lt;/code&gt; on Android GKI
without exported kernel symbols.&lt;/p&gt;
&lt;h2 id="background"&gt;background
&lt;/h2&gt;&lt;p&gt;Since Linux 5.7 &lt;code&gt;kallsyms_lookup_name&lt;/code&gt; is no longer exported. on Android GKI
kernels this means kernel modules cannot look up symbols by name.&lt;/p&gt;
&lt;h2 id="solution"&gt;solution
&lt;/h2&gt;&lt;p&gt;the module starts from a single exported symbol (&lt;code&gt;sprint_symbol&lt;/code&gt;) and
rebuilds the full kallsyms lookup chain in 8 steps.&lt;/p&gt;
&lt;h3 id="1-anchor"&gt;1. anchor
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;&amp;amp;sprint_symbol&lt;/code&gt; is a function pointer — the linker fills in the real
address via &lt;code&gt;R_AARCH64_ABS64&lt;/code&gt; relocation. mask off the page offset to
get the kernel base.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sprint_addr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt;)&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;sprint_symbol;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kernel_base &lt;span style="color:#f92672"&gt;=&lt;/span&gt; sprint_addr &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; &lt;span style="color:#f92672"&gt;~&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0x1FFFFFULL&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-sys_call_table"&gt;2. sys_call_table
&lt;/h3&gt;&lt;p&gt;walk the x29 frame pointer chain out of the module init call. strip PAC
signatures from return addresses. scan backwards for &lt;code&gt;do_el0_svc&lt;/code&gt; frames.&lt;/p&gt;
&lt;p&gt;inside &lt;code&gt;do_el0_svc&lt;/code&gt;, the compiler emits an ADRP+ADD+B triplet to load
&lt;code&gt;sys_call_table&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;find_sct&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; fp_ret &lt;span style="color:#f92672"&gt;*&lt;/span&gt;frames, &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; nf)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; nf &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i&lt;span style="color:#f92672"&gt;--&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt; base &lt;span style="color:#f92672"&gt;=&lt;/span&gt; frames[i].addr &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;128&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;scan_adrp_add&lt;/span&gt;(base, MAX_SCAN, adrps, MAX_ADRP);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; j &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; j &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; na; j&lt;span style="color:#f92672"&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;adrps[j].has_b) &lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;check_sct&lt;/span&gt;(adrps[j].target)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sys_call_table_addr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; adrps[j].target;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; adrps[j].target;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;scan_adrp_add&lt;/code&gt; decodes the ARM64 instructions: ADRP extracts bits 21-16
of the page address, ADD supplies the page offset, and B gives the final
target address of the instruction sequence after the ADRP+ADD pair.&lt;/p&gt;
&lt;h3 id="3-bl-chain"&gt;3. BL chain
&lt;/h3&gt;&lt;p&gt;trace the BL (branch-and-link) instruction chain recursively from
&lt;code&gt;sprint_symbol&lt;/code&gt;. each BL instruction at offset &lt;code&gt;i&lt;/code&gt; targets
&lt;code&gt;fn + i*4 + imm26*4&lt;/code&gt;. collect all visited functions (37 on this device).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;follow_bl&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt; fn, &lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;visited, &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;nv_cnt, &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; depth)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;256&lt;/span&gt;; i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; insn &lt;span style="color:#f92672"&gt;=&lt;/span&gt; bl_buf[i];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ((insn &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0xFC000000&lt;/span&gt;) &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x94000000&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt; imm26 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; insn &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x3FFFFFF&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (imm26 &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x2000000&lt;/span&gt;) imm26 &lt;span style="color:#f92672"&gt;|=&lt;/span&gt; &lt;span style="color:#f92672"&gt;~&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0x3FFFFFF&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt; tgt &lt;span style="color:#f92672"&gt;=&lt;/span&gt; fn &lt;span style="color:#f92672"&gt;+&lt;/span&gt; i &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; imm26 &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;is_ktxt&lt;/span&gt;(tgt)) &lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; visited[(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;nv_cnt)&lt;span style="color:#f92672"&gt;++&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; tgt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;follow_bl&lt;/span&gt;(tgt, visited, nv_cnt, depth &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="4-adrp-pages"&gt;4. ADRP pages
&lt;/h3&gt;&lt;p&gt;for each visited function, scan 256 instructions for ADRP instructions.
extract the target page: &lt;code&gt;(pc &amp;amp; ~0xFFF) + (imm &amp;lt;&amp;lt; 12)&lt;/code&gt;. collect
74 unique pages across all functions.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;collect_adrp_pages&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt; fn, &lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;pages, &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; max)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;256&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; n &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; max; i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; insn &lt;span style="color:#f92672"&gt;=&lt;/span&gt; buf[i];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ((insn &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x9F000000&lt;/span&gt;) &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x90000000&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt; imm &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ((insn &lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;) &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x7FFFF&lt;/span&gt;) &lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ((insn &lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt;) &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt; page &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ((fn &lt;span style="color:#f92672"&gt;+&lt;/span&gt; i &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;) &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; &lt;span style="color:#f92672"&gt;~&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0xFFF&lt;/span&gt;) &lt;span style="color:#f92672"&gt;+&lt;/span&gt; (imm &lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pages[n&lt;span style="color:#f92672"&gt;++&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; page;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="5-find-klbase"&gt;5. find klbase
&lt;/h3&gt;&lt;p&gt;scan every ADRP page for an 8-byte value matching &lt;code&gt;kernel_base&lt;/code&gt;.
this value is &lt;code&gt;kallsyms_relative_base&lt;/code&gt; (= &lt;code&gt;_text&lt;/code&gt;).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; pi &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; pi &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; total_pages &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#f92672"&gt;!&lt;/span&gt;klbase_addr; pi&lt;span style="color:#f92672"&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; off &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; off &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x1000&lt;/span&gt;; off &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt; v;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;safe_read&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;v, (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)(page &lt;span style="color:#f92672"&gt;+&lt;/span&gt; off), &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (v &lt;span style="color:#f92672"&gt;==&lt;/span&gt; kernel_base) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; klbase_addr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; page &lt;span style="color:#f92672"&gt;+&lt;/span&gt; off;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="6-find-kloffs"&gt;6. find kloffs
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;kallsyms_offsets[0]&lt;/code&gt; is always 0 — the first symbol&amp;rsquo;s address equals
&lt;code&gt;kallsyms_relative_base&lt;/code&gt;. scan every 4-byte position in every ADRP page
for a u32 value of 0.&lt;/p&gt;
&lt;p&gt;verify each candidate by passing the first 4 offsets through &lt;code&gt;sprint_symbol&lt;/code&gt;
— the kernel&amp;rsquo;s own resolver. if any returns raw hex (&lt;code&gt;0x...&lt;/code&gt;) instead of a
symbol name, the candidate is rejected. &lt;code&gt;sprint_symbol&lt;/code&gt; always returns the
correct answer because it uses the kernel&amp;rsquo;s internal lookup path.&lt;/p&gt;
&lt;p&gt;walk the sorted u32 sequence from each verified candidate. pick the one
with the longest run. the real &lt;code&gt;kallsyms_offsets&lt;/code&gt; has &lt;code&gt;num_syms&lt;/code&gt; entries
(126252 on these devices), unmatched by any other &lt;code&gt;.rodata&lt;/code&gt; region.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// offsets[0] is always 0 (_text - relative_base)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (v &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// sprint_symbol verify: first 4 offsets must resolve to real names
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ok; i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sprint_symbol&lt;/span&gt;(name, klbase_val &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;read_u32&lt;/span&gt;(addr &lt;span style="color:#f92672"&gt;+&lt;/span&gt; i &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (name[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;] &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; name[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;] &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;x&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ok &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// sprint_symbol returned raw hex = no symbol here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;ok) &lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// count consecutive sorted u32 entries, pick the longest
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; len &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, prev &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;500000&lt;/span&gt;; i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; v &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;read_u32&lt;/span&gt;(addr &lt;span style="color:#f92672"&gt;+&lt;/span&gt; i &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ((&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;)v &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; prev) &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; prev &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;)v;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; len&lt;span style="color:#f92672"&gt;++&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (len &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; best_len) { best_len &lt;span style="color:#f92672"&gt;=&lt;/span&gt; len; best_addr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; addr; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="7-layout-derivation"&gt;7. layout derivation
&lt;/h3&gt;&lt;p&gt;from the kernel source (&lt;code&gt;scripts/kallsyms.c&lt;/code&gt;) the data structures are
laid out in &lt;code&gt;.rodata&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;num_syms (4B)
names (compressed)
markers (u32 × ceil(num_syms/256))
token_table (256 null-terminated strings)
token_index (256 × u16 = 512B)
offsets (u32 × num_syms)
relative_base (u64)
seqs_of_names (3B × num_syms)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;all addresses are derived from &lt;code&gt;klbase&lt;/code&gt; and &lt;code&gt;kloffs&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;klnum_val &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (klbase_addr &lt;span style="color:#f92672"&gt;-&lt;/span&gt; kloffs_addr) &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// num_syms
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;klindex_addr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; kloffs_addr &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;512&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// token_index
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;klseqs_addr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; klbase_addr &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// seqs_of_names
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// find klnum_addr: match value == klnum_val in ADRP pages
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// find kltable_addr: backward scan from token_index for 256 strings
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// compute klmarks_addr and klnames_addr from layout
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="8-name-lookup"&gt;8. name lookup
&lt;/h3&gt;&lt;p&gt;implement both directions:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;kallsyms_name_to_addr&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;name)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; low &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, high &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;)klnum_val &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (low &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; high) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; mid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; low &lt;span style="color:#f92672"&gt;+&lt;/span&gt; (high &lt;span style="color:#f92672"&gt;-&lt;/span&gt; low) &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; seq &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get_sym_seq&lt;/span&gt;(mid); &lt;span style="color:#75715e"&gt;// name-sorted -&amp;gt; original idx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; off &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get_sym_offset&lt;/span&gt;(seq); &lt;span style="color:#75715e"&gt;// idx -&amp;gt; names offset
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;expand_sym&lt;/span&gt;(off, nbuf, &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(nbuf)); &lt;span style="color:#75715e"&gt;// decompress
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; r &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;strcmp&lt;/span&gt;(name, nbuf);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (r &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) low &lt;span style="color:#f92672"&gt;=&lt;/span&gt; mid &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (r &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) high &lt;span style="color:#f92672"&gt;=&lt;/span&gt; mid &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sym_addr&lt;/span&gt;(seq); &lt;span style="color:#75715e"&gt;// offsets[seq] + klbase
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;verify with kprobe + &lt;code&gt;sprint_symbol&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt; test_addr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;resolve&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;kallsyms_lookup_name&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sprint_symbol_no_offset&lt;/span&gt;(truth, test_addr);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sym_name_at&lt;/span&gt;(test_addr, our, &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(our)); &lt;span style="color:#75715e"&gt;// addr -&amp;gt; name
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt; lookup &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;kallsyms_name_to_addr&lt;/span&gt;(truth); &lt;span style="color:#75715e"&gt;// name -&amp;gt; addr
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="conclusion"&gt;conclusion
&lt;/h2&gt;&lt;p&gt;full kallsyms lookup without any exported symbol dependency.
&lt;code&gt;sym_name_at&lt;/code&gt; and &lt;code&gt;kallsyms_name_to_addr&lt;/code&gt; match kernel values on device.&lt;/p&gt;
&lt;h2 id="repo"&gt;repo
&lt;/h2&gt;&lt;p&gt;&lt;a class="link" href="https://github.com/Dere3046/ksymless_Android" target="_blank" rel="noopener"
 &gt;github.com/Dere3046/ksymless_Android&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="references"&gt;references
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/rota1001/ksymless" target="_blank" rel="noopener"
 &gt;rota1001/ksymless&lt;/a&gt; — original x86_64 technique&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://xcellerator.github.io/posts/linux_rootkits_11/" target="_blank" rel="noopener"
 &gt;xcellerator: linux rootkits 11&lt;/a&gt; — kallsyms internals&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>