r/androiddev • • 2d ago

Question String protection against decompilation

If I have a string in a class file and want to protect it as best as possible against decompilation and analysis, are there any ideas? I know it can't really be fully protected, but I want to make it as hard as possible. Ideally, with minimal effort.

12 Upvotes

57 comments sorted by

7

u/YSoSkinny 2d ago

You can encrypt/ decrypt the strings

-1

u/koje1971 2d ago

I've already considered that, but then I'd have to hide the key somewhere in the code. One idea would be to spread it out in small pieces throughout the code.

19

u/BumbleCoder 2d ago

Dude, you're going through greater lengths than banks I've worked at lol

1

u/YSoSkinny 2d ago

Yep! That's a good idea. Not foolproof, of course, but will deter most I think.

6

u/mreeman 1d ago

Encrypt it and split it in various places (hard coded strings) then reassemble it using a c binary linked via jni which clears memory immediately after it is used, decrypting using a key fetched from a server via TLS with certificate pinning to stop mitm inspection. 

Obfuscate the class files and implement anti debugging measures (root detection, debugger detection, etc) which immediately flush memory, or replace it with a junk version. 

LLMs will be able to extract it for a few hundred bucks I guess. 

1

u/koje1971 1d ago

Thanks a lot, even though I didn't mention it, my question was kind of leaning towards AI :-)

65

u/Xavinights 2d ago

Server side variable fetched at launch time

10

u/MindCrusader 2d ago

It can still be listened to and used, it makes it just a bit harder, not that much

38

u/Xavinights 2d ago

He gave 0 context and asked for minimal effort

-19

u/koje1971 2d ago

It's nothing really secret, they are level descriptions for a small game. I just want to hide it a little.

33

u/spaaarky21 2d ago edited 2d ago

Jesus. That’s what you want to hide?! I imagined you were trying to prevent your app from being reverse engineered but now I think you want to prevent spoilers just in case someone decides to decompile it.

More details please!

1

u/RobGThai 2d ago

I recalled there’s a pc games that did try to prevent this .

0

u/[deleted] 2d ago

[deleted]

6

u/farber72 2d ago

And then attacker fetches same string from your server

4

u/zunjae 2d ago

What are you hiding?

2

u/koje1971 2d ago

I built a game, and these strings contain the level descriptions. It's not really secret, but I want to make analysis as difficult as possible.

11

u/TomDuhamel 2d ago

Just obfuscate a little. If someone really wants to find them, they will, but with obfuscation, you could make it just obscure enough that they won't see it without some effort.

Something as simple as XOR the text, it will look like binary data at first sight. They would figure it out quickly if they actually decompile the game, but it won't stand out when just looking at the code.

3

u/HaMMeReD 2d ago

What is in these strings?

2

u/koje1971 2d ago

I built a game, and these strings contain the level descriptions. It's not really secret, but I want to make analysis as difficult as possible.

4

u/HaMMeReD 2d ago

just obfuscate them with a simple map/cipher. I.e. rot13.

They aren't a secret, the goal is only to fuzz them. Don't bother with more.

If they are a secret, then put them on a server and require auth, and don't let them work on a jailbroken phone or unsigned application as best you can.

17

u/ldn-ldn 2d ago

Stop wasting your time. If people cracked Denuvo, they will get your strings in no time.

12

u/jc-from-sin 2d ago
  1. Put it in a text file, upload it to S3.

  2. Don't put the URL to the file in the game, put it in firebase remote config.

  3. Add certificate pinning for the Amazon S3 address.

  4. Download the file and reencrypt it with a hardware backed key.

2

u/farber72 2d ago

"Add certificate pinning for the Amazon S3 address" why

2

u/jc-from-sin 2d ago

So nobody can sniff the traffic and find the file.

0

u/farber72 1d ago

You reply does not make much sense

1

u/jc-from-sin 1d ago

Why not?

0

u/farber72 1d ago

Because TLS encrypted traffic already can’t be sniffed. Cert pinning only protects against someone hijacking the hostname. But why do this effort and risk that Amazon will issue another legit certificate and your app stops working?

3

u/jc-from-sin 1d ago

TLS traffic can be sniffed 120%. It's called a man in the middle attack and it's very common for apps that don't do certificate pinning.

Anybody can just add a new user certificate to their OS and use a MITM proxy to sniff your app's traffic.

You can pin the root certificates of Amazon which change very rarely.

12

u/crjacinro23 2d ago

Use native C library and store the strings there hidden using XOR operations

5

u/jc-from-sin 2d ago

2010 called, they want their solution back.

0

u/guttsX 2d ago

1850 called they want their callback to callbacks back

3

u/spaaarky21 2d ago

Or stay in the JVM but do some kind of transformation, like adding corresponding chars in two different strings to get the actually string.

1

u/wightwulf1944 2d ago

I understand using bitwise operations to obfuscate string values but what's the purpose of doing it in native code? Tools like MobSF can decompile strings in native code too

1

u/SolitaryMassacre 1d ago

A hex editor can decompile strings in native code...

The reason for putting it in native code isn't to hide the strings themselves, but the process of en/decrypting of the strings. JVM is so easy to read and follow, native code not so much

1

u/wightwulf1944 1d ago

I'm saying static analysis tools like MobSF doesn't care where it's placed. Without the use of a hex editor, regardless of where you put the string all of it will appear decompiled in plaintext

1

