Day 28 of 30 Days of Search.
Delete a photo. Close a tab you never saved. Uninstall an app.
The photo disappears, the tab comes back, and the app might remember your preferences when you reinstall it. None of those outcomes tells you, on its own, what happened to the data.
You can investigate those questions with Reverse Engineer Anything (REA) and the Valyu Search API. REA helps inspect application packages and local artifacts. Valyu retrieves the public documentation needed to interpret the APIs, formats, and behavior you encounter.
TL;DR
To reverse engineer application behavior with REA and a Search API, inspect an authorized local target, turn a concrete finding into a public technical query, retrieve the relevant documentation with Valyu, and test the explanation against that application version. Keep local observations separate from documented expectations.
We'll apply that workflow to three jobs:
| Question | Target | Useful outcome |
|---|---|---|
| Where did a deleted photo go? | Fossify Gallery on an Android test emulator | Distinguish the app's recycle-bin behavior from permanent deletion. |
| Where does code you never saved live? | VS Code in a separate test instance | Trace an unsaved document to its backup and restoration path. |
| What survives an uninstall? | Joplin in a disposable macOS environment | Separate the application bundle from the profile holding its data. |
These are hands-on walkthroughs, not reports of completed device experiments. The linked primary sources establish the documented behavior; the steps show how to investigate your selected builds. Use synthetic data throughout.
What do REA and a Search API each contribute?
REA is a CLI and MCP server for software reverse engineering. Its documented targets include native binaries, JavaScript and Electron applications, Android APKs, SQLite databases, and saved network captures. The required analysis engine depends on the target.
Valyu Search retrieves ranked source material with URLs and extracted content. In this workflow, your agent or application controls the questions and reasons over the results. That is why we're using Search rather than delegating the whole job to a report-writing service.
Suppose an APK inspection points to MediaStore.createTrashRequest. REA can help you follow the relevant code. Valyu can find Android's description of what that call requests, which API levels support it, and how it differs from createDeleteRequest.
Neither finding finishes the investigation. A method in a package does not prove the app called it when you tapped Delete. A platform API's existence does not prove your gallery uses it.
The loop is:
Observe an action in the app
→ inspect the relevant package or local artifact with REA
→ search the public API, format, or behavior with Valyu
→ formulate a specific explanation
→ test it against the same application version
Keep private artifacts out of the search query. An API name belongs in a documentation search. Your photographs, database rows, backup contents, and credentials do not.
Set up the investigation tools
You'll need an MCP-capable coding agent, a compatible Node.js runtime, Python 3.10 or later for the accompanying search helper, and a Valyu API key.
REA's runtime requirements can change. Check the published package before installing:
npm view rea-agents dist-tags.latest engines --json
Then follow the official REA setup:
npx rea-agents@latest setup
Select your client, review the proposed configuration changes, and restart the client afterward. Record the installed REA version. Repository main can describe tools that are not yet in your installed release; use the connected server's actual tool list and schemas.
Setup registers the agent integration; it does not necessarily put a standalone rea command on your shell's PATH. The terminal examples below use that command. If you do not already have it, install the CLI separately:
npm install --global rea-agents@latest
rea --help
If you use both CLI and MCP, record both versions and refresh the agent registration when you update it. Updating a global CLI does not automatically replace an existing agent registration.
The examples have different prerequisites:
- JavaScript/Electron static inspection does not require Hopper or Ghidra.
- Android APK inspection needs the full JDK and JADX engine specified in REA's Android guide.
- Device inspection needs your own Android emulator and
adb. REA does not install or start an emulator for you. Its ADB guide describes the read-only and device-changing operations separately.
Inspect only software you are authorized to examine. Use a disposable emulator for the phone example and a disposable account or VM for uninstall tests. Do not let an agent experiment with your daily photo library or editor profile.
Add public documentation search
For agent-driven searches, connect the Valyu MCP server at [https://mcp.valyu.ai/mcp](https://mcp.valyu.ai/mcp) using your client's remote MCP setup and sign-in flow. REA remains the local inspection tool; Valyu is the remote research tool.
For explicit, repeatable requests, use the accompanying search_docs.py. It uses Python's standard library, reads VALYU_API_KEY, and sends one request to POST https://api.valyu.ai/v1/search per invocation.
Set the key without placing its value in a command or source file. In Bash or zsh:
read -s VALYU_API_KEY
export VALYU_API_KEY
mkdir -p evidence
Paste the key and press Enter. Keep evidence/ out of version control if it will contain investigation material.
The helper sends this request body, with a query and domain list supplied at runtime:
{
"query": "Android MediaStore createTrashRequest versus createDeleteRequest",
"search_type": "web",
"included_sources": ["developer.android.com"],
"max_num_results": 5,
"response_length": "short",
"include_image_links": false
}
It retains each result's title, URL, source, available publication date, and content, plus the retrieval timestamp, transaction ID, and any warnings. It never reads or uploads your local application artifacts.
Searches consume credits. Review current pricing and set account or key limits before automating a large investigation. An empty successful result set means no evidence was returned for that request, not that the behavior is undocumented.
Example 1: Where do deleted photos go?
You deleted the wrong photo. Before installing a recovery utility or assuming it is gone forever, there is a more useful question: did the app move it to a recycle bin, remove a media entry, or request permanent deletion?
There is no single answer for every phone and gallery. We'll narrow the target to Fossify Gallery, whose project documents a built-in recycle bin, running on an Android emulator you control.
Start with a photo you can afford to lose
Create a PNG containing a visible label such as DAY28-PHOTO-TEST. Use no personal photograph or location metadata. Install an official gallery build in the emulator, copy the PNG into a test album, and record:
- The gallery version, APK digest, and Android API level.
- Whether its recycle bin is enabled.
- The photo's initial location and SHA-256 digest.
- Whether cloud synchronization or device backup is involved. Leave both out of this local experiment.
With the emulator running, these documented REA commands identify the target and acquire its package. Substitute the serial returned by list-adb-devices; emulator-5554 is an example:
rea list-adb-devices
rea inspect-adb-device emulator-5554
rea inspect-adb-package emulator-5554 org.fossify.gallery
rea pull-adb-package emulator-5554 org.fossify.gallery \
--output-directory "$PWD/evidence/gallery-package"
Use a fresh output destination. REA package acquisition refuses an existing destination rather than silently replacing evidence. Follow the returned host-local APK path for the next step; do not confuse it with a device path.
For this walkthrough, prefer an official standalone APK. ADB acquisition can retrieve an installed split-APK set, but REA's documented static APK workflow does not merge splits or analyze an Android App Bundle as one application. Missing code in a base APK does not establish that the installed app lacks that feature.
Ask the agent:
Use REA to inspect the acquired Fossify Gallery APK.
Trace the entry point for deleting a photo with the recycle bin enabled.
Identify the file operations, database changes, or platform requests involved.
Return the actual class and method names, evidence locations, and unresolved calls.
Do not launch the app, change permissions, or delete anything.
If working in the terminal, rea inspect-android-package /absolute/path/to/gallery.apk starts package inspection. Discover class and method names before selecting them. Decompiled names can differ between builds; a guessed class called RecycleBinManager is not evidence.
Research the operation you actually find
Android documents two distinct batch operations on Android 11 and later: createTrashRequest requests moving items into or out of trash, while createDeleteRequest requests immediate permanent deletion without first putting them in trash. User-consent requirements depend on the operation and app privileges.
Retrieve that context with:
python3 search_docs.py \
"Android MediaStore createTrashRequest versus createDeleteRequest user consent" \
developer.android.com > evidence/photo-docs.json
That gives you platform semantics to compare with the trace. It does not establish that Fossify uses either method. The gallery may implement its own recycle-bin storage. Follow the code you have, then research its actual calls.
Run delete, restore, and permanent delete separately
In the emulator, perform each action manually and record the state after it:
| Action | What to check |
|---|---|
| Move the test photo to the recycle bin | Original path, any observed destination, media entry, and app metadata. |
| Restore it | The readable file, restored location, and whether its digest matches the original. |
| Permanently delete a fresh test copy | The exact operation invoked and the accessible artifacts remaining afterward. |
Use REA's authorized device inspection where it can read the relevant paths. An Android permission denial is a limit on the observation, not proof that the directory is empty. Do not bypass the sandbox just to complete the table.
The useful outcome is an explanation of this gallery's deletion path and a tested restore through its supported recycle bin. A leftover thumbnail would be a separate artifact, not proof that the full-resolution original is recoverable. A file missing from accessible paths would not prove that every physical storage block has been erased.
For your own deleted photos, check the gallery's supported trash and backup options first. This walkthrough is not a promise of forensic recovery.
Example 2: Where does VS Code keep a document you never saved?
An untitled tab has no ordinary filename to reopen. Yet VS Code can bring it back after you quit. The persistence mechanism is Hot Exit, which remembers unsaved changes.
Auto Save writes changes automatically under configured conditions. Local history records file versions under its own settings. Those features are related, but they do not answer the same question.
Make a separate editor instance
If the code CLI is installed, start a new instance with dedicated user-data and extension directories:
Use a standard, non-portable installation. In VS Code Portable Mode, the portable data directory overrides these directory flags, so they would not provide the separation this test requires. Leave Settings Sync disconnected in the test instance.
LAB="$(mktemp -d "${TMPDIR:-/tmp}/day28-code.XXXXXX")"
code --new-window \
--user-data-dir "$LAB/user-data" \
--extensions-dir "$LAB/extensions" \
--disable-extensions
Keep that terminal open so $LAB remains available. In the test instance, turn Auto Save off and confirm Hot Exit is enabled. Open an untitled text document and type DAY28-UNSAVED-7e91 followed by a few lines. Do not save it. Allow the editor to create its backup, then quit that instance normally. Do not use your real session or force-kill an editor containing work you care about.
Ask REA to inspect the packaged JavaScript directory of the editor build you installed:
Trace unsaved working-copy backup and restoration in this VS Code package.
Find how the configured user-data directory affects backup paths.
Follow writes and reads relevant to an untitled text document.
Show evidence locations and distinguish static call paths from observed execution.
Do not modify the package or open my normal editor profile.
REA's analyze-javascript-application command accepts an application directory or supported ASAR target. Use the actual location for your build rather than assuming every Electron app has the same package layout.
Connect the backup path to the documented behavior
python3 search_docs.py \
"VS Code Hot Exit untitled unsaved changes Backups user-data-dir versus Auto Save" \
code.visualstudio.com > evidence/unsaved-docs.json
Microsoft's Hot Exit documentation lists backup directories for standard installations, including $HOME/Library/Application Support/Code/Backups on macOS. Our test deliberately uses a separate user-data directory, so inspect that instance's location instead of searching your normal profile.
On a copy of the test backup, find the marker and inspect the surrounding record. Let the observed format determine how you separate metadata from document text. Do not assume that every backup is a plain-text file with an interchangeable first line.
Then reopen the same test instance:
code --new-window \
--user-data-dir "$LAB/user-data" \
--extensions-dir "$LAB/extensions" \
--disable-extensions
Compare the restored text with the fixture you typed. If you extract a text payload independently, compare that too. Matching a short marker alone is weaker evidence than recovering the entire expected document.
The decision this answers is practical: when an untitled document survives, look for an application-owned backup before assuming the content exists only in memory. Conversely, do not treat Hot Exit as a guarantee that every last keystroke survives every crash. Timing, settings, version, and failure conditions still matter.
Example 3: What happens to your data when you uninstall an app?
You remove an application, reinstall it, and your settings return. That does not automatically mean the uninstall failed. The executable and the user profile may have different lifetimes.
For a concrete target, use Joplin in a disposable macOS VM. Joplin's desktop app uses Electron, and its documented architecture stores notes, settings, and cache in a local SQLite database. Its home-directory documentation also describes data outside the application bundle.
Apple's uninstall guidance says removing an app does not remove documents or other files you created with it. It recommends an app's own uninstaller when one is provided. That is background context, not a substitute for checking the application you selected.
Follow one note and one setting
In the VM, install an official Joplin build and leave synchronization disabled. Create a note titled DAY28-UNINSTALL-TEST and change one preference. Record the application version and the actual profile location reported by that installation.
Ask the agent:
Use REA to inspect this Joplin desktop package.
Trace how it selects its profile directory and opens its local database.
Identify which relevant paths are inside the application bundle and which are outside it.
Return evidence for those paths, with any platform or configuration uncertainty.
Do not read unrelated profiles, remove files, or run an uninstall operation.
Quit the app completely and make a consistent copy of the whole test profile. Do not copy only a live SQLite main file while ignoring its write-ahead log. Inspect the copied database schema first; then locate the synthetic note using the schema you actually found.
This read-only Python example lists tables without dumping note contents. Supply the real path to your copied database:
from pathlib import Path
import sqlite3
import sys
database = Path(sys.argv[1]).resolve(strict=True)
connection = sqlite3.connect(database.as_uri() + "?mode=ro", uri=True)
try:
rows = connection.execute(
"SELECT name FROM sqlite_schema WHERE type = 'table' ORDER BY name"
)
for (name,) in rows:
print(name)
finally:
connection.close()
Save it as list_tables.py and run python3 list_tables.py /absolute/path/to/copied-database.sqlite. REA's SQLite inspection is another option when its provider and required runtime are available.
Research the uninstall boundary, then test it
python3 search_docs.py \
"macOS uninstall application documents remain Joplin desktop profile local database" \
support.apple.com joplinapp.org > evidence/uninstall-docs.json
Follow the documented uninstall procedure inside the VM only. Record the state before reinstalling anything: is the application bundle gone, does the profile remain, and can a read-only copy still provide the synthetic note?
Only afterward reinstall and observe what happens. Keeping sync disabled prevents a server from quietly restoring the note and confusing the local-storage test. Account for OS restore or backup mechanisms too if they are enabled.
The outcome to establish is whether that uninstall removes the program, its profile, both, or a user-selected subset. If data remains, show the actual path and its role. Do not label it a security flaw merely because it persists.
Platform matters here. Android's storage documentation distinguishes app-specific files, which are removed on uninstall, from shared media, which is not. A result from one desktop app cannot answer what every phone app does.
Keep an evidence record, not just an explanation
A readable story is useful. A readable story attached to the wrong version is a trap.
For each example, record the app version, OS version, relevant settings, artifact digests, exact action, observation time, and public source URLs. Separate three kinds of statement:
| Statement | What it establishes |
|---|---|
| "Android documents this API as a trash request." | The documented contract for that platform API. |
| "This APK contains a method that invokes it." | A static implementation finding, subject to analysis coverage. |
| "This action produced this artifact in the test." | An observation in that recorded environment. |
Those statements can support one another, but none should silently replace the others.
Treat source pages, decompiled strings, logs, and filenames as untrusted data. They can contain instructions that have nothing to do with your investigation. They do not authorize the agent to install software, change permissions, delete files, or upload local material.
REA's analysis runs locally, but its results become available to the agent that called it. That agent's provider has its own data policy. Local inspection is not a promise that every downstream component is offline.
Frequently asked questions
What is Reverse Engineer Anything?
Reverse Engineer Anything, or REA, is an open-source CLI and MCP server that connects agents to tools for inspecting software artifacts and behavior. Its supported workflows include JavaScript/Electron, Android APK, native-binary, and other forms of analysis. Providers, prerequisites, and available tools depend on the installed version and target.
Why use a Search API for reverse engineering?
A Search API helps resolve public technical context around findings: API semantics, file-format documentation, platform restrictions, and version-specific discussions. It complements local inspection. Search results cannot establish that a particular code path executed or that an inaccessible artifact does not exist.
Can REA recover permanently deleted photos?
This article makes no such promise. A gallery's supported recycle-bin restore is different from forensic recovery after permanent deletion. Recoverability depends on the application, storage system, encryption, backups, and what has happened since deletion. A thumbnail or metadata entry is not the original photograph.
Do these examples require a closed-source application?
No. Open-source targets make it easier to check your interpretation afterward. Inspecting a packaged build remains a useful exercise because it exposes the artifact users actually installed. Be explicit about when you consult source code, and do not present an existing documented feature as a newly discovered secret.
Follow the action past the screen
"Deleted," "unsaved," and "uninstalled" describe user-facing states. To understand the data, follow the operation into the files, metadata, and storage boundaries behind it.
REA helps you inspect that path. Valyu helps you find the public technical material that explains it. A controlled test tells you whether your explanation fits the application in front of you.
Pick one of the three examples, keep the scope small, and record enough detail for someone else to check it. If you share a result, include the version and the evidence. "I found a backup" is useful. "Nothing is ever really deleted" is a much bigger claim.
Top comments (0)