Jump to content
  • 0

How to find my level value in the encoded string


nok1a
 Share

Question

Game: https://play.google.com/store/apps/details?id=com.unicostudio.gemdoku&hl=en_IN&gl=US

I want to locate the level value in the com.unicostudio.gemdoku.v2.playerprefs.xml file so i can edit it with GG or CheatDroid. Normally i can cheat the level by overwriting the current com.unicostudio.gemdoku.v2.playerprefs.xml file with the one from older versions since the names and values where readable back then as shown in the screenshots.
image.thumb.png.3ba7d973d76789e9ffd3c3149ad410db.png

It was a quick work around but i am rather interested in finding out how the player level is really stored in the current xml file because i noticed quite some games have values like coins stored in a long string. On top of that the string will include more then just the coins, for example it can include some functions that are needed to have the coins appear properly. So if you don't edit the string correctly you will get a undesired result.

So i started running some basic tests that i am familiar with. Like comparing the content in the .xml file when i was a level 5 with the content in the .xml file when i became lv6. Then replace the old string with the new string to see which string makes me go back to level 5. Eventually it came down to this string, the string when i was a level 5:

    <string name="1EBXq7XeVC545LnqsugT4jS%2FTXFJQZG%2BkJ1CodU1l%2BGkd5zLuX%2BoPk2Z1QWV9JkXAJmyRo9KdrM%3D">1EBXq7XeVC5e6TxnIVs%2FT%2BMZXc3zTi%2FMR5bkR5NzbftgLsNAbMjgO2EU4JrjCwSZusRXHZl1d4Li7vw0P3fcuvB36rs0RvYSfwduwbvRwLX%2Fi58tS5lkESmKdSQfxJFpIyTxQcSMn6qkwSNCDJhFDCf7Mp3mA9baBgWYX9q0oKTmi1l2NZ48vf1OXIehi0zKQpAMt6nTIMgQYxIhfxAOxVBrd0180%2FGzugECxwjNwcjfLy%2FaYaoiKA%3D%3D</string>


Then when i whent to level 6 the string changed to this:

    <string name="1EBXq7XeVC545LnqsugT4jS%2FTXFJQZG%2BkJ1CodU1l%2BGkd5zLuX%2BoPk2Z1QWV9JkXAJmyRo9KdrM%3D">1EBXq7XeVC5e6TxnIVs%2FT%2BMZXc3zTi%2FMR5bkR5NzbftgLsNAbMjgO2EU4JrjCwSZusRXHZl1d4Li7vw0P3fcuvB36rs0RvYSe3e5rsbaG7LN%2FfLGOhZwig%2FMiGabQt1ZHSZBQ4B9j%2BAtDkZvUP2cKg9VEQkyvFwu7vRSk%2BtVVpC4EXD6C4IcgN8BjpNq%2FIuWKud5LzCmdIr9TlyHoYtMyuc%2FO%2BdfyyhyJhuGPpaK98AkejcbIKUeIKrfAcOjp%2F0gQSKbb6ZZdJo%3D</string>

Only whent up one level in the game. Did not do any extra changes. So i believe every different between both strings should be related to the level.

I dunno nothing about encoding or encryption but i did saw that "%2F" and "%3D" occurred a lot in both strings and the internet says that it is common in URL's although i doubt it's a URL did try to decode it as a URL and then it shows me the slashes in the string. Making it look like this (first string is level 5, second string level 6):
image.thumb.png.2ffcf79bc8aad139ace8647599766597.png

-- decoded level 5
1EBXq7XeVC5e6TxnIVs/T+MZXc3zTi/MR5bkR5NzbftgLsNAbMjgO2EU4JrjCwSZusRXHZl1d4Li7vw0P3fcuvB36rs0RvYSfwduwbvRwLX/i58tS5lkESmKdSQfxJFpIyTxQcSMn6qkwSNCDJhFDCf7Mp3mA9baBgWYX9q0oKTmi1l2NZ48vf1OXIehi0zKQpAMt6nTIMgQYxIhfxAOxVBrd0180/GzugECxwjNwcjfLy/aYaoiKA==

