diff --git a/CMakeLists.txt b/CMakeLists.txt index bd365cc..49f7899 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ if(${BUILD_BARON_DEBUG}) -O0\ -fno-inline\ -fno-omit-frame-pointer\ - -DBARON_DEBUG + -DBARON_DEBUG\ ") else() set(BUILD_FAKE_JNI_DEBUG OFF CACHE BOOL "") @@ -28,6 +28,9 @@ endif() set(BUILD_FAKE_JNI_TESTS OFF CACHE BOOL "") set(BUILD_FAKE_JNI_EXAMPLES OFF CACHE BOOL "") +set(CMAKE_CXX_FLAGS ${compiler_flags}) +set(CMAKE_C_FLAGS ${compiler_flags}) + add_subdirectory(fake-jni) file(GLOB_RECURSE BARON_SRC "src/**.cpp") diff --git a/example/jni/src/jni.cpp b/example/jni/src/jni.cpp index 85ea738..cd5abe5 100644 --- a/example/jni/src/jni.cpp +++ b/example/jni/src/jni.cpp @@ -5,6 +5,11 @@ JNIEXPORT jint JNI_OnLoad(JavaVM * vm, void *) { printf("JNI_OnLoad!\n"); + JNIEnv *env; + vm->GetEnv((void **)&env, JNI_VERSION_1_8); + auto clazz = env->FindClass("yo_this is not a valid class name_"); + auto mid = env->GetMethodID(clazz, "exampleMethod", "()V"); + auto fid = env->GetFieldID(clazz, "someField", "I"); return JNI_VERSION_1_8; } diff --git a/example/probe/src/main.cpp b/example/probe/src/main.cpp index 3c7065f..96b3eba 100644 --- a/example/probe/src/main.cpp +++ b/example/probe/src/main.cpp @@ -11,5 +11,7 @@ int main(int argc, char **argv) { vm.removeLibrary("./libjni.so"); + vm.destroy(); + return 0; } \ No newline at end of file diff --git a/fake-jni b/fake-jni index 1cca983..42f40f8 160000 --- a/fake-jni +++ b/fake-jni @@ -1 +1 @@ -Subproject commit 1cca9836a9bf1d718a18a6668acea3865cf7c8d1 +Subproject commit 42f40f8d7d54eeac7deb0690801b0436e89e759a diff --git a/include/baron/baron.h b/include/baron/baron.h index e588c4f..9bc0794 100644 --- a/include/baron/baron.h +++ b/include/baron/baron.h @@ -7,5 +7,6 @@ #include "baron/impl/interface/jvmti.h" #include "baron/impl/env/jni.h" #include "baron/impl/env/jvmti.h" +#include "baron/util/util.h" namespace Baron {} \ No newline at end of file diff --git a/include/baron/impl/interface/native.h b/include/baron/impl/interface/native.h index 5bce6bb..93dec13 100644 --- a/include/baron/impl/interface/native.h +++ b/include/baron/impl/interface/native.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "baron/impl/jvm.h" @@ -13,7 +14,7 @@ namespace Baron::Interface { //inpl/interface/native/object.cpp jobject allocObject(jclass) const override; - jobject newObjectV(jclass, jmethodID, va_list) const override; + jobject newObjectV(jclass, jmethodID, CX::va_list_t&) const override; jobject newObjectA(jclass, jmethodID, const jvalue *) const override; jclass getObjectClass(jobject) const override; jboolean isInstanceOf(jobject, jclass) const override; diff --git a/include/baron/impl/jvm.h b/include/baron/impl/jvm.h index 3c49e7a..11e4be4 100644 --- a/include/baron/impl/jvm.h +++ b/include/baron/impl/jvm.h @@ -25,7 +25,7 @@ namespace Baron { //FakeJni::Jvm overrides virtual const FakeJni::JClass * findClass(const char * name) const override; - virtual void destroy() override; + virtual jint destroy() override; //baron specific virtual bool isClassBlacklisted(const char * name); diff --git a/include/baron/util/util.h b/include/baron/util/util.h new file mode 100644 index 0000000..5b6277e --- /dev/null +++ b/include/baron/util/util.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +namespace Baron { + std::string deserializeClassModifiers(uint32_t modifiers); + std::string deserializeFieldModifiers(uint32_t modifiers); + std::string deserializeMethodModifiers(uint32_t modifiers); +} \ No newline at end of file diff --git a/src/impl/interface/native/field.cpp b/src/impl/interface/native/field.cpp index 5a6c958..f6e31ca 100644 --- a/src/impl/interface/native/field.cpp +++ b/src/impl/interface/native/field.cpp @@ -2,21 +2,35 @@ #ifdef BARON_DEBUG #define LOG_BLACKLIST_MATCH \ -fprintf( - vm.getLog(), - "BARON INFO: Ignored blacklisted field lookup '%s#%s::%s'!\n", - className, - name, - sig +fprintf(\ + vm.getLog(),\ + "BARON INFO: Ignored blacklisted field lookup '%s#%s::%s'!\n",\ + className,\ + name,\ + sig\ ); #else #define LOG_BLACKLIST_MATCH #endif +#ifdef BARON_DEBUG +#define LOG_FABRICATED_FIELD \ +fprintf(\ + vm.getLog(),\ + "BARON INFO: Fabricated field %s::%s -> 0x%lx\n",\ + name,\ + sig,\ + (intptr_t)fid\ +); +#else +#define LOG_FABRICATED_FIELD +#endif + #define CHECK_BLACKLIST \ JClass * clazz = *jclazz;\ const auto className = clazz->getName();\ if (vm.isClassBlacklisted(className) || vm.isFieldBlacklisted(name, sig, className)) {\ + LOG_BLACKLIST_MATCH\ return nullptr;\ } @@ -41,6 +55,7 @@ namespace Baron::Interface { fid = new JFieldID(fabricatedGetCallback, fabricatedSetCallback, name, sig, JFieldID::PUBLIC); JClass * clazz = *jclazz; clazz->registerField(fid); + LOG_FABRICATED_FIELD } return fid; } @@ -54,6 +69,7 @@ namespace Baron::Interface { fid = new JFieldID(fabricatedGetCallback, fabricatedSetCallback, name, sig, JFieldID::PUBLIC | JFieldID::STATIC); JClass * clazz = *jclazz; clazz->registerField(fid); + LOG_FABRICATED_FIELD } return fid; } diff --git a/src/impl/interface/native/method.cpp b/src/impl/interface/native/method.cpp index 5d87930..f4f098b 100644 --- a/src/impl/interface/native/method.cpp +++ b/src/impl/interface/native/method.cpp @@ -13,6 +13,13 @@ fprintf(\ #define LOG_BLACKLIST_MATCH #endif +#ifdef BARON_DEBUG +#define LOG_FABRICATED_METHOD \ +fprintf(vm.getLog(), "BARON INFO: Fabricated method '%s%s' -> 0x%lx\n", name, sig, (intptr_t)mid); +#else +#define LOG_FABRICATED_CLASS +#endif + #define CHECK_BLACKLIST \ JClass * clazz = *jclazz;\ const auto className = clazz->getName();\ @@ -42,6 +49,7 @@ namespace Baron::Interface { mid = new JMethodID(fabricatedMethodCallback, sig, name, JMethodID::PUBLIC); JClass * clazz = *jclazz; clazz->registerMethod(mid); + LOG_FABRICATED_METHOD } return mid; } @@ -55,6 +63,7 @@ namespace Baron::Interface { mid = new JMethodID(fabricatedMethodCallback, sig, name, JMethodID::PUBLIC | JMethodID::STATIC); JClass * clazz = *jclazz; clazz->registerMethod(mid); + LOG_FABRICATED_METHOD } return mid; } diff --git a/src/impl/interface/native/object.cpp b/src/impl/interface/native/object.cpp index a4dcc05..919dc64 100644 --- a/src/impl/interface/native/object.cpp +++ b/src/impl/interface/native/object.cpp @@ -7,7 +7,7 @@ namespace Baron::Interface { return vm.fabricateInstance(jclazz); } - jobject NativeInterface::newObjectV(jclass jclazz, jmethodID jmid, va_list list) const { + jobject NativeInterface::newObjectV(jclass jclazz, jmethodID jmid, CX::va_list_t& list) const { using namespace FakeJni; auto mid = (JMethodID *)jmid; if (mid->isArbitrary) { diff --git a/src/impl/jvm.cpp b/src/impl/jvm.cpp index a227d1b..42179b4 100644 --- a/src/impl/jvm.cpp +++ b/src/impl/jvm.cpp @@ -6,6 +6,7 @@ #include "baron/impl/interface/jvmti.h" #include "baron/impl/env/jni.h" #include "baron/impl/env/jvmti.h" +#include "baron/util/util.h" #include @@ -33,14 +34,18 @@ namespace Baron { auto& ref = const_cast(*this); //Ignore class lookups for blacklisted classes if (std::find(blacklistedClasses.begin(), blacklistedClasses.end(), name) != blacklistedClasses.end()) { +#ifdef BARON_DEBUG fprintf(getLog(), "BARON INFO: Ignored lookup request for blacklisted class '%s'\n", name); +#endif return nullptr; } auto clazz = FakeJni::Jvm::findClass(name); if (!clazz) { clazz = new JClass(name); ref.registerClass(clazz); +#ifdef BARON_DEBUG fprintf(getLog(), "BARON INFO: Fabricated class '%s' -> 0x%lx\n", name, (intptr_t)clazz); +#endif } return clazz; } @@ -48,34 +53,37 @@ namespace Baron { //TODO print more information // - field and function access / invocation counts // - field and function access locations (with stack traces once libunwind is integrated) - // - serialize field and function modifiers to their respective names and print them as a list - void Jvm::destroy() { + jint Jvm::destroy() { auto & classes = getClasses(); const auto & log = getLog(); if (classes.size() > 0) { fprintf(log, "BARON INFO: The following classes were registered during execution:\n"); for (auto clazz : getClasses()) { fprintf(log, "\t'%s':\n", clazz->getName()); - fprintf(log, "\t - Modifiers: 0x%x\n", clazz->modifiers); + auto mods = clazz->modifiers; + fprintf(log, "\t - Modifiers: 0x%x [%s]\n", mods, deserializeClassModifiers(mods).c_str()); fprintf(log, "\t - Parent: '%s'\n", clazz->parent.getName()); fprintf(log, "\t - Fabricated: %s\n", (clazz->isArbitrary ? "yes" : "no")); auto & fields = clazz->getFields(); fprintf(log, "\t - Fields: %u\n", fields.size()); for (auto & field : fields) { fprintf(log, "\t\t'%s' -> '%s':\n", field->getName(), field->getSignature()); - fprintf(log, "\t\t - Modifiers: 0x%x\n", field->getModifiers()); + mods = field->getModifiers(); + fprintf(log, "\t\t - Modifiers: 0x%x [%s]\n", mods, deserializeFieldModifiers(mods).c_str()); fprintf(log, "\t\t - Fabricated: %s\n", (field->isArbitrary ? "yes" : "no")); } auto & methods = clazz->getMethods(); for (auto & method : methods) { fprintf(log, "\t\t'%s%s':\n", method->getName(), method->getSignature()); - fprintf(log, "\t\t - Modifiers: 0x%x\n", method->getModifiers()); + mods = method->getModifiers(); + fprintf(log, "\t\t - Modifiers: 0x%x [%s]\n", mods, deserializeMethodModifiers(mods).c_str()); fprintf(log, "\t\t - Fabricated: %s\n", (method->isArbitrary ? "yes" : "no")); } } } else { fprintf(log, "BARON INFO: No classes were registered during execution.\n"); } + return JNI_OK; } bool Jvm::isClassBlacklisted(const char * name) { diff --git a/src/util/util.cpp b/src/util/util.cpp new file mode 100644 index 0000000..7666fac --- /dev/null +++ b/src/util/util.cpp @@ -0,0 +1,56 @@ +#include "baron/util/util.h" + +#define _MODIFIER_CASE(clazz, modifier) \ +if ((modifiers & clazz::modifier) == clazz::modifier) {\ + smods.append(#modifier);\ +} + +#include + +namespace Baron { + std::string deserializeClassModifiers(uint32_t modifiers) { + std::string smods; + _MODIFIER_CASE(FakeJni::JClass, PUBLIC) + _MODIFIER_CASE(FakeJni::JClass, PRIVATE) + _MODIFIER_CASE(FakeJni::JClass, PROTECTED) + _MODIFIER_CASE(FakeJni::JClass, STATIC) + _MODIFIER_CASE(FakeJni::JClass, FINAL) + _MODIFIER_CASE(FakeJni::JClass, INTERFACE) + _MODIFIER_CASE(FakeJni::JClass, ABSTRACT) + _MODIFIER_CASE(FakeJni::JClass, SYNTHETIC) + _MODIFIER_CASE(FakeJni::JClass, ANNOTATION) + _MODIFIER_CASE(FakeJni::JClass, ENUM) + return smods; + } + + std::string deserializeFieldModifiers(uint32_t modifiers) { + std::string smods; + _MODIFIER_CASE(FakeJni::JMethodID, PUBLIC) + _MODIFIER_CASE(FakeJni::JMethodID, PRIVATE) + _MODIFIER_CASE(FakeJni::JMethodID, PROTECTED) + _MODIFIER_CASE(FakeJni::JMethodID, STATIC) + _MODIFIER_CASE(FakeJni::JMethodID, FINAL) + _MODIFIER_CASE(FakeJni::JMethodID, SYNCHRONIZED) + _MODIFIER_CASE(FakeJni::JMethodID, BRIDGE) + _MODIFIER_CASE(FakeJni::JMethodID, VARARGS) + _MODIFIER_CASE(FakeJni::JMethodID, NATIVE) + _MODIFIER_CASE(FakeJni::JMethodID, ABSTRACT) + _MODIFIER_CASE(FakeJni::JMethodID, STRICT) + _MODIFIER_CASE(FakeJni::JMethodID, SYNTHETIC) + return smods; + } + + std::string deserializeMethodModifiers(uint32_t modifiers) { + std::string smods; + _MODIFIER_CASE(FakeJni::JFieldID, PUBLIC) + _MODIFIER_CASE(FakeJni::JFieldID, PRIVATE) + _MODIFIER_CASE(FakeJni::JFieldID, PROTECTED) + _MODIFIER_CASE(FakeJni::JFieldID, STATIC) + _MODIFIER_CASE(FakeJni::JFieldID, FINAL) + _MODIFIER_CASE(FakeJni::JFieldID, VOLATILE) + _MODIFIER_CASE(FakeJni::JFieldID, TRANSIENT) + _MODIFIER_CASE(FakeJni::JFieldID, SYNTHETIC) + _MODIFIER_CASE(FakeJni::JFieldID, ENUM) + return smods; + } +} \ No newline at end of file