I am developing game using LibGDX framework . I want to know how to make the game more secure . For example a user with rooted android device can change save .xml file so the game will be hacked , or he/she can use GameKiller or a program like that and change game runtime values (money ,exp etc.). So how can I prevent those?
And the same thing for desktop version , save file is not hidden and the player can find that file on PC too . And can use CheatEngine or other program for hacking and again change runtime values.
If you are not storing private/important data but only want to make it hard to hack your game (for example by changing xml with levels of your game) you can implement encryption basen on GWT Crypto library
The way you are initializing encryptor is:
//this will be used for encrypting and decrypting strings
private TripleDesCipher encryptor;
...
//creating key for encryptor
TripleDesKeyGenerator generator = new TripleDesKeyGenerator();
byte[] key = generator.decodeKey("04578a8f0be3a7109d9e5e86839e3bc41654927034df92ec"); //you can pass your own string here
//initializing encryptor with generated key
encryptor = new TripleDesCipher();
encryptor.setKey(key);
...
And way of using it:
private String encryptString(String string)
{
try
{
string = encryptor.encrypt( string );
}
catch (DataLengthException e1)
{
e1.printStackTrace();
}
catch (IllegalStateException e1)
{
e1.printStackTrace();
}
catch (InvalidCipherTextException e1)
{
e1.printStackTrace();
}
return string;
}
private String decryptString(String string)
{
try
{
string = encryptor.decrypt(string);
}
catch (DataLengthException e)
{
e.printStackTrace();
} catch (IllegalStateException e)
{
e.printStackTrace();
} catch (InvalidCipherTextException e)
{
e.printStackTrace();
}
return string;
}
I also recommend you not to use XMLs but JSONs - they are more convenient and weights less. Read how to handle it here
Remember that generally client-side encryption is not very good idea and always can be hacked in some way - but I'm pretty sure that if it is not about money noone will think it worth.
If you are interested in more advanced way of keeping your data save the best idea would be sending all data by SSL and save it in some well-guard server - although I'm not very sure if Libgdx has any good SSL mechanism and don't know 3rd part libraries that I could recommend.
The example of service to keep files can be Shephertz (I was using their nice AppWarp and going to implement this one in my app also).
You can use those for runtime
Twin variables
Twin for a cheatengine and gamekiller
int health=15;
int twinhealth=15;
if(HPtaken())
{
health+=10;//those twins will always change together
twinhealth+=10;
}
if(health!=twinhealth)//if they are different this means there is hack attempt
{
//punishment for hacker
}
Crypted variables
Actually its not a crypt its just little change on variables so hacker cant change easly via gamekiller or cheatengine.
int health=15*7;
int twinhealth=15*7;
if(HPtaken())
{
health+=10*7;//those twins will always change together
twinhealth+=10*7;
}
drawhealth( health/7 );// So hacker going to see and search wrong value on cheatengine
Crypted twin variables :D
Hacker ban freeze and change both twin with a same value. So at least one of the twins will be crypted.
int health=15;
int twinhealth=15*5;
if(HPtaken())
{
health+=10;//those twins will always change together
twinhealth+=10*5;
}
if(health!=twinhealth*5)//if they are different this means there is hack attempt
{
//punishment for hacker
}
Of course hacker can decompile apk and hack your game but it makes little bit harder to hack game. By the way you can use random variables for editing variables.
You can apply to xml or preferences those but you can use little bit complicated crypt because speed not an issue since you only import/export few times.
Related
I have an android app. I have a few users who have a recurring problem: When the app shuts down, every file the app saved is gone. Every folder created is gone. Everything is completely wiped back to square one.
I am carefully saving the game data during every transition and game event, so I am very confident that this is not a case of the user crashing out before the data can be written. Somehow, the data that IS being written but then it's just not persisting after the app is removed from memory.
So-- has anyone had this situation and solved it? The only thing I can imagine is that there's some kind of "filesystem.commit" command I need to call after writing the files, but I can't find that documented anywhere.
Please help!
(Edit) I'm using native code to read and write files. The code I use to write a file is this:
bool WriteFile(char *theFilename, char *theDataPtr, int theLen)
{
FILE* aFile=fopen(theFilename,"w+");
if(!aFile) {Alert("unable to create file %s with error %d", theFilename, errno);return false;}
if(aFile) fclose(aFile);
aFile=fopen(theFilename,"w+b");
if(!aFile) {Alert ("unable to open file %s", theFilename);return false;}
if (aFile)
{
fwrite(theDataPtr, 1, theLen,aFile);
fclose(aFile);
return true;
}
return false;
}
Note:No customers are reporting any alert popups, which are just normal Android message boxes. Also note that this code works on almost every other system-- there's just a few customers that get the wiped data, so I was wondering if it's some weird security or some extra step I need to do to be 100% compatible with all systems.
(Edit) One more piece of information... this is the Java code I use to get the storage path for the app... all files that I try to write are put in this folder.
private void SetFilePath()
{
String storagePath = getFilesDir().getAbsolutePath();
// SDCARD
try {
String storageState = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(storageState))
storagePath = getExternalFilesDir(null).getAbsolutePath();
} catch (Exception e) {
Log.v(IDS.LOG,
"No permission to access external storage, missing android.permission.WRITE_EXTERNAL_STORAGE");
}
SetFilePathNative(storagePath); // Tells the native code the path
mStorageDir = storagePath;
}
Good day. The main amazing thing about the BeanShell is the idea that i can control what i want to be done dynamically from the server and i thought it would be amazing.
Although i never succeded in achieving that and seems no one else tried to start activity from the beanshell either.
Here how it goes. I simply want to pass the code from the server side to the Android,Android is going to evaluate that code within interpreter and run that.
The issue is that i am getting the exception from BeanShell no matter what i try.
The code from server side is the next.
$response['method'] = "import my.some.name.*;"
. "startActivity(new Intent(this,MyProfile.class))";
The code for Android is the next.
try {
String responseBody = response.body().string();
JSONObject jsonObject = new JSONObject(responseBody);
String method = jsonObject.optString("method");
Interpreter interpreter = new Interpreter();
try {
Object res = interpreter.eval(method);
} catch (EvalError evalError) {
evalError.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
}
But i am getting the next exception from the BeanShell
Sourced file: inline evaluation of: ``import my.some.name.*;startActivity(new Intent(this,MyProfile.class));'' : Class: MyProfile not found in namespace : at Line: 1 : in file: inline evaluation of: ``import my.some.name.*;startActivity(new Intent(this,MyProfile.class));'' : MyProfile
Any ideas what is going on?
Just in case if anyone needs the same solution i am posting for everyone to know.
Here how it goes.
Firstly you need to know that whatever you are trying to do on the server side remember that the BeanShell actually does not know anything about the String code you are passing itself,as it is going to interpret it just like a code out of box so with the help of CommonWare hint about full name path i managed to get it working.
So first step to do is to initialize the Interpreter.
Basic initialization goes like this :
String responseBody = response.body().string();
JSONObject jsonObject = new JSONObject(responseBody);
String method = jsonObject.optString("method");
Interpreter interpreter = new Interpreter();
try {
interpreter.set("context",getApplicationContext());
Object res = interpreter.eval(method);
} catch (EvalError evalError) {
evalError.printStackTrace();
}
Take a very attentive notice about the context as it was my main issue going back and forth as at the moment when i succeded to actually force BeanShell recognize my classes,the BeanShell started to throw Method not found exception about the startActivity() so by thinking logically we can assume that we would set the context as activity as the parent one for our remote methods and start evaluating everything from the context. So here how the remote code is looking.
$response['method'] = "import ink.va.activities;"
. "import android.content.Intent;"
. "import android.content.*;"
. "context.startActivity(new android.content.Intent(context, my.package.name.MyProfile.class));";
The most important things to notice here.
• We are importing everything possible for BeanSherll to recognize our classes,even if they are Android-Build,no matter,still we need to import them.
• If you are going to use any class,then as CommonWare noticed out,you MUST specify the full path to that Class E.G my.package.name.MyProfile.class.
• As i was getting Command Not Found i started to think about the context.startActivity() as i have defined the context beforehand in BeanShell as my parent from which i am going to use methods and Woala,everything worked like a charm!
Possible Problems
I don't know a lot about BeanShell, but there's a couple of issues here
You can import a class (in a compiled language) at runtime
You're trying to do the equivalent of Reflection (but aren't doing any)
Security. No user would consent to you having control to open a screen on their app remotely
Presumably BeanShell is supposed to do the reflection under the covers, but in an case you won't be able to do the import.
Possible solutions
The class/activity using the library should import everything (I'm not sure if a compiler will even retain this)
You can use reflection directly, with things like "method from name". The downside is it's very limited what code you can send from the server unless you handle a myriad of cases.
You could only send names/commands; to specific endpoints in your java app (this is what I recommend) and plan the actions you want ahead of time
$response['method'] = "my.some.name.MyProfile";
JSONObject jsonObject = new JSONObject(response.body().string());
String nameParam = jsonObject.optString("method");
Class<? extends Activity> clazz = Class.forName(nameParam); //wrap with try
startActivity( new Intent(this, clazz) )
I'm developing an app for a company and I need to integrate it with Google Drive. I can't use the native API because the company has files not created by the application that needs to be handled, I need the full drive scope, so the REST API is what I must use.
Here's the problem, the tutorials are not basic enough for me to get started since I only have a very basic understanding of JSON and REST.
The tutorial: https://developers.google.com/drive/web/integrate-create
As I understand it I need to create JSON in my Java code and then pass that through the example code?
JSON
{
"action":"create",
"folderId":"0ADK06pfg",
"userId":"103354693083460731603"
}
JAVA
public class State {
/**
* Action intended by the state.
*/
public String action;
/**
* IDs of files on which to take action.
*/
public Collection<String> ids;
/**
* Parent ID related to the given action.
*/
public String parentId;
/**
* Empty constructor required by Gson.
*/
public State() {}
/**
* Create a new State given its JSON representation.
*
* #param json Serialized representation of a State.
*/
public State(String json) {
GsonBuilder builder = new GsonBuilder();
Gson gson = builder.create();
State other = gson.fromJson(json, State.class);
this.action = other.action;
this.ids = other.ids;
this.parentId = other.parentId;
}
}
The problem is that I have no idea how to create JSON nor do I quite understand how to use the JSON when created to do things like create files and query for files.
If someone can get me as far as creating an empty file in a users root folder then I can probably take it from there, but I could really use a nudge in the right direction!
Assuming, that you're talking about an Android app, there is no need to create JSON. The Java REST Api is quite easy to use on Android. If the official docs and the examples do not suffice, you may look at this demo. It is a bit more complex that needs to be (in order to maintain compatibility with the GDAA version), but with a few simple steps, you may simplify it.
I certainly can't copy all the code here, but you can just snatch the REST class, supply a GooDrive account to setSelectedAccountName() (or omit the method and let the service handle it) and simplify the connect() / disconnect() methods. The connect() method (for compatibility with GDAA) should be) replaced by a try/catch construct like this:
com.google.api.services.drive.Drive mGOOSvc;
...
try {
mGOOSvc...execute();
} catch (UserRecoverableAuthIOException uraIOEx) {
// standard authorization failure - user fixable
} catch (GoogleAuthIOException gaIOEx) {
// usually PackageName / SHA1 mismatch in DevConsole
} catch (IOException e) {
// '404 not found' in FILE scope, still, consider connected
if (e instanceof GoogleJsonResponseException) {
if (404 == ((GoogleJsonResponseException) e).getStatusCode())
mConnected = true;
}
} catch (Exception e) {
// "the name must not be empty" indicates
// UNREGISTERED / EMPTY account in 'setSelectedAccountName()' ???
}
anywhere you find the '...execute()' method in the REST class in order to catch sudden loss of authorization, etc... (can happen anytime). Otherwise, I've been running this CRUD implementation for some time and never experienced problems.
One general note about the REST Api. Since it is 'network state dependent', I would recommend to disconnect it completely from your app's UI and run it in some type of sync service invoked when there is an active network (WIFI, cellular) traffic. See the network related episodes here.
Good Luck
In my app I want to catch all types of exceptions and send reports by e-mail. For that I'm using global try catch block. But now I need to recognize exception by type. How can I do it?
try{
...
}
catch (Exception e){
//Here I need to recognize exception by type
send(Error);
}
Why you don't simple send the whole stacktrace?
send(e.getStackTrace())
It not only contains the Exception type but also where (file, class, line) it occurred.
Additionally, you can also simply use the toString() method.
See the java doc for further information
Instead of rolling your own error logging and reporting mechninism I strongly recommend you use ACRA Its free, open source, and supports sending error logs to email. I have used it for quite some time and it is very good.
This will give you all sorts of information such as phone make, model, resolution, free memory, as well as a full stack trace of the error. Its by far the easiest way to get quality error reporting into an Android app.
The best part is it takes all of about 5 minutes to get setup and integrated.
e.getClass() // will give you Class object
e.getClass().getName() // will give you class name
However if you know the class names already you can use
if(e instanceof A)
{
// some processing
}
else if(e instanceof B)
{
//some processing
}
else
{
//
}
on Android phones, under Call -> Additional settings -> Caller ID
it is possible to hide your caller ID. I want to do that programatically from my code, but was not able to find a way to do that.
I searched through
android.provider
android.telephony
for 2.1 release and was not able to find it.
Has anybody successfully solved this issue?
Thanks in advance. Best regards.
Here I will describe two approaches I tried.
1.) It is possible to display Additional Call Settings screen from your application. Although it looks like it is part of the Settings application, that is not true. This Activity is part of the Native Phone Application, and it may be approached with the following intent:
Intent additionalCallSettingsIntent = new Intent("android.intent.action.MAIN");
ComponentName distantActivity = new ComponentName("com.android.phone", "com.android.phone.GsmUmtsAdditionalCallOptions");
additionalCallSettingsIntent.setComponent(distantActivity);
startActivity(additionalCallSettingsIntent);
Then user has to manually press on the CallerID preference and gets radio button with 3 options.
This was not actually what I wanted to achieve when I asked this question. I wanted to avoid step where user has to select any further options.
2.) When approach described under 1.) is executed in the Native Phone Application, function setOutgoingCallerIdDisplay() from com.android.internal.telephony.Phone has been used.
This was the basis for the next approach: use Java Reflection on this class and try to invoke the function with appropriate parameters:
try
{
Class <?> phoneFactoryClass = Class.forName("com.android.internal.telephony.PhoneFactory");
try
{
Method getDefaultPhoneMethod = phoneFactoryClass.getDeclaredMethod("getDefaultPhone");
Method makeDefaultPhoneMethod = phoneFactoryClass.getMethod("makeDefaultPhone" , Context.class);
try
{
makeDefaultPhoneMethod.invoke(null, this);
Object defaultPhone = getDefaultPhoneMethod.invoke(null);
Class <?> phoneInterface = Class.forName("com.android.internal.telephony.Phone");
Method getPhoneServiceMethod = phoneInterface.getMethod("setOutgoingCallerIdDisplay", int.class, Message.class);
getPhoneServiceMethod.invoke(defaultPhone, 1, null);
}
catch (InvocationTargetException ex)
{
ex.printStackTrace();
}
catch (IllegalAccessException ex)
{
ex.printStackTrace();
}
}
catch (NoSuchMethodException ex)
{
ex.printStackTrace();
}
}
catch (ClassNotFoundException ex)
{
ex.printStackTrace();
}
Firstly I tried just to use getDefaultPhone(), but I get RuntimeException
"PhoneFactory.getDefaultPhone must be called from Looper thread"
Obviously, issue lies in the fact that I tried to call this method from the Message Loop that was not the Native Phone App one.
Tried to avoid this by making own default phone, but this was a security violation:
ERROR/AndroidRuntime(2338): java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.provider.Telephony.SPN_STRINGS_UPDATED from pid=2338, uid=10048
The only way to overcome (both of) this would be to sign your app with the same key as the core systems app, as described under
Run secure API calls as root, android
I'm not sure if this is a global feature, but Australian phones can hide their number by prefixing the caller's number with #31# or 1831. This may not be the perfect solution, but a prefix like this could possibly work for your requirements during coding.