-- decoded level 6
1EBXq7XeVC5e6TxnIVs/T+MZXc3zTi/MR5bkR5NzbftgLsNAbMjgO2EU4JrjCwSZusRXHZl1d4Li7vw0P3fcuvB36rs0RvYSe3e5rsbaG7LN/fLGOhZwig/MiGabQt1ZHSZBQ4B9j+AtDkZvUP2cKg9VEQkyvFwu7vRSk+tVVpC4EXD6C4IcgN8BjpNq/IuWKud5LzCmdIr9TlyHoYtMyuc/O+dfyyhyJhuGPpaK98AkejcbIKUeIKrfAcOjp/0gQSKbb6ZZdJo=

Then copy pasted MR5bkR5NzbftgLsNAbMjgO2EU4JrjCwSZusRXHZl1d4Li7vw0P3fcuvB36rs0RvYSfwduwbvRwLX into MR5bkR5NzbftgLsNAbMjgO2EU4JrjCwSZusRXHZl1d4Li7vw0P3fcuvB36rs0RvYSe3e5rsbaG7LN  and then encoded it back which resulted the game to kind act weird. The font shows lv1 but then when trying to enter the map it shows lv500 with nothing on the background.

image.thumb.png.0e00ac53ff51c4bf954abf3243865e7d.png

image.thumb.png.5ae1496a848b01d74dc9afc550792a96.png

This was not the intended result. Some help would be appreciated.

Edited by nok1a
corrected some sentences
Link to comment
Share on other sites

10 answers to this question

Recommended Posts

  • 0
On 11/1/2023 at 10:07 PM, nok1a said:

I want to locate the level value in the com.unicostudio.gemdoku.v2.playerprefs.xml file so i can edit it with GG

That doesn't require doing anything with preferences file though and in this case it seems easier to do it in process memory.

But if I understood correctly, you are researching how storing data in preferences works in case of this game. If that's so, start by doing the usual analysis of Unity games. Get the dump, open dummy dlls in dnSpy, look for things with relevant names within Assembly-CSharp.dll. Then check how those things are implemented in libil2cpp.so. First step should give a surface-level understanding of what's going on there. Second step will provide you with particular answers on how exactly it works.

Link to comment
Share on other sites

  • 0
12 hours ago, CmP said:

That doesn't require doing anything with preferences file though and in this case it seems easier to do it in process memory.

I am not sure if it would be more easy to do it in process memory. If it is a method of a class then i would not say it is easy, at least for my opinion because i never edit methods since the results after editing usually don´t make sense to me.

13 hours ago, CmP said:

That doesn't require doing anything with preferences file though

How so not?  Finding the name and value in the preference file and then editing that value in process memory is more easy for me because i will know where and what exactly i need to edit, also because everything in shared pref is location in java heap, java and region Other. and values in shared pref files change addresses each time the client writes to the shared pref file. So if you don´t know how to edit methods this is gone be the second thing you gone try. Checking if the value can be found in pref...if so make a script and edit it with GG.

 

13 hours ago, CmP said:

Get the dump, open dummy dlls in dnSpy, look for things with relevant names within Assembly-CSharp.dll. Then check how those things are implemented in libil2cpp.so. First step should give a surface-level understanding of what's going on there. Second step will provide you with particular answers on how exactly it works.

Interesting, will take a look and see what it gives on the surface level. But if the level value is located in a method of a class then it will probably be more hard for me to edit it from the region where the executable is located. But the point is to find the level value in that string. But if i need to dump the game for find it then i will do that.

Link to comment
Share on other sites

  • 0
7 hours ago, nok1a said:

I am not sure if it would be more easy to do it in process memory. If it is a method of a class then i would not say it is easy, at least for my opinion because i never edit methods since the results after editing usually don´t make sense to me.

Didn't mean modifying the code, meant the regular GG-way of modifying the value. The only challenge here may be that the value is encrypted, so need to figure out how it works first. Though, I am not sure that it's encrypted value that needs to be modified, since according to the dump value of level exists in both encrypted and unencrypted forms.

7 hours ago, nok1a said:

How so not?

Because finding the value in process memory doesn't require figuring out how it is stored in preferences.

7 hours ago, nok1a said:

But if i need to dump the game for find it then i will do that.

I am somewhat surprised that you haven't checked it as one of the first things, since I see it as the "usual way" of finding desired values in Unity games.

Link to comment
Share on other sites

  • 0
On 11/3/2023 at 8:20 PM, CmP said:

Because finding the value in process memory doesn't require figuring out how it is stored in preferences.

