Recently I've had some problems with people cheating using an app for root users called Gamecih. Gamecih let's users pause games and change variables in runtime.
If I obfuscate my code I though it'll be hard for cheaters to know what variables to change in runtime, but I'm also worried it might cause some other problems.
I serialize game objects using Javas Serializable interface and then write them out to a file. Now let's say I'm serializing an object of the class "Player". It gets serialized and saved to a file. Then a user downloads the update with the Proguard implementation. Proguard will rename classes and class member names. Won't that cause major errors when trying to read in an already saved Player object?
If I had not yet launched my game, this wouldn't be a problem. But now some players are playing on the same saved game(it's an RPG) for months. They would be pretty pissed off if they downloaded an update and had to start over from scratch.
I know I can instruct Proguard not to obfuscate certain classes, but it's the Player class I really need to obfuscate.
Clarification: Let's say I have the following simple unobfuscated class:
public class Player {
private int gold;
private String name;
//Lots more.
public Player(String name)
{
this.name = name;
}
public int getGold() {
return gold;
}
public void setGold(int gold) {
this.gold = gold;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
A player is created, serialized and saved to a file. After I implement obfuscator, it might look like this:
public class Axynasf {
private int akdmakn;
private String anxcmjna;
public Axynasf(String adna)
{
anxcmjna=adna;
}
public int getAkdmakn() {
return akdmakn;
}
public void setAkdmakn(int akdmakn) {
this.akdmakn = akdmakn;
}
public String getAnxcmjna() {
return anxcmjna;
}
public void setAnxcmjna(String anxcmjna) {
this.anxcmjna = anxcmjna;
}
}
Imagine that I post an update now and a player that has an unobfuscated version of Player downloads that update. When trying to read that Object there will be different member names and a different class name. I'll most likely get ClassCastException or something of the sorts.
No expert in Proguard, but I think you're right to assume it is going to break serialisation.
One possible way of solving this might be to implement a layer over your current save structure - You can tell Proguard which classes you don't want to obfuscate. Leave the Player (and alike objects) the same for now and don't obfuscate. Once the object has been de-serialised, pass it up to your new layer (which is obfuscated) which the rest of the game deals with - if you don't retain the non-obfuscated object, then it'll cause cheaters problems tweaking during game play (although not at load time). At the same time, you could look at moving your player's game files over to another save option that doesn't depend on serialisation, which will probably make such issues easier in the future.
For ensuring compatible serialization in ProGuard:
ProGuard manual > Examples > Processing serializable classes
For upgrading a serialized class to a different class in Java:
JDK documentation > Serialization > Object Input Classes > readResolve
JDK documentation > Serialization > Object Serialization Examples > Evolution/Substitution
I understand ppl can update vars # runtime w/ the app you named.
If you change the member names, the values will still give hints.
If you obfuscate, the class name will change but new name will end on a forum anyway.
So this is not enough
What you could do in your update is, at startup, load serialized data in old object, transfer to "new" obfuscated class, use a custom serialization (with an XOR using the deviceID value or the gmail adress so to make it less obvious).
Try to have your player data into several classes too.
What I would do in your situation:
Release an update with obfuscated and non-obfuscated class. When player gets loaded it will try with both classes. If player got loaded with non-obf. class then map this class to your obfuscated class.
When player gets saved it will save with obfuscated class.
After a proper amount of time release an update with only the obfuscated classes.
Related
I'm fairly new to Java. I'm coming from PHP and I used to create registry classes in php using the magic __get and __set methods. So that other parts of the system can easily do:
registry.foo = new Foo();
I should mention I'm trying to create game engine. Here is my registry in Java atm:
class Registry {
private static Map<String, Object> box = new HashMap<String, Object>();
public static Object get(String key) {
if (Registry.box.get(key) != null) {
return Registry.box.get(key);
}else {
return null;
}
}
public static void set(String key, Object o) {
Registry.box.put(key, o);
}
}
Then for the other parts of the system to access the registry, I currently need this whole thing:
((Object) Registry.get("Object")).doSomething();
Which is really a lot of code. In php this would be accomplished by simply:
Registry.foo.doSomething();
Any way to make this a bit more simpler? I guess I could make public fields, but then the regsitry class would need to implicitly create these fields as the possibility of new objects may need to be added which are unknown to the registry class itself, which is.. annoying :P
Thanks in advance!
This is a two pronged problem:
Java is a statically type language, and does not offer in-language flexibility for defining objects at runtime (you can use a library to synthesize classes at runtime, but, see #2)
A global registry for objects defeats a lot of safeties in a type-safe language. If your entire application centers around getting and putting objects into a global Map, there likely safer and less-coupled designs.
How can this be solved?
Redesign your application structure to not need a global map.
Use a dynamic language subset for Java (such as Groovy).
Use Scala 2.10 (JVM compatible) which features a Dynamic type which does exactly what you want.
First of all this method is too verbose:
public static Object get(String key) {
if (Registry.box.get(key) != null) {
return Registry.box.get(key);
}else {
return null;
}
}
It could be just:
public static Object get(String key) {
return Registry.box.get(key);
}
But second, this is definitely a bad design. Global repository - doesn't sound reasonable. A storage of objects of all types by string key - it's terrible.
Any way to make this a bit more simpler?
Not in any practical way. Java is a statically typed language, and the structure of objects has to be known up front. The very idea of an equivalent of PHP's __get and __set is antithetical to the language.
For what it's worth, your "registry" looks like bad design anyway. (Admittedly making some pretty wild assumptions from the little code you've shown.) You shouldn't need a global repository of what appear to be unrelated objects. You should consider some sort of dependency injection instead.
Based on your comment, instead of structuring your code like this:
class World implements GameSystem {
public void update() {
Registry.get("game").doSomething();
}
}
you should do:
class World implements GameSystem {
Game game;
public World(Game game) { // and other dependencies
this.game = game;
}
public void update() {
this.game.doSomething();
}
}
The idea is that components of your program don't really have any business knowing how to find the other components. It also makes dependencies between the components explicit, and helps you avoid circular dependencies.
I have to access some application through an mbean so that I can change its application properties. Now i think this can be done in two ways:
First, either I ask the developer of that application to register all the application properties in an arraylist which my mbean will access.
Secondly, if there is any other way, such that the developer will only need to register editable properties and still my mbean can access both readable/editable(r/w) application properties.
Now since I don't know where these application properties are stored in the JVM, is there a way to implement my second point so that the mbean will just need to access that object and it will get all application properties?
Seems like you have some contradicting requirements here.
You want to change minimal code in the application.
You want to be cause to expose all properties for read and/or write.
You may or may not be talking about System.getProperty(...). If not then I guess you are talking about just fields in various objects.
There are (at least) two ways of doing this. Without knowing how you are exporting the mbeans from the source code right now, I can't tailor my answer to your specific config. My answer will instead show how you might use my SimpleJMX package to expose your properties.
If you are talking about System.getProperty(...) then you could write a JMX mbean that could query any property and return the value:
#JmxOperation(description = "Query for property")
public String queryForProperty(String name) {
return System.getProperty(name);
}
If, instead, you need to export of fields from some list of objects then you are going to either have to add annotations to each fields you are exporting or you are going to have to write beans that export the fields through delegation. I see no easy way and I know of no package that will easily export a series of objects for you without some sort of information about what is to be exported and how.
Using SimpleJMX, you can export a field by annotating either the field or the get method:
#JmxAttributeField(description = "Number of hits in the cache")
private int hitCount;
...
// this can also be specified as #JmxAttributeMethod on the getter/setter methods
#JmxAttributeMethod(description = "Number of misses in the cache")
private int getMissCount() {
return missCount;
}
The #JmxAttributeField supports a isWritable = true to allow the value to be set by JMX. You can also annotation the setter with #JmxAttributeMethod to make it writable.
If you don't want to add annotations to each of your classes, then you are going to have to write some sort of JMX container class that exports the values through delegation:
public class JmxPublisher {
private Class1 object1;
private Class2 object2;
...
public JmxPublisher(Class1 object1, Class2 object2) {
this.object1 = object1;
this.object2 = object2;
...
}
#JmxAttributeMethod(description = "Number of hits in the cache")
public int getClass1HitCount() {
return object1.getHitCount();
}
#JmxAttributeMethod(description = "Shutdown the background thread")
public void setClass2Shutdown(boolean shutdown) {
return object2.setShutdown(shutdown);
}
...
}
I also think you should express yourself more clearly.
From what I understood - why not providing a way to query the remote application, and get information on all properties and if they are Read-only, Write-only or RW?
This way the list of properties will not be mentioned at the source code of the client application - maybe you should let the user of the client application see the list of properties, and let him edit the properties he can edit, and prevent him from editing the properties he can't.
In a Google App Engine JPA Entity a java.lang.String is limited to 500 character, while a com.google.appengine.api.datastore.Text has an unlimited size (with the caveat that entityManager.persist doesn't work with entities bigger than 1 Mb - I believe, but can't find the reference about it).
However, if I use the Google specific Text type, I would tightly couple my application with Google App Engine. I was wondering if there is a more lightweight way to achieve the same result, such as through some standard annotation.
Maybe, annotating a String with a JSR-303 annotation. If the size is above 500, it would know to use the non-indexed Text type. Example: #Size(max = 3000)
Obvsiously I'm just dreaming, but maybe there is some standard way to avoid App Engine specific data types. Anybody knows?
UPDATE: found issue 10, Support #Lob JPA annotation in datanucleus-appengine
DataNucleus plugin for Google App Engine.
I'm guessing you might have thought of this already; but I'm posting this anyway since it adds a point not covered in your question. My solution here was to make it private, and then for my object definition I don't ever return a Text object. I admit this doesn't accomplish your goal of avoiding the App Engine specific data type; but it at least makes it so that you don't have to rewrite code outside of the one class which relies on the Text object should you decide to port your application off of app engine.
So, for example, assuming text is a blogPost variable...
public class BlogPost {
private Text post;
// ...
public String getPost() {
return post.getValue();
}
public void setPost(String val) {
this.post = new Text(val);
}
}
If that code feels a little sloppy it might be slightly (I don't know how the Text#getValue method works internally) more efficient to do this...
public class BlogPost {
private Text post;
private String postValue;
// ...
public String getPost() {
return postValue;
}
public void setPost(String val) {
this.post = new Text(val);
this.postValue = val;
}
}
I'm totally new to posting questions on here, however I have been reading a lot on here for years. Normally I always am able to find my answers by thoroughly searching the web, but this time I am at a loss...
After having spent yet another day of trying to figure out why this is not working I decided to ask for help, hoping you guys can give me a few pointers, or better, a solution.
The problem:
In an Android game I have come to the point where I have to make the application remember its state when a user e.g. presses the HOME-screen button. After some searches I realised that in order to make my classes initialize back to their appropriate states after re-opening the application I had to support the Parcelable interface to pass them with the Bundle.
In my onStop and onStart functions I respectively save and restore the game state to and from a Bundle, however when I call the putParcelable and getParcelable functions on the Bundle the object's writeToParcel and createFromParcel functions are never called.
Fearing that this may have been due to the relative complexity of the game I figured I had best create a very simple application to try to get it to work.
Based on many Parcelable examples I have seen online, this became my class:
public class ParcelableTest implements Parcelable {
int id;
public ParcelableTest(int newID)
{
id = newID;
}
private ParcelableTest(Parcel in) {
readFromParcel(in);
}
public void writeToParcel(Parcel out, int arg1) {
writeToParcel(out);
}
public void writeToParcel(Parcel out) {
Log.v("ParcelableTest","Writing to parcel");
out.writeInt(id);
}
public void readFromParcel(Parcel in) {
id = in.readInt();
}
public int describeContents() {
return 0;
}
public static final Parcelable.Creator<ParcelableTest> CREATOR = new
Parcelable.Creator<ParcelableTest>() {
public ParcelableTest createFromParcel(Parcel in) {
Log.v("ParcelableTest","Creating from parcel");
return new ParcelableTest(in);
}
public ParcelableTest[] newArray(int size) {
return new ParcelableTest[size];
}
};
}
And from my Main activity I would call the following functions to save / restore the data:
public Bundle saveToBundle(Bundle savedState)
{
savedState.putParcelable("Test1",mTest1);
savedState.putParcelable("Test2",mTest2);
return savedState;
}
public void restoreFromBundle(Bundle savedState)
{
mTest1 = savedState.getParcelable("Test1");
mTest2 = savedState.getParcelable("Test2");
}
But for some reason neither of the functions (with the putParcelable and getParcelable functions) will result in the appropriate Parcelable calls in my test class.
The strangest thing is that it does somehow read the correct values (I have tried with more variables in the class), but my debugging and my log shows that tha application never gets to writeToParcel and createFromParcel.
What am I missing here?
Any help / thoughts would be appreciated.
Apparently the Android Bundle class does not adhere to the parcelable protocol that instead is followed during IPC marshalling.
Instead, it seems like the Bundle implementation just writes and reads the Parcelable object into its own internal map by means of reflection. From a test we did, it seems that the Bundle writes/reads every field defined in your Parcelable-derived class, just because you have declared those fields.
Technically, the documentation doesn't say that writeToParcel or createFromParcel are called from onSaveInstance. As a matter of fact, if you check the savedState in your code you are going to find that it is exactly the same object instance in both the save and the restore cases; it makes sense to avoid serialize-deserialize if you can. OTOH, the documentation doesn't say either that serialization is not done. The conclusion should be that you shouldn't depend on either case, just assume that you get the correct bundle.
Also, you may want to check http://developer.android.com/guide/topics/resources/runtime-changes.html
I confirm what superjos said.
On the saveToBundle event, Android bundle just stores the class's members per reflection and doesn't call the Parcelable functions.
I have lost one day on this problem! sad....
This is really bad .... This means you potentially stores a huge amount of data for nothing using this way.
What is the best and most flexible way of maintaining different version of documents for a web application?
Let's say you have a Pet store web application.You need to make changes to a printable document with info of your Pet, but these changes are only effective for every Pet object created from a x date , but for Pets created before x date then use the previous version of the report. Somehow keeping multiple versions of the files and choosing them with hardcoded rules seems messy, is there any other way?
If I understand you correctly you simply need to bind your Pet objects to DocumentTemplate objects. You could just add a field to the Pet object:
public class Pet {
private final String name;
private final Template template;
.
.
.
}
This way you would not need to make checks like:
if (pet.getCreationDate().after(date)) {
print(template1);
}
else {
print(template2);
}
but you can simply do:
print(pet.getTemplate());
This would be the standard way to do it if I understand you correctly.