The main question is: is it safe to change some 'string" information inside *.class
file (java compiled classes).
What I'm doing is:
using regexp I'm trying to find all IP address stings inside some compiled project"
find . -type f | xargs grep -E "[0-9]{3}\.[0-9]{3}\.1\.[0-9]{0,3}"
This command telling me that some binary files are matching my regexp. And it is pointing that this binary files are .jar
and .class
. When I open those .class
files using vi
I can see a lot of strange characters and also something like "http://192.168.1.111" among this binary garbage.
My final task is replace all IP addresses (using sed -i
) to FQDN.
Is it safe? Or only working solution to disassemble all project and recompile again?
I test it this way:
Create Change.java
public class Change {
public static String CHANGE_ME="SOME_TEST_STRING";
public static void main (String[] argv){
System.out.println(CHANGE_ME);
}
}
Run it and saw this in terminal
$ java Change
SOME_TEST_STRING
Compile it and run replacing:
sed -i 's/SOME_TEST_STRING/AAAAA/g' Change.class
After this run again
$ java Change
Exception in thread "main" java.lang.ClassFormatError: Illegal UTF8 string in constant pool in class file Change
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:455)
at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:367)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:495)
No, that is not safe. It is so far from safe that it's outside the solar system. Recompile the project.
You could use sed to replace the IP in the source code, though. That has a good chance of working.
String in .class
file is encoded with 2 bytes representing its bytes length, then its byte representation in modified UTF-8 encoding. You can safely replace uniqoue ASCII string with the same length. Other replacements are not safe. And that's not recommended anyway, if you have access to sources, you should recompile files.
Example how that works:
$ cat Test.java
public class Test {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
$ javac Test.java
$ java Test
Hello, World!
$ hexdump -C Test.class
...
00000060 2f 53 74 72 69 6e 67 3b 29 56 01 00 0a 53 6f 75 |/String;)V...Sou|
00000070 72 63 65 46 69 6c 65 01 00 09 54 65 73 74 2e 6a |rceFile...Test.j|
00000080 61 76 61 0c 00 07 00 08 07 00 17 0c 00 18 00 19 |ava.............|
00000090 01 00 0d 48 65 6c 6c 6f 2c 20 57 6f 72 6c 64 21 |...Hello, World!|
000000a0 07 00 1a 0c 00 1b 00 1c 01 00 04 54 65 73 74 01 |...........Test.|
000000b0 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 |..java/lang/Obje|
000000c0 63 74 01 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 53 |ct...java/lang/S|
...
we can see that "Hello, World!" string is located at 0x93 offset. Now we will replace that string with "Hello, Earth!".
$ echo -n Hello, Earth! | dd conv=notrunc of=Test.class bs=1 seek=$((0x93))
$ java Test
Hello, Earth!
echo -n Hello Earth!
prints 12 bytes to its stdout. dd conv=notrunc of=Test.class bs=1 seek=$((0x93))
replaces bytes in the file Test.class
from 0x93 offset with its input (Hello Earth
in our case).
here's full transcript: http://pastebin.com/rJi4cRX1
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With