Call JNI methods that were not written for your class - java

It seems that JNI methods need to be written with the Java class signature built in to them. I want to call a JNI method that I didn't write. Can I call a native method on a library that was not written with my class in mind?

Given:
package com.mycompany.package
class MyClass
{
public native void doSomething();
}
is transformed (mangled) into a natively linked method name of:
Java_com_mycompany_package_MyClass_doSomething
it seems you would need the same class in the same package in order to connect the native method to the Java method. This seems like it's likely to be problematic and/or error prone if you don't have control over the native library. And packaging your code in a foreign package is a bad idea, esp. if the foreign package is signed and sealed.
Also problematic is that native invocation generally have some specific considerations which you might be violating - like thread-safety concerns, or releasing memory or lock (the need to call other native functions around the one you're using).
From my (considerable) experience with JNI I wouldn't recommend it unless you're desperate and have no other options, and you're really familiar with the target system and API.
Your better option would be to write a simple native wrapper around the target O/S API(s) you want to use.

Related

How can you tell if a JDK class is implemented natively instead of in java code?

For example, when exploring source classes in IntelliJ, and you find a class like Constructor in java.lang.reflect...The parameters to all the methods are var0,var1,var2,...varN. But other than that, how would one know it is implemented natively?
EDIT: The correct question really is how to tell whether a method is native in Java, because, as pointed out by responders, classes themselves can't be "native."
In general, classes themselves are never native. Only methods can have native implementation.
But that doesn't mean the JVM can't treat some classes in special way. But you shouldn't be able to tell the difference. The JVM treats them differently as an optimization (for example String class) or because doing otherwise would be very inconvenient (for example NoClassDefFoundError is treated in a special way, and can be thrown and printed even if the class doesn't exist on your classpath. You can try it by moving/renaming rt.jar and running java).
As for the constructor arguments being named varN, it's likely because you didn't actually install JDK source, and whatever IDE you use shows you decompiled java code, which doesn't have variable names preserved. In the case of Constructor class, the constructor is likely to be actually implemented in java, but called, and the object returned, from native code.
A method is native if it has native modifier. But there are also methods that JVM treats as intrinsics. The only way to know those, together with special classes, for sure is to look at JVM source. There is also a very thin line between what can be considered JVM optimization and what can be considered intrinsic, and because you don't normally modify JVM code, so unless you are JDK developer, it doesn't really matter. This is also an implementation detail that can change in different JVM or different JVM version. In fact, there are attempts at writing JVMs completely in java, without any real native code, aside of some tiny startup wrapper. In those cases, everything is in java. There is no native code.

Use prebuilt JNI library in Android Studio 3.1

I was given a shared object (*.so file) that I need to reference from my app. I know for a fact that the shared object uses JNI. Now, I have some experience with Android app development, but none with native code. I have looked at a lot of answers here on StackOverflow and on Google in general, but none seem to fit in my question.
Basically, this shared object was for another app, and I have the code for that app, and now I need to implement it in my app. I am lost as to where I should start or what I should do. If anyone can help guide me through this process that would be very nice.
Also, I do not have the source files nor the header files for the shared object. I do know the name of the native method.
If you don't have the Java sources that defined these native methods originally, you can often reverse engineer the necessary native method definitions from the .so file itself. E.g., if the library exports Java_com_example_testjni_MainActivity_stringFromJni, then you must add a Java class
package com.example.thestjni;
class MainActivity {
public native static String stringFromJni();
}
This does not give your the correct parameters or return types for the native methods. Also, you must guess whether the native method should be declared static or not.
To be on the safe side, you will add a static constructor to this class, to make sure the library is loaded:
package com.example.thestjni;
class MainActivity {
static {
System.loadLibrary("thirdparty");
}
public native static String stringFromJni();
}
You are free to rename the 3rd party library to your liking, but not the package and not the class. You don't care if the original Java class declared the native method private, you can safely declare it public in your project.
To find the names of JNI functions exported by prebuilt library libthirdparty.so, you can use the nm tool provided with Android NDK toolchains:
nm -D libthirdparty.so | grep Java_
If you have the Java code for another app that uses it- find the Java code in the other library that calls it. Those functions should be defined with the keyword native. Take that class(es), without renaming or changing the package, and put it in your project. Now you can call those native functions via the Java native function definitions.
Of course without source you can't compile for any other architecture. So hopefully you have the .so files for all the appropriate ones. Remember to load the library if those class(es) don't do it for you.

Migrating C++ project to Java, protecting implementation details

