mirror of
https://github.com/morluto/rea
synced 2026-10-25 22:08:11 -04:00
feat(website): add an Aegis APK code-generation showcase
This commit is contained in:
+17
-1
@@ -4,7 +4,7 @@
|
||||
>
|
||||
> — N0zoM1z0
|
||||
|
||||
An English static website with explanatory figures, worked guides and DX-Ball, Notion, TH04 and CTF investigations.
|
||||
An English static website with explanatory figures, worked guides and Aegis, DX-Ball, Notion, TH04 and CTF investigations.
|
||||
The public files are in `website/public/`. The site uses HTML, CSS and small
|
||||
scripts for copying code, following code comparisons and playing the dinosaur
|
||||
speed reconstruction. Python
|
||||
@@ -30,6 +30,7 @@ Open <http://127.0.0.1:4173/>. Refresh the browser after editing a file.
|
||||
- `public/examples/dino-lab/index.html`: adjustable-speed mini-game, recovered rule, original-game check and browser analysis steps.
|
||||
- `public/first-investigation/index.html`: a guided Notes export investigation, from setup to a checked CSV prediction.
|
||||
- `public/showcase/index.html`: the case-study index.
|
||||
- `public/showcase/aegis/index.html`: Aegis's Android login-code calculation, with an adjustable clock and reference checks.
|
||||
- `public/showcase/dx-ball/index.html`: sound-pan investigation and project status.
|
||||
- `public/showcase/notion/index.html`: Notion's Electron clipboard bridge and rich clipboard format.
|
||||
- `public/showcase/th04/index.html`: TH04's 16-bit DOS bullet-angle calculation and compiler checks.
|
||||
@@ -158,6 +159,21 @@ the website.
|
||||
[evidence/notion-clipboard.md](evidence/notion-clipboard.md) records the REA
|
||||
package version, selected findings, source anchors and module-probe scope.
|
||||
|
||||
## Aegis Android case study
|
||||
|
||||
The Aegis case inspects the official 3.4.3 APK through REA 6.1.0. It follows
|
||||
the default login-code calculation from class search and display references to
|
||||
the time block, keyed hash and six-digit output. Selected decompiled Java is
|
||||
paired with a readable summary; the original app and excerpts are credited to
|
||||
Aegis under its GPL-3.0 license.
|
||||
|
||||
`public/assets/aegis-otp.js` is a new teaching reconstruction using the fixed,
|
||||
public RFC 6238 test key. `aegis-demo.js` connects it to the clock slider and
|
||||
reference-check button. The diagram remains readable and controls stay disabled
|
||||
without JavaScript. Keep the demo, selected code and
|
||||
[evidence/aegis-login-code.md](evidence/aegis-login-code.md) aligned. The APK and
|
||||
analysis-provider JAR remain official external downloads.
|
||||
|
||||
## TH04 case study
|
||||
|
||||
The TH04 case inspects the original PC-98 DOS angle helper through REA 4.1.0.
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
# Aegis Android login-code evidence
|
||||
|
||||
Inspection on 9 October 2026, using the published REA 6.1.0 CLI with the
|
||||
caller-supplied `jadx-headless-mcp` 0.7.1 provider and OpenJDK 21.0.12.1 on
|
||||
Linux x64. The case follows the default time-based code in
|
||||
[Aegis Authenticator](https://github.com/beemdevelopment/Aegis).
|
||||
|
||||
## Target
|
||||
|
||||
- [Official release](https://github.com/beemdevelopment/Aegis/releases/tag/v3.4.3): v3.4.3, published 6 September 2026.
|
||||
- Artifact: `aegis-v3.4.3.apk`, 6,881,897 bytes.
|
||||
- SHA-256: `fa091c91912c0d56ec3553394fac4158f9a9d178e93bcbb35419601d788cb528`.
|
||||
- Package: `com.beemdevelopment.aegis`, version code 82.
|
||||
- Reported inventory: 3,077 classes and 1,106 resources.
|
||||
- Matching source commit: `d6f4e5925a97e4e91593f1542085eae03432a759`.
|
||||
- Android provider JAR SHA-256: `6e5eacf500b64292bfb73c49797c1958f6ee44646e43e868039ae7feb573ff75`.
|
||||
- Provider source revision: `5844800a486d2248fa949b74c9896285f5b54de2`.
|
||||
|
||||
The artifact's SHA-256 matches the official GitHub release asset digest and every
|
||||
saved REA record. The APK and provider JAR were downloaded into temporary storage.
|
||||
They are linked from their official releases; neither file is a website asset.
|
||||
|
||||
The CLI used `REA_JADX_MCP_JAR` for its own process. The connected MCP server's
|
||||
Android provider was initially unavailable; it was not reconfigured. The page
|
||||
expresses the inspected selections as REA tool requests, using the same operation
|
||||
parameters as the successful CLI calls. Input paths and result package prefixes
|
||||
are shortened for display, as noted beside those blocks.
|
||||
|
||||
## REA findings
|
||||
|
||||
Twenty REA operations completed successfully against this artifact. These are the
|
||||
records used for the page's main findings:
|
||||
|
||||
| Operation | Finding | Evidence ID |
|
||||
| -------------------------- | -------------------------------------------------------- | --------------------------------------------------------------------- |
|
||||
| `inspect_android_method` | Display calls the timestamp overload for TotpInfo. | `ev_c4b51611c987a398359f526dc64866d97a99b146d0ec9177bc1d583a55d64bdc` |
|
||||
| `trace_android_references` | TotpInfo is one of the three incoming generator callers. | `ev_6b5457705a67bd4952f7e17630bcf948538424fae5bc2951c08e921af7448d58` |
|
||||
| `inspect_android_method` | Eight-byte big-endian counter, account key and HMAC. | `ev_cad4c03faf5b07347cba699d4f8f643c69e5a8f0c85f622fc8cbebe3f834f228` |
|
||||
| `inspect_android_method` | Hash-byte selection produces a 31-bit integer. | `ev_5797488db16e72a4e9ad559a8f07e355adc1f73b9eb50566cfb46d47d1b6a883` |
|
||||
| `inspect_android_method` | Algorithm name is prefixed with Hmac. | `ev_bffbfa3924c79823168df7daa01e8a3f62c4914d3fb4b54e5d4e60d21e75110f` |
|
||||
| `trace_android_references` | Display and copy callers of the base method. | `ev_d90e3ed81b0bb6815826e4edf312eadec91b9d20ff06aaff61d38a191403676b` |
|
||||
| `inspect_android_method` | Default SHA1 algorithm and six digits. | `ev_64294487704fa2a9877938017c95163e41c399ba958ea43c5b365118403ae0fe` |
|
||||
| `inspect_android_method` | Decimal remainder and leading-zero padding. | `ev_5d0906d19ea9281fed36309794fd5697b54cac3abfbd17e2f78665e758e0eb60` |
|
||||
| `inspect_android_method` | Class discriminator 0 selects the OTP formatting branch. | `ev_f0a82295bf6124055b7a12a21533950644267e8e8340038bca9c32db57d8d71f` |
|
||||
| `inspect_android_package` | Package identity; 3,077 classes. | `ev_de07111c281cd76c4f2304f42448b06ef3199268815515d59caa02ea2480eb67` |
|
||||
| `inspect_android_class` | Both getOtp overloads and their selection indices. | `ev_870577d702741f3023494c1bcb6567381a672a7132a60fd35ea2dd21ab9804c8` |
|
||||
| `search_android_classes` | Three matches for the case-sensitive query Totp. | `ev_deeb75a09990e253881d0dc1932097abe00f94447d29a64c782fb48c42e9f492` |
|
||||
| `inspect_android_method` | Current clock in milliseconds is converted to seconds. | `ev_ff4d8be5b4797e6f118d37ed55a2f65c9ceb8df39e8058d2cf36cd5561dc4bfd` |
|
||||
| `inspect_android_method` | Default period: 30 seconds. | `ev_67af69cd39faceec616a9b1b48b03a5ea71b9c94ff2d1263a0a0063029cc1104` |
|
||||
| `inspect_android_method` | Time is floored into a block before generation. | `ev_f282f536e5690e3e2253903bd979687687cfa5a9a4480758b4cd261da145caaf` |
|
||||
|
||||
All selected methods returned complete Java representations without a fallback.
|
||||
Signatures are provider display signatures; exact DEX descriptors, source-line
|
||||
locations and instruction offsets are not available from these results.
|
||||
Reference lists are static incoming references, with complete coverage of the
|
||||
engine's reported set; reflection and dynamic loading remain unverified.
|
||||
|
||||
## Interpretation
|
||||
|
||||
`TotpInfo.getOtp()` obtains Unix time in seconds. Its timestamp overload uses
|
||||
`floor(seconds / period)` as the generator's counter. The default constructor
|
||||
sets the period to 30; the base constructor sets SHA1 and six digits.
|
||||
These are defaults, not settings imposed on every imported account.
|
||||
|
||||
`getAlgorithm()` constructs `HmacSHA1` for that default. The generator encodes the
|
||||
counter as eight big-endian bytes, calculates the keyed hash, uses the low four
|
||||
bits of the final hash byte as an offset, and selects a positive 31-bit integer.
|
||||
The `OTP.toString()` branch for discriminator 0 reduces it modulo the requested
|
||||
power of ten and prepends zeroes. The inspected generator passes discriminator 0
|
||||
into the constructor, connecting that branch to the generated code.
|
||||
|
||||
The release exposes `generateOTP` and `getHash` under `kotlin.ExceptionsKt`.
|
||||
Original-source naming alone would not identify that class in this APK.
|
||||
The call returned from `TotpInfo.getOtp(long)` supplies the helper name; REA's
|
||||
method inspection and reference tracing establish its calculation and callers.
|
||||
|
||||
The base `OtpInfo.getOtp` reference list includes `EntryHolder.getOtp` and
|
||||
`MainActivity.copyEntryCode`. Inspecting `EntryHolder.getOtp(int)` then shows that
|
||||
the display calls the timestamp overload for a `TotpInfo` account, with an
|
||||
optional period offset. The page uses the unshifted code calculation.
|
||||
|
||||
## Reconstruction checks
|
||||
|
||||
A temporary JVM harness assembled six method bodies directly from saved REA
|
||||
results: the timestamp method, algorithm getter, hash method, generator, output
|
||||
constructor and output formatter. Imports, enclosing classes, fields, exception
|
||||
type and test driver were supplied for the harness. The original APK was not run.
|
||||
|
||||
An independently authored Python calculation agreed with those Java methods on
|
||||
133 inputs. The website's separately authored WebCrypto implementation then
|
||||
agreed with all 133 recorded Java outputs.
|
||||
|
||||
The cases include:
|
||||
|
||||
- All six [RFC 6238 SHA-1 reference vectors](https://www.rfc-editor.org/rfc/rfc6238.html#appendix-B) at eight digits, plus the corresponding six-digit remainders.
|
||||
- Every integer second from 0 through 120, checking four complete 30-second blocks and four boundary samples.
|
||||
- A leading-zero result at Unix time 1,111,111,109: `081804`.
|
||||
|
||||
The fixed key is the public ASCII test string `12345678901234567890`.
|
||||
At 30 and 59 seconds the result is `287082`; at 60 seconds it is `359152`.
|
||||
The diagram labels these as example clock inputs. A code is recomputed for each
|
||||
block; the checked examples change at their boundaries. Adjacent codes need not
|
||||
be universally distinct.
|
||||
|
||||
The page's “Run reference checks” button tests the browser calculation against
|
||||
all six reference inputs at both digit lengths. Slider updates use a revision
|
||||
number so an earlier asynchronous calculation cannot overwrite a later input.
|
||||
The reference JSON contains public test data, not a captured account key.
|
||||
|
||||
## Source comparison and attribution
|
||||
|
||||
After obtaining the calculation through REA, selected files from the matching
|
||||
release source were read for corroboration:
|
||||
|
||||
- [HOTP.java](https://github.com/beemdevelopment/Aegis/blob/d6f4e5925a97e4e91593f1542085eae03432a759/app/src/main/java/com/beemdevelopment/aegis/crypto/otp/HOTP.java): counter encoding, HMAC and byte selection.
|
||||
- [TOTP.java](https://github.com/beemdevelopment/Aegis/blob/d6f4e5925a97e4e91593f1542085eae03432a759/app/src/main/java/com/beemdevelopment/aegis/crypto/otp/TOTP.java): time-to-counter transformation.
|
||||
- [OTP.java](https://github.com/beemdevelopment/Aegis/blob/d6f4e5925a97e4e91593f1542085eae03432a759/app/src/main/java/com/beemdevelopment/aegis/crypto/otp/OTP.java): decimal output and zero padding.
|
||||
|
||||
These files confirm the interpretation. The public page's selected decompiled
|
||||
Java comes from the APK evidence. It includes fragments from several methods and
|
||||
line wrapping for display; the paired readable summary is an explanation.
|
||||
The expanded generator panel retains its complete returned body, with formatting
|
||||
changes. Aegis excerpts are credited under the upstream
|
||||
[GPL-3.0 license](https://github.com/beemdevelopment/Aegis/blob/d6f4e5925a97e4e91593f1542085eae03432a759/LICENSE).
|
||||
The diagram, explanatory summary, demo and its WebCrypto implementation are new
|
||||
teaching material; the demo is not recovered original application source.
|
||||
|
||||
## Scope and maintenance
|
||||
|
||||
The claim is a static APK investigation and a checked reconstruction of its
|
||||
default code calculation. It covers neither Android UI execution nor APK
|
||||
signature verification, split APK handling, native libraries or vault storage.
|
||||
The shell walkthrough was executed on Linux. The PowerShell recipe uses the
|
||||
same CLI/environment inputs but was not executed on a Windows host.
|
||||
|
||||
Raw REA results, provider scratch paths, Java harness classes and the downloaded
|
||||
binaries remain outside the public website. The public page uses generic filenames
|
||||
and the public test key. Update the release identity, selected excerpts, demo,
|
||||
reference data and these notes together when moving to another Aegis version.
|
||||
@@ -73,6 +73,18 @@ are new teaching code. Check that the fallback is visible with JavaScript
|
||||
disabled and hidden when the playable canvas loads. Keep the speed settings,
|
||||
source excerpt, reconstruction and original-result table consistent.
|
||||
|
||||
## Aegis login-code figure
|
||||
|
||||
The Aegis overview and adjustable-clock figure are semantic HTML. The clock
|
||||
diagram shows seconds, the 30-second block and the resulting six-digit code,
|
||||
using the public RFC 6238 test key. It retains a static 59-second example when
|
||||
JavaScript is disabled. The three code selections connect each operation to the
|
||||
APK's selected Java and an explanatory summary.
|
||||
|
||||
[evidence/aegis-login-code.md](evidence/aegis-login-code.md) records the inspected
|
||||
APK, methods, source attribution and reconstruction checks. Keep the block
|
||||
formula, default settings, slider outputs and reference cases consistent.
|
||||
|
||||
## Original image generation prompts
|
||||
|
||||
## Prompt 1
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
import { generateExampleCode } from "./aegis-otp.js";
|
||||
|
||||
async function initializeAegisDemo() {
|
||||
const demo = document.querySelector("[data-aegis-demo]");
|
||||
if (demo === null) return;
|
||||
const clock = demo.querySelector("input[type=range]");
|
||||
const controls = demo.querySelectorAll("input, button");
|
||||
const status = demo.querySelector("[data-aegis-status]");
|
||||
let revision = 0;
|
||||
|
||||
const updateTime = async (seconds) => {
|
||||
const currentRevision = ++revision;
|
||||
try {
|
||||
const code = await generateExampleCode(seconds);
|
||||
if (currentRevision !== revision) return false;
|
||||
const block = Math.floor(seconds / 30);
|
||||
demo.querySelector("[data-aegis-seconds]").textContent = String(seconds);
|
||||
demo.querySelector("[data-aegis-block]").textContent = String(block);
|
||||
demo.querySelector("[data-aegis-division]").textContent =
|
||||
`floor(${seconds} / 30)`;
|
||||
demo.querySelector("[data-aegis-window]").textContent =
|
||||
`${block * 30}–${block * 30 + 29} seconds`;
|
||||
demo.querySelector("[data-aegis-code]").textContent = code;
|
||||
clock.setAttribute(
|
||||
"aria-valuetext",
|
||||
`${seconds} seconds, time block ${block}`,
|
||||
);
|
||||
status.textContent = "";
|
||||
return true;
|
||||
} catch {
|
||||
if (currentRevision === revision) {
|
||||
status.textContent =
|
||||
"Interactive calculation is unavailable in this browser. The example shows the code at 59 seconds.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
if (!(await updateTime(Number(clock.value)))) return;
|
||||
controls.forEach((control) => {
|
||||
control.disabled = false;
|
||||
});
|
||||
clock.addEventListener("input", async () => {
|
||||
await updateTime(Number(clock.value));
|
||||
});
|
||||
demo.querySelectorAll("[data-aegis-time]").forEach((button) => {
|
||||
button.addEventListener("click", async () => {
|
||||
clock.value = button.getAttribute("data-aegis-time");
|
||||
await updateTime(Number(clock.value));
|
||||
});
|
||||
});
|
||||
|
||||
const checkButton = document.querySelector("[data-aegis-check]");
|
||||
const checkResult = document.querySelector("[data-aegis-check-result]");
|
||||
checkButton.disabled = false;
|
||||
checkButton.addEventListener("click", async () => {
|
||||
checkButton.disabled = true;
|
||||
checkResult.textContent = "Checking…";
|
||||
try {
|
||||
const response = await fetch(
|
||||
new URL("../showcase/aegis/test-vectors.json", import.meta.url),
|
||||
);
|
||||
if (!response.ok) throw new Error("Reference data unavailable");
|
||||
const { vectors } = await response.json();
|
||||
let passed = 0;
|
||||
for (const vector of vectors) {
|
||||
for (const digits of [6, 8]) {
|
||||
const code = await generateExampleCode(vector.seconds, digits);
|
||||
if (code === vector.sha1.slice(-digits)) passed += 1;
|
||||
}
|
||||
}
|
||||
checkResult.textContent =
|
||||
`${passed} / ${vectors.length * 2} checks passed ` +
|
||||
"(six reference cases, at six and eight digits).";
|
||||
} catch {
|
||||
checkResult.textContent =
|
||||
"Could not run the reference checks. Try again.";
|
||||
} finally {
|
||||
checkButton.disabled = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
await initializeAegisDemo();
|
||||
@@ -0,0 +1,36 @@
|
||||
// Teaching reconstruction of the calculation inspected in Aegis v3.4.3.
|
||||
// The key is public RFC 6238 test data, not an account credential.
|
||||
const testKey = new TextEncoder().encode("12345678901234567890");
|
||||
let importedKey;
|
||||
|
||||
/** Generate a code with the public test key and a 30-second time step. */
|
||||
export async function generateExampleCode(seconds, digits = 6) {
|
||||
if (
|
||||
!Number.isSafeInteger(seconds) ||
|
||||
seconds < 0 ||
|
||||
![6, 8].includes(digits)
|
||||
) {
|
||||
throw new RangeError(
|
||||
"Use a nonnegative integer time and six or eight digits.",
|
||||
);
|
||||
}
|
||||
importedKey ??= crypto.subtle.importKey(
|
||||
"raw",
|
||||
testKey,
|
||||
{ name: "HMAC", hash: "SHA-1" },
|
||||
false,
|
||||
["sign"],
|
||||
);
|
||||
const key = await importedKey;
|
||||
const block = Math.floor(seconds / 30);
|
||||
const counter = new ArrayBuffer(8);
|
||||
new DataView(counter).setBigUint64(0, BigInt(block), false);
|
||||
const hash = new Uint8Array(await crypto.subtle.sign("HMAC", key, counter));
|
||||
const offset = hash[hash.length - 1] & 15;
|
||||
const number =
|
||||
((hash[offset] & 127) << 24) |
|
||||
((hash[offset + 1] & 255) << 16) |
|
||||
((hash[offset + 2] & 255) << 8) |
|
||||
(hash[offset + 3] & 255);
|
||||
return String(number % 10 ** digits).padStart(digits, "0");
|
||||
}
|
||||
@@ -261,6 +261,14 @@ section[id] {
|
||||
background: #38424e;
|
||||
text-decoration: none;
|
||||
}
|
||||
.button.secondary {
|
||||
border-color: var(--line);
|
||||
background: var(--page);
|
||||
color: var(--ink);
|
||||
}
|
||||
.button.secondary:hover {
|
||||
background: var(--soft);
|
||||
}
|
||||
.text-link {
|
||||
font-size: 0.95rem;
|
||||
font-weight: 500;
|
||||
@@ -689,6 +697,59 @@ pre code {
|
||||
.case-figure {
|
||||
margin-bottom: 3.2rem;
|
||||
}
|
||||
.aegis-step-selector {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
.aegis-step-selector button {
|
||||
min-height: 44px;
|
||||
}
|
||||
.aegis-calculation .flow-node {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.35rem;
|
||||
min-height: 3.5rem;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.aegis-calculation .aegis-code {
|
||||
font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
|
||||
font-size: 1.5rem;
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
.aegis-clock-controls {
|
||||
margin-top: 1.7rem;
|
||||
}
|
||||
.aegis-clock-controls label {
|
||||
display: block;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
.aegis-clock-controls input {
|
||||
display: block;
|
||||
width: 100%;
|
||||
min-height: 44px;
|
||||
margin: 0;
|
||||
accent-color: var(--accent);
|
||||
}
|
||||
.aegis-clock-scale {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
color: var(--muted);
|
||||
font-size: 0.75rem;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.aegis-clock-controls .actions {
|
||||
gap: 0.7rem;
|
||||
margin-top: 1.2rem;
|
||||
}
|
||||
.aegis-clock-controls .caption {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.aegis-demo .button:disabled,
|
||||
[data-aegis-check]:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: default;
|
||||
}
|
||||
.step-selector {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
||||
@@ -1456,7 +1517,7 @@ pre code {
|
||||
.comparison-label {
|
||||
padding-bottom: 0.8rem;
|
||||
border-bottom: 1px solid var(--line);
|
||||
font-size: 0.875rem;
|
||||
font-size: 1.125rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
.agent-investigation > .comparison-label {
|
||||
|
||||
@@ -167,7 +167,10 @@
|
||||
class="manual-investigation step-comparison"
|
||||
data-step-comparison
|
||||
>
|
||||
<p class="comparison-label">Before REA · You investigate</p>
|
||||
<p class="comparison-label">
|
||||
Before REA · <strong class="prose-highlight">You</strong>
|
||||
investigate
|
||||
</p>
|
||||
<div
|
||||
class="step-selector expert-step-selector"
|
||||
role="group"
|
||||
@@ -316,7 +319,10 @@
|
||||
</p>
|
||||
</div>
|
||||
<div class="agent-investigation" id="ask-your-agent">
|
||||
<p class="comparison-label">With REA · You ask your agent</p>
|
||||
<p class="comparison-label">
|
||||
With REA · You ask
|
||||
<strong class="prose-highlight">your agent</strong>
|
||||
</p>
|
||||
<h3 class="agent-one-prompt">One prompt.</h3>
|
||||
<p class="agent-intro">
|
||||
Ask your agent <strong>in plain English.</strong>
|
||||
|
||||
@@ -0,0 +1,682 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>How an authenticator generates a login code — REA</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Inspect the Aegis Android APK with REA, recover its six-digit login-code calculation and try a reconstruction with an adjustable clock."
|
||||
/>
|
||||
<meta name="theme-color" content="#ffffff" />
|
||||
<link rel="icon" href="../../assets/favicon.svg" type="image/svg+xml" />
|
||||
<link rel="stylesheet" href="../../assets/styles.css" />
|
||||
<script src="../../assets/main.js" defer></script>
|
||||
<script type="module" src="../../assets/aegis-demo.js"></script>
|
||||
</head>
|
||||
<body id="top">
|
||||
<a class="skip-link" href="#main">Skip to content</a>
|
||||
<header class="site-header">
|
||||
<div class="container header-inner">
|
||||
<a class="brand" href="../../" aria-label="REA home"
|
||||
><span class="brand-name">REA</span
|
||||
><span class="brand-caption">Reverse Engineer Anything</span></a
|
||||
>
|
||||
<nav class="navigation" aria-label="Main navigation">
|
||||
<a href="../">Showcases</a>
|
||||
<a class="nav-start" href="../../get-started/">Get started</a>
|
||||
<a href="../../guides/">Guides</a>
|
||||
<a href="../../faq/">FAQ</a>
|
||||
</nav>
|
||||
<a
|
||||
class="nav-github"
|
||||
href="https://github.com/morluto/rea"
|
||||
aria-label="REA on GitHub"
|
||||
title="REA on GitHub"
|
||||
>
|
||||
<svg
|
||||
width="22"
|
||||
height="22"
|
||||
viewBox="0 0 16 16"
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82a7.65 7.65 0 0 1 2-.27c.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8Z"
|
||||
/>
|
||||
</svg>
|
||||
<span class="nav-github-count" hidden aria-hidden="true"></span>
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
<main id="main" class="container">
|
||||
<div class="page-heading">
|
||||
<p class="breadcrumb">
|
||||
<a href="../../">Home</a> / <a href="../">Showcases</a> / Android
|
||||
</p>
|
||||
<p class="eyebrow">Case study · Aegis Authenticator</p>
|
||||
<h1>How does an authenticator<br />generate a login code?</h1>
|
||||
<p class="lede">
|
||||
A six-digit code changes every 30 seconds. Use REA to find the
|
||||
calculation in an Android APK, then rebuild it with a clock you can
|
||||
control.
|
||||
</p>
|
||||
<p class="page-meta">
|
||||
Aegis 3.4.3 · Android · Official release APK · 6.9 MB
|
||||
</p>
|
||||
<a class="text-link" href="https://github.com/beemdevelopment/Aegis"
|
||||
>View Aegis on GitHub</a
|
||||
>
|
||||
</div>
|
||||
|
||||
<figure class="workflow-figure case-figure">
|
||||
<p class="figure-title">From an APK to a code you can reproduce</p>
|
||||
<ol class="flow-steps">
|
||||
<li>
|
||||
<span class="flow-label">01 · Locate the feature</span
|
||||
><strong class="flow-node"
|
||||
>3,077 classes → generating methods</strong
|
||||
><span class="flow-note"
|
||||
>REA searches the package and traces the code used by the display
|
||||
and copy actions.</span
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<span class="flow-label">02 · Read the calculation</span
|
||||
><strong class="flow-node">Time + account key → six digits</strong
|
||||
><span class="flow-note"
|
||||
>REA returns the methods and defaults. The agent explains how they
|
||||
fit together.</span
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<span class="flow-label">03 · Rebuild and check</span
|
||||
><strong class="flow-node">Change the clock. Watch the code.</strong
|
||||
><span class="flow-note"
|
||||
>A new browser demo reproduces the rule and checks it against
|
||||
public reference cases.</span
|
||||
>
|
||||
</li>
|
||||
</ol>
|
||||
</figure>
|
||||
|
||||
<div class="article-layout">
|
||||
<nav class="contents" aria-label="On this page">
|
||||
<p>In this case study</p>
|
||||
<ul>
|
||||
<li><a href="#ask">Ask your agent</a></li>
|
||||
<li><a href="#demo">Try the code generator</a></li>
|
||||
<li><a href="#find">Find the code with REA</a></li>
|
||||
<li><a href="#calculation">Read the calculation</a></li>
|
||||
<li><a href="#verify">Check the reconstruction</a></li>
|
||||
<li><a href="#try">Inspect the APK yourself</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
<article class="article" aria-label="Aegis APK case study">
|
||||
<section class="article-section" id="ask">
|
||||
<h2>Ask your agent</h2>
|
||||
<p>
|
||||
The app shows a changing login code. We want to find
|
||||
<strong>what makes it change</strong> and reproduce that behavior.
|
||||
</p>
|
||||
<div class="agent-terminal">
|
||||
<div class="terminal-header">
|
||||
<span class="terminal-title"
|
||||
><span class="terminal-dots" aria-hidden="true"
|
||||
><i></i><i></i><i></i></span
|
||||
>Your coding agent</span
|
||||
><button
|
||||
class="copy-button"
|
||||
type="button"
|
||||
data-copy="aegis-prompt"
|
||||
aria-label="Copy Aegis example prompt"
|
||||
>
|
||||
Copy
|
||||
</button>
|
||||
</div>
|
||||
<p class="terminal-prompt">
|
||||
<span class="prompt-symbol" aria-hidden="true">›</span
|
||||
><span id="aegis-prompt"
|
||||
>Use REA to inspect aegis-v3.4.3.apk. Find how it generates
|
||||
the six-digit login code, explain why it changes every 30
|
||||
seconds, and rebuild a small demo where I can change the
|
||||
time.</span
|
||||
><span class="terminal-cursor" aria-hidden="true"></span>
|
||||
</p>
|
||||
</div>
|
||||
<p class="caption">
|
||||
An example prompt for the downloaded APK, with REA's Android
|
||||
analysis configured.
|
||||
<a href="#try">Get the APK and analysis setup ↓</a>
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="article-section" id="demo">
|
||||
<h2>Try the code generator</h2>
|
||||
<p>
|
||||
The app groups time into
|
||||
<mark class="prose-highlight">30-second blocks.</mark> It combines
|
||||
the block number with the account key to generate a code. The same
|
||||
key and block produce the same code.
|
||||
</p>
|
||||
<figure class="workflow-figure aegis-demo" data-aegis-demo>
|
||||
<p class="figure-title">Move the clock across 60 seconds</p>
|
||||
<ol class="flow-steps aegis-calculation">
|
||||
<li>
|
||||
<span class="flow-label">Time</span
|
||||
><strong class="flow-node"
|
||||
><output data-aegis-seconds>59</output> seconds</strong
|
||||
><span class="flow-note">Our adjustable example clock</span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="flow-label">30-second block</span
|
||||
><strong class="flow-node"
|
||||
>Block <output data-aegis-block>1</output></strong
|
||||
><span class="flow-note"
|
||||
><code data-aegis-division>floor(59 / 30)</code><br /><span
|
||||
data-aegis-window
|
||||
>30–59 seconds</span
|
||||
></span
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<span class="flow-label">Generated code</span
|
||||
><strong class="flow-node aegis-code"
|
||||
><output
|
||||
data-aegis-code
|
||||
aria-live="polite"
|
||||
aria-atomic="true"
|
||||
>287082</output
|
||||
></strong
|
||||
><span class="flow-note"
|
||||
>Account key + block → six digits</span
|
||||
>
|
||||
</li>
|
||||
</ol>
|
||||
<div class="aegis-clock-controls">
|
||||
<label for="aegis-clock">Example time, in seconds</label>
|
||||
<input
|
||||
id="aegis-clock"
|
||||
type="range"
|
||||
min="0"
|
||||
max="120"
|
||||
step="1"
|
||||
value="59"
|
||||
disabled
|
||||
/>
|
||||
<div class="aegis-clock-scale" aria-hidden="true">
|
||||
<span>0</span><span>30</span><span>60</span><span>90</span
|
||||
><span>120</span>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button
|
||||
class="button secondary"
|
||||
type="button"
|
||||
data-aegis-time="59"
|
||||
disabled
|
||||
>
|
||||
59 seconds</button
|
||||
><button
|
||||
class="button secondary"
|
||||
type="button"
|
||||
data-aegis-time="60"
|
||||
disabled
|
||||
>
|
||||
60 seconds
|
||||
</button>
|
||||
</div>
|
||||
<p class="caption">
|
||||
At 59 seconds: <strong>287082.</strong> At 60 seconds:
|
||||
<strong>359152.</strong> Moving within one block leaves the
|
||||
code unchanged.
|
||||
</p>
|
||||
<p class="caption" data-aegis-status role="status"></p>
|
||||
</div>
|
||||
<figcaption>
|
||||
The key is fixed, public
|
||||
<a href="https://www.rfc-editor.org/rfc/rfc6238.html#appendix-B"
|
||||
>RFC 6238 test data</a
|
||||
>. The demo implements the calculation recovered from the APK.
|
||||
</figcaption>
|
||||
<noscript
|
||||
><p class="caption">
|
||||
The diagram shows the result at 59 seconds. Enable JavaScript
|
||||
to change the clock.
|
||||
</p></noscript
|
||||
>
|
||||
</figure>
|
||||
</section>
|
||||
|
||||
<section class="article-section" id="find">
|
||||
<h2>Find the code with REA</h2>
|
||||
<ol class="rea-queries">
|
||||
<li>
|
||||
<h4>Narrow the APK to three classes</h4>
|
||||
<div class="rea-query-pair">
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>Agent → REA</span></div>
|
||||
<pre><code>inspect_android_package
|
||||
{"path": "aegis-v3.4.3.apk"}
|
||||
|
||||
search_android_classes
|
||||
{"path": "aegis-v3.4.3.apk",
|
||||
"query": "Totp"}</code></pre>
|
||||
</div>
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>REA → agent · selected results</span>
|
||||
</div>
|
||||
<pre><code>Package: com.beemdevelopment.aegis
|
||||
Version: 3.4.3
|
||||
Classes: 3,077
|
||||
|
||||
Three matches:
|
||||
otp.TotpInfo
|
||||
ui.views.TotpProgressBar
|
||||
importers.TotpAuthenticatorImporter</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
<code>TotpInfo</code> is the calculation candidate; the other
|
||||
two concern the progress bar and imported accounts. TOTP means
|
||||
a time-based one-time password.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<h4>Connect the generator to the app's display</h4>
|
||||
<div class="rea-query-pair">
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>Agent → REA</span></div>
|
||||
<pre><code>inspect_android_class
|
||||
{"path": "aegis-v3.4.3.apk",
|
||||
"class_name":
|
||||
"com.beemdevelopment.aegis.otp.TotpInfo"}
|
||||
|
||||
trace_android_references
|
||||
{"path": "aegis-v3.4.3.apk",
|
||||
"class_name":
|
||||
"com.beemdevelopment.aegis.otp.OtpInfo",
|
||||
"method_name": "getOtp"}</code></pre>
|
||||
</div>
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>REA → agent · methods and callers</span>
|
||||
</div>
|
||||
<pre><code>TotpInfo methods:
|
||||
getOtp() · overload 0
|
||||
getOtp(long) · overload 1
|
||||
|
||||
OtpInfo.getOtp callers:
|
||||
ui.views.EntryHolder.getOtp
|
||||
ui.MainActivity.copyEntryCode</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
REA identifies the timestamp overload and finds the base
|
||||
method's callers. Inspecting
|
||||
<code>EntryHolder.getOtp</code> then shows the display calling
|
||||
<code>TotpInfo.getOtp(timestamp)</code>.
|
||||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
<p class="caption">
|
||||
Requests show a shortened input path. Result class names omit the
|
||||
common <code>com.beemdevelopment.aegis</code> prefix.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="article-section" id="calculation">
|
||||
<h2>Read the calculation</h2>
|
||||
<p>
|
||||
REA returns
|
||||
<strong
|
||||
>the clock conversion, default settings and generating
|
||||
methods.</strong
|
||||
>
|
||||
The constructors set a 30-second interval and six digits; the
|
||||
timestamp method turns seconds into a block number.
|
||||
</p>
|
||||
<div class="step-comparison" data-step-comparison>
|
||||
<div
|
||||
class="step-selector aegis-step-selector"
|
||||
role="group"
|
||||
aria-label="Follow the login-code calculation"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
data-select-step="1"
|
||||
aria-pressed="true"
|
||||
aria-controls="aegis-java aegis-summary"
|
||||
>
|
||||
<span>01</span> Time block
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
data-select-step="2"
|
||||
aria-pressed="false"
|
||||
aria-controls="aegis-java aegis-summary"
|
||||
>
|
||||
<span>02</span> Key + block
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
data-select-step="3"
|
||||
aria-pressed="false"
|
||||
aria-controls="aegis-java aegis-summary"
|
||||
>
|
||||
<span>03</span> Six digits
|
||||
</button>
|
||||
</div>
|
||||
<div class="code-comparison">
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>REA · selected decompiled Java</span>
|
||||
</div>
|
||||
<pre><code id="aegis-java"><span class="code-step is-active" data-step="1">// TotpInfo defaults and clock
|
||||
setPeriod(30);
|
||||
getOtp(System.currentTimeMillis() / 1000);
|
||||
|
||||
// OtpInfo default algorithm and digits
|
||||
this(bArr, "SHA1", 6);
|
||||
|
||||
// Block passed to the generator
|
||||
(long) Math.floor(j / ((double) this._period))</span>
|
||||
|
||||
<span class="code-step" data-step="2">// generateOTP → getHash
|
||||
byte[] hash = getHash(bArr, str, j);
|
||||
|
||||
// getHash: account key + encoded block
|
||||
Mac mac = Mac.getInstance(str);
|
||||
mac.init(secretKeySpec);
|
||||
return mac.doFinal(bArrArray);</span>
|
||||
|
||||
<span class="code-step" data-step="3">// OTP.toString, case 0
|
||||
this._code % ((int) Math.pow(10.0d, i))
|
||||
|
||||
// Keep leading zeroes
|
||||
while (sb.length() < i) {
|
||||
sb.insert(0, "0");
|
||||
}</span></code></pre>
|
||||
</div>
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Readable summary · agent's interpretation</span>
|
||||
</div>
|
||||
<pre><code id="aegis-summary"><span class="code-step is-active" data-step="1">// Group time into 30-second blocks
|
||||
seconds = current_time_ms / 1000
|
||||
block = floor(seconds / 30)</span>
|
||||
|
||||
<span class="code-step" data-step="2">// Generate a number from the key and block
|
||||
hash = HMAC_SHA1(account_key,
|
||||
big_endian_8_bytes(block))
|
||||
number = select_31_bits(hash)</span>
|
||||
|
||||
<span class="code-step" data-step="3">// Format the default six-digit code
|
||||
code = number % 1_000_000
|
||||
code = pad_with_zeroes(code, 6)</span></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="step-detail" data-step-note="1">
|
||||
<p>
|
||||
<strong>Time chooses the block.</strong> Seconds 30 through 59
|
||||
all give block 1. At 60 seconds, the block becomes 2.
|
||||
</p>
|
||||
</div>
|
||||
<div class="step-detail" data-step-note="2">
|
||||
<p>
|
||||
<strong>The key matters too.</strong> The generator combines
|
||||
the account key with the block. An account with a different
|
||||
key can show a different code at the same time.
|
||||
</p>
|
||||
</div>
|
||||
<div class="step-detail" data-step-note="3">
|
||||
<p>
|
||||
<strong>Keep six digits.</strong> The remainder after division
|
||||
by 1,000,000 is padded with zeroes when needed, so a code can
|
||||
begin with 0.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<p class="caption">
|
||||
Excerpts from several inspected methods, with line wrapping for
|
||||
display. The right panel is an explanatory summary.
|
||||
<a
|
||||
href="https://github.com/beemdevelopment/Aegis/blob/d6f4e5925a97e4e91593f1542085eae03432a759/LICENSE"
|
||||
>Aegis code is GPL-3.0.</a
|
||||
>
|
||||
</p>
|
||||
<details class="evidence-details">
|
||||
<summary>Inside the generator</summary>
|
||||
<p>
|
||||
The released APK puts <code>generateOTP</code> in
|
||||
<code>kotlin.ExceptionsKt</code>. REA follows the call from
|
||||
<code>TotpInfo</code> and returns this body; the original source
|
||||
calls the helper <code>HOTP</code>.
|
||||
</p>
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>REA · generateOTP, complete body</span>
|
||||
</div>
|
||||
<pre><code>public static OTP generateOTP(byte[] bArr, String str,
|
||||
int i, long j)
|
||||
throws NoSuchAlgorithmException, InvalidKeyException {
|
||||
byte[] hash = getHash(bArr, str, j);
|
||||
int i2 = hash[hash.length - 1] & 15;
|
||||
return new OTP(
|
||||
(hash[i2 + 3] & 255)
|
||||
| ((hash[i2] & 127) << 24)
|
||||
| ((hash[i2 + 1] & 255) << 16)
|
||||
| ((hash[i2 + 2] & 255) << 8), i, 0);
|
||||
}</code></pre>
|
||||
</div>
|
||||
<p>
|
||||
The last hash byte selects a position. Four bytes at that
|
||||
position provide a positive 31-bit number; formatting reduces it
|
||||
to the requested number of digits. The constructor's last
|
||||
argument selects the code-formatting branch introduced by
|
||||
compilation.
|
||||
</p>
|
||||
<p>
|
||||
<a
|
||||
href="https://github.com/beemdevelopment/Aegis/blob/d6f4e5925a97e4e91593f1542085eae03432a759/app/src/main/java/com/beemdevelopment/aegis/crypto/otp/HOTP.java"
|
||||
>Compare with the matching release source</a
|
||||
>.
|
||||
</p>
|
||||
</details>
|
||||
</section>
|
||||
|
||||
<section class="article-section" id="verify">
|
||||
<h2>Check the reconstruction</h2>
|
||||
<p>
|
||||
We assembled the selected REA-returned Java methods in a small
|
||||
test program. Their output matched an independent reconstruction
|
||||
on <strong>133 test cases</strong>, including time-block
|
||||
boundaries and codes beginning with zero.
|
||||
</p>
|
||||
<div class="evidence-table-wrap">
|
||||
<table class="evidence-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Example time</th>
|
||||
<th>Block</th>
|
||||
<th>Six-digit code</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>30 seconds</td>
|
||||
<td>1</td>
|
||||
<td><code>287082</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>59 seconds</td>
|
||||
<td>1</td>
|
||||
<td><code>287082</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>60 seconds</td>
|
||||
<td>2</td>
|
||||
<td><code>359152</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,111,111,109 seconds</td>
|
||||
<td>37,037,036</td>
|
||||
<td><code>081804</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p>
|
||||
The generator also matches the six published SHA-1 reference cases
|
||||
in
|
||||
<a href="https://www.rfc-editor.org/rfc/rfc6238.html#appendix-B"
|
||||
>RFC 6238</a
|
||||
>. Check the browser implementation against them:
|
||||
</p>
|
||||
<div class="actions">
|
||||
<button
|
||||
class="button secondary"
|
||||
type="button"
|
||||
data-aegis-check
|
||||
disabled
|
||||
>
|
||||
Run reference checks</button
|
||||
><a class="text-link" href="../../assets/aegis-otp.js"
|
||||
>Read the demo's calculation</a
|
||||
>
|
||||
</div>
|
||||
<p
|
||||
class="caption"
|
||||
data-aegis-check-result
|
||||
role="status"
|
||||
aria-live="polite"
|
||||
>
|
||||
The reference cases use eight digits. The check also verifies
|
||||
their six-digit results.
|
||||
</p>
|
||||
<p class="caption">
|
||||
Verification runs extracted Java methods and the new demo. The
|
||||
Android APK was inspected statically.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="article-section" id="try">
|
||||
<h2>Inspect the APK yourself</h2>
|
||||
<p>
|
||||
<a href="../../get-started/">Set up REA</a>, then download these
|
||||
two files into the same folder. Android analysis needs Java; this
|
||||
case was checked with Java 21.
|
||||
</p>
|
||||
<div class="actions">
|
||||
<a
|
||||
class="button"
|
||||
href="https://github.com/beemdevelopment/Aegis/releases/download/v3.4.3/aegis-v3.4.3.apk"
|
||||
>Download Aegis APK</a
|
||||
><a
|
||||
class="text-link"
|
||||
href="https://github.com/1013503897/jadx-headless-mcp/releases/download/v0.7.1/jadx-headless-mcp-0.7.1-all.jar"
|
||||
>Download Android analysis provider</a
|
||||
>
|
||||
</div>
|
||||
<p>Point REA at the provider file and inspect the APK:</p>
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>macOS / Linux</span
|
||||
><button
|
||||
class="copy-button"
|
||||
type="button"
|
||||
data-copy="aegis-inspect-command"
|
||||
aria-label="Copy APK inspection command"
|
||||
>
|
||||
Copy
|
||||
</button>
|
||||
</div>
|
||||
<pre><code id="aegis-inspect-command">REA_JADX_MCP_JAR="$PWD/jadx-headless-mcp-0.7.1-all.jar" \
|
||||
npx rea-agents@latest inspect-android-package \
|
||||
./aegis-v3.4.3.apk --format json --full-output</code></pre>
|
||||
</div>
|
||||
<details class="evidence-details">
|
||||
<summary>Windows PowerShell</summary>
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>PowerShell</span
|
||||
><button
|
||||
class="copy-button"
|
||||
type="button"
|
||||
data-copy="aegis-powershell-command"
|
||||
aria-label="Copy PowerShell APK inspection command"
|
||||
>
|
||||
Copy
|
||||
</button>
|
||||
</div>
|
||||
<pre><code id="aegis-powershell-command">$env:REA_JADX_MCP_JAR = (Resolve-Path ./jadx-headless-mcp-0.7.1-all.jar).Path
|
||||
npx rea-agents@latest inspect-android-package ./aegis-v3.4.3.apk --format json --full-output</code></pre>
|
||||
</div>
|
||||
</details>
|
||||
<p>
|
||||
Your agent can continue through REA's CLI using the prompt above.
|
||||
For MCP, add <code>REA_JADX_MCP_JAR</code> to the REA server's
|
||||
environment and reconnect it.
|
||||
</p>
|
||||
<p>
|
||||
A next question:
|
||||
<strong
|
||||
>what happens when an account uses eight digits or a different
|
||||
time interval?</strong
|
||||
>
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="article-section" id="sources">
|
||||
<h2>Sources</h2>
|
||||
<ul class="compact-list">
|
||||
<li>
|
||||
<a
|
||||
href="https://github.com/beemdevelopment/Aegis/releases/tag/v3.4.3"
|
||||
>Official Aegis 3.4.3 release</a
|
||||
>
|
||||
·
|
||||
<a
|
||||
href="https://github.com/beemdevelopment/Aegis/tree/d6f4e5925a97e4e91593f1542085eae03432a759"
|
||||
>Matching source commit</a
|
||||
>
|
||||
·
|
||||
<a
|
||||
href="https://github.com/beemdevelopment/Aegis/blob/d6f4e5925a97e4e91593f1542085eae03432a759/LICENSE"
|
||||
>GPL-3.0 license</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://www.rfc-editor.org/rfc/rfc6238.html#appendix-B"
|
||||
>RFC 6238 reference cases</a
|
||||
>
|
||||
· <a href="test-vectors.json">Demo test data</a>
|
||||
</li>
|
||||
</ul>
|
||||
<p class="caption">
|
||||
Inspected with REA 6.1.0 on 9 October 2026. Decompiled excerpts
|
||||
are credited to Aegis; the diagram, readable summary and browser
|
||||
reconstruction are new teaching material.
|
||||
</p>
|
||||
</section>
|
||||
</article>
|
||||
</div>
|
||||
</main>
|
||||
<footer class="site-footer">
|
||||
<div class="container footer-inner">
|
||||
<p>REA · Reverse Engineer Anything</p>
|
||||
<div class="footer-links">
|
||||
<a href="https://github.com/morluto/rea">Source</a
|
||||
><a href="https://github.com/morluto/rea/blob/main/LICENSE"
|
||||
>MIT license</a
|
||||
><a href="https://discord.gg/GkcryMnJDM">Community</a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<p class="sr-only" id="copy-status" role="status" aria-live="polite"></p>
|
||||
<a class="back-to-top" href="#top" aria-label="Back to top"
|
||||
><span aria-hidden="true">↑</span> Top</a
|
||||
>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"source": "https://www.rfc-editor.org/rfc/rfc6238.html#appendix-B",
|
||||
"public_test_key_ascii": "12345678901234567890",
|
||||
"algorithm": "HMAC-SHA1",
|
||||
"period_seconds": 30,
|
||||
"vectors": [
|
||||
{ "seconds": 59, "sha1": "94287082" },
|
||||
{ "seconds": 1111111109, "sha1": "07081804" },
|
||||
{ "seconds": 1111111111, "sha1": "14050471" },
|
||||
{ "seconds": 1234567890, "sha1": "89005924" },
|
||||
{ "seconds": 2000000000, "sha1": "69279037" },
|
||||
{ "seconds": 20000000000, "sha1": "65353130" }
|
||||
]
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>Case studies — REA</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Follow REA investigations through code and figures: DX-Ball, Notion, TH04 and a DownUnderCTF flag checker."
|
||||
content="Follow REA investigations through code, figures and demos: an Android authenticator, DX-Ball, Notion, TH04 and a DownUnderCTF flag checker."
|
||||
/>
|
||||
<meta name="theme-color" content="#ffffff" />
|
||||
<link rel="icon" href="../assets/favicon.svg" type="image/svg+xml" />
|
||||
@@ -54,11 +54,29 @@
|
||||
<p class="breadcrumb"><a href="../">Home</a> / Showcases</p>
|
||||
<h1>REA case studies.</h1>
|
||||
<p class="lede">
|
||||
Game reconstruction, Electron analysis and a CTF challenge, with code,
|
||||
figures and checked results.
|
||||
Android, games, Electron and a CTF challenge, with code, figures and
|
||||
checked results.
|
||||
</p>
|
||||
</div>
|
||||
<div class="guide-index">
|
||||
<section class="guide-entry">
|
||||
<p class="eyebrow">Android · APK analysis</p>
|
||||
<div>
|
||||
<h2>How an authenticator generates a login code</h2>
|
||||
<p>
|
||||
Find Aegis's six-digit code calculation in its released APK. Trace
|
||||
the generating methods with REA, then move a demo clock to see why
|
||||
the code changes every 30 seconds.
|
||||
</p>
|
||||
<div class="guide-route">
|
||||
<span>APK</span> <b aria-hidden="true">→</b>
|
||||
<span>Generating code</span> <b aria-hidden="true">→</b>
|
||||
<span>Recovered rule</span> <b aria-hidden="true">→</b>
|
||||
<span>Adjustable clock</span>
|
||||
</div>
|
||||
<a class="text-link" href="aegis/">Read the Android case study</a>
|
||||
</div>
|
||||
</section>
|
||||
<section class="guide-entry">
|
||||
<p class="eyebrow">CTF · Native analysis</p>
|
||||
<div>
|
||||
|
||||
@@ -142,14 +142,15 @@ purposes, and immutable commit links for checkpoint-dependent facts.
|
||||
Each figure should answer a question that a reader can name. Choose the visual
|
||||
form that fits it:
|
||||
|
||||
| Relationship | Existing example | Useful form |
|
||||
| ----------------------------------------- | ---------------------------------------- | ------------------------------------------------------- |
|
||||
| Analysis and verification steps | DX-Ball sound pan | Flow with separate verification branches |
|
||||
| Code across process boundaries | Electron CSV export and Notion clipboard | HTML flow with APIs and channel names |
|
||||
| A mathematical transformation | TH04's fixed and aimed rings | SVG drawn from the angle formula |
|
||||
| Original instructions and readable source | DX-Ball and TH04 | Selectable HTML code with matching step highlights |
|
||||
| A request caused by an action | Notes browser export | Flow, observed result table and script excerpt |
|
||||
| Recovered behavior and a new experiment | Dinosaur speed reconstruction | Inspected code, playable demo and original-result check |
|
||||
| Relationship | Existing example | Useful form |
|
||||
| ----------------------------------------- | ---------------------------------------- | ---------------------------------------------------------------- |
|
||||
| Analysis and verification steps | DX-Ball sound pan | Flow with separate verification branches |
|
||||
| Code across process boundaries | Electron CSV export and Notion clipboard | HTML flow with APIs and channel names |
|
||||
| A mathematical transformation | TH04's fixed and aimed rings | SVG drawn from the angle formula |
|
||||
| Original instructions and readable source | DX-Ball and TH04 | Selectable HTML code with matching step highlights |
|
||||
| A request caused by an action | Notes browser export | Flow, observed result table and script excerpt |
|
||||
| Recovered behavior and a new experiment | Dinosaur speed reconstruction | Inspected code, playable demo and original-result check |
|
||||
| Time blocks and changing output | Aegis login-code reconstruction | Adjustable clock, block number and code beside recovered methods |
|
||||
|
||||
Use SVG or semantic HTML for diagrams with exact text, numbers and arrows.
|
||||
Generated illustrations can help explore a layout, but the published labels,
|
||||
|
||||
Reference in New Issue
Block a user