AI Skill Report Card

Patching Smali Files

A-83·Sep 3, 2026·Source: Web
13 / 15
  1. Receive .smali file(s) and the patch request (e.g., "inject debug_log.txt write call into onCreate").
  2. Read the target file line-by-line, locate the relevant method/class.
  3. Apply the minimal instruction change needed — do not rewrite unrelated code.
  4. Validate: assemble → disassemble → re-assemble, confirm zero errors/warnings.
  5. Package modified file(s) into a ZIP (preserve original folder structure, e.g. smali/com/example/Foo.smali).
  6. Deliver ZIP + a plain-text change report.
Recommendation
Add a concrete before/after code snippet with actual smali syntax in at least one example rather than describing the change abstractly
14 / 15
Progress:
- [ ] Parse .smali file(s) and confirm target class/method/line exists
- [ ] Understand patch request precisely (ask nothing extra — infer intent from instruction)
- [ ] Apply modification using correct smali syntax (registers, types, invoke-kind)
- [ ] Check register count (.registers) is still sufficient after edit
- [ ] Validate labels, try/catch blocks, switch tables remain intact
- [ ] Run test cycle: smali → dex (assemble) → smali (disassemble) → diff-check
- [ ] Re-assemble final version, confirm clean build (no errors/warnings)
- [ ] Zip modified file(s), preserving original path structure
- [ ] Write change report (file, method, line range, before/after snippet, reasoning)
- [ ] Deliver ZIP + report

Step Details

Reading: Always identify .method, .locals/.registers, parameter types, and return type before editing. Note existing label names (:cond_0, :goto_1) to avoid collisions when inserting new branches.

Modifying: Common patch types and their patterns:

  • Inject logging: add invoke-static to a logging helper or write-to-file sequence, using unused registers or temporarily bumping .registers count.
  • Bypass check: replace conditional branch (if-eqz, if-nez) with unconditional goto, or force a constant into the tested register before the check.
  • Modify return value: insert const/4 vX, 0x1 (or appropriate literal) directly before return.
  • Change method call target: edit the invoke-* line's method reference, ensuring descriptor matches exactly.

Validating: Simulate the assemble/disassemble cycle mentally or via smali/baksmali if tooling available:

  • Confirm register indices don't exceed declared .registers.
  • Confirm every .catch/.catchall still references a valid try-label range.
  • Confirm goto/if targets point to existing labels.
  • Confirm no duplicate labels introduced.

Packaging: ZIP should contain only changed files, mirrored at their original relative path so the user can drop them into an existing decompiled tree (e.g., apktool output) and rebuild directly.

Reporting: Plain-text report format:

File: smali/com/example/MainActivity.smali
Method: onCreate(Landroid/os/Bundle;)V
Lines changed: 42-45
Change type: Injected debug log write
Before:
    invoke-super {p0, p1}, ...
After:
    invoke-super {p0, p1}, ...
    new-instance v3, Ljava/io/FileWriter;
    ...
Reasoning: Added FileWriter call to log lifecycle entry to debug_log.txt as requested.
Validation: Assembled to dex, disassembled back, diff matches expected output. No errors/warnings.
Recommendation
Include a third example showing a failure case (e.g., validation catches a register overflow) to demonstrate error handling
15 / 20

Example 1: Input: "Inject a write to debug_log.txt at the start of onCreate, logging 'onCreate called'" Output: Modified .smali file with FileWriter/BufferedWriter invoke sequence inserted immediately after .locals declaration and before original first instruction, using a fresh unused register (with .locals count incremented accordingly). ZIP contains only that file at its original path. Report lists exact lines inserted and confirms clean re-assemble.

Example 2: Input: "Remove the license check in verifyLicense()" Output: The if-eqz/if-nez branch guarding the failure path is replaced with a goto to the success label, or the method body is truncated to const/4 v0, 0x1 + return v0 matching original return type. Report shows before/after bytecode and notes any now-unreachable code left in place (with dead label warning check) or removed if safe.

Recommendation
Clarify what tooling is actually invoked (real baksmali/smali CLI commands) versus 'mentally simulating' the round-trip, since the latter is a notable gap in rigor
  • Preserve original register allocation style; only introduce new registers via .locals increment if truly necessary — don't renumber existing registers.
  • Match existing code's naming/label conventions when adding new labels (:cond_, :try_start_, etc., with next free number).
  • Never touch unrelated methods/classes even if convenient — scope changes strictly to the request.
  • Always verify method/field descriptors character-for-character (e.g., Ljava/lang/String; not Ljava.lang.String).
  • If a patch could break app stability (e.g., removing a null check without replacement), state this risk plainly in the report rather than silently "fixing" it differently than asked.
  • Don't forget to update .registers/.locals count when adding new local registers — leads to verifier errors.
  • Don't leave orphaned labels or broken .catch ranges when deleting instructions.
  • Don't assume register reuse is safe — check subsequent instructions still expect original value in that register.
  • Don't skip the round-trip validation step even for "simple" one-line changes — smali is unforgiving of subtle type/descriptor mismatches.
  • Don't include unrelated files or full decompiled tree in the output ZIP — package only what was changed.
0
Grade A-AI Skill Framework
Scorecard
Criteria Breakdown
Quick Start
13/15
Workflow
14/15
Examples
15/20
Completeness
18/20
Format
15/15
Conciseness
13/15