Background: I'm injecting the Minecraft Launcher to obtain the applet (which I've done), but now I wish to load minecraft's file through my class loader. I found the method which GameUpdater.java (Minecraft's gameupdater, also dispatcher for the client's applet), and under which has a method called "createApplet".
GameUpdater.java:
public Applet createApplet() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class localClass = classLoader.loadClass("net.minecraft.client.MinecraftApplet");
return (Applet)localClass.newInstance();
}
Okay, well simple enough, replace classLoader.loadClass with your own static load method. So, I tried, in my classloader, here is my transformation code:
for(Method method : generator.getMethods()) {
if(method.getName().equals("createApplet")) {
ConstantPoolGen cpg = generator.getConstantPool();
MethodGen methodGen = new MethodGen(method, generator.getClassName(), cpg);
Instruction instruction = null;
InstructionList instructionList = methodGen.getInstructionList();
InstructionHandle[] instructionHandles = instructionList.getInstructionHandles();
for(int i = 0; i < instructionHandles.length; i++) {
//System.out.println(instructionHandles[i].getInstruction()); //debug
if(instructionHandles[i].getInstruction() instanceof LDC) {
instruction = instructionHandles[i].getInstruction();
InstructionFactory instructionFactory = new InstructionFactory(generator, cpg);
InvokeInstruction classLoaderCall =
instructionFactory.createInvoke(
"MinecraftLauncher", "loadClass", Type.CLASS, new Type[]{Type.STRING},Constants.INVOKESTATIC);
instructionList.insert(instruction, classLoaderCall);
methodGen.setInstructionList(instructionList);
instructionList.setPositions();
methodGen.setMaxStack();
methodGen.setMaxLocals();
methodGen.removeLineNumbers();
generator.replaceMethod(method, methodGen.getMethod());
generator.getJavaClass().dump("gameupdater.class");
}
}
}
Yet, I fell on my face. Here is the updated gameupdater.class (as you see above, I dump it)
public Applet createApplet() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class localClass = MinecraftLauncher.loadClass(classLoader).loadClass("net.minecraft.client.MinecraftApplet");
return (Applet)localClass.newInstance();
}
Here is a picture of the bytecode for the method createApplet in GameUpdater
Now, I have no other idea how else to do this. If someone could point me into the right direction, that would be awesome! In the mean time, I'm going to keep trying, and reading the bcel doc.
If you have any questions regarding more code, etc, please tell me.
Solved. The trick is to delete the InvokerVirtual (delete the OPCODE from the instruction list) after adding your new one(your static method replacing the load function).
Example
instructionList.insert(instruction, classLoaderCall);
instructionList.delete(instruction);
Related
I've included my code below. Following some other examples, I even tried to dynamically load the class in order to force it to run the static block, but that doesn't solve my problem. The class is loaded and class.getName() is printed successfully, but still, when it gets to the last line in the main method it throws an error saying the array is null.
All the other answers address things which don't seem to apply here, like how using the "final" keyword can allow the compiler to skip static blocks. Any help is appreciated!
package helper;
public class StaticTest {
public static boolean [] ALL_TRUE;
private static void setArray(){
ALL_TRUE = new boolean[8];
for(int i=0;i<ALL_TRUE.length;i++){
ALL_TRUE[i] = true;
}
}
static {
setArray();
}
public static void main(String [] args){
ClassLoader cLoader = StaticTest.class.getClassLoader();
try{
Class aClass = cLoader.loadClass("helper.StaticTest");
System.out.println("aClass.getName() = " + aClass.getName());
} catch(ClassNotFoundException e){
e.printStackTrace(System.out);
}
System.out.println(StaticTest.ALL_TRUE[0]);
}
}
In case anyone else lands here, the problem was that I had checked the Netbeans option "Compile on Save" (under Build->Compiling). Somehow, compiling files immediately upon saving was preventing the static block from being run.
Again, thanks to everyone who chimed in to verify that the code itself worked as expected.
I'm trying to work with this enum and add new materials.
Anything not already removed has hard dependencies elsewhere, even still, this is nearly at the java byte limit according to the mods author so there isn't really a lot of room to work with anyway.
GregoriousT mentioned "There is one way. Overmind hacked the Enum using Reflection to add his own stuff. No Idea how he did that and also no idea how long he takes to reply to things if you ask him."
Enum we're talking about:
http://pastebin.com/g0aJ2Qjd
So I simply ask, how would I go about this?
This is what my current attempt throws [FML]: Variable m:1|newInstance|public java.lang.Object sun.reflect.DelegatingConstructorAccessorImpl.newInstance(java.lang.Object[]) throws java.lang.InstantiationException,java.lang.IllegalArgumentException,java.lang.reflect.InvocationTargetException|false
before the client crashes. (Log code removed for easy reading)
Current attempt:
public class MaterialsNew {
public static void getGregMaterials() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, SecurityException{
Utils.LOG_WARNING("Stepping through the process of Greg's materials.");
Constructor<?> con = Materials.class.getDeclaredConstructors()[0];
java.lang.reflect.Method[] methods = con.getClass().getDeclaredMethods();
for (java.lang.reflect.Method m1 : methods) {
if (m1.getName().equals("acquireConstructorAccessor")) {
m1.setAccessible(true);
m1.invoke(con, new Object[0]);}
}
Field[] fields = con.getClass().getDeclaredFields();
Object ca = null;
for (Field f : fields) {
if (f.getName().equals("constructorAccessor")) {
f.setAccessible(true);
ca = f.get(con);
}
}
Method m = ca.getClass().getMethod( "newInstance", new Class[] { Object[].class });
m.setAccessible(true);
Materials v = (Materials) m.invoke(ca, new Object[] { new Object[] { "NEWMATERIAL", Integer.MAX_VALUE } });
System.out.println(v.getClass() + ":" + v.name() + ":" + v.ordinal());}}
Any help or suggestions appreciated, they guys over at the Forge IRC weren't really sure either.
JVMs are supposed to prevent such sneaky enum instance creations. So you have to either use a flaw that soon might get solved or hack such deep into the JRE that the slightest change may break it.
Here is a trick which works with Oracle’s current JRE 8, perhaps JRE 7 as well, and is surprisingly simple:
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor;
import java.util.EnumSet;
public class EnumHack {
public static void main(String[] args) throws Throwable {
Constructor<Thread.State> c
= Thread.State.class.getDeclaredConstructor(String.class, int.class);
c.setAccessible(true);
MethodHandle h=MethodHandles.lookup().unreflectConstructor(c);
Thread.State state=(Thread.State)h.invokeExact("FLYING", 42);
System.out.println("created Thread.State "+state+"("+state.ordinal()+')');
System.out.println(EnumSet.allOf(Thread.State.class).contains(state));
}
}
But don’t expect this solution to persist…
I am trying to follow a piece of code to open and read a text file. To do this I have a package called readText. Within I build a class readLocalFile to open and read the file, and a main method to call it. Below are these two classes.
public class readFileLocal {
private String path;
public readFileLocal(String file_path){
path = file_path;
}
int readLines() throws IOException{
FileReader file_to_read = new FileReader(path);
BufferedReader lines = new BufferedReader (file_to_read);
int numberOfLines = 0;
while(lines.readLine()!= null) {
numberOfLines ++;
}
lines.close();
return numberOfLines;
}
public String[] openFile() throws IOException{
FileReader freader = new FileReader (path);
BufferedReader textReader = new BufferedReader (freader);
int numberOfLines = readLines();
String[] textData = new String[numberOfLines];
int i; /* put all the lines of text from the file to the array*/
for (i=0; i<numberOfLines; i++){
textData[i] = textReader.readLine();
}
textReader.close();
return textData;
}
}
Then I have a main class to call it. The code is below:
public class fileData {
public static void main(String[] args) throws IOException{
String file_name = "F:/Testfile.exl";
try{
readFileLocal file = new readFileLocal(file_name);
String[] arylines = file.openFile();
int i;
for (i=0; i<arylines.length; i++){
System.out.println(arylines[i]);
}
}
catch(IOException e) {
System.out.println(e.getMessage());
}
}
}
When I ran it, Eclipse gave me this error message:
Error: Main method not found in class readText.fileData, please define the main method as:public static void main(String[] args) or a JavaFX application class must extend javafx.application.Application
Any idea what went wrong?
You probably should start a new project. Eclipse thinks that you are running a JavaFX program (in which case filedata should extend Application).
Just do a normal build without JavaFX.
Probably, you have declared your own String class in the same package. In this case Eclipse doesn't recognize expected java.lang.String in your main method. Edit your main method declaration as
public static void main(java.lang.String[] args)
and try to run it.
I loaded your code into my copy of Eclipse and it ran the main method without a problem. One curious thing, when I saved the file, I got a message about characters being encoded as "Cp1252" encoding rather than the expected UTF-8. I cut and paste your code into Eclipse from StackOverflow. Maybe this has something to do with the problem?
In Eclipse, you can check what is going on by selecting
Run > Run Configurations...
The "Main" tab will display what Eclipse thinks is the main method to be invoked, and other tabs will show if there are any arguments being sent in.
Also, it might be worth running
Project > Clean
for you project.
Crazy thing to check: are there any other classes with the same name?
Do you have more than one class defined on the same class document?
Another thing to check, navigate to the class document, "fileData" (really should be FileData, follow conventions because otherwise it adds to everyone's confusion who is trying to help or work with you), and right click. Does the right click give you the following?
Run As > 1) Java Application
Or does it show this?
Run As > Run Configurations...
The first case indicates it found the main method, in the second case, no main method was found.
The stuff about JavaFX can be ignored. You aren't running JavaFX according to any code I see displayed, so that issue is moot.
BTW, in your main method, you catch IOException in the try/catch, so there is no need to include "throws IOException" in the main method.
I'm pretty new to groovy, and scripting in java generally, and I really
hope there is a simple solution for my problem.
In our application, the users can execute groovy scripts which they write
themselves, and we need to control what those scripts can and can not do.
I read a lot of stuff about sandboxing groovy, but either I am looking at
wrong places or I am overlooking the obvious.
To make it simple, I have a small example which demonstrates the problem.
This is my class loader which should prevent java.lang.System from being
loaded and available to scripts:
public class MyClassLoader extends ClassLoader {
#Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name.startsWith("java.lang.System")) {
throw new ClassNotFoundException("Class not found: " + name);
}
return super.loadClass(name);
}
}
And this is a simple program that tries to call System.currentTimeMillis():
public static void main(String[] args) {
String code = "java.lang.System.currentTimeMillis();";
ClassLoader classLoader = new MyClassLoader();
Thread.currentThread().setContextClassLoader(classLoader);
GroovyShell shell = new GroovyShell();
Script script = shell.parse(code);
Object result = script.run();
log.debug(result);
}
MyClassLoader throws exceptions for java.lang.SystemBeanInfo
and java.lang.SystemCustomizer, but the code executes.
Same thing happens if I use javax.script classes:
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("Groovy");
Object o = engine.eval(code);
log.debug(o);
And if I try it with JavaScript engine, it works as expected (just replace
"Groovy" with "JavaScript" in the above example).
Can anyone help me with this? BTW, I'm using groovy-all-1.8.8.jar, with
jdk1.7.0_55.
Thanks
I can recommend Groovy Sandbox for this purpose. In contrast to SecureASTCustomizer it will check if an execution is allowed dynamically at runtime. It intercepts every method call, object allocations, property/attribute access, array access, and so on - and you thus have a very fine grained control on what you allow (white-listing).
Naturally the configuration on what is allowed is very important. For example you may want to allow using Strings and use methods like substring, but probably not the execute method on String, which could be exploited with something like 'rm -R ~/*'.execute().
Creating a configuration that is really safe is a challenge, and it is more difficult the more you allow.
Downside of the Groovy Sandbox is that the code must run with the interceptor registered and you will have a performance penalty during execution.
This image [1] shows an example from a project where we used Groovy Sandbox for Groovy code entered by the user. The code is run to valide the script - so if the statement there would actually be executed as part of it, the application would have exited before I could do the screenshot ;)
Perhaps you'd be interested in using a SecureASTCustomizer in conjunction with a CompilerConfiguration. If you are concerned with security, an explicit white list might be better than a black list.
def s = new SecureASTCustomizer()
s.importsWhiteList = [ 'a.legal.Klass', 'other.legal.Klass' ]
def c = new CompilerConfiguration()
c.addCompilationCustomizers(s)
def sh = new GroovyShell(c)
Take a look at that class, it contains a lot of options that are ready to use.
import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyShell;
import groovy.lang.Script;
public class SandboxGroovyClassLoader extends ClassLoader {
public SandboxGroovyClassLoader(ClassLoader parent) {
super(parent);
}
#Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name.startsWith("java.lang.System"))
return null;
return super.loadClass(name);
}
#Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
if (name.startsWith("java.lang.System"))
return null;
return super.loadClass(name, resolve);
}
static void runWithGroovyClassLoader() throws Exception {
System.out.println("Begin runWithGroovyClassLoader");
String code = "def hello_world() { java.lang.System.currentTimeMillis(); };";
GroovyClassLoader groovyClassLoader = new GroovyClassLoader();
Class<?> scriptClass = groovyClassLoader.parseClass(code);
Object scriptInstance = scriptClass.newInstance();
Object result = scriptClass.getDeclaredMethod("hello_world", new Class[] {}).invoke(scriptInstance, new Object[] {});
System.out.println(result);
groovyClassLoader.close();
System.out.println("End runWithGroovyClassLoader");
}
static void runWithSandboxGroovyClassLoader() throws Exception {
System.out.println("Begin runWithSandboxGroovyClassLoader");
ClassLoader parentClassLoader = SandboxGroovyClassLoader.class.getClassLoader();
SandboxGroovyClassLoader classLoader = new SandboxGroovyClassLoader(parentClassLoader);
String code = "def hello_world() { java.lang.System.currentTimeMillis(); };";
GroovyClassLoader groovyClassLoader = new GroovyClassLoader(classLoader);
Class<?> scriptClass = groovyClassLoader.parseClass(code);
Object scriptInstance = scriptClass.newInstance();
Object result = scriptClass.getDeclaredMethod("hello_world", new Class[] {}).invoke(scriptInstance, new Object[] {});
System.out.println(result);
groovyClassLoader.close();
System.out.println("End runWithSandboxGroovyClassLoader");
}
static void runWithSandboxGroovyShellClassLoader() throws Exception {
System.out.println("Begin runWithSandboxGroovyShellClassLoader");
String code = "java.lang.System.currentTimeMillis();";
ClassLoader parentClassLoader = SandboxGroovyClassLoader.class.getClassLoader();
SandboxGroovyClassLoader classLoader = new SandboxGroovyClassLoader(parentClassLoader);
Thread.currentThread().setContextClassLoader(classLoader);
GroovyShell shell = new GroovyShell();
Script script = shell.parse(code);
Object result = script.run();
System.out.println(result);
System.out.println("End runWithSandboxGroovyShellClassLoader");
}
public static void main(String[] args) throws Exception {
runWithGroovyClassLoader();
runWithSandboxGroovyClassLoader();
runWithSandboxGroovyShellClassLoader();
}
}
Is it what you want ?
I have Java-related question:
I want to know is there a way to create path to class (in program) by using a variable(s).
Im making a program that will download pictures from certain sites and show them to a user. However, different sites have different forms, that's why I have to define a series of functions specific to each. They cannot be put in the same class because functions that preform same job (just for another site) would have to have same names. I'm trying to make adding support for another site later as simple as possible.
Anyway, the question is, could I call a function in program using a variable to determine its location.
For example: code.picturesite.functionINeed();
code is the package containing all of the coding, and picturesite is not a class but rather a variable containing the name of the desired class - that way I can only change value of the variable to call a different function (or the same function in a different class).
I don't really expect that to be possible (this was more for you to understand the nature of the problem), but is there another way to do what I'm trying to achieve here?
Yes, there is a way. It's called reflection.
Given a String containing the class name, you can get an instance like this:
Class<?> c = Class.forName("com.foo.SomeClass");
Object o = c.newInstance(); // assuming there's a default constructor
If there isn't a default constructor, you can get a reference to one via c.getConstructor(param1.getClass(), param2.getClass(), etc)
Given a String containing the method name and an instance, you can invoke that method like this:
Method m = o.getClass().getMethod("someMethod", param1.getClass(), param2.getClass(), etc);
Object result = m.invoke(o, param1, param2, etc);
I'm not immediately seeing anything in your question that couldn't be solved by, instead of having a variable containing a class name, having a variable containing an instance of that class -- to call a function on the class, you would have to know it implements that function, so you could put the function in an interface.
interface SiteThatCanFoo {
void foo();
}
And
class SiteA extends Site implements SiteThatCanFoo {
public void foo() {
System.out.println("Foo");
}
}
Then:
Site currentSite = getCurrentSite(); // or getSiteObjectForName(siteName), or similar
if (SiteThatCanFoo.isAssignableFrom(currentSite.class)) {
((SiteThatCanFoo)currentSite).foo();
}
So you want to do something like this (check ImageDownloader.getImageFrom method)
class SiteADownloader {
public static Image getImage(URI uri) {
System.out.println("invoking SiteADownloader on "+uri);
Image i = null;
// logic for dowlnoading image from siteA
return i;
}
}
class SiteBDownloader {
public static Image getImage(URI uri) {
System.out.println("invoking SiteBDownloader on "+uri);
Image i = null;
// logic for dowlnoading image from siteB
return i;
}
}
// MAIN CLASS
class ImageDownloader {
public static Image getImageFrom(String serverName, URI uri) {
Image i = null;
try {
// load class
Class<?> c = Class.forName(serverName + "Downloader");
// find method to dowload img
Method m = c.getDeclaredMethod("getImage", URI.class);
// invoke method and store result (method should be invoked on
// object, in case of static methods they are invoked on class
// object stored earlier in c reference
i = (Image) m.invoke(c, uri);
} catch (NoSuchMethodException | SecurityException
| IllegalAccessException | IllegalArgumentException
| InvocationTargetException | ClassNotFoundException e) {
e.printStackTrace();
}
return i;
}
// time for test
public static void main(String[] args) {
try {
Image img = ImageDownloader.getImageFrom("SiteB", new URI(
"adress"));
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
}