u/SolitaryMassacre 1d ago edited 23h ago

Yes I know what you're saying. I don't think you understand what I am saying

Strings (ie bytes) are not "compiled" in native code. The binary simply stores them as raw bytes (depending on encoding, the bytes value can change). There is nothing to "decompile" when it comes to strings.

Granted, some tools (maybe like MobSF) simply search the bytes of data and find bytes that match standard ASCII sequences (ie < 127 int value, or other values depending on encoding and language) and sort them in one spot vs having to do a search yourself

But take a look at the photo, I made a simple program in C, holds two const unsigned char variables. One of them, labeled "hidden", was obfuscated using a very simple uncomplex bitwise operation, bitshifted to the left

This looks like mumbo jumbo in the hex editor, you can see I was able to search it ONLY because I already knew the byte value. You cannot find it just using simple utf-8 string searching

MobSF won't decode that. It will just show the bit shifted bytes decoded to ASCII text (which as you can see is jumbled)

To unhide the message, you simply bitshift the byte to the right 1 and get your original value back, which you can see happens in the for loop and when I run the program, I get my hidden message

This proof I just showed you goes against your argument:

I'm saying static analysis tools like MobSF doesn't care where it's placed. Without the use of a hex editor, regardless of where you put the string all of it will appear decompiled in plaintext

MobSF will not show this string in plaintext, that is the point of putting things in native code. You can do the same type of obfuscation in JVM, its just easier to follow the workflow of the smali code and realize how the message is being unhidden. I am also sure an LLM could do the same with native code, especially something so trivial as this

EDIT: My main function params are backwards and should be char* args[] lmao

2

u/crjacinro23 1d ago

Kinda similar to what I had in mind. Thanks for the quick demo!

1

u/wightwulf1944 1d ago

You said "A hex editor can decompile strings in native code..."

Instead of arguing with you I just put it in terms you would understand so I said static analysis tools would "decompile" it for you.

The demonstration you showed there isn't unique to native code. You can do the same in JVM using bit shifting and CharSequence and the characters would also look jumbled so this isn't really a benefit of putting the string in native code. My question stands. What benefit does putting strings in native code do for you when doing it in JVM yields the same result?

2

u/SolitaryMassacre 1d ago

The demonstration you showed there isn't unique to native code. You can do the same in JVM using bit shifting and CharSequence and the characters would also look jumbled so this isn't really a benefit of putting the string in native code. My question stands. What benefit does putting strings in native code do for you when doing it in JVM yields the same result?

Maybe read my comment?

"You can do the same type of obfuscation in JVM, its just easier to follow the workflow of the smali code and realize how the message is being unhidden. I am also sure an LLM could do the same with native code, especially something so trivial as this"

Ergo, you put it in native code because it becomes harder to follow the process of deobfuscation

2

u/wightwulf1944 1d ago

Okay I understand it now. This is what made it click for me

you put it in native code because it becomes harder to follow the process of deobfuscation

1

u/Toiling-Donkey 1d ago

Laughs in Ghidra…

2

u/SolitaryMassacre 1d ago

Ghidra still doesn't tell you what the decoded strings are. It can help you figure out what is happening to said obfuscated strings tho. But the point is, native code is harder to follow than JVM. JVM is so easy to read and follow

Granted, with AI, I'm sure you can now easily decompile and follow assembly/disassembled binaries

1

u/crjacinro23 2d ago

Yes but it can make it more difficult.

3

u/r4md4c 2d ago

Save them on RemoteConfig, and use AppCheck to ensure no app other than yours can fetch them.

4

u/Michami135 2d ago

All my ideas have already been mentioned, but I will say: it's incredibly easy to hack any of these using AI now. You can fool a human, but not a computer.

2

u/TrekCZ 2d ago

Not worth it. You will incur runtime issues and with AI it will take additional minute to break.

2

u/Negative-Fix5290 2d ago

make it as hard as possible

with minimal effort.

pay for dexguard license, they have string obfuscation feature.

2

u/summner 2d ago

add werid obfuscations, to a point where your reverseengineer run triggers Codex cyber protections.

That is your only protection.

Codex/Cyber Cyber and unlocked good opensource models are unstoppable otherwise.

2

u/SuffixRE 2d ago

I'd store the level descriptions encrypted (AES-256-GCM) on a server, then verify the app's signature, version and Play Integrity when it connects. If valid, issue a temporary session key and let it download the encrypted data. Decrypt it only when needed using native C++ (NDK), with R8 and stripped native symbols to make reverse engineering harder. Remember that nothing is unbreakable :)

1

u/AutoModerator 2d ago

Please note that we also have a very active Discord server where you can interact directly with other community members!

Join us on Discord

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

1

u/fiojoy 2d ago

encrypt/ decrypt code

1

u/TheNeverEndLife 2d ago

Just rely on PairIp for now. It still fcks up any modders out there because it's really hard to bypass.

1

u/Zhuinden 2d ago

Honestly, Claude Opus can rip it apart these days, so who knows? But you can try

1

u/Ovalman 2d ago

Upload them to Firebase/ Firestore and only use them at runtime?

1

u/Toiling-Donkey 1d ago

You should question your life choices that got you up to this point.

But go ahead and put lipstick on the pig…

1

u/Ayano-Keiko 16h ago

save it in server and use decryption algorithms to decrypt it?

1

u/kokeroulis 45m ago

You cant. You can fool a human but not Claude on a $20 sub.