I have a quite complex project to migrate from C++ (Linux) to Java
Currently, the C++ version is being distributed as a shared library (.so) followed by top-level interface header class. The implementation details are fully hidden from the final user.
This question is not about porting the C++ code to Java, but rather about creating similar distribution package.
Let's assume I have a very simple 'public' class in C++, topapi.h:
class TopApi
{
public:
void do( const string& v );
}
The actual implementation is hidden from the API user. The actual project may contain another 100 files/classes do() will call.
The distribution will contain 2 files: topapi.so and topapi.h
Users will #include "topapi.h" in their code, and link their applications with topapi.so.
The questions are:
1. How can I achieve a similar effect in Java (hide the IP related code)
2. How do I show public methods to the user ( not related to code protection, just a java version of the header file above )
Check out proguard. It will at least obfuscate the jar file, which otherwise is basically human readable. It's not absolutely safe from reverse engineering, but I guess neither is an so file.
I'm not an expert with Java, but this is what we have done to protect implementations in the past.
I don't know exactly what the motivations are for a Java port, but if it is just to support a Java end user, you could consider a JNI wrapper. I guess this probably isn't the case, but I thought I would mention it.
As far as exposing interface code to the user, you could write a Java interface class (like a pure virtual abstract c++ class) and simply not proguard that class.
To answer the question of how to show public methods to the user. This is usually done through a combination of declaring the internal classes without an access modifier, which makes them only accessible from within the same package, and not documenting them. Don't depend on the former though, it's easily circumventable, but it sends the message to the user that those classes are internal.
Java 9 adds modules which allow you to encapsulate entire packages, but it's not here yet, and you would still be able to circumvent the encapsulation.
One side effect of ahead of time compilation (usually the case with C++) is that the distributed code is already optimized, and contains no metadata, so it's harder to reverse engineer. Java is distributed in an intermediate language, but the actual machine code is generated at runtime (JIT compilation). The intermediate language is practically un-optimized, so it's easier to reverse engineer. Java also merges the idea of header files and source files where a .class file will contain all the metadata you need to use it.

How to make a function accessible to certain classes only?

I am working on an API for a software so my users can extend it without modifying the source code. But, I want only certain functions to be accessed by certain classes for security reasons. Is there anyway to do this? Also, I have no code because I have no idea on how to do this.
Thanks! -Trent
I have two thoughts on this, one is that you can look at how Minecraft Forge created their plugin API.
Another way is to have a limited API between your core code and the actual plugins, but, you need to be careful of the platform. For example, if you write the core application in Java or C#, then I can use Aspect Oriented Programming (AOP) to bypass your security and have my code change the behavior of yours.
If you use functional programming (FP) languages, then you can protect more from this type of approach, if you also are not using languages on these platforms, but they are not perfect.
So, there is a trade-off between power and convenience, so how useful do you want your application to be, and how secure?
One possible solution that may work is if you go with something similar to Minecraft, though I doubt they do this, but, give a stub application to the user. They can extend it with plugins, and the interface functions they can modify are in the stub. When the program starts, the plugins are loaded, and the interface may be modified or extended, but, then the core program is pulled down and put into the stub, and then the actual program runs. The core program can be recompiled and manipulated so method names are changed, so reflection is harder to use, but taking this approach, and doing it well, would be hard.
BTW, I like Alex T's response, I just gave different terms to some of his, such as AOP instead of reflection and immutability is part of FP.
You mention jar, which means you are using something that runs on a JVM, so you may want to read up on AspectJ, as it can significantly alter the behavior of applications. You can have private methods, but I can put code that runs instead of yours, or change the parameters or the return value before or after the method is called.
To protect variables inside of classes, you can make them private, and accessible via getter and setter methods with varying levels of protection. This also applies to classes themselves; if you wanted to prevent the user from being able to instantiate a class, you could mark the class' constructor as protected to allow instantiation only within it's package.
If you wanted to hide the implementation details of a class altogether, you could declare the class as class X instead of public class X, which would hide methods from the API for standard development.
This will quickly get you the behaviour you're after, but there's an aspect of Java called reflection, which allows an executable Java program to analyze and manipulate it's own implementation; in this regard, no field or method is ever completely safe.
You can also safeguard variables by providing access to them via 'immutable' Objects; these are objects designed to forbid the caller from modifying the original source contents.

bytecode instrumentation to native java functions

I am using asm to do byte code instrumentation into java function.
Is there a way to do the same for jre native functions? Maybe a way to wrap the native function with a java function?
My purpose at the end is to get a list of all functions that ran with their arguments.
Since the native methods are declared in the class file, you can replace them just like any other method. The tricky part is how to invoke the original method. To achieve this you can create another native method which will be linked to the original native code.
This must happen at loading time as most JVMs do not support adding methods afterwards. There is a feature to help linking your new helper method to the original code, the native method prefix. The documentation of Instrumentation.setNativeMethodPrefix explains the details.

Categories

Resources