But why would they have it in process memory if they already have it in the shared pref? These small puzzle games with lots of adds often have there coins and level values in region Java Heap, Other or Java. Since i usually don't dump the game the quickest way for me would be opening sharedpref file. Search the key name of the coins or level and then edit it in GG  in it's appropiate memory region, otherwise it's really hard to find the level or coins value with a regular GG search.

On 11/3/2023 at 8:20 PM, CmP said:

Though, I am not sure that it's encrypted value that needs to be modified, since according to the dump value of level exists in both encrypted and unencrypted forms.

Not to sure how you found that out, may i know where in dump you see that it says both encrypted and unencrypted exist?
I dumped the game but can't find anything yet about the level, lot's of classes but not really providing me results. I believe im forced to check the libil2cpp.so and edit those methods although i prefer to stay with the green regions which is more understandable.
 

On 11/3/2023 at 8:20 PM, CmP said:

I am somewhat surprised that you haven't checked it as one of the first things, since I see it as the "usual way" of finding desired values in Unity games

Well, dumping is for me last resort. Usually i rely on my typical GG search techniques. As far i understand my GG search skill the dump doesn't usually provide me more advantage in finding something then i would without. But this depends on the knowledge one has about the dumps and executables.

Edited by nok1a
Link to comment
Share on other sites

  • 0
47 minutes ago, nok1a said:

But why would they have it in process memory if they already have it in the shared pref?

Because shared preferences is merely a way of preserving data between different runs of application. There is no way to read/write value from/to shared preferences without having it in process memory.

54 minutes ago, nok1a said:

Not to sure how you found that out, may i know where in dump you see that it says both encrypted and unencrypted exist?

Search for fields named "currentAdventureLevel":

image.thumb.png.359610f54c2e9d3857ae57b24c498ef6.png

57 minutes ago, nok1a said:

As far i understand my GG search skill the dump doesn't usually provide me more advantage in finding something then i would without.

When names of things are not obfuscated, data from the dump provides everything one needs to know to find basically any value in scope of (used by) libil2cpp.so.

Link to comment
Share on other sites

  • 0

I checked these fields but when editing the values no changes happen. Personally i think that aside from editing the values in java region you will only find the level value in the regions where the executable is located.

Link to comment
Share on other sites

  • 0

As for encoding of data that the game uses in preferences (and not only), dump with meaningful names also significantly simplifies research, revealing most of information that needs to be known.

First step for decoding, that is specific to data in shared preferences, is mentioned in first post of the topic - URL decoding. Then, after base64 decoding, the data needs to be decrypted with Triple DES in ECB mode with 128-bit key "8a76f557475b615a6dcaedeaadd4d27b" (bytes of the key in hex). The result is also base64 encoded, so it needs to be decoded and the last step is to decompress the data as gzip. Below is a CyberChef recipe that implements the decoding: 
https://gchq.github.io/CyberChef/#recipe=From_Base64('A-Za-z0-9%2B/%3D',false,true)Triple_DES_Decrypt({'option':'Hex','string':'8a76f557475b615a6dcaedeaadd4d27b'},{'option':'Hex','string':''},'ECB','Raw','Raw')From_Base64('A-Za-z0-9%2B/%3D',false,true)Gunzip()

And to illustrate it with examples, value for level 5 from topic's first post after decoding is: 

{"CheckSum":"1EBXq7XeVC5e6TxnIVs/T9kE2J8rLG9IeYdOBc3Nxs9INiuzkhi6urMRRl858UeQdgjO1dLqpfw=","Offset":620,"Value":625}

and value for level 6 after decoding is:

{"CheckSum":"1EBXq7XeVC5e6TxnIVs/T9kE2J8rLG9IOjAKjtrE26cgX17n25az4rF8y2+JN4AVv8YyOpD9PI8AmbJGj0p2sw==","Offset":-836,"Value":-830}

both of which are JSON serializations of structures of "SafeInt" type that the game uses for values that it needs to protect.

Link to comment
Share on other sites

  • 0
On 11/20/2023 at 5:17 AM, CmP said:

Then, after base64 decoding, the data needs to be decrypted with Triple DES in ECB mode with 128-bit key "8a76f557475b615a6dcaedeaadd4d27b" (bytes of the key in hex).

How you found the key? I can´t find that. Well, could not find anything mentioned actually due lack of understanding, but i see you explain it as clear as possible. I was assuming you found it somewhere here:
 

