/*
* Copyright ( C ) 2016 The Android Open Source Project
*
* Licensed under the Apache License , Version 2 . 0 ( the " License " ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an " AS IS " BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
*/
package art;
import java.lang.reflect.*;
import java.util.Base64;
import java.nio.ByteBuffer;
public class Test1949 {
private final static boolean isDalvik = System.getProperty("java.vm.name" ).equals("Dalvik" );
// This dex file is specifically crafted to have exactly 4 methodIDs in it. They are (in order):
// (0) Ljava/lang/Object;-><init>()V
// (1) Lxyz/Transform;-><init>()V
// (2) Lxyz/Transform;->bar()V
// (3) Lxyz/Transform;->foo()V
//
// In the transformed version of the dex file there is a new method. The new list of methodIDs is:
// (0) Lart/Test1949;->doNothing()V
// (1) Ljava/lang/Object;-><init>()V
// (2) Lxyz/Transform;-><init>()V
// (3) Lxyz/Transform;->bar()V
// (4) Lxyz/Transform;->foo()V
//
// This test tries to get the JIT to read out-of-bounds on the initial dex file by getting it to
// read the 5th method id of the new file (Lxyz/Transform;->foo()V) from the old dex file (which
// only has 4 method ids).
//
// To do this we need to make sure that the class being transformed is near the end of the
// alphabet (package xyz, method foo). If it is further forward than the other method-ids then the
// JIT will read an incorrect (but valid) method-id from the old-dex file. This is why the error
// wasn't caught in our other tests (package art is always at the front).
//
// The final method that causes the OOB read needs to be a native method because that is the only
// method-type the jit uses dex-file information to keep track of.
/**
* base64 encoded class / dex file for
* package xyz ;
* public class Transform {
* public native void foo ( ) ;
* public void bar ( ) { }
* }
*/
private static final byte [] CLASS_BYTES_INIT = Base64.getDecoder().decode(
"yv66vgAAADUADwoAAwAMBwANBwAOAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJU" +
"YWJsZQEAA2ZvbwEAA2JhcgEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwABAAFAQANeHl6" +
"L1RyYW5zZm9ybQEAEGphdmEvbGFuZy9PYmplY3QAIQACAAMAAAAAAAMAAQAEAAUAAQAGAAAAHQAB" +
"AAEAAAAFKrcAAbEAAAABAAcAAAAGAAEAAAACAQEACAAFAAAAAQAJAAUAAQAGAAAAGQAAAAEAAAAB" +
"sQAAAAEABwAAAAYAAQAAAAQAAQAKAAAAAgAL" );
private static final byte [] DEX_BYTES_INIT = Base64.getDecoder().decode(
"ZGV4CjAzNQBDUutFJpeT+okk+aXah8NQ61q2XRtkmChwAgAAcAAAAHhWNBIAAAAAAAAAANwBAAAI" +
"AAAAcAAAAAMAAACQAAAAAQAAAJwAAAAAAAAAAAAAAAQAAACoAAAAAQAAAMgAAACIAQAA6AAAABwB" +
"AAAkAQAAOAEAAEkBAABZAQAAXAEAAGEBAABmAQAAAQAAAAIAAAAEAAAABAAAAAIAAAAAAAAAAAAA" +
"AAAAAAABAAAAAAAAAAEAAAAFAAAAAQAAAAYAAAABAAAAAQAAAAAAAAAAAAAAAwAAAAAAAADDAQAA" +
"AAAAAAEAAQABAAAAEgEAAAQAAABwEAAAAAAOAAEAAQAAAAAAFgEAAAEAAAAOAAIADgAEAA4AAAAG" +
"PGluaXQ+ABJMamF2YS9sYW5nL09iamVjdDsAD0x4eXovVHJhbnNmb3JtOwAOVHJhbnNmb3JtLmph" +
"dmEAAVYAA2JhcgADZm9vAFt+fkQ4eyJtaW4tYXBpIjoxLCJzaGEtMSI6IjkwZWYyMjkwNWMzZmVj" +
"Y2FiMjMwMzBhNmJkYzU2NTcwYTMzNWVmMDUiLCJ2ZXJzaW9uIjoidjEuMS44LWRldiJ9AAAAAQIB" +
"gYAE6AECAYACAYECAAAAAAAAAAAMAAAAAAAAAAEAAAAAAAAAAQAAAAgAAABwAAAAAgAAAAMAAACQ" +
"AAAAAwAAAAEAAACcAAAABQAAAAQAAACoAAAABgAAAAEAAADIAAAAASAAAAIAAADoAAAAAyAAAAIA" +
"AAASAQAAAiAAAAgAAAAcAQAAACAAAAEAAADDAQAAAxAAAAEAAADYAQAAABAAAAEAAADcAQAA" );
/**
* base64 encoded class / dex file for
* package xyz ;
* public class Transform {
* public native void foo ( ) ;
* public void bar ( ) {
* // Make sure the methodID is before any of the ones in Transform
* art . Test1949 . doNothing ( ) ;
* }
* }
*/
private static final byte [] CLASS_BYTES_FINAL = Base64.getDecoder().decode(
"yv66vgAAADUAFAoABAANCgAOAA8HABAHABEBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51" +
"bWJlclRhYmxlAQADZm9vAQADYmFyAQAKU291cmNlRmlsZQEADlRyYW5zZm9ybS5qYXZhDAAFAAYH" +
"ABIMABMABgEADXh5ei9UcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2JqZWN0AQAMYXJ0L1Rlc3QxOTQ5" +
"AQAJZG9Ob3RoaW5nACEAAwAEAAAAAAADAAEABQAGAAEABwAAAB0AAQABAAAABSq3AAGxAAAAAQAI" +
"AAAABgABAAAAAgEBAAkABgAAAAEACgAGAAEABwAAABwAAAABAAAABLgAArEAAAABAAgAAAAGAAEA" +
"AAAEAAEACwAAAAIADA==" );
private static final byte [] DEX_BYTES_FINAL = Base64.getDecoder().decode(
"ZGV4CjAzNQBHXBiw7Hso1vnmaXE1VCV41f4+0aECixOgAgAAcAAAAHhWNBIAAAAAAAAAAAwCAAAK" +
"AAAAcAAAAAQAAACYAAAAAQAAAKgAAAAAAAAAAAAAAAUAAAC0AAAAAQAAANwAAACkAQAA/AAAADQB" +
"AAA8AQAATAEAAGABAABxAQAAgQEAAIQBAACJAQAAlAEAAJkBAAABAAAAAgAAAAMAAAAFAAAABQAA" +
"AAMAAAAAAAAAAAAAAAcAAAABAAAAAAAAAAIAAAAAAAAAAgAAAAYAAAACAAAACAAAAAIAAAABAAAA" +
"AQAAAAAAAAAEAAAAAAAAAPYBAAAAAAAAAQABAAEAAAAsAQAABAAAAHAQAQAAAA4AAQABAAAAAAAw" +
"AQAABAAAAHEAAAAAAA4AAgAOAAQADgAGPGluaXQ+AA5MYXJ0L1Rlc3QxOTQ5OwASTGphdmEvbGFu" +
"Zy9PYmplY3Q7AA9MeHl6L1RyYW5zZm9ybTsADlRyYW5zZm9ybS5qYXZhAAFWAANiYXIACWRvTm90" +
"aGluZwADZm9vAFt+fkQ4eyJtaW4tYXBpIjoxLCJzaGEtMSI6IjkwZWYyMjkwNWMzZmVjY2FiMjMw" +
"MzBhNmJkYzU2NTcwYTMzNWVmMDUiLCJ2ZXJzaW9uIjoidjEuMS44LWRldiJ9AAAAAQICgYAE/AED" +
"AZQCAYECAAAAAAAMAAAAAAAAAAEAAAAAAAAAAQAAAAoAAABwAAAAAgAAAAQAAACYAAAAAwAAAAEA" +
"AACoAAAABQAAAAUAAAC0AAAABgAAAAEAAADcAAAAASAAAAIAAAD8AAAAAyAAAAIAAAAsAQAAAiAA" +
"AAoAAAA0AQAAACAAAAEAAAD2AQAAAxAAAAEAAAAIAgAAABAAAAEAAAAMAgAA" );
public static void run() throws Exception {
Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE);
doTest();
}
// A method with a methodID before anything in Transform.
public static void doNothing() {}
private static ClassLoader CreateClassLoader(byte [] clz, byte [] dex) throws Exception {
if (isDalvik) {
Class <?> class_loader_class = Class .forName("dalvik.system.InMemoryDexClassLoader" );
Constructor<?> ctor = class_loader_class.getConstructor(ByteBuffer.class , ClassLoader.class );
/* on Dalvik, this is a DexFile; otherwise, it's null */
return (ClassLoader)ctor.newInstance(ByteBuffer.wrap(dex), Test1949.class .getClassLoader());
} else {
return new ClassLoader() {
public Class <?> findClass(String name) throws ClassNotFoundException {
if (name.equals("xyz.Transform" )) {
return defineClass(name, clz, 0 , clz.length);
} else {
throw new ClassNotFoundException("Couldn't find class: " + name);
}
}
};
}
}
public static void doTest() throws Exception {
Class c = CreateClassLoader(CLASS_BYTES_INIT, DEX_BYTES_INIT).loadClass("xyz.Transform" );
Redefinition.doCommonClassRedefinition(c, CLASS_BYTES_FINAL, DEX_BYTES_FINAL);
System.out.println("Passed" );
}
}
Messung V0.5 in Prozent C=91 H=92 G=91
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet am 2026-06-29)
¤
*© Formatika GbR, Deutschland