int main(int argc, char *argv[]) { Class *array_class, *main_class; Object *system_loader, *array; MethodBlock *mb; InitArgs args; int class_arg; char *cpntr; int status; int i; setDefaultInitArgs(&args); class_arg = parseCommandLine(argc, argv, &args); args.main_stack_base = &array_class; if(!initVM(&args)) { printf("Could not initialise VM. Aborting.\n"); exit(1); } if((system_loader = getSystemClassLoader()) == NULL) goto error; mainThreadSetContextClassLoader(system_loader); for(cpntr = argv[class_arg]; *cpntr; cpntr++) if(*cpntr == '.') *cpntr = '/'; main_class = findClassFromClassLoader(argv[class_arg], system_loader); if(main_class != NULL) initClass(main_class); if(exceptionOccurred()) goto error; mb = lookupMethod(main_class, SYMBOL(main), SYMBOL(_array_java_lang_String__V)); if(mb == NULL || !(mb->access_flags & ACC_STATIC)) { signalException(java_lang_NoSuchMethodError, "main"); goto error; } /* Create the String array holding the command line args */ i = class_arg + 1; if((array_class = findArrayClass(SYMBOL(array_java_lang_String))) && (array = allocArray(array_class, argc - i, sizeof(Object*)))) { Object **args = ARRAY_DATA(array, Object*) - i; for(; i < argc; i++) if(!(args[i] = Cstr2String(argv[i]))) break; /* Call the main method */ if(i == argc) executeStaticMethod(main_class, mb, array); }
int main(int argc, char *argv[]) { Class *array_class, *main_class; Object *system_loader, *array; MethodBlock *mb; InitArgs args; int class_arg; char *cpntr; int status; int i; setDefaultInitArgs(&args); class_arg = parseCommandLine(argc, argv, &args); args.main_stack_base = &array_class; initVM(&args); if((system_loader = getSystemClassLoader()) == NULL) { printf("Cannot create system class loader\n"); printException(); exitVM(1); } mainThreadSetContextClassLoader(system_loader); for(cpntr = argv[class_arg]; *cpntr; cpntr++) if(*cpntr == '.') *cpntr = '/'; if((main_class = findClassFromClassLoader(argv[class_arg], system_loader)) != NULL) initClass(main_class); if(exceptionOccurred()) { printException(); exitVM(1); } mb = lookupMethod(main_class, SYMBOL(main), SYMBOL(_array_java_lang_String__V)); if(!mb || !(mb->access_flags & ACC_STATIC)) { printf("Static method \"main\" not found in %s\n", argv[class_arg]); exitVM(1); } /* Create the String array holding the command line args */ i = class_arg + 1; if((array_class = findArrayClass(SYMBOL(array_java_lang_String))) && (array = allocArray(array_class, argc - i, sizeof(Object*)))) { Object **args = (Object**)ARRAY_DATA(array) - i; for(; i < argc; i++) if(!(args[i] = Cstr2String(argv[i]))) break; /* Call the main method */ if(i == argc) executeStaticMethod(main_class, mb, array); } /* ExceptionOccurred returns the exception or NULL, which is OK for normal conditionals, but not here... */ if((status = exceptionOccurred() ? 1 : 0)) printException(); /* Wait for all but daemon threads to die */ mainThreadWaitToExitVM(); exitVM(status); }
v8::Local<v8::Value> Java::createJVM(JavaVM** jvm, JNIEnv** env) { v8::Local<v8::Value> asyncOptions = this->handle()->Get(Nan::New<v8::String>("asyncOptions").ToLocalChecked()); if (asyncOptions->IsObject()) { configureAsync(asyncOptions); } // setup classpath std::ostringstream classPath; classPath << "-Djava.class.path="; v8::Local<v8::Value> classPathValue = this->handle()->Get(Nan::New<v8::String>("classpath").ToLocalChecked()); if(!classPathValue->IsArray()) { return Nan::TypeError("Classpath must be an array"); } v8::Local<v8::Array> classPathArrayTemp = v8::Local<v8::Array>::Cast(classPathValue); m_classPathArray.Reset(classPathArrayTemp); for(uint32_t i=0; i<classPathArrayTemp->Length(); i++) { if(i != 0) { #ifdef WIN32 classPath << ";"; #else classPath << ":"; #endif } v8::Local<v8::Value> arrayItemValue = classPathArrayTemp->Get(i); if(!arrayItemValue->IsString()) { return Nan::TypeError("Classpath must only contain strings"); } v8::Local<v8::String> arrayItem = arrayItemValue->ToString(); v8::String::Utf8Value arrayItemStr(arrayItem); classPath << *arrayItemStr; } // set the native binding location v8::Local<v8::Value> v8NativeBindingLocation = this->handle()->Get(Nan::New<v8::String>("nativeBindingLocation").ToLocalChecked()); v8::String::Utf8Value nativeBindingLocationStr(v8NativeBindingLocation); s_nativeBindingLocation = *nativeBindingLocationStr; // get other options v8::Local<v8::Value> optionsValue = this->handle()->Get(Nan::New<v8::String>("options").ToLocalChecked()); if(!optionsValue->IsArray()) { return Nan::TypeError("options must be an array"); } v8::Local<v8::Array> optionsArrayTemp = v8::Local<v8::Array>::Cast(optionsValue); m_optionsArray.Reset(optionsArrayTemp); // create vm options int vmOptionsCount = optionsArrayTemp->Length() + 1; JavaVMOption* vmOptions = new JavaVMOption[vmOptionsCount]; //printf("classPath: %s\n", classPath.str().c_str()); vmOptions[0].optionString = strdup(classPath.str().c_str()); for(uint32_t i=0; i<optionsArrayTemp->Length(); i++) { v8::Local<v8::Value> arrayItemValue = optionsArrayTemp->Get(i); if(!arrayItemValue->IsString()) { delete[] vmOptions; return Nan::TypeError("options must only contain strings"); } v8::Local<v8::String> arrayItem = arrayItemValue->ToString(); v8::String::Utf8Value arrayItemStr(arrayItem); vmOptions[i+1].optionString = strdup(*arrayItemStr); } JavaVMInitArgs args; // The JNI invocation is documented to include a function JNI_GetDefaultJavaVMInitArgs that // was formerly called here. But the documentation from Oracle is confusing/contradictory. // 1) It claims that the caller must set args.version before calling JNI_GetDefaultJavaVMInitArgs, which // we did not do. // 2) The sample code provide at the top of the doc doesn't even call JNI_GetDefaultJavaVMInitArgs. // 3) The Oracle documentation for Java 6 through Java 8 all contain a comment "Note that in the JDK/JRE, there is no // longer any need to call JNI_GetDefaultJavaVMInitArgs." // 4) It seems that some platforms don't implement JNI_GetDefaultJavaVMInitArgs, or have // marked it deprecated. // Omitting the call to JNI_GetDefaultJavaVMInitArgs works fine on Mac and Linux with Java 7 and Java 8. // The Oracle documentation is here: // http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/invocation.html // http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/invocation.html // http://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html args.version = JNI_BEST_VERSION; // JNI_GetDefaultJavaVMInitArgs(&args); // If this turns out to be necessary, it should be called here. args.ignoreUnrecognized = false; args.options = vmOptions; args.nOptions = vmOptionsCount; JavaVM* jvmTemp; JNI_CreateJavaVM(&jvmTemp, (void **)env, &args); *jvm = jvmTemp; delete [] vmOptions; m_classLoader = getSystemClassLoader(*env); v8::Local<v8::Value> onJvmCreated = this->handle()->Get(Nan::New<v8::String>("onJvmCreated").ToLocalChecked()); // TODO: this handles sets put doesn't prevent modifing the underlying data. So java.classpath.push will still work which is invalid. Nan::SetAccessor(this->handle(), Nan::New<v8::String>("classpath").ToLocalChecked(), AccessorProhibitsOverwritingGetter, AccessorProhibitsOverwritingSetter); Nan::SetAccessor(this->handle(), Nan::New<v8::String>("options").ToLocalChecked(), AccessorProhibitsOverwritingGetter, AccessorProhibitsOverwritingSetter); Nan::SetAccessor(this->handle(), Nan::New<v8::String>("nativeBindingLocation").ToLocalChecked(), AccessorProhibitsOverwritingGetter, AccessorProhibitsOverwritingSetter); Nan::SetAccessor(this->handle(), Nan::New<v8::String>("asyncOptions").ToLocalChecked(), AccessorProhibitsOverwritingGetter, AccessorProhibitsOverwritingSetter); Nan::SetAccessor(this->handle(), Nan::New<v8::String>("onJvmCreated").ToLocalChecked(), AccessorProhibitsOverwritingGetter, AccessorProhibitsOverwritingSetter); if (onJvmCreated->IsFunction()) { v8::Local<v8::Function> onJvmCreatedFunc = onJvmCreated.As<v8::Function>(); v8::Local<v8::Object> context = Nan::New<v8::Object>(); onJvmCreatedFunc->Call(context, 0, NULL); } return Nan::Null(); }
int ElfTransaction::elfHookRunningApp(char * arg) { LOGD("elfHookRunningAPP %s",arg); JavaVM* jvm = AndroidRuntime::getJavaVM(); if (jvm == NULL) { LOGD("jvm is NULL"); return -1; } jvm->AttachCurrentThread(&jni_env, NULL); if (jni_env == NULL) { LOGD("jni_env is NULL"); return -1; } jstring apk_path = jni_env->NewStringUTF("/data/ElfInject.apk"); jstring dex_out_path = jni_env->NewStringUTF("/data/"); jclass dexloader_claxx = jni_env->FindClass("dalvik/system/DexClassLoader"); snprintf(sig_buffer, 512, "(%s%s%s%s)V", JSTRING, JSTRING, JSTRING, JCLASS_LOADER); jmethodID dexloader_init_method = jni_env->GetMethodID(dexloader_claxx, "<init>", sig_buffer); if (dexloader_init_method == NULL) { LOGD("dexloader_init_method is NULL"); return -1; } snprintf(sig_buffer, 512, "(%s)%s", JSTRING, JCLASS); jmethodID loadClass_method = jni_env->GetMethodID(dexloader_claxx, "loadClass", sig_buffer); if (loadClass_method == NULL) { LOGD("loadClass_method is NULL"); return -1; } jobject class_loader = getSystemClassLoader(); if (class_loader == NULL) { LOGD("class_loader is NULL"); return -1; } LOGD("getSystemClassLoader finished..."); jobject dex_loader_obj = jni_env->NewObject(dexloader_claxx, dexloader_init_method, apk_path, dex_out_path, NULL, class_loader); LOGD("dex_loader_obj is %p", dex_loader_obj); if (dex_loader_obj == NULL) { LOGD("dex_loader_obj is NULL"); return -1; } jstring class_name = jni_env->NewStringUTF("com.elf.inject.EntryClass"); jclass entry_class = static_cast<jclass>(jni_env->CallObjectMethod( dex_loader_obj, loadClass_method, class_name)); if (entry_class == NULL) { LOGD("entry_class is NULL"); return -1; } LOGD("entry_class is %p", entry_class); jmethodID invoke_method = jni_env->GetStaticMethodID(entry_class, "invoke", "()[Ljava/lang/Object;"); if (invoke_method == NULL) { LOGD("invoke_method is NULL"); return -1; } // //check_value(invoke_method); // jobjectArray objectarray = (jobjectArray) jni_env->CallStaticObjectMethod( entry_class, invoke_method, 0); if (objectarray == NULL) { LOGD("objectarray is NULL"); return -1; } //check_value(objectarray); jsize size = jni_env->GetArrayLength(objectarray); sp<IServiceManager> servicemanager = defaultServiceManager(); LOGD("size is : %d", size); for (jsize i = 0; i < size; i += 2) { jstring name = static_cast<jstring>(jni_env->GetObjectArrayElement( objectarray, i)); jobject obj = jni_env->GetObjectArrayElement(objectarray, i + 1); const char* c_name = jni_env->GetStringUTFChars(name, NULL); LOGD("c_name is %s", c_name); DummyJavaBBinder* binder = (DummyJavaBBinder*) servicemanager->getService(String16(c_name)).get(); binder->changObj(jni_env->NewGlobalRef(obj)); } LOGD("******* hooking end *****\n"); }