Files
reverse-engineering-anything/src/domain/android/androidPartialObservation.ts
T
gensokyo-dev 570abe95f2 feat(android): link native declarations to static JNI candidates (#7472)
Link original DEX native declarations to per-ABI function exports and relocated static JNI table candidates through shared CLI/MCP workflows. Preserve global attribution ambiguity, exact provenance, partial coverage and retained Evidence; default MCP delivery to bounded summaries with filtered/batch pages.

Use one immutable ELF relocation decoder with streaming IL2CPP materialization, cooperative bounded export/version parsing and bounded JNI state. Reuse validated session inventories without loading target libraries or executing JNI code.

Validation: relevant type/lint/build and parser/domain/public CLI/MCP regressions; genuine four-ABI NDK fixtures and independent library/slot oracles; actual JDK/JADX Conscrypt workflows with retained-source removal. Full measurements and limitations are recorded in docs/verification/android-jni-bindings-2026-10-27.md.

Closes #6403.
2026-10-27 18:53:22 +08:00

63 lines
1.9 KiB
TypeScript

import { z } from "zod";
import { digestSchema } from "../digests.js";
import { jsonObjectSchema, jsonValueSchema } from "../jsonValue.js";
import { localPathStringSchema } from "../localPath.js";
import { androidJniPartialFactsSchema } from "./androidJniBindings.js";
const operationSchema = z.enum([
"inspect_android_package",
"inspect_android_jni_bindings",
"search_android_classes",
"inspect_android_class",
"inspect_android_method",
"trace_android_references",
]);
/** JSON-safe Android provider facts collected before an analysis failure. */
export const androidPartialObservationSchema = z
.strictObject({
provider_id: z.literal("jadx"),
operation: operationSchema,
target: z.strictObject({
selected_path: localPathStringSchema,
path: localPathStringSchema,
sha256: digestSchema,
format: z.literal("apk"),
}),
provider_facts: z.strictObject({
jar_sha256: digestSchema.nullable(),
bridge_sha256: digestSchema.nullable(),
bridge_name: z.string().min(1),
bridge_version: z.string().min(1),
server_name: z.string().nullable(),
server_version: z.string().nullable(),
engine_version: z.string().min(1).nullable(),
}),
calls: z.array(
z.strictObject({
operation: z.string().min(1),
input: jsonObjectSchema,
response: jsonValueSchema,
}),
),
jni: androidJniPartialFactsSchema.optional(),
})
.superRefine((observation, context) => {
if (
observation.jni !== undefined &&
observation.operation !== "inspect_android_jni_bindings"
)
context.addIssue({
code: "custom",
path: ["jni"],
message:
"Parsed JNI facts belong only to inspect_android_jni_bindings observations",
});
});
/** JSON-safe Android provider facts retained when analysis fails. */
export type AndroidPartialObservation = z.infer<
typeof androidPartialObservationSchema
>;