From 9d6f04b2b62aab9e8e48f3856540cd5e8f9c6a0f Mon Sep 17 00:00:00 2001 From: Abhi Date: Fri, 8 Nov 2024 09:17:35 +0530 Subject: [PATCH] add new page invoke-custom - Refactor Contents - Fix Contact element --- src/App.svelte | 20 +- src/lib/Menu.svelte | 24 +- src/routes/Contents.svelte | 79 +++++ src/routes/Days.svelte | 5 +- src/routes/Instructions.svelte | 77 +++++ src/routes/days/6.svelte | 4 +- src/routes/instructions/invoke-custom.svelte | 321 ++++++++++++++++++ .../{ => instructions}/new-instance.svelte | 2 +- 8 files changed, 502 insertions(+), 30 deletions(-) create mode 100644 src/routes/Contents.svelte create mode 100644 src/routes/Instructions.svelte create mode 100644 src/routes/instructions/invoke-custom.svelte rename src/routes/{ => instructions}/new-instance.svelte (99%) diff --git a/src/App.svelte b/src/App.svelte index 71e9074..69593b3 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -2,11 +2,15 @@ import { Router, Route } from "svelte-routing"; import Home from "./routes/Home.svelte"; import About from "./routes/about.svelte"; - import NewInstance from "./routes/new-instance.svelte"; + import Contents from "./routes/Contents.svelte"; import Days from "./routes/Days.svelte"; + import Instructions from "./routes/Instructions.svelte"; let days = Array.from({ length: 7 }, (_, i) => i + 1); + let instructions = ["invoke-custom", "new-instance"]; let loadComponent = (path) => () => import(`./routes/days/${path}.svelte`); + let loadComponentInstructions = (path) => () => + import(`./routes/instructions/${path}.svelte`); let url = ""; const dayTitles = { @@ -28,8 +32,9 @@ } else if (path.startsWith("/days/")) { const day = path.split("/").pop(); document.title = dayTitles[day] || `Day ${day} - Understand Smali`; - } else if (path === "/new-instance") { - document.title = "Instructions - new-instance"; + } else if (path.startsWith("/instructions/")) { + const instruction = path.split("/").pop(); + document.title = `Instructions - ${instruction}`; } else if (path === "/days") { document.title = "Days Overview - Understand Smali"; } else { @@ -46,8 +51,15 @@ {#each days as day} {/each} - + {#each instructions as instruction} + + {/each} + +

Not found

diff --git a/src/lib/Menu.svelte b/src/lib/Menu.svelte index dfd496f..ea14f0a 100644 --- a/src/lib/Menu.svelte +++ b/src/lib/Menu.svelte @@ -8,7 +8,7 @@ {#if open} -
+ {/if} diff --git a/src/routes/Days.svelte b/src/routes/Days.svelte index 5ad77c9..5023bb4 100644 --- a/src/routes/Days.svelte +++ b/src/routes/Days.svelte @@ -3,16 +3,15 @@
-

Table of Contents

+

Days

  • Day 1 - Introduction
  • Day 2 - Basics
  • Day 3 - Registers
  • Day 4 - Registers Conti...
  • Day 5 - Examples
  • Day 6 - CrackMe's
  • -
  • Instructions - new-instance
  • - +

    diff --git a/src/routes/Instructions.svelte b/src/routes/Instructions.svelte new file mode 100644 index 0000000..596d6a4 --- /dev/null +++ b/src/routes/Instructions.svelte @@ -0,0 +1,77 @@ + + +
    +

    Instructions

    +
  • new-instance
  • +
  • invoke-custom
  • +

    + + + +

    +
    + +
    + +
    + + diff --git a/src/routes/days/6.svelte b/src/routes/days/6.svelte index 2497a98..4cdd490 100644 --- a/src/routes/days/6.svelte +++ b/src/routes/days/6.svelte @@ -592,7 +592,7 @@ print( FlagGuard class. To Understand new-instance better you can read - new-instance i've made + new-instance i've made sure to use this same example to make it easier for you to understand.

    @@ -859,7 +859,7 @@ invoke-direct {`{v0}`}, Ljava/lang/StringBuilder;->()V" class object, which will be used to build the final unscrambled string. Again if you want to know about new-instance you can refer to - new-instance. + new-instance.

    + import { Hamburger } from "svelte-hamburgers"; + import Highlight, { LineNumbers } from "svelte-highlight"; + import java, { smali } from "svelte-highlight/languages/smali"; + import Menu from "../../lib/Menu.svelte"; + + import { FooterCopyright } from "flowbite-svelte"; + let prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches; + + if (prefersDark) { + import("svelte-highlight/styles/github-dark.css"); + } else { + import("svelte-highlight/styles/github.css"); + } + window + .matchMedia("(prefers-color-scheme: dark)") + .addEventListener("change", (event) => { + prefersDark = event.matches; + if (prefersDark) { + import("svelte-highlight/styles/github-dark.css"); + } else { + import("svelte-highlight/styles/github.css"); + } + }); + + const code = `invoke-custom {vC, vD, vE, vF, vG}, call_site@BBBB`; + const code_2 = `{ + bootstrap_method: VALUE_METHOD_HANDLE (e.g., LambdaMetafactory.metafactory), + method_name: VALUE_STRING (e.g., "isSplitMetaElement"), + method_type: VALUE_METHOD_TYPE (e.g., (Lcom/reandroid/arsc/chunk/xml/ResXmlElement;)Z) +}`; + const code_3 = `FilterIterator.of(manifest.recursiveElements(), ApkSplitInfoCleaner::isSplitMetaElement)`; + const code_4 = `invoke-custom {}, call_site_2("test", ()Ljava/util/function/Predicate;, (Ljava/lang/Object;)Z, invoke-static@Lcom/reandroid/apk/ApkSplitInfoCleaner;->isSplitMetaElement(Lcom/reandroid/arsc/chunk/xml/ResXmlElement;)Z, (Lcom/reandroid/arsc/chunk/xml/ResXmlElement;)Z)@Ljava/lang/invoke/LambdaMetafactory;->metafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;`; + + const codeStyle = `margin-bottom: 1rem; + padding: 5px; + border: 1px solid #ccc; + border-radius: 4px; + font-family: monospace;`; + + let open; + + +
    +
    + +
    + + + +
    +

    invoke-custom

    +

    + Starting from DEX version 038, the invoke-custom instruction + was introduced to enable flexible, dynamic invocation of methods. It plays + a crucial role in dynamic method handling, particularly useful for lambda + expressions and functional programming in Java and allows Dalvik VM to + dynamically call methods at runtime by referencing a "call + site", which points to specific runtime metadata defining the method + to be called. In simple terms, invoke-custom makes it + possible to execute methods that are not directly known or accessible at + compile time but are defined dynamically when the application runs. This + dynamic invocation mechanism aligns with Java's + java.lang.invoke API and provides key support for features like + lambda expressions. +

    +

    + Instruction Syntax and Structure +

    +

    Here’s a basic outline of the syntax:

    + +
      +
    • + {`{vC, vD, vE, vF, vG}`}: Registers containing arguments + passed to the invoked method. +
    • +
    • + call_site@BBBB: Reference to a "call site" in the + DEX file (identified by the index BBBB), which points to a + method and the metadata required for invocation. +
    • +
    +

    Each invoke-custom instruction has the following fields:

    +
      +
    • + Argument word count (4 bits): Specifies the number of + arguments for the method. +
    • +
    • + Call site reference index (16 bits): An index pointing + to the call_site_item in the DEX file, which contains all the + metadata for the invocation. +
    • +
    • + Argument registers: Up to five registers that hold the + method's arguments. +
    • +
    +

    + The Role of call_site_item +

    +

    + call_site_item is a special DEX structure used to hold metadata + about a call site. It's located in the DEX file's data section and + contains details about the method to be invoked, including the following: +

    +
      +
    1. + Bootstrap Method Handle: A reference to a + "bootstrap" method that sets up the call site. This method + typically belongs to classes like LambdaMetafactory in Java + and must return a java.lang.invoke.CallSite. +
    2. +
    3. + Method Name: A string representing the name of the + method to be resolved. +
    4. +
    5. + Method Type: A descriptor defining the method’s + argument and return types. +
    6. +
    +

    + This setup gives invoke-custom the information needed to invoke + a method dynamically. +

    +

    + Example of a call_site_item +

    +

    + Here’s what a typical call_site_item would look like conceptually: +

    + +

    + Additional arguments can also be included as constant values, passed to + the bootstrap method in order. +

    +

    + Execution Phases of invoke-custom +

    +

    + The invoke-custom instruction executes in two main phases: +

    +
      +
    1. +

      Call Site Resolution:

      +
        +
      • + The DEX interpreter checks if there’s an existing CallSite object for the specified call site. +
      • +
      • + If a CallSite doesn’t exist, the bootstrap method + specified in call_site_item is invoked with the + provided arguments. This bootstrap method returns a + CallSite object that represents the method to be called. +
      • +
      • + The CallSite object is cached for future calls to improve + performance. +
      • +
      +
    2. +
    3. +

      Call Site Invocation:

      +
        +
      • + After the CallSite is resolved, the + MethodHandle + within the CallSite is invoked. +
      • +
      • + This invocation works similarly to the invoke-polymorphic + instruction, where the arguments passed in the + invoke-custom instruction are used directly. +
      • +
      +
    4. +
    +

    + Practical Example: invoke-custom in Action +

    +

    + Consider this Java code in the ApkSplitInfoCleaner + class: +

    + +

    + In bytecode, this invocation of isSplitMetaElement as a + lambda will be compiled into an invoke-custom call, where the + DEX file contains a call_site_item that references + LambdaMetafactory.metafactory to create a lambda expression. +

    +

    Bytecode Example

    +

    Here’s what this might look like in Dalvik bytecode:

    + +

    This example showcases the following:

    +
      +
    1. + call_site_2 defines the arguments for the + LambdaMetafactory.metafactory bootstrap method. +
    2. +
    3. + The bootstrap method generates a CallSite instance, + enabling the isSplitMetaElement method to be invoked as a lambda + expression matching a functional interface. +
    4. +
    +

    invoke-polymorphic

    +

    + invoke-polymorphic is another bytecode instruction (Also + introduced starting from DEX version 038 onwards) similar to + invoke-custom, but it's specifically used for invoking + MethodHandle + methods like invoke or invokeExact. While + invoke-custom + is for more general dynamic invocation, invoke-polymorphic is + restricted to methods directly supporting polymorphic invocation in + MethodHandle. +

    + +

    References

    + +
    + + +
    +
    + + + + + + + + + + diff --git a/src/routes/new-instance.svelte b/src/routes/instructions/new-instance.svelte similarity index 99% rename from src/routes/new-instance.svelte rename to src/routes/instructions/new-instance.svelte index d5916f4..0583058 100644 --- a/src/routes/new-instance.svelte +++ b/src/routes/instructions/new-instance.svelte @@ -2,7 +2,7 @@ import { Hamburger } from "svelte-hamburgers"; import Highlight, { LineNumbers } from "svelte-highlight"; import java, { smali } from "svelte-highlight/languages/smali"; - import Menu from "../lib/Menu.svelte"; + import Menu from "../../lib/Menu.svelte"; import { FooterCopyright } from "flowbite-svelte"; let prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;