implementing an inaccessible class and calling illegal methods.

just in case you really really really want to call a private methods with an argument of a private class which is inaccessible, like … :

i was looking on [icode]Throwable.printStackTrace(PrintStream s)[/icode] and found that there is a much lighter method next to it

[icode]private void printStackTrace(PrintStreamOrWriter s)[/icode], fair enough. to access it we can use reflections :


final Class<?> throwableClazz           = Class.forName("java.lang.Throwable");
final Class<?> printStreamOrWriterClazz = Class.forName("java.lang.Throwable$PrintStreamOrWriter");
final Method   printStackTraceMethod    = throwableClazz.getDeclaredMethod("printStackTrace",printStreamOrWriterClazz);
printStackTraceMethod.setAccessible(true);

now we cannot invoke [icode]printStackTraceMethod[/icode] cos’ the argument needs to be a [icode]PrintStreamOrWriter[/icode] object which looks like this :

private abstract static class PrintStreamOrWriter
{
  abstract Object lock();
  abstract void println(Object o);
}

afaik, there is no way to implement it. a private abstract (inner) class. but it’s just what is required for [icode]Throwable.printStackTrace()[/icode], not a clumsy [icode]PrintStream[/icode]!.

so we can just write something that looks similar, no [icode]extends[/icode] or [icode]implements[/icode], just a simple class but its methods match (mostly) the signatures/modifiers of [icode]PrintStreamOrWriter[/icode], even if that is abstract :

class MyPrintStreamOrWriter
{
  public final StringBuilder str;

  public MyPrintStreamOrWriter(final StringBuilder str) { this.str = str; }

  public Object lock() { return str; }
  public void println(final Object o) { str.append(o.toString()).append('\n'); }
}

obviously that will not work :

final Error                 someError = new Error(new RuntimeException());
final StringBuilder         str       = new StringBuilder(32);
final MyPrintStreamOrWriter wrapper   = new MyPrintStreamOrWriter(str);

printStackTraceMethod.invoke(someError,wrapper);

= java.lang.IllegalArgumentException: argument type mismatch

to make that work we can use sun.misc.Unsafe to make [icode]MyPrintStreamOrWriter[/icode] castable to [icode]PrintStreamOrWriter[/icode].

thanks to Serkan Özal who wrote down all the offsets required for that (http://zeroturnaround.com/rebellabs/dangerous-code-how-to-be-unsafe-with-java-classes-objects-in-memory/4/) :


private final static sun.misc.Unsafe unsafe = [...] // if you do not know how to obtain unsafe you should not use it :P

public static void makeCastable(final Class<?> from,final Class<?> to)
{
  final long pt_from = getPointer(from);
  final long pt_to   = getPointer(to);

  switch(Unsafe.ADDRESS_SIZE)
  {
    case 4 :
      unsafe.putAddress(pt_from + 32 + 4, pt_to); // write to "primary supers" array index 1
      break;
    case 8 :
      unsafe.putAddress(pt_from + 56 + 8, pt_to);
      break;
    default :
      throw new IllegalStateException();
  }
}

private final static boolean compressedOOPS = Unsafe.ADDRESS_SIZE == 8 && Unsafe.ARRAY_OBJECT_INDEX_SCALE == 4;

public static long getPointer(final Class<?> o)
{
  switch(Unsafe.ADDRESS_SIZE)
  {
    case 4 :
      return unsafe.getInt(o,80L);
    case 8 :
      if(compressedOOPS)
        return int2ulong(unsafe.getInt(o,84L));
      else
        return unsafe.getLong(o,160L);
    default :
      throw new IllegalStateException();
  }
}

public static long int2ulong(final int x)
{
  if(x >= 0) return x;
  return( ~0L>>>32 ) & x;
}


using this :


makeCastable(MyPrintStreamOrWriter.class, printStreamOrWriterClazz);

final Error                 someError = new Error(new RuntimeException());
final StringBuilder         str       = new StringBuilder(32);
final MyPrintStreamOrWriter wrapper   = new MyPrintStreamOrWriter(str);

printStackTraceMethod.invoke(someError,wrapper);

final String stackTraceString = str.toString();

actually works even if illegal and prints into str as desired.

\o/

  • create a class which looks like another class you cannot implement
  • use unsafe to make it castable to that class, even if illegal
  • use reflections to invoke methods as usual
  • win

In HotSpot you know you’re on 64-bit hardware if:

[icode]public static final boolean is64Bit = Unsafe.ADDRESS_SIZE == 8[/icode]

and this tells you the size of a pointer (well an OOP) :

[icode]public static final boolean is64BitPointer = Unsafe.ARRAY_OBJECT_INDEX_SCALE == 8[/icode]

Another (hotspot) only solution is to have a helper class that extends [icode]sun.reflect.MagicAccessorImpl[/icode]. That class can perform all kinds of illegal functionality (the verifier will not be run on it).

thanks Roquen, edited it in.

Serkan will be happy to be named here :wink: I’ll tell him (a colleague of mine :-))

I don’t want to be too much if a party pooper here, disregarding all that evil hackery, but it seems like you started off with the issue that you wanted to stuff your Exception in a String.


StringWriter sw = new StringWriter();
exc.printStackTrace(new PrintWriter(sw));
String dump = sw.toString();

Seems pretty straightforward to me.

Having said that, nice hack!

That’s not exactly true, I guess you found out about that somewhere from code I posted :wink: The verifier won’t run if you inject that class into the system classloader but normal classloaders do test it (btw it needs to be injected anyways because you have to subclass ;-)).

The verifier will still verify the class under normal condition, therefore you have to generate legal bytecode but since you inject into the system classloader there is no verifier activated (for speed reasons). I can proof that using other tricks :wink: The real deal here is to create a class which has no security checks!

@Riven : dont worry :slight_smile: i’m aware of that.

it was more a “i ll try that again” after getting annoyed by the defensive and bloated code style of java. i think it’s an simple example, easy to understand and to apply (if you really really really want to access private things) somewhere else.

You should generate those classes at runtime and use Unsafe::defineAnnonymousClass and give them an enclosing class. The newly created class acts as an inner class then and has full access to all other kinds of members of the enclosing class :slight_smile:

that sounds like something i would try when running into java.nio.Bits again. thanks for the hint.

I know about it from one of the JDK mailing lists…what’s the code you posted somewhere? By “not exactly true” I’m assuming you mean I didn’t provide all the details. There are a fair number of options for doing this kind of thing. Another is:


// system ClassLoader and ProtectionDomain: go go evil!
// name = full qual. name, b = byte array of illegal def
unsafe.defineClass(name, b, 0, b.length, null, null);

Thank you very much for this information! I just tried it with ASM 5.0.4 and JDK 1.8.0_45. Generating a class with the appropriate inner class statement. However, that inner class tag does not seem to have any effect. (this might also be the reason why javac generates those package-private “accessor” bridge methods when an inner class accesses an outer class’es private members.)
What had an effect was which “host class” was chosen for “defineAnonymousClass”.
Your solution works perfectly well if the host class is set to the outer class (i.e. the class one wants to access its private members). Then, and only then apparently, does the defined class have access to private members.
Your solution is a perfect solution for serialization frameworks, or any other frameworks that rely on reflectivity.

EDIT: This (http://pastebin.java-gaming.org/3da9f450d301d) is a small working example illustrating it. Tested on JRE1.7.0_55 and JRE1.8.0_45.