Full Stack Developer
https://everettjf.github.io/
Mon, 05 Jan 2026 16:35:18 +0000Mon, 05 Jan 2026 16:35:18 +0000Jekyll v3.10.0Getting Started with KernelSU: Installing a Minimal App Hiding Module on Pixel 6<p>Having spent time with iOS jailbreaking, I decided to explore process injection and app hiding on Android. This article walks through building a <strong>minimal working module chain (app hiding)</strong> based on KernelSU from scratch on a Pixel 6 running Android 15.</p>
<blockquote>
<p>Note that this app hiding implementation is fairly basic—it simply hooks Java-level APIs for retrieving the app list. Regardless, this workflow provides a direct way to experience app hiding capabilities.</p>
</blockquote>
<!-- more -->
<hr />
<h2 id="what-is-kernelsu">What is KernelSU</h2>
<p>KernelSU is a root solution designed for <strong>Android GKI devices</strong>. The official homepage is:</p>
<ul>
<li><a href="https://kernelsu.org/">https://kernelsu.org/</a></li>
</ul>
<p>Unlike traditional root solutions that primarily operate in userspace, KernelSU’s core logic runs in <strong>kernel space</strong>, directly granting root privileges to userspace applications from within the kernel.</p>
<p>From an implementation perspective, KernelSU doesn’t rely on modifying <code class="language-plaintext highlighter-rouge">init</code>, <code class="language-plaintext highlighter-rouge">zygote</code>, or the system partition. Instead, it provides capabilities through the kernel itself. This allows it to access interfaces that userspace solutions have difficulty utilizing stably.</p>
<p>In terms of capabilities, KernelSU provides <strong>kernel-level interfaces</strong>, such as:</p>
<ul>
<li>Setting hardware breakpoints for arbitrary processes in kernel space</li>
<li>Accessing a process’s physical memory with lower visibility</li>
<li>Intercepting system calls (syscalls) in kernel space</li>
<li>Intervening earlier in the process execution flow</li>
</ul>
<p>These capabilities don’t directly correspond to specific functional modules, but they form the technical foundation of KernelSU.</p>
<hr />
<h2 id="metamodule-mechanism">Metamodule Mechanism</h2>
<p>KernelSU also introduces a module system called <strong>Metamodule</strong>. Related documentation can be found in the official docs:</p>
<ul>
<li><a href="https://kernelsu.org/guide/what-is-kernelsu.html">https://kernelsu.org/guide/what-is-kernelsu.html</a></li>
</ul>
<p>KernelSU itself only provides low-level capabilities and interfaces. Specific mounting and systemless modification logic aren’t hardcoded into the core, but are instead implemented by Metamodules.</p>
<p>For example:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">meta-overlayfs</code> provides systemless modification capabilities for the <code class="language-plaintext highlighter-rouge">/system</code> partition</li>
<li>Different types of modification behaviors are split into independent modules</li>
<li>This prevents core functionality from bloating as module requirements grow</li>
</ul>
<p>Module lists and available Metamodules can be viewed on the official site:</p>
<ul>
<li><a href="https://modules.kernelsu.org/">https://modules.kernelsu.org/</a></li>
</ul>
<hr />
<h2 id="test-environment">Test Environment</h2>
<p>The test environment for this experiment:</p>
<ul>
<li>Device: Pixel 6 (oriole)</li>
<li>System: Android 15 (BP1A.250505.005, May 2025)</li>
<li>Root solution: KernelSU (LKM mode)</li>
<li>Module chain: KernelSU → Zygisk Next → LSPosed</li>
<li>Verification target: Hide My Applist</li>
</ul>
<hr />
<h2 id="flashing-official-android-15">Flashing Official Android 15</h2>
<p>No customizations were made to the system. We used Google’s official Factory Image, flashed via the Web Flash Tool.</p>
<p>After flashing, the device was in a completely clean Android 15 state, with only the bootloader unlocked for subsequent experiments.</p>
<hr />
<h2 id="kernelsu-lkm-mode-installation-notes">KernelSU (LKM Mode) Installation Notes</h2>
<p>KernelSU’s LKM mode installation process is similar to Magisk’s approach. The overall steps are as follows:</p>
<p>First, extract <code class="language-plaintext highlighter-rouge">boot.img</code> from the Factory Image and push it to the device:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>adb push boot.img /sdcard/Download/
</code></pre></div></div>
<p>Then use <strong>KernelSU Manager</strong> on the device to patch <code class="language-plaintext highlighter-rouge">boot.img</code>, generating a patched boot image.</p>
<p>Pull the patched image back to the local machine and flash it:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>adb pull /sdcard/Download/kernelsu_patched.img
adb reboot bootloader
fastboot flash boot kernelsu_patched.img
fastboot reboot
</code></pre></div></div>
<p>After rebooting, KernelSU Manager can properly detect the root status, indicating that the kernel-side changes have taken effect.</p>
<hr />
<h2 id="basic-tools-setup">Basic Tools Setup</h2>
<p>To facilitate subsequent operations, we installed some basic tools:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>adb <span class="nb">install </span>MT_File_Manager.apk
adb <span class="nb">install </span>F-Droid.apk
adb <span class="nb">install </span>Termux.apk
</code></pre></div></div>
<p>These tools are only used to assist with viewing files, installing applications, and executing commands. They don’t affect how KernelSU itself works.</p>
<hr />
<h2 id="zygisk-next-and-lsposed">Zygisk Next and LSPosed</h2>
<p>KernelSU doesn’t implement Zygisk itself, so we need to load <strong>Zygisk Next</strong> separately, then use <strong>LSPosed (Zygisk version)</strong> on top of it.</p>
<p>The LSPosed module is pushed and loaded as a zip file:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>adb push LSPosed-zygisk-release.zip /sdcard/Download/
</code></pre></div></div>
<p>After enabling the module in KernelSU Manager and rebooting, LSPosed Manager shows the Framework as Active, indicating that the hook chain has been established.</p>
<hr />
<h2 id="verifying-hook-capabilities-with-hide-my-applist">Verifying Hook Capabilities with Hide My Applist</h2>
<p>As the first verification point, we chose <strong>Hide My Applist</strong>:</p>
<ul>
<li>Project repository: <a href="https://github.com/Dr-TSNG/Hide-My-Applist">https://github.com/Dr-TSNG/Hide-My-Applist</a></li>
</ul>
<p>The module’s behavior is straightforward:
It controls whether target applications can retrieve the complete list of installed applications.</p>
<p>After installing Hide My Applist, enable the module for specific applications in LSPosed and configure hiding rules. After restarting the target application, the app list behavior changes, and the results match expectations.</p>
<p>This result verifies that the following chain is functional in the current environment:</p>
<blockquote>
<p>KernelSU → Zygisk Next → LSPosed → Application behavior changes</p>
</blockquote>
<hr />
<h2 id="summary">Summary</h2>
<p>Some straightforward conclusions:</p>
<ul>
<li>Using KernelSU on Pixel 6 with Android 15 is feasible</li>
<li>The LKM mode installation path is clear and the process is stable</li>
<li>Zygisk Next + LSPosed can serve as a basic hook combination under KernelSU</li>
<li>Hide My Applist provides a simple, direct verification entry point</li>
</ul>
Mon, 05 Jan 2026 00:00:00 +0000
https://everettjf.github.io/2026/01/05/kernelsu-first/
https://everettjf.github.io/2026/01/05/kernelsu-first/KernelSUAndroidRootLSPosedZygiskApp HidingPixel 6Android 15Alma: Reverse Engineering an AI Provider Orchestration Desktop App<h3 id="what-is-alma">What is Alma?</h3>
<p><strong>Alma</strong> is a desktop <strong>AI Provider orchestration and management application</strong>. It has recently received widespread praise on X, and the author is very active. The development pace is extremely fast, with releases coming like rain. I’ve been playing around with this software recently and deeply appreciate the author’s solid technical foundation.</p>
<!-- more -->
<p>On its official website (<a href="https://alma.now/">https://alma.now/</a>), it positions itself very directly:</p>
<blockquote>
<p><strong>Elegant AI Provider Orchestration</strong></p>
</blockquote>
<p>In other words, Alma doesn’t aim to be just a “chat window”—it wants to become a <strong>desktop workbench that uniformly schedules, combines, and runs multiple AI capabilities</strong>.</p>
<p>Based on the official website and actual code structure, Alma focuses on these areas:</p>
<ul>
<li>Unified management of multiple AI Providers (OpenAI, Anthropic, Google Gemini, DeepSeek, and custom APIs)</li>
<li>Conversation-centric UI with Markdown support, code highlighting, and streaming output</li>
<li>Memory and context management, visualized in the UI</li>
<li>Browser-based capabilities like WebFetch / WebSearch</li>
<li>Composable extensions through Prompt Apps and Skills</li>
<li><strong>Extensive direct integration of local capabilities, rather than “cloud-only”</strong></li>
</ul>
<p>Overall, it feels more like an <strong>“AI capability orchestration layer + desktop IDE-like experience”</strong>:
It handles models, credentials, and protocols, while also actually running tools locally.</p>
<hr />
<h3 id="author-and-project-source">Author and Project Source</h3>
<p>Alma is developed and maintained by <strong>yetone</strong>. The project is closed-source, though the source code appears to be hosted on GitHub (inferred from configuration files):
<a href="https://github.com/yetone/alma.git">https://github.com/yetone/alma.git</a> The author’s GitHub is https://github.com/yetone, with multiple high-starred projects, showing strong technical passion and worth learning from for developers.</p>
<p>Back to Alma. Based on code scale, engineering organization, and continuous version evolution, this isn’t a one-off demo—it’s a <strong>long-term evolving desktop AI project</strong>.
The author demonstrates solid engineering practices in the following areas:</p>
<ul>
<li>Electron / macOS desktop application architecture</li>
<li>Node.js / TypeScript engineering</li>
<li>Unified abstraction of multiple AI Providers</li>
<li>Local tool integration (PTY, Playwright, Whisper)</li>
<li>Emerging model protocols like MCP / ACP</li>
<li>Complete OAuth / PKCE authorization lifecycle</li>
</ul>
<hr />
<h2 id="1-shell-and-release-information">1. Shell and Release Information</h2>
<ul>
<li><code class="language-plaintext highlighter-rouge">Info.plist</code> shows Bundle ID as <code class="language-plaintext highlighter-rouge">com.yetone.alma</code>, version <strong>0.0.170</strong>, minimum system <strong>macOS 12.0</strong>, main class <code class="language-plaintext highlighter-rouge">AtomApplication</code>, clearly belonging to the <strong>Electron / Atom shell family</strong>.</li>
<li><code class="language-plaintext highlighter-rouge">NSAllowsArbitraryLoads</code> is enabled along with local network access exemptions, indicating the app needs to freely communicate with various model services, proxies, or local services.</li>
<li>Auto-update configuration is located at <code class="language-plaintext highlighter-rouge">Resources/app-update.yml</code>, with update source pointing to a self-hosted feed: <code class="language-plaintext highlighter-rouge">https://updates.alma.now/</code>, meaning the official team maintains a complete update publishing backend.</li>
<li>Core logic is packaged in <code class="language-plaintext highlighter-rouge">app.asar</code>, which unpacks to a typical Electron structure: <code class="language-plaintext highlighter-rouge">out/</code>, <code class="language-plaintext highlighter-rouge">node_modules/</code>, <code class="language-plaintext highlighter-rouge">package.json</code>.</li>
</ul>
<hr />
<h2 id="2-project-structure-and-dependencies">2. Project Structure and Dependencies</h2>
<p><code class="language-plaintext highlighter-rouge">package.json</code> defines Alma as an <strong>“AI Provider Management Desktop App”</strong>, using <strong>pnpm</strong> for dependency management, with <code class="language-plaintext highlighter-rouge">onlyBuiltDependencies</code> enabled for Electron native modules.
It also fixes the <code class="language-plaintext highlighter-rouge">node-abi</code> version via overrides to match the built-in <code class="language-plaintext highlighter-rouge">node-pty</code> beta.</p>
<p>Dependencies can be roughly divided into four categories:</p>
<h3 id="21-ai-provider-sdk">2.1 AI Provider SDK</h3>
<ul>
<li><code class="language-plaintext highlighter-rouge">@ai-sdk/*</code> (openai / anthropic / azure / google / deepseek / openrouter)</li>
<li><code class="language-plaintext highlighter-rouge">@ai-sdk/provider</code></li>
<li><code class="language-plaintext highlighter-rouge">@mcpc-tech/acp-ai-provider</code></li>
<li><code class="language-plaintext highlighter-rouge">@aihubmix/ai-sdk-provider</code></li>
</ul>
<p>Used to uniformly abstract generation, streaming output, and tool calling across different models.</p>
<h3 id="22-desktop-local-capabilities-key-focus">2.2 Desktop Local Capabilities (Key Focus)</h3>
<ul>
<li><code class="language-plaintext highlighter-rouge">better-sqlite3</code>, <code class="language-plaintext highlighter-rouge">sqlite-vec</code></li>
<li><code class="language-plaintext highlighter-rouge">[email protected]</code></li>
<li><strong><code class="language-plaintext highlighter-rouge">playwright@^1.57.0</code></strong></li>
<li><code class="language-plaintext highlighter-rouge">chromium-bidi</code></li>
<li><code class="language-plaintext highlighter-rouge">@fugood/whisper.node</code></li>
</ul>
<p>This group of dependencies is crucial—it clearly shows:
<strong>Alma isn’t “pretending to be desktop”—it actually runs tools locally.</strong></p>
<h3 id="23-document-and-content-preview">2.3 Document and Content Preview</h3>
<p>PDF, Excel, Word, tokenization, image dimensions, Emoji processing capabilities for multi-format content display.</p>
<h3 id="24-ui-and-monitoring">2.4 UI and Monitoring</h3>
<p>Radix, framer-motion, sonner, PostHog, Sentry, forming a modern React desktop UI and observability system.</p>
<hr />
<h2 id="3-main-process-outmainindexjs-deep-dive">3. Main Process (<code class="language-plaintext highlighter-rouge">out/main/index.js</code>) Deep Dive</h2>
<p>The main process is Alma’s “control tower,” bringing together system capabilities, local services, databases, and AI Providers.</p>
<h3 id="31-environment-setup-and-dependency-injection">3.1 Environment Setup and Dependency Injection</h3>
<ul>
<li>Electron core module loading</li>
<li>Uses <code class="language-plaintext highlighter-rouge">fix-path</code> to fix CLI environment on macOS</li>
<li>Starts local Express API + WebSocket server</li>
<li>Uses <code class="language-plaintext highlighter-rouge">zod</code> for interface schema validation</li>
<li>Initializes Sentry and AI Tool middleware</li>
</ul>
<hr />
<h3 id="32-database-layer-drizzle--sqlite">3.2 Database Layer (Drizzle + SQLite)</h3>
<ul>
<li>Covers core tables: Prompt, Workspace, Chat, Provider, Skill, MCP, Theme</li>
<li>Version 0.0.170 adds subscription types (like <code class="language-plaintext highlighter-rouge">claude-subscription</code>) and configuration fields to the Provider table</li>
<li>Uses Drizzle relations to explicitly express complex UI relationships</li>
</ul>
<hr />
<h3 id="33-ai-provider--tool-system">3.3 AI Provider / Tool System</h3>
<ul>
<li>Uses <code class="language-plaintext highlighter-rouge">ai</code> package to unify text and streaming output across different models</li>
<li>Integrates ACP tool system with UI tool stream support</li>
<li>Built-in Proxy + Retry + Timeout, supports HTTP / SOCKS5</li>
</ul>
<hr />
<h3 id="34-local-api--mcp--oauth">3.4 Local API + MCP / OAuth</h3>
<ul>
<li>Local REST API + WebSocket push</li>
<li>Complete MCP OAuth lifecycle (authorization, refresh, revocation)</li>
<li>Claude Subscription authorization flow built into IPC</li>
</ul>
<hr />
<h3 id="35-playwright-not-an-afterthought-but-explicit-infrastructure">3.5 <strong>Playwright: Not an Afterthought, but Explicit Infrastructure</strong></h3>
<p>Playwright in Alma is <strong>explicitly present, explicitly used, and explicitly lifecycle-managed</strong>—not a future placeholder option.</p>
<p><strong>First, at the dependency level:</strong></p>
<ul>
<li><code class="language-plaintext highlighter-rouge">package.json</code> directly declares <code class="language-plaintext highlighter-rouge">"playwright": "^1.57.0"</code></li>
<li>Placed in the same group of “desktop automation dependencies” as <code class="language-plaintext highlighter-rouge">node-pty</code> and <code class="language-plaintext highlighter-rouge">chromium-bidi</code></li>
<li>This means <strong>Playwright is installed into the app during the build phase</strong> (not via runtime npm install)</li>
</ul>
<p><strong>Second, installation and state management logic in the main process:</strong></p>
<ul>
<li>
<p>The main process maintains a complete Playwright installation detection flow:</p>
<ul>
<li>Checks <code class="language-plaintext highlighter-rouge">~/Library/Caches/ms-playwright/</code> (macOS) or <code class="language-plaintext highlighter-rouge">%LOCALAPPDATA%/ms-playwright</code></li>
<li>Determines if <code class="language-plaintext highlighter-rouge">chromium-*</code> directories already exist</li>
</ul>
</li>
<li>
<p>If not installed:</p>
<ul>
<li>Pulls browser kernel via <code class="language-plaintext highlighter-rouge">playwright-core/cli.js install chromium</code></li>
<li>Installation status recorded in <code class="language-plaintext highlighter-rouge">ta = { installed, installing, progress }</code></li>
</ul>
</li>
<li>
<p>Exposes complete control surface via IPC:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">playwright-get-status</code></li>
<li><code class="language-plaintext highlighter-rouge">playwright-install</code></li>
<li><code class="language-plaintext highlighter-rouge">playwright-install-status</code> (real-time progress events)</li>
</ul>
</li>
</ul>
<p><strong>The purpose of this mechanism is very clear:</strong></p>
<blockquote>
<p>To provide Alma’s <strong>WebFetch / WebSearch / automated scraping capabilities</strong> with a <strong>controllable, stable, version-fixed Chromium kernel</strong>.</p>
</blockquote>
<p>Therefore:</p>
<ul>
<li>The app calls <code class="language-plaintext highlighter-rouge">ra()</code> during startup to attempt <strong>silent installation</strong></li>
<li>UI allows users to view installation status or manually trigger again</li>
<li>Only when the Playwright browser is ready will background web scraping and script execution capabilities actually be enabled</li>
</ul>
<p>This also explains why Alma <strong>must be a desktop application</strong>:
These capabilities are almost impossible to reliably implement in a pure web environment.</p>
<hr />
<h3 id="36-system-capabilities-and-ipc-interfaces">3.6 System Capabilities and IPC Interfaces</h3>
<p>IPC covers almost all desktop capabilities:</p>
<ul>
<li>Multi-window management</li>
<li>Global and dynamic keyboard shortcuts</li>
<li>Clipboard and file system</li>
<li>Microphone, Whisper, Playwright status</li>
<li>Auto-updates</li>
<li>Copilot / Claude token management</li>
<li>MCP OAuth</li>
<li>WebFetch / WebSearch debug windows</li>
</ul>
<hr />
<h2 id="4-renderer-layer-react--vite">4. Renderer Layer (React + Vite)</h2>
<ul>
<li>React + Vite + SWR + jotai</li>
<li>An aggregated Context as the UI logic bus</li>
<li>Chat, tool management, multi-window control</li>
<li>Full-format content preview</li>
<li>Radix UI + animations</li>
<li>PostHog / Sentry monitoring</li>
</ul>
<p>All capabilities uniformly call the main process via IPC injected through preload.</p>
<hr />
<h2 id="5-development-and-debugging">5. Development and Debugging</h2>
<ul>
<li>Supports Vite DevServer hot reload</li>
<li>TypeScript + pnpm workspaces</li>
<li>Official GitHub source code is more suitable for reading and secondary development than the bundle</li>
</ul>
<hr />
<h2 id="6-security-privacy-and-system-permissions">6. Security, Privacy, and System Permissions</h2>
<ul>
<li>Requests microphone, Bluetooth, camera permissions</li>
<li>Supports proxy configuration</li>
<li>Telemetry (Sentry / PostHog) should be evaluated based on deployment scenario</li>
<li>MCP OAuth uses PKCE, supports token revoke / refresh</li>
</ul>
<hr />
<h2 id="7-summary">7. Summary</h2>
<p><strong>Alma 0.0.170</strong> demonstrates a very “substantial” desktop AI application form:</p>
<ul>
<li>Upper layer: Multi-window, conversation-driven UI</li>
<li>Middle layer: Unified orchestration of Provider, Prompt, Skill, MCP</li>
<li>Lower layer: <strong>Real local infrastructure</strong>—database, terminal, Playwright Chromium, voice models</li>
</ul>
<p>Combining the official positioning with actual engineering implementation, Alma is more like an <strong>AI capability scheduling and execution platform</strong>, not just a chat tool.
In the direction of “AI desktop applications,” it provides a structurally complete, engineering-solid implementation sample that clearly has room to grow.</p>
Sun, 04 Jan 2026 00:00:00 +0000
https://everettjf.github.io/2026/01/04/alma-analyze/
https://everettjf.github.io/2026/01/04/alma-analyze/almaelectronaidesktopreverse-engineeringplaywrightmcptypescriptDia: A Technical Deep Dive into The Browser Company's macOS Browser<p>If you’ve been following Arc, you’ve probably heard of <strong>Dia</strong>.
It’s another browser product from The Browser Company, currently targeting macOS.</p>
<p>From a user experience perspective, Dia continues some of Arc’s design philosophy; but if you dig into the Dia.app bundle contents, you’ll find that its engineering structure and system integration are quite “traditional” and interesting.</p>
<!-- more -->
<p>This article doesn’t discuss whether the experience is good or bad, nor does it predict future directions. It does one thing:</p>
<blockquote>
<p><strong>Examine how Dia is actually built from a technical perspective.</strong></p>
</blockquote>
<hr />
<h2 id="the-company-behind-dia-the-browser-company">The Company Behind Dia: The Browser Company</h2>
<p>Let me provide some brief background.</p>
<p>The Browser Company was founded in <strong>2019</strong>, headquartered in New York, and first gained attention with the <strong>Arc browser</strong>. The company’s public mission has been clear: explore new interaction patterns and usage models around the “browser” as a platform.</p>
<p>Regarding funding, based on publicly available information:</p>
<ul>
<li>The company has raised approximately <strong>$128 million</strong> in total</li>
<li>This includes a <strong>$50 million round in 2024</strong></li>
<li>Investors include both venture capital firms and individual investors with backgrounds in internet products</li>
</ul>
<p>As of now, <strong>The Browser Company has not been acquired</strong> and continues to operate independently, with Dia being part of its in-house product line.</p>
<hr />
<h2 id="what-kind-of-application-is-dia">What Kind of Application is Dia?</h2>
<p>Open <code class="language-plaintext highlighter-rouge">Contents/MacOS/Dia</code> in Dia.app, and you’ll see something familiar:</p>
<ul>
<li><strong>arm64 Mach-O</strong></li>
<li>Built with <strong>Xcode 16.4</strong></li>
<li>Minimum system version: <strong>macOS 14</strong></li>
<li>Entry point is <strong>AppKit’s MainMenu.nib</strong></li>
</ul>
<p>This pretty much tells you everything:</p>
<blockquote>
<p>Dia is a standard native macOS application.</p>
</blockquote>
<p>It’s not Electron, and it’s not a “wrapped web page.”
This is also evident from its use of system capabilities, such as:</p>
<ul>
<li>AppleScript (<code class="language-plaintext highlighter-rouge">Dia.sdef</code>)</li>
<li>Dock Tile plugins</li>
<li><code class="language-plaintext highlighter-rouge">NSUserActivityTypeBrowsingWeb</code></li>
<li>Native registration of <code class="language-plaintext highlighter-rouge">http / https</code> schemes</li>
<li>Declarations for camera, microphone, Bluetooth, location, desktop, downloads, and other permissions</li>
</ul>
<p>These are all <strong>standard operations in the AppKit world</strong>, but they’re typically cumbersome in cross-platform frameworks.</p>
<hr />
<h2 id="browser-engine-not-webkit-but-arccore">Browser Engine: Not WebKit, but ArcCore</h2>
<p>At the rendering layer, Dia doesn’t follow Safari’s WebKit path.</p>
<p>It relies on a private framework called <strong>ArcCore.framework</strong>.
From the Info metadata, you can see:</p>
<ul>
<li>Version: <strong>143.0.7499.170</strong></li>
<li>Corresponding Chromium: <code class="language-plaintext highlighter-rouge">branch-heads/7499@{#3400}</code></li>
</ul>
<p>In other words, Dia embeds <strong>a Chromium branch maintained by the Arc team</strong>.</p>
<p>If you look at dependencies with <code class="language-plaintext highlighter-rouge">otool -L</code>, you’ll find a typical combination:</p>
<ul>
<li>UI / System layer: AppKit, SwiftUI, Combine</li>
<li>Rendering / Scripting: Chromium (via ArcCore), JavaScriptCore</li>
<li>Performance: Metal, Accelerate</li>
</ul>
<p>The overall architecture can be understood as:</p>
<blockquote>
<p><strong>Native macOS application + Chromium as web rendering component</strong></p>
</blockquote>
<p>Browser windows, animations, and interactions are handled at the native layer, while Chromium primarily handles web content itself.</p>
<hr />
<h2 id="a-notable-design-extensive-use-of-bundles">A Notable Design: Extensive Use of Bundles</h2>
<p>The truly “engineering-focused” part is in <code class="language-plaintext highlighter-rouge">Contents/Resources</code>.</p>
<p>This isn’t just a simple resource directory—it’s packed with bundles, such as:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">BoostBrowser_TabUI.bundle</code></li>
<li>Download panel-related bundles</li>
<li>Personalization modules</li>
<li>Supertab-related components</li>
<li>A series of <code class="language-plaintext highlighter-rouge">ARC_*</code> bundles</li>
</ul>
<p>What these bundles have in common:</p>
<ul>
<li>Each has its own <code class="language-plaintext highlighter-rouge">Info.plist</code></li>
<li>Built separately by Xcode</li>
<li>Each declares its minimum macOS version</li>
</ul>
<p>This indicates that Dia uses a <strong>modular architecture</strong> at the functional level:
Features like tab UI, downloads, and personalization aren’t all compiled into one large binary.</p>
<p>From an engineering perspective, this approach makes it easier to:</p>
<ul>
<li>Develop and debug independently</li>
<li>Control feature loading</li>
<li>Manage complex UI components</li>
</ul>
<hr />
<h2 id="data-updates-and-stability-conventional-choices">Data, Updates, and Stability: Conventional Choices</h2>
<p>For infrastructure, Dia uses mature solutions:</p>
<ul>
<li><strong>GRDB.framework (SQLite ORM)</strong>
For local data storage</li>
<li><strong>Sparkle.framework</strong>
For automatic application updates
Update source is explicitly declared in Info.plist</li>
<li><strong>Sentry.framework</strong>
For crash and performance monitoring</li>
</ul>
<p>You can also see dependencies like Datadog, ZIPFoundation, and SDWebImage, all focused on logging, resource handling, and stability.</p>
<p>Overall, this layer doesn’t have much “experimental design”—it leans toward stable, proven implementations.</p>
<hr />
<h2 id="local-ai-infrastructure-already-in-place">Local AI: Infrastructure Already in Place</h2>
<p>In the resources directory, there’s another notable group of bundles:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">swift-transformers_Hub.bundle</code></li>
<li><code class="language-plaintext highlighter-rouge">mlx-swift_Cmlx.bundle</code></li>
<li><code class="language-plaintext highlighter-rouge">AIInfra_LocalClassification.bundle</code></li>
<li><code class="language-plaintext highlighter-rouge">OnDeviceLoRAadaptors.bundle</code></li>
</ul>
<p>Based on their names and Info metadata, these components involve:</p>
<ul>
<li>Swift Transformers</li>
<li>Apple MLX</li>
<li>Local model inference</li>
<li>LoRA adapters</li>
</ul>
<p>They’re also built with Xcode, with minimum support for macOS 13.
This shows that Dia has <strong>already prepared the engineering foundation for local ML inference</strong> in its architecture; what specific features use it depends on product-level implementation.</p>
<hr />
<h2 id="closing-thoughts">Closing Thoughts</h2>
<p>If we only look at the application bundle and dependency structure, Dia’s architecture is quite clear:</p>
<ul>
<li>It’s a <strong>native macOS application</strong></li>
<li>Uses a <strong>custom Chromium branch</strong> as its web rendering engine</li>
<li>Employs a <strong>bundle-based modular organization</strong> for features</li>
<li>Infrastructure choices lean toward mature and stable solutions</li>
<li>Has already prepared the engineering foundation for local ML capabilities</li>
</ul>
<p>Not radical, not conservative—more like a serious approach to <strong>“building a browser” within the macOS ecosystem</strong>.</p>
Fri, 02 Jan 2026 00:00:00 +0000
https://everettjf.github.io/2026/01/02/dia-analyze/
https://everettjf.github.io/2026/01/02/dia-analyze/browserdiaarcchromiummacosappkitreverse-engineeringtechnical-analysisJavaScript Runtime with deno_core<blockquote>
<p>If you’re not familiar with Deno, check out the official website at https://deno.land/. In short, Deno is a more secure alternative to Node (the name is literally Node reversed: no_de -> de_no), created by the same founder as Node.</p>
</blockquote>
<p>A couple of days ago, the Deno blog published an article titled “Roll your own JavaScript runtime”</p>
<blockquote>
<p>https://deno.com/blog/roll-your-own-javascript-runtime</p>
</blockquote>
<!-- more -->
<p><img src="/media/16592798557784.jpg" alt="" /></p>
<blockquote>
<p>I was inspired to write this learning note after reading the article.
Note: This is not a word-for-word translation, but rather a learning record with minor modifications while preserving the original meaning.
The “inspiration” came from the fact that about six months ago, I looked at Deno’s documentation on Embedding Deno (https://deno.land/manual/embedding_deno), but it didn’t have much content—it just pointed to the deno_core documentation (https://crates.io/crates/deno_core) without any getting started tutorial. At the time, my Rust skills weren’t strong enough, so I didn’t continue exploring.</p>
</blockquote>
<p>Without further ado, let’s get started.</p>
<h1 id="main-content">Main Content</h1>
<p>This article explains how to create a custom JavaScript runtime called runjs. Think of it as a very simple version of Deno. The goal is to develop a command-line program that can execute local JavaScript files, with the ability to read, write, and delete files, plus a console API.</p>
<p>Let’s begin.</p>
<h1 id="prerequisites">Prerequisites</h1>
<p>This tutorial assumes you have knowledge of:</p>
<ul>
<li>Basic Rust</li>
<li>Basic understanding of JavaScript event loops</li>
</ul>
<p>Make sure you have Rust installed (cargo is automatically installed with Rust) with version 1.62.0 or higher. Visit https://www.rust-lang.org/learn/get-started to install it.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cargo --version
cargo 1.62.0 (a748cf5a3 2022-06-08)
</code></pre></div></div>
<h1 id="creating-the-project">Creating the Project</h1>
<p>First, let’s create a new Rust project called runjs:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cargo new runjs
Created binary (application) package
</code></pre></div></div>
<p>Navigate to the runjs folder and open it in your editor. Make sure everything works:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cd runjs
$ cargo run
Compiling runjs v0.1.0 (/Users/ib/dev/runjs)
Finished dev [unoptimized + debuginfo] target(s) in 1.76s
Running `target/debug/runjs`
Hello, world!
</code></pre></div></div>
<p>Perfect! Now let’s start building our own JavaScript runtime.</p>
<h1 id="dependencies">Dependencies</h1>
<p>Next, add the dependencies deno_core and tokio:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cargo add deno_core
Updating crates.io index
Adding deno_core v0.142.0 to dependencies.
$ cargo add tokio --features=full
Updating crates.io index
Adding tokio v1.19.2 to dependencies.
</code></pre></div></div>
<p>Your <code class="language-plaintext highlighter-rouge">Cargo.toml</code> file should now look like this:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[package]
name = "runjs"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
deno_core = "0.142.0"
tokio = { version = "1.19.2", features = ["full"] }
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">deno_core</code> is a Rust crate developed by the Deno team that abstracts the V8 JavaScript engine interface. V8 is a complex project with many APIs. To make V8 easier to use, deno_core provides the <code class="language-plaintext highlighter-rouge">JsRuntime</code> struct, which wraps a V8 engine instance (also called an Isolate) and supports event loops.</p>
<p><code class="language-plaintext highlighter-rouge">tokio</code> is an asynchronous Rust runtime that we’ll use to implement the event loop. Tokio can interact with system sockets and the file system. Together, deno_core and tokio enable mapping JavaScript Promises to Rust Futures (i.e., JS async/await maps to Rust async/await).</p>
<p>With a JavaScript engine and an event loop, we can create a JavaScript runtime.</p>
<h1 id="hello-runjs">Hello, runjs!</h1>
<p>Now let’s write an async Rust function that creates a JsRuntime instance for executing JavaScript:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// main.rs
use std::rc::Rc;
use deno_core::error::AnyError;
async fn run_js(file_path: &str) -> Result<(), AnyError> {
let main_module = deno_core::resolve_path(file_path)?;
let mut js_runtime = deno_core::JsRuntime::new(deno_core::RuntimeOptions {
module_loader: Some(Rc::new(deno_core::FsModuleLoader)),
..Default::default()
});
let mod_id = js_runtime.load_main_module(&main_module, None).await?;
let result = js_runtime.mod_evaluate(mod_id);
js_runtime.run_event_loop(false).await?;
result.await?
}
fn main() {
println!("Hello, world!");
}
</code></pre></div></div>
<p>There’s a lot to unpack here. The async <code class="language-plaintext highlighter-rouge">run_js</code> function creates a <code class="language-plaintext highlighter-rouge">JsRuntime</code> instance that uses a file system-based module loader (<code class="language-plaintext highlighter-rouge">deno_core::FsModuleLoader</code>). Then, we load a module (<code class="language-plaintext highlighter-rouge">main_module</code>) with <code class="language-plaintext highlighter-rouge">js_runtime</code>, evaluate it (<code class="language-plaintext highlighter-rouge">mod_evaluate</code>), and run an event loop (<code class="language-plaintext highlighter-rouge">run_event_loop</code>).</p>
<p>The <code class="language-plaintext highlighter-rouge">run_js</code> function encompasses the entire lifecycle of JavaScript code execution. But first, we need to create a single-threaded tokio runtime to execute the <code class="language-plaintext highlighter-rouge">run_js</code> function:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// main.rs
fn main() {
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap();
if let Err(error) = runtime.block_on(run_js("./example.js")) {
eprintln!("error: {}", error);
}
}
</code></pre></div></div>
<p>Let’s execute some JavaScript code. Create an <code class="language-plaintext highlighter-rouge">example.js</code> file that outputs “Hello runjs!”:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// example.js
Deno.core.print("Hello runjs!");
</code></pre></div></div>
<blockquote>
<p>Note: <code class="language-plaintext highlighter-rouge">example.js</code> is in the project root folder. <code class="language-plaintext highlighter-rouge">cargo run</code> uses the root folder as the working directory.</p>
</blockquote>
<p><img src="/media/16592798777424.jpg" alt="" /></p>
<p>Note that we’re using the <code class="language-plaintext highlighter-rouge">print</code> function from <code class="language-plaintext highlighter-rouge">Deno.core</code>. <code class="language-plaintext highlighter-rouge">Deno.core</code> is a globally available built-in object provided by <code class="language-plaintext highlighter-rouge">deno_core</code>.</p>
<p>Now let’s run it:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.05s
Running `target/debug/runjs`
Hello runjs!⏎
</code></pre></div></div>
<p>Success! We’ve created a simple JavaScript runtime that can execute local files with just 25 lines of code. Of course, this runtime can’t do much yet (for example, it doesn’t support <code class="language-plaintext highlighter-rouge">console.log</code>). We’ve now integrated the V8 JavaScript engine and tokio into our project.</p>
<h1 id="adding-the-console-api">Adding the Console API</h1>
<p>Let’s implement the console API. First, create a <code class="language-plaintext highlighter-rouge">src/runtime.js</code> file that implements the global console object:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// src/runtime.js
((globalThis) => {
const core = Deno.core;
function argsToMessage(...args) {
return args.map((arg) => JSON.stringify(arg)).join(" ");
}
globalThis.console = {
log: (...args) => {
core.print(`[out]: ${argsToMessage(...args)}\n`, false);
},
error: (...args) => {
core.print(`[err]: ${argsToMessage(...args)}\n`, true);
},
};
})(globalThis);
</code></pre></div></div>
<blockquote>
<p>Note: This <code class="language-plaintext highlighter-rouge">runtime.js</code> file is in the <code class="language-plaintext highlighter-rouge">src</code> folder.</p>
</blockquote>
<p><img src="/media/16592798868051.jpg" alt="" /></p>
<p>The <code class="language-plaintext highlighter-rouge">console.log</code> and <code class="language-plaintext highlighter-rouge">console.error</code> functions can accept multiple arguments, serialize them to JSON (so we can view non-native JS objects), and prefix each message with “log” or “error”. This is a somewhat “old-school” JavaScript file, like writing JavaScript in the browser before ES modules existed.</p>
<p>We use an <a href="https://developer.mozilla.org/en-US/docs/Glossary/IIFE">IIFE</a> to execute the code to avoid polluting the global scope. Otherwise, the <code class="language-plaintext highlighter-rouge">argsToMessage</code> helper function would be globally available in our runtime.</p>
<p>Now let’s execute this code every time we run:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>let mut js_runtime = deno_core::JsRuntime::new(deno_core::RuntimeOptions {
module_loader: Some(Rc::new(deno_core::FsModuleLoader)),
..Default::default()
});
+ js_runtime.execute_script("[runjs:runtime.js]", include_str!("./runtime.js")).unwrap();
</code></pre></div></div>
<blockquote>
<p>Note: <code class="language-plaintext highlighter-rouge">include_str!</code> reads the contents of <code class="language-plaintext highlighter-rouge">runtime.js</code> from the same directory as <code class="language-plaintext highlighter-rouge">main.rs</code> (i.e., the <code class="language-plaintext highlighter-rouge">src</code> directory).</p>
</blockquote>
<p>Finally, we can call the new console API in <code class="language-plaintext highlighter-rouge">example.js</code>:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>- Deno.core.print("Hello runjs!");
+ console.log("Hello", "runjs!");
+ console.error("Boom!");
</code></pre></div></div>
<p>Run it:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.05s
Running `target/debug/runjs`
[out]: "Hello" "runjs!"
[err]: "Boom!"
</code></pre></div></div>
<h1 id="adding-file-system-apis">Adding File System APIs</h1>
<p>First, update the <code class="language-plaintext highlighter-rouge">runtime.js</code> file:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>};
+ globalThis.runjs = {
+ readFile: (path) => {
+ return core.opAsync("op_read_file", path);
+ },
+ writeFile: (path, contents) => {
+ return core.opAsync("op_write_file", path, contents);
+ },
+ removeFile: (path) => {
+ return core.opSync("op_remove_file", path);
+ },
+ };
})(globalThis);
</code></pre></div></div>
<p>We’ve added a new global object <code class="language-plaintext highlighter-rouge">runjs</code> with three methods: <code class="language-plaintext highlighter-rouge">readFile</code>, <code class="language-plaintext highlighter-rouge">writeFile</code>, and <code class="language-plaintext highlighter-rouge">removeFile</code>. The first two are async, and the last one is synchronous.</p>
<p>You might be wondering what <code class="language-plaintext highlighter-rouge">core.opAsync</code> and <code class="language-plaintext highlighter-rouge">core.opSync</code> are. They’re mechanisms provided by <code class="language-plaintext highlighter-rouge">deno_core</code> to bind JavaScript and Rust functions. When called from JavaScript, <code class="language-plaintext highlighter-rouge">deno_core</code> will look for a Rust function with the same name marked with the <code class="language-plaintext highlighter-rouge">#[op]</code> attribute.</p>
<p>Let’s update <code class="language-plaintext highlighter-rouge">main.rs</code> to see it in action:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>+ use deno_core::op;
+ use deno_core::Extension;
use deno_core::error::AnyError;
use std::rc::Rc;
+ #[op]
+ async fn op_read_file(path: String) -> Result<String, AnyError> {
+ let contents = tokio::fs::read_to_string(path).await?;
+ Ok(contents)
+ }
+
+ #[op]
+ async fn op_write_file(path: String, contents: String) -> Result<(), AnyError> {
+ tokio::fs::write(path, contents).await?;
+ Ok(())
+ }
+
+ #[op]
+ fn op_remove_file(path: String) -> Result<(), AnyError> {
+ std::fs::remove_file(path)?;
+ Ok(())
+ }
</code></pre></div></div>
<p>We’ve defined three <code class="language-plaintext highlighter-rouge">ops</code> that JavaScript can call, but to make them available to JavaScript code, we need to register an extension with <code class="language-plaintext highlighter-rouge">JsRuntime</code>:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>async fn run_js(file_path: &str) -> Result<(), AnyError> {
let main_module = deno_core::resolve_path(file_path)?;
+ let runjs_extension = Extension::builder()
+ .ops(vec![
+ op_read_file::decl(),
+ op_write_file::decl(),
+ op_remove_file::decl(),
+ ])
+ .build();
let mut js_runtime = deno_core::JsRuntime::new(deno_core::RuntimeOptions {
module_loader: Some(Rc::new(deno_core::FsModuleLoader)),
+ extensions: vec![runjs_extension],
..Default::default()
});
</code></pre></div></div>
<p>We can configure <code class="language-plaintext highlighter-rouge">JsRuntime</code> with <code class="language-plaintext highlighter-rouge">Extensions</code> to expose Rust functions to JavaScript, and do more advanced things (like loading additional JavaScript code).</p>
<p>Update <code class="language-plaintext highlighter-rouge">example.js</code> again:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>console.log("Hello", "runjs!");
console.error("Boom!");
+
+ const path = "./log.txt";
+ try {
+ const contents = await runjs.readFile(path);
+ console.log("Read from a file", contents);
+ } catch (err) {
+ console.error("Unable to read file", path, err);
+ }
+
+ await runjs.writeFile(path, "I can write to a file.");
+ const contents = await runjs.readFile(path);
+ console.log("Read from a file", path, "contents:", contents);
+ console.log("Removing file", path);
+ runjs.removeFile(path);
+ console.log("File removed");
+
</code></pre></div></div>
<p>Run it:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cargo run
Compiling runjs v0.1.0 (/Users/ib/dev/runjs)
Finished dev [unoptimized + debuginfo] target(s) in 0.97s
Running `target/debug/runjs`
[out]: "Hello" "runjs!"
[err]: "Boom!"
[err]: "Unable to read file" "./log.txt" {"code":"ENOENT"}
[out]: "Read from a file" "./log.txt" "contents:" "I can write to a file."
[out]: "Removing file" "./log.txt"
[out]: "File removed"
</code></pre></div></div>
<p>🎉 Congratulations! Our runjs runtime now supports the file system. Notice how we implemented JavaScript calling Rust code with very little code: <code class="language-plaintext highlighter-rouge">deno_core</code> handles all the communication between JavaScript and Rust.</p>
<h1 id="summary">Summary</h1>
<p>In this brief example, we’ve implemented a Rust project that integrates a powerful JavaScript engine (V8) with an efficient event loop (tokio).</p>
<p>For the complete example code, check out denoland’s GitHub:</p>
<blockquote>
<p>https://github.com/denoland/roll-your-own-javascript-runtime</p>
</blockquote>
Sun, 31 Jul 2022 00:00:00 +0000
https://everettjf.github.io/2022/07/31/roll-your-own-javascript-runtime/
https://everettjf.github.io/2022/07/31/roll-your-own-javascript-runtime/javascriptruntimedenoV8webLLDB Breakpoint All UIPasteboard Methods<p>iOS14 added a privacy protection feature, when current App reads content other Apps copied to clipboard, will have a brief prompt. As below:
<img src="/media/15930990964673.jpg" alt="-w431" /></p>
<p>Can breakpoint all UIPasteboard methods to check all clipboard-related behaviors in App.</p>
<p>Breakpoint all UIPasteboard methods can use command below:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>breakpoint set -r '\[UIPasteboard .*\]$'
</code></pre></div></div>
<p>First breakpoint at main, then input above command in lldb terminal.</p>
<p><img src="/media/15930999653054.jpg" alt="-w728" /></p>
<p>(Figure above only screenshotted part of UIPasteboard methods)</p>
<h2 id="summary">Summary</h2>
<p>Hmm, everyone try~ Will discover besides our own calls, system also occasionally triggers UIPasteboard related calls.</p>
<p>Very interesting~</p>
Thu, 25 Jun 2020 00:00:00 +0000
https://everettjf.github.io/2020/06/25/break-on-uipasteboard/
https://everettjf.github.io/2020/06/25/break-on-uipasteboard/iOS14lldbdebuggingiOSUIPasteboardHow to List All +load Methods in App<p><code class="language-plaintext highlighter-rouge">Objective C +load</code> method is a magical and evil method.</p>
<!-- more -->
<ul>
<li>When beginners get it, will be amazed by its magic.</li>
<li>When experts get it, will be addicted unable to extricate.</li>
<li>When veterans get it, will be terrified by its evil.</li>
</ul>
<p>Most large Apps already or are trying to get rid of it. Then, how to quickly see how many +load methods in your App, see how deep the poison.</p>
<p>Assume scenario below:</p>
<p>One day you happily debugging program with Xcode,</p>
<p>Open Xcode, press F5,</p>
<p>Suddenly, you want to see how many +load methods in App?</p>
<p>Click Pause, then input</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>br s -r "\+\[.+ load\]$"
</code></pre></div></div>
<p><img src="/media/15880051383019.jpg" alt="-w352" /></p>
<p>Then input</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>br list
</code></pre></div></div>
<p><img src="/media/15880052076002.jpg" alt="-w930" /></p>
<p>Perhaps you’ll be surprised, turns out my App has so many (or few) +load methods</p>
<h2 id="principle">Principle</h2>
<p>Used lldb’s breakpoint command.</p>
<p><img src="/media/15880053337758.jpg" alt="-w576" /></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>br s -r "regex"
is
breakpoint set -r "regex"
</code></pre></div></div>
<p>Set breakpoint through regex matching symbols.</p>
<h2 id="small-question">Small Question</h2>
<p>Then think, if code in these +load methods crashes, can your crash monitoring (bugly, etc.) monitor it?</p>
<p>Of course 90% answer is: Won’t Crash.</p>
<p>Makes me think of Trump’s words: My “code” is perfect.</p>
<p>Haha :)</p>
<h2 id="summary">Summary</h2>
<p>Very interesting:)</p>
<p>Ah, I’m so inexperienced, I need to learn “Bridge-based Full Method Hook” now</p>
<p>http://satanwoo.github.io/2020/04/26/TrampolineHookOpenSource/</p>
<hr />
<p>If everyone likes, follow subscription account to encourage:</p>
<p><img src="/images/fun.png" alt="" /></p>
Tue, 28 Apr 2020 00:00:00 +0000
https://everettjf.github.io/2020/04/28/quick-list-load-method/
https://everettjf.github.io/2020/04/28/quick-list-load-method/tutoriallearningguidedevelopmenttoolsHow to Breakpoint at Function's return<p>Has a complex function with many code lines, internally has many returns, step debugging very slow, how to quickly find which line returned?</p>
<!-- more -->
<p>For example code:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>void foo() {
int i = arc4random() %100;
if (i > 30) {
if (i < 40) {
return;
}
if (i > 77) {
return;
}
if (i < 66) {
return;
}
}
switch (i) {
case 0:
return;
case 1:
return;
case 2:
return;
case 3:
return;
case 4:
return;
default:
return;
}
}
int main(int argc, const char * argv[]) {
foo();
return 0;
}
</code></pre></div></div>
<p>Assume foo is a very long complex function with many returns, how to know which line returned?</p>
<p>Can use lldb’s breakpoint</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>breakpoint set -p return
or
br set -p return
</code></pre></div></div>
<p>First add breakpoint at foo’s first line</p>
<p><img src="/media/15875739886610.jpg" alt="" /></p>
<p>After breakpoint triggers, console input <code class="language-plaintext highlighter-rouge">br set -p return</code>
<img src="/media/15875740456070.jpg" alt="" /></p>
<p>Then continue, will breakpoint at function’s return line.</p>
<p><img src="/media/15875741244090.jpg" alt="" /></p>
<p>Very interesting~</p>
<hr />
<p>If everyone likes, follow subscription account to encourage:</p>
<p><img src="/images/fun.png" alt="" /></p>
Thu, 23 Apr 2020 00:00:00 +0000
https://everettjf.github.io/2020/04/23/how-to-break-on-return/
https://everettjf.github.io/2020/04/23/how-to-break-on-return/lldbdebuggingbreakpointiOSreturnWhen Does ObjC Object in C++ Class dealloc<p>When using Objective C++, can use C++’s struct or class to store Objective C objects.</p>
<!-- more -->
<p>For example:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>struct CppStruct {
MyObject *obj;
};
</code></pre></div></div>
<p>Then suddenly think, if CppStruct destructs, will MyObject dealloc? Don’t need to think much, definitely will. But how is it done?</p>
<p>Write code to verify,</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
@interface MyObject : NSObject
@end
@implementation MyObject
- (instancetype)init {
self = [super init];
if (self) {
NSLog(@"MyObject init");
}
return self;
}
- (void)dealloc {
NSLog(@"MyObject dealloc");
}
@end
struct CppStruct {
MyObject *obj;
CppStruct() {
NSLog(@"CppStruct constructor");
}
~CppStruct() {
NSLog(@"CppStruct destructor");
}
};
CppStruct * CreateStruct() {
CppStruct * s = new CppStruct();
s->obj = [[MyObject alloc] init];
return s;
}
void FreeStruct(CppStruct *s) {
delete s;
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
CppStruct *s = CreateStruct();
FreeStruct(s);
}
return 0;
}
</code></pre></div></div>
<p>Output below</p>
<p><img src="/media/15871350384682.jpg" alt="" /></p>
<p>Can know, MyObject indeed dealloced.</p>
<p>Then, breakpoint at dealloc, see how called.</p>
<p><img src="/media/15871351008102.jpg" alt="" /></p>
<p>See figure above has two <code class="language-plaintext highlighter-rouge">~CppStruct()</code>, one called <code class="language-plaintext highlighter-rouge">objc_storeStrong</code>, objc_storeStrong further triggered MyObject’s dealloc.</p>
<p><img src="/media/15871352168452.jpg" alt="" /></p>
<p>From figure above can know, compiler must generated objc_storeStrong call code.</p>
<p><img src="/media/15871352826095.jpg" alt="" /></p>
<p>Look at Disassembly, indeed generated objc_storeStrong call code.
<img src="/media/15871353987126.jpg" alt="" /></p>
<p>Further confirmed.</p>
<p>How LLVM generates this logic, won’t search ha.</p>
<h2 id="references">References</h2>
<p>Above debugging used compilable objc runtime, GitHub has many, can search corresponding objc version:</p>
<p>https://github.com/search?q=objc+779.1
https://github.com/LGCooci/objc4_debug</p>
<h2 id="summary">Summary</h2>
<p>In future can boldly use C++ struct to store Objective C objects.</p>
<hr />
<p>Very interesting :)</p>
<hr />
<p>If everyone likes, follow subscription account to encourage:</p>
<p><img src="/images/fun.png" alt="" /></p>
Fri, 17 Apr 2020 00:00:00 +0000
https://everettjf.github.io/2020/04/17/how-cpp-delete-dealloc-objc-object/
https://everettjf.github.io/2020/04/17/how-cpp-delete-dealloc-objc-object/tutoriallearningguidedevelopmenttoolsHidden Symbol in ?WhatsApp App Name<p>Welcome everyone to watch this episode of “Approaching Science: WhatsApp Mysterious Symbol”~</p>
<!-- more -->
<h2 id="crime-scene">Crime Scene</h2>
<p>About half a year or even longer ago, when using frida-ios-dump, accidentally discovered WhatsApp app’s name a bit strange.</p>
<blockquote>
<p>frida-ios-dump is a jailbreak iOS App decryption tool (can also list iOS app list).
Address: https://github.com/AloneMonkey/frida-ios-dump</p>
</blockquote>
<p>Carefully look at WhatsApp in figure below:
<img src="/media/15855012198617.jpg" alt="" /></p>
<p>WhatsApp’s name left alignment different from other Apps.</p>
<p>… How many times hurriedly passed by … How many times treated as non-existent …</p>
<p>Until today I finally got curious once, want to see why not aligned here.</p>
<h2 id="start">Start</h2>
<p>Smash, try smashing.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>python dump.py net.whatsapp.WhatsApp
</code></pre></div></div>
<p>After smashing, as below. Appears a question mark. <code class="language-plaintext highlighter-rouge">?WhatsApp.ipa</code>, what is question mark.</p>
<p><img src="/media/15855017374127.jpg" alt="" /></p>
<p>Prepare <code class="language-plaintext highlighter-rouge">mv</code> to other folder to research, at this moment…</p>
<p><img src="/media/15855018704881.jpg" alt="" /></p>
<p>Mysterious character <code class="language-plaintext highlighter-rouge">\342\200\216</code> appeared, just curious…</p>
<h2 id="search">Search</h2>
<p>Casually searched … really found :)</p>
<p><img src="/media/15855020124999.jpg" alt="" /></p>
<blockquote>
<p>https://graphemica.com/200E</p>
</blockquote>
<p>Open to see, really has meaning~ <code class="language-plaintext highlighter-rouge">left-to-right mark</code></p>
<p><img src="/media/15855021218820.jpg" alt="" /></p>
<h2 id="truth-revealed">Truth Revealed</h2>
<p>Wikipedia also has explanation</p>
<blockquote>
<p>The left-to-right mark (LRM) is a control character (an invisible formatting character) used in computerized typesetting (including word processing in a program like Microsoft Word) of text that contains a mixture of left-to-right text (such as English or Russian) and right-to-left text (such as Arabic, Persian or Hebrew). It is used to set the way adjacent characters are grouped with respect to text direction.</p>
</blockquote>
<blockquote>
<p>https://en.wikipedia.org/wiki/Left-to-right_mark</p>
</blockquote>
<p>Paste translation:</p>
<blockquote>
<p>Left-to-right mark (Left-to-right mark,LRM) is a control character, or invisible typesetting symbol. Used in computer bidirectional text typesetting.</p>
</blockquote>
<p>I say in plain language. Left-to-right mark is an invisible symbol, used to include <code class="language-plaintext highlighter-rouge">left-to-right</code> text in <code class="language-plaintext highlighter-rouge">right-to-left</code> typesetting languages (for example Arabic).</p>
<p>Example in figure below is clearer: after using LRM symbol, Arabic (right-to-left) contains displayed <code class="language-plaintext highlighter-rouge">C++</code> (left-to-right).</p>
<p><img src="/media/15855024011241.jpg" alt="" /></p>
<h2 id="extended-reading">Extended Reading</h2>
<p>Has <code class="language-plaintext highlighter-rouge">Left-to-right mark</code>, also has <code class="language-plaintext highlighter-rouge">Right-to-left mark</code>.</p>
<blockquote>
<p>https://en.wikipedia.org/wiki/Right-to-left_mark</p>
</blockquote>
<h2 id="further">Further</h2>
<p>Take WhatsApp’s <code class="language-plaintext highlighter-rouge">Info.plist</code> file out to look, seems nothing special.</p>
<p><img src="/media/15855026225476.jpg" alt="" /></p>
<p>Look with binary editor.</p>
<p><img src="/media/15855027112567.jpg" alt="" /></p>
<p><code class="language-plaintext highlighter-rouge">\342\200\216</code> is <code class="language-plaintext highlighter-rouge">0xE2 0x80 0x8E (e2808e)</code></p>
<p><img src="/media/15855027969727.jpg" alt="" /></p>
<p>This way in code getting <code class="language-plaintext highlighter-rouge">CFBundleDisplayName</code> and concatenating with other localized languages, can ensure WhatsApp’s order from left to right.</p>
<hr />
<p>Very interesting :)</p>
<p>If everyone likes, follow subscription account to encourage:</p>
<p><img src="/images/fun.png" alt="" /></p>
Mon, 30 Mar 2020 00:00:00 +0000
https://everettjf.github.io/2020/03/30/left-to-right-mark/
https://everettjf.github.io/2020/03/30/left-to-right-mark/assemblysymbolobfuscationClow-levelRunning Android on iPhone<p>First time in history to make Android system run on iPhone. Currently (March 6, 2020) version only supports iPhone7/7 Plus. (iOS system version no requirement)</p>
<p>Project Sandcastle: Android for the iPhone
Project address: https://projectsandcastle.org/</p>
<p>Happened to have an iPhone7, experienced it. Steps simply summarized, share with everyone. Ideal steps below, but due to macOS security mechanisms, steps 2 and 3 not so smooth and pleasant.</p>
<ol>
<li>Use checkra1n to jailbreak</li>
<li>Run start_mac.sh</li>
<li>Run setup_mac.sh</li>
</ol>
<!-- more -->
<h2 id="jailbreak">Jailbreak</h2>
<p>Download https://checkra.in/ follow steps to jailbreak. (iPhone connect to Mac using USB.)</p>
<p><img src="/media/15834927122755.jpg" alt="-w480" /></p>
<p><img src="/media/15834927589010.jpg" alt="-w480" />
<img src="/media/15834927957183.jpg" alt="-w246" /></p>
<p><img src="/media/15834928119092.jpg" alt="-w480" /></p>
<p>After jailbreak, enter iOS.</p>
<h2 id="download-android-build">Download Android Build</h2>
<p>Download Android Build at https://projectsandcastle.org/status.</p>
<p><img src="/media/15835109011989.jpg" alt="" /></p>
<p>Extract downloaded file.
<img src="/media/15835110829022.jpg" alt="-w234" /></p>
<h2 id="setup_macsh">setup_mac.sh</h2>
<p>iPhone connect to Mac using USB. Ideally, execute <code class="language-plaintext highlighter-rouge">./setup_mac.sh</code> on macOS. But my execution not smooth. Built-in iproxy and two dynamic libraries’ signatures first execution still need trust. But actually functionality is iproxy’s functionality, so below manually execute steps in setup_mac.sh.</p>
<p>Can first ssh connect to iOS, ensure manual connection succeeds. Then reference steps below.</p>
<p>(1)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>iproxy 2222 44
</code></pre></div></div>
<p>(2)
Copy isetup to iOS’s /tmp/setup.sh</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>scp -P2222 -o StrictHostKeyChecking=no isetup root@localhost:/tmp/setup.sh
</code></pre></div></div>
<p>(3)
Two methods:</p>
<p>One, FQ.
Or, modify network connection test address in setup.sh, for example specifically test if internet works baidu (looks like foreigners also correspondingly use google to test ha)</p>
<p><img src="/media/15835114471189.jpg" alt="-w627" /></p>
<p>Recommend using FQ method, because this script will download 470MB file, my home Wi-Fi without FQ, downloading this file very slow, after FQ seems few minutes done.</p>
<p><img src="/media/15835117141314.jpg" alt="" /></p>
<p>(4) Execute /tmp/setup.sh</p>
<p><img src="/media/15835063026640.jpg" alt="-w462" /></p>
<h2 id="enter-dfu-mode">Enter DFU Mode</h2>
<ol>
<li>iPhone power off.</li>
<li>Simultaneously press volume down + power button, 10 seconds (strictly 10 seconds).</li>
<li>Release power button, continue holding volume down.</li>
<li>At this time phone screen will stay black, indicates entered DFU mode.</li>
</ol>
<p>Then in DFU mode, execute <code class="language-plaintext highlighter-rouge">./start_mac.sh</code>.</p>
<p>Ideally, after execution completes done. But reality cruel, I saw popup below (ten thousand alpacas running in heart, afraid phone broken…), of course click Cancel.</p>
<p><img src="/media/15835119951796.jpg" alt="-w420" /></p>
<p>Enter System Preferences -> Security & Privacy -> General, click Allow Anyway.</p>
<p><img src="/media/15835120714520.jpg" alt="-w608" /></p>
<p>At this time still not OK, to prevent just in case, first command then execute once</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./load-linux.mac
</code></pre></div></div>
<p>Then can click Open.</p>
<p><img src="/media/15835077352704.jpg" alt="-w469" /></p>
<p>But at this time re-executing <code class="language-plaintext highlighter-rouge">start_mac.sh</code> seems can’t “resume continue”, heart X#@%$$. “Smart” me looked at start_mac.sh’s code, looks can execute this step.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./load-linux.mac Android.lzma dtbpack
</code></pre></div></div>
<p>Finally succeeded, Android system started on iPhone.</p>
<h2 id="screenshots">Screenshots</h2>
<p><img src="/media/15835124510615.jpg" alt="" /></p>
<p><img src="/media/15835124757092.jpg" alt="" /></p>
<h2 id="summary">Summary</h2>
<ol>
<li>Runs quite laggy.</li>
<li>Restart returns to iOS.</li>
</ol>
<p>Still quite interesting, video can search everettjf on Douyin to view.</p>
<hr />
<p>If everyone likes, follow subscription account to encourage:</p>
<p><img src="/images/fun.png" alt="" /></p>
Fri, 06 Mar 2020 00:00:00 +0000
https://everettjf.github.io/2020/03/06/android-on-iphone/
https://everettjf.github.io/2020/03/06/android-on-iphone/iOSdevelopmentmobile