namespace System.Security.Cryptography
{
	// Token: 0x02000303 RID: 771
	[Token(Token = "0x2000303")]
	internal class TripleDESTransform : SymmetricTransform
	{
		// Token: 0x0600190B RID: 6411 RVA: 0x00002053 File Offset: 0x00000253
		[Token(Token = "0x600190B")]
		[Address(RVA = "0xEC3CCC", Offset = "0xEC3CCC", VA = "0xEC3CCC")]
		public TripleDESTransform(TripleDES algo, bool encryption, byte[] key, byte[] iv)
		{
		}

		// Token: 0x0600190C RID: 6412 RVA: 0x00002053 File Offset: 0x00000253
		[Token(Token = "0x600190C")]
		[Address(RVA = "0xED0E18", Offset = "0xED0E18", VA = "0xED0E18", Slot = "15")]
		protected override void ECB(byte[] input, byte[] output)
		{
		}

		// Token: 0x0600190D RID: 6413 RVA: 0x00002050 File Offset: 0x00000250
		[Token(Token = "0x600190D")]
		[Address(RVA = "0xED0D54", Offset = "0xED0D54", VA = "0xED0D54")]
		internal static byte[] GetStrongKey()
		{
			return null;
		}

		// Token: 0x04000CF9 RID: 3321
		[Token(Token = "0x4000CF9")]
		[FieldOffset(Offset = "0x34")]
		private DESTransform E1;

		// Token: 0x04000CFA RID: 3322
		[Token(Token = "0x4000CFA")]
		[FieldOffset(Offset = "0x38")]
		private DESTransform D2;

		// Token: 0x04000CFB RID: 3323
		[Token(Token = "0x4000CFB")]
		[FieldOffset(Offset = "0x3C")]
		private DESTransform E3;

		// Token: 0x04000CFC RID: 3324
		[Token(Token = "0x4000CFC")]
		[FieldOffset(Offset = "0x40")]
		private DESTransform D1;

		// Token: 0x04000CFD RID: 3325
		[Token(Token = "0x4000CFD")]
		[FieldOffset(Offset = "0x44")]
		private DESTransform E2;

		// Token: 0x04000CFE RID: 3326
		[Token(Token = "0x4000CFE")]
		[FieldOffset(Offset = "0x48")]
		private DESTransform D3;
	}
}

Then first result i got after searching destransform E1 brought me to this github that follows something similair as the above and the encryption method you mentioned: https://github.com/mono/mono/blob/main/mcs/class/corlib/System.Security.Cryptography/TripleDESCryptoServiceProvider.cs

On 11/20/2023 at 5:17 AM, CmP said:

The result is also base64 encoded, so it needs to be decoded and the last step is to decompress the data as gzip.

I guess to decode the result in base64 i need another key? Because i tried decoding in base64 with some basic base64 decoder...without any key and then use a gzip decompresser but i got an error that im using invalid characters.

Edited by nok1a
Link to comment
Share on other sites

  • 0
5 minutes ago, nok1a said:

How you found the key?

Checked implementation of "GetTripleDESCryptoServiceProvider" method that shows how key is derived from "KEY" constant: 

image.thumb.png.5efc171ffe51de5eeb0103e581f46147.png

14 minutes ago, nok1a said:

but i got an error that im using invalid characters

Because one can't just convert binary data to text and back and expect it to work, that leads to information loss. Use representation that is suitable for binary data. Or use a tool that allows to perform multiple transformations without a need for intermediate representations of data between steps, like the above-mentioned CyberChef.

Link to comment
Share on other sites

  • 0
On 11/22/2023 at 11:35 PM, CmP said:

Checked implementation of "GetTripleDESCryptoServiceProvider" method that shows how key is derived from "KEY" constant: 

image.thumb.png.5efc171ffe51de5eeb0103e581f46147.png

Because one can't just convert binary data to text and back and expect it to work, that leads to information loss. Use representation that is suitable for binary data. Or use a tool that allows to perform multiple transformations without a need for intermediate representations of data between steps, like the above-mentioned CyberChef.

Hello mate! Trying to find same method ("GetTripleDESCryptoServiceProvider") in game https://play.google.com/store/apps/details?id=com.superplanet.airship&hl=en&gl=US. One tool show me that method in global-metada.dat, but with jadx cant find any KEY. Meybe you remember wher do you locate that method? Thanks anyway.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.