首页
论坛
课程
招聘
[原创]frida源码阅读之frida-java
2018-6-27 11:06 19869

[原创]frida源码阅读之frida-java

2018-6-27 11:06
19869

frida源码阅读之frida-java

frida-java简介

frida的JavaScript API按功能划分了许多模块,frida-java具体实现了其中的Java模块,提供了Java Runtime相关的API。我们知道JNI连接了native世界和java世界,而frida-java相当于实现了一个js世界到java世界的单向通道。利用frida-java,我们可以使用js代码实现:调用java方法、创建java对象、对java函数进行hook等操作。

 

frida-java源码结构如下:

  • index.js: 封装了JavaScript API中Java模块的api
  • lib
    • android.js: 封装了一些Android虚拟机的api
    • api.js
    • class-factory.js: java类的一些处理函数
    • env.js: js中实现了JNIEnv的一个代理
    • mkdex.js: dex文件的一些处理函数
    • result.js: 检测jni调用是否产生异常
    • vm.js: js中实现了JavaVM的一个代理

接下来通过下面两个问题来分析frida-java源码:

  1. frida-java是如何连通到java世界的?
  2. frida-java如何实现java方法hook?

frida-java是如何连通到java世界?

总的来说frida-java通过两步实现js世界到java世界的单向通道,首先利用frida-gum提供的js接口操作native世界,然后再基于jni连通到java世界。

 

 

主要步骤如下:

  1. 连通native世界,获得一些虚拟机的接口,如JNI_GetCreatedJavaVMs
  2. 获得JavaVM
  3. 获得JNIEnv
  4. 获得java类的class引用
  5. 操作该java类,如创建对象,调用方法等。

连通native世界

利用frida-gum中提供的Module、Memory、NativeFunction等模块,可以实现查找、调用、hook导出函数;读写、分配内存等操作。如下面例子所示, 可以在js代码中调用native函数。

var friendlyFunctionName = new NativeFunction(friendlyFunctionPtr, 'void', ['pointer', 'pointer']);
var returnValue = Memory.alloc(sizeOfLargeObject);
friendlyFunctionName(returnValue, thisPtr);

获得JavaVM

想要使用JNI连通java世界,首先需要获取的就是JavaVM,frida-java通过调用JNI_GetCreatedJavaVMs来获取JavaVM,Dalvik虚拟机和ART虚拟机均实现了该函数。核心代码如下:

//lib/android.js
const vms = Memory.alloc(pointerSize);
const vmCount = Memory.alloc(jsizeSize);
checkJniResult('JNI_GetCreatedJavaVMs', temporaryApi.JNI_GetCreatedJavaVMs(vms, 1, vmCount));
if (Memory.readInt(vmCount) === 0) {
  return null;
}
temporaryApi.vm = Memory.readPointer(vms);

此时获取的vm只是JavaVM的一个指针,在此基础上frida-java还会构造一个VM对象,该对象相当于在js层实现了一个JavaVM的代理对象,封装了一些JavaVM的方法,如getEnv,其中vm.handle中保存的是原始的JavaVM对象。

//lib/vm.js
function VM (api) {
  let handle = null;  //保存JavaVM指针
  let attachCurrentThread = null;  //封装了JavaVM.AttachCurrentThread
  let detachCurrentThread = null;  //封装了JavaVM.DetachCurrentThread;
  let getEnv = null;  //封装了JavaVM.getEnv
  const attachedThreads = {};
  function initialize () {
    handle = api.vm;
    //获取JavaVM的虚函数表
    const vtable = Memory.readPointer(handle);
    attachCurrentThread = new NativeFunction(Memory.readPointer(vtable.add(4 * pointerSize)), 'int32', ['pointer', 'pointer', 'pointer']);
    detachCurrentThread = new NativeFunction(Memory.readPointer(vtable.add(5 * pointerSize)), 'int32', ['pointer']);
    getEnv = new NativeFunction(Memory.readPointer(vtable.add(6 * pointerSize)), 'int32', ['pointer', 'pointer', 'int32']);
  }
}

VM的初始化过程为首先获取JavaVM的指针(通过JNI_GetCreatedJavaVMs调用),然后读取JavaVM的虚函数表,获得JavaVM的一些重要方法,并在js层包装一层,这样就在js层实现了一个JavaVM的代理,可以通过调用VM.getEnv来实现native层的JavaVM.getEnV调用。

获得JNIEnv

获取到JavaVM后,就可以通过将当前线程与JavaVM相关联,然后得到JNIEnv对象,进行后续操作。上述工作由VM.perform完成,看下VM.perform源码:

//vm.js
this.tryGetEnv = function () {
    const envBuf = Memory.alloc(pointerSize);
    const result = getEnv(handle, envBuf, JNI_VERSION_1_6);
    if (result !== JNI_OK) {
      return null;
    }
    return new Env(Memory.readPointer(envBuf), this);
  };
this.perform = function (fn) {
    let threadId = null;
    //将当前线程附加到JavaVM,获取JNIEnv对象
    let env = this.tryGetEnv();
    const alreadyAttached = env !== null;
    if (!alreadyAttached) {
      env = this.attachCurrentThread();

      threadId = Process.getCurrentThreadId();
      attachedThreads[threadId] = true;
    }
    try {
      fn();  //执行fn
    } finally {
      if (!alreadyAttached) {
        const allowedToDetach = attachedThreads[threadId];
        delete attachedThreads[threadId];

        if (allowedToDetach) {
          this.detachCurrentThread();
        }
      }
    }
  };

和JavaVM一样,frida-java也会在js层为JNIEnv建立一个代理,具体在env.js实现

获得Java类的class引用

和JNI操作方式一样,我们在native层获得了JNIEnv后,要想操作java类,可以通过调用env->findClass来获得java类的class引用。但是这里有个问题,因为frida-java所在的线程是通过pthread_create创造的,然后通过AttachCurrentThread获取的JNIEnv,此时FindClass只会从系统的classloader开始查找,所以app自身的类是无法通过env->findClass来获取。因此需要手工的获取到加载该app的classloader。Java.perform在调用VM.perform之前会先获取加载该app的classloader,并保存到classFactory.loader。

this.perform = function (fn) {
    assertJavaApiIsAvailable();
      //目标进程不是app,并且classloader已经初始化
    if (!isAppProcess() || classFactory.loader !== null) {
      threadsInPerform++;
      try {
        vm.perform(fn);
      } catch (e) {
        setTimeout(() => { throw e; }, 0);
      } finally {
        threadsInPerform--;
      }
    } else {
      //第一次调用java.perform时,会先获取加载该app的classloader
      pending.push(fn);
      if (pending.length === 1) {
        threadsInPerform++;
        try {
          vm.perform(() => {
            const ActivityThread = classFactory.use('android.app.ActivityThread');
            const app = ActivityThread.currentApplication();
            if (app !== null) {
                    //获取到加载该app的classloader
              classFactory.loader = app.getClassLoader();
              performPending(); // already initialized, continue
            } else {
              const m = ActivityThread.getPackageInfoNoCheck;
              let initialized = false;
              m.implementation = function () {
                const apk = m.apply(this, arguments);
                if (!initialized) {
                  initialized = true;
                  classFactory.loader = apk.getClassLoader();
                  performPending();
                }
                return apk;
              };
            }
          });
        } finally {
          threadsInPerform--;
        }
      }
    }
  };

frida-java使用Java.use来获得java类的class引用,Java.use(className),返回java类的一个wrapper,在js世界里,用该wrapper来操作对应的java类。Java.use直接调用了classFactory.use,代码如下:

//lib/class-factory.js
this.use = function (className) {
    let C = classes[className]; //先从缓存中查找 
    if (!C) {
      const env = vm.getEnv();  //获取jni_env, 调用native层的JavaVm.GetEnv   
      if (loader !== null) {  //loader已经在Java.perform中初始化了
        const usedLoader = loader;

        if (cachedLoaderMethod === null) {
          cachedLoaderInvoke = env.vaMethod('pointer', ['pointer']);
          cachedLoaderMethod = loader.loadClass.overload('java.lang.String').handle;
        }

        const getClassHandle = function (env) {
          const classNameValue = env.newStringUtf(className);
          const tid = Process.getCurrentThreadId();
          ignore(tid);
          try {       //env.handle 指向jni层的JNIEnv, 利用jni调用classloader.loadClass(className)
            return cachedLoaderInvoke(env.handle, usedLoader.$handle, cachedLoaderMethod, classNameValue);
          } finally {
            unignore(tid);
            env.deleteLocalRef(classNameValue);
          }
        };
        //构建对应java类的wrapper
        C = ensureClass(getClassHandle, className);
      }
    }

借助于该wrapper,可以对java类进行操作,如调用构造函数创建对象。该wrapper的初始化过程如下:

//lib/class-factory.js
function initializeClass () {
    klass.__name__ = name;

    let ctor = null;
    let getCtor = function (type) {};
    //定义了一些每个类都公有的函数和属性
    Object.defineProperty(klass.prototype, '$new', {});
    Object.defineProperty(klass.prototype, '$alloc', {});
    Object.defineProperty(klass.prototype, '$init', {});
    klass.prototype.$dispose = dispose;
    klass.prototype.$isSameObject = function (obj) {});
    Object.defineProperty(klass.prototype, 'class', {});
    Object.defineProperty(klass.prototype, '$className', {});
    //添加该类特有的函数和属性
    addMethodsAndFields();
}

借助于该wrapper的$init方法,就可以创建java对象。

frida-java如何实现java方法调用与java方法hook?

frida-java Dalvik Hook原理

frida-java采用常见的Dalvik Hook方案,将待hook的java函数修改为native函数,当调用该函数时,会执行自定义的native函数。但是和其他hook框架不同的是,使用frida时,我们hook的代码是js实现的,所以有一个基于js代码生成native函数过程。具体hook实现代码如下:

      function replaceDalvikImplementation (fn) {
        if (fn === null && dalvikOriginalMethod === null) {
          return;
        }
        //保存原Method结构
        if (dalvikOriginalMethod === null) {
          dalvikOriginalMethod = Memory.dup(methodId, DVM_METHOD_SIZE);
          dalvikTargetMethodId = Memory.dup(methodId, DVM_METHOD_SIZE);
        }
        if (fn !== null) {
          implementation = implement(f, fn);  //由js代码生成对应的native函数

          let argsSize = argTypes.reduce((acc, t) => (acc + t.size), 0);
          if (type === INSTANCE_METHOD) {
            argsSize++;
          }
          /*
           * make method native (with kAccNative)
           * insSize and registersSize are set to arguments size
           */
          const accessFlags = (Memory.readU32(methodId.add(DVM_METHOD_OFFSET_ACCESS_FLAGS)) | kAccNative) >>> 0;
          const registersSize = argsSize;
          const outsSize = 0;
          const insSize = argsSize;

          Memory.writeU32(methodId.add(DVM_METHOD_OFFSET_ACCESS_FLAGS), accessFlags);
          Memory.writeU16(methodId.add(DVM_METHOD_OFFSET_REGISTERS_SIZE), registersSize);
          Memory.writeU16(methodId.add(DVM_METHOD_OFFSET_OUTS_SIZE), outsSize);
          Memory.writeU16(methodId.add(DVM_METHOD_OFFSET_INS_SIZE), insSize);
          Memory.writeU32(methodId.add(DVM_METHOD_OFFSET_JNI_ARG_INFO), computeDalvikJniArgInfo(methodId));
          //利用 dvmUSeJNIBridge完成替换Method结构的insns和NativeFunc
          api.dvmUseJNIBridge(methodId, implementation);
          patchedMethods.add(f);
        } else {
          patchedMethods.delete(f);

          Memory.copy(methodId, dalvikOriginalMethod, DVM_METHOD_SIZE);
          implementation = null;
        }
      }

hook后执行的native函数就是用implement函数实现的,该函数时最终调用frida-node的new NativeCallback接口实现将js函数转换为native函数。

frida-java ART Hook原理

常见的ART Hook方法为:替换方法的入口点,即ArtMethod的entry_point_from_quick_compiledcode,并将原方法的信息备份到entry_point_fromjni。替换后的入口点,会重新准备栈和寄存器,执行hook的方法。

 

frida-java采用的hook方法,我在其他地方并未遇见过,其原理为:首先将方法native化,然后将ArtMethod的entry_point_fromjni替换为hook的方法,并将entry_point_from_quick_compiledcode替换为art_quick_generic_jni_trampoline。当调用被hook的方法时,首先会跳转到art_quick_generic_jni_trampoline,该函数会做一些jni调用的准备,然后跳转到ArtMethod结构的entry_point_fromjni所指向的hook方法,这样就完成了一次hook。完成art hook的源码如下:

function replaceArtImplementation (fn) {
      if (fn === null && artOriginalMethodInfo === null) {
        return;
      }
      const artMethodSpec = getArtMethodSpec(vm);
      const artMethodOffset = artMethodSpec.offset; //获取ArtMethod各个字段的偏移
      if (artOriginalMethodInfo === null) {
        artOriginalMethodInfo = fetchMethod(methodId);    //保存原方法信息
      }
      if (fn !== null) {
        implementation = implement(f, fn);

        // kAccFastNative so that the VM doesn't get suspended while executing JNI
        // (so that we can modify the ArtMethod on the fly)
        patchMethod(methodId, {
           //替换entry_point_from_jni_为hook的方法;
          'jniCode': implementation,
           //native化
          'accessFlags': (Memory.readU32(methodId.add(artMethodOffset.accessFlags)) | kAccNative | kAccFastNative) >>> 0,
           //替换entry_point_from_quick_compiled_code_为art_quick_generic_jni_trampoline;
          'quickCode': api.artQuickGenericJniTrampoline,
           //entry_point_from_interpreter_;
          'interpreterCode': api.artInterpreterToCompiledCodeBridge
        });

        patchedMethods.add(f);
      } else {
        patchedMethods.delete(f);

        patchMethod(methodId, artOriginalMethodInfo);
        implementation = null;
      }
    }

然后看下art_quick_generic_jni_trampoline源码,art_quick_generic_jni_trampoline主要负责jni调用的准备,包括堆栈的设置,参数的设置等。个人能力有限只能大概看看流程。

ENTRY art_quick_generic_jni_trampoline
    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_R0

    // Save rSELF
    mov r11, rSELF
    // Save SP , so we can have static CFI info. r10 is saved in ref_and_args.
    mov r10, sp
    .cfi_def_cfa_register r10

    sub sp, sp, #5120

    // prepare for artQuickGenericJniTrampoline call, 转为为c调用约定
    // (Thread*,  SP)
    //    r0      r1   <= C calling convention
    //  rSELF     r10  <= where they are

    mov r0, rSELF   // Thread*
    mov r1, r10     // ArtMethod**
    //调用c的 artQuickGenericJniTrampoline 
    blx artQuickGenericJniTrampoline  // (Thread*, sp)

    // The C call will have registered the complete save-frame on success.
    // The result of the call is:
    // r0: pointer to native code, 0 on error.
    // r1: pointer to the bottom of the used area of the alloca, can restore stack till there.

    // Check for error = 0.
    cbz r0, .Lexception_in_native

    // Release part of the alloca.
    mov sp, r1

    // Save the code pointer
    mov r12, r0

    // Load parameters from frame into registers.
    pop {r0-r3}

主要是将调用约定转换为c的调用约定,将参数准备好,然后调用artQuickGenericJniTrampoline,该函数源码如下:

extern "C" TwoWordReturn artQuickGenericJniTrampoline(Thread* self, ArtMethod** sp)
    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
  ArtMethod* called = *sp;
  DCHECK(called->IsNative()) << PrettyMethod(called, true);
  uint32_t shorty_len = 0;
  const char* shorty = called->GetShorty(&shorty_len);

  // Run the visitor and update sp.
  BuildGenericJniFrameVisitor visitor(self, called->IsStatic(), shorty, shorty_len, &sp);
  visitor.VisitArguments();
  visitor.FinalizeHandleScope(self);

  // Fix up managed-stack things in Thread.
  self->SetTopOfStack(sp);

  self->VerifyStack();

  // Start JNI, save the cookie.
  uint32_t cookie;
  if (called->IsSynchronized()) {
    cookie = JniMethodStartSynchronized(visitor.GetFirstHandleScopeJObject(), self);
    if (self->IsExceptionPending()) {
      self->PopHandleScope();
      // A negative value denotes an error.
      return GetTwoWordFailureValue();
    }
  } else {
    cookie = JniMethodStart(self);
  }
  uint32_t* sp32 = reinterpret_cast<uint32_t*>(sp);
  *(sp32 - 1) = cookie;

  // Retrieve the stored native code.
  //获取到ArtMethod结构的entry_point_from_jni_
  void* nativeCode = called->GetEntryPointFromJni();

  // There are two cases for the content of nativeCode:
  // 1) Pointer to the native function.
  // 2) Pointer to the trampoline for native code binding.
  // In the second case, we need to execute the binding and continue with the actual native function
  // pointer.
  DCHECK(nativeCode != nullptr);
  if (nativeCode == GetJniDlsymLookupStub()) {
#if defined(__arm__) || defined(__aarch64__)
    nativeCode = artFindNativeMethod();
#else
    nativeCode = artFindNativeMethod(self);
#endif
    if (nativeCode == nullptr) {
      DCHECK(self->IsExceptionPending());    // There should be an exception pending now.
      DCHECK(self->IsExceptionPending());    // There should be an exception pending now.

      // End JNI, as the assembly will move to deliver the exception.
      jobject lock = called->IsSynchronized() ? visitor.GetFirstHandleScopeJObject() : nullptr;
      if (shorty[0] == 'L') {
        artQuickGenericJniEndJNIRef(self, cookie, nullptr, lock);
      } else {
        artQuickGenericJniEndJNINonRef(self, cookie, lock);
      }

      return GetTwoWordFailureValue();
    }
    // Note that the native code pointer will be automatically set by artFindNativeMethod().
  }

  // Return native code addr(lo) and bottom of alloca address(hi).
  return GetTwoWordSuccessValue(reinterpret_cast<uintptr_t>(visitor.GetBottomOfUsedArea()),
                                reinterpret_cast<uintptr_t>(nativeCode));
}

总结

笔记分析的还是很粗糙的,发出来是希望可以抛砖引玉,可以在论坛看到更多frida的文章,如有错误,恳请大佬指出。


第五届安全开发者峰会(SDC 2021)议题征集正式开启!

收藏
点赞1
打赏
分享
最新回复 (24)
雪    币: 208
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
YerikK 活跃值 2018-6-27 14:00
2
0
Frida在腾讯手游助手这个模拟器上,会导致蓝屏
雪    币: 153
活跃值: 活跃值 (215)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
人在塔在 活跃值 2018-6-27 17:01
3
0
尝试ptrace都会蓝吧
雪    币: 1905
活跃值: 活跃值 (818)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
Vn小帆 活跃值 2018-7-12 22:17
4
0
YerikK Frida在腾讯手游助手这个模拟器上,会导致蓝屏
你可以 看看 他的代码  为何导致 蓝屏
雪    币: 208
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
YerikK 活跃值 2018-7-14 15:08
5
0
Vn小帆 你可以 看看 他的代码 为何导致 蓝屏
谁的代码。。。模拟器的吗?模拟器的代码没有源码好吧。。。
雪    币: 1905
活跃值: 活跃值 (818)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
Vn小帆 活跃值 2018-7-14 15:48
6
0
YerikK 谁的代码。。。模拟器的吗?模拟器的代码没有源码好吧。。。
你可以反编译啊
雪    币: 594
活跃值: 活跃值 (764)
能力值: ( LV11,RANK:180 )
在线值:
发帖
回帖
粉丝
wuaiwu 活跃值 3 2018-7-17 10:45
7
0
很棒啊
雪    币: 6
活跃值: 活跃值 (135)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
南山瘦竹 活跃值 2019-1-18 17:47
8
0
这是兼容性问题吧,artmethod这个东西在很多定制系统和模拟器上是有变化的
雪    币: 2
活跃值: 活跃值 (186)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
晨曦遇晓 活跃值 2019-1-18 18:28
9
0
666
雪    币: 294
活跃值: 活跃值 (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
我叫菠菜的菠 活跃值 2019-4-17 00:58
10
0
原issue地址是:https://github.com/frida/frida-java/issues/78
问题是:

I have a question in "java.lang.Class.getMethod".

public Method getMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException { return getMethod(name, parameterTypes, true); }

the second parameter need a "[Ljava.lang.Object;" type, and java code like this:

getMethod("say", new Class[]{String.class,int.class});
getMethod("say", new Class[]{Integer.TYPE,Integer.TYPE});

so How can i create this array using js or other ways ?

in addition,I created a obj array like this:
var Integerclass = Java.use("java.lang.Integer");
var objectArr = Java.array('Ljava.lang.Class;',[Integerclass.TYPE,Integerclass.TYPE]);

but i got a "invalid argument value" error.
{'type': 'error', 'description': 'Error: invalid argument value', 'stack': 'Error: invalid argument value\n at frida/node_modules/frida-java/lib/env.js:515\n at frida/node_modules/frida-java/lib/class-factory.js:2592\n at toJniObjectArray (frida/node_modules/frida-java/lib/class-factory.js:2640)\n at java.js:4489\n at frida/node_modules/frida-java/lib/class-factory.js:743\n at [anon] (script1.js:28)\n at input:1', 'fileName': 'frida/node_modules/frida-java/lib/env.js', 'lineNumber': 515, 'columnNumber': 1}

这个问题我也遇到了,就是在js中反射方式调用java的函数,那么就需要创建java.lang.Class类型的数组,在Java中,基本类型可以表达为int.class,boolean.class等,但是就如上面问题所诉,在frida的script中该如何创建int.class,boolean.class等呢。
雪    币: 171
活跃值: 活跃值 (219)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
glider菜鸟 活跃值 1 2019-4-17 10:17
11
0
我叫菠菜的菠 原issue地址是:https://github.com/frida/frida-java/issues/78 问题是: I have a question in "java.lan ...
 var intClass = Java.use("java.lang.Integer").class;
 var booleanClass = Java.use("java.lang.Boolean").class;
 var objectArr = Java.array("Ljava.lang.Class;", [intClass, booleanClass]);
雪    币: 294
活跃值: 活跃值 (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
我叫菠菜的菠 活跃值 2019-4-17 14:04
12
0
大佬,你看我提到的那个问题没有,其实是这样的,假如我有个函数是:
public int test(int i){
        return i;
    }
那么我在frida中也可以用反射的方式调用此函数,那么我的js代码可以这样写:
var Platform1 = Java.use("com.example.cryptutils.util.Test");
var method = Platform1.class.getDeclaredMethod("test",Java.array('java.lang.Class', [xxx]) );
这里构造getDeclaredMethod函数的时候,第二次参数是一个Class类型的数组,就是test函数入参的class类型的数组是不是。
按照java的写法,Java.array('java.lang.Class', [xxx])这里的xxx应该就是int.class,但是js是识别不了int.class,那就就需要构造,按照你的写法,int.class 写成了Java.use("java.lang.Integer").class的话,那就这里的method变量就称为了:
var method = Platform1.class.getDeclaredMethod("test",Java.array('java.lang.Class', [Java.use("java.lang.Integer").class]) );
但是在java中int.class 和Java.use("java.lang.Integer").class是两回事,就会导致frida直接抛出MethodNotFound的错误。
雪    币: 294
活跃值: 活跃值 (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
我叫菠菜的菠 活跃值 2019-4-17 14:14
13
0
glider菜鸟 var intClass = Java.use("java.lang.Integer").class; var booleanClass = Java.use("j ...
盼大佬回复的啊,这个问题已经很久了一直都在解决,其实在github上也有人提了这问题,当时他的做法是
var integerClass = Java.use("java.lang.Integer");
var intClass = integerClass.TYPE;
这样来代替,因为在java中int.class == Integer.TYPE;但是这样的话,在js中构造Class数组,Java.array('java.lang.Class', [integerClass.TYPE]) 
这样构造的话,frida出会报错:invalid argument value的错误。
雪    币: 2370
活跃值: 活跃值 (131)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
petersonhz 活跃值 2019-6-13 16:09
14
0
YerikK Frida在腾讯手游助手这个模拟器上,会导致蓝屏
安卓不会蓝屏吧,导致windows蓝屏?
雪    币: 2370
活跃值: 活跃值 (131)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
petersonhz 活跃值 2019-6-13 16:21
15
0
YerikK Frida在腾讯手游助手这个模拟器上,会导致蓝屏
android.js,为什么很多js文件?
雪    币: 654
活跃值: 活跃值 (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
miyuecao 活跃值 2019-6-14 15:12
16
0
高手,膜拜下,先mark慢慢学习
雪    币: 50
活跃值: 活跃值 (332)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
cydian 活跃值 2019-11-5 23:29
17
0
厉害
雪    币: 59
活跃值: 活跃值 (369)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
iceway 活跃值 2019-11-5 23:31
18
0
我叫菠菜的菠 盼大佬回复的啊,这个问题已经很久了一直都在解决,其实在github上也有人提了这问题,当时他的做法是 var integerClass = Java.use("java.lang.Inte ...
var Integer = Java.use("java.lang.Integer");

var int_clz=Integer.class.getField("TYPE").get(null);

console.warn(int_clz);

var Bool=Java.use("java.lang.Boolean");

var boolean_clz=Bool.class.getField("TYPE").get(null);

console.warn(boolean_clz);

var Byte=Java.use("java.lang.Byte");

var byte_clz=Byte.class.getField("TYPE").get(null);

console.warn(byte_clz);
雪    币: 55
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
梁小无拆 活跃值 2019-11-23 10:25
19
0
怎么把frida-java集成到vscode里面去编写然后编译的啊????
雪    币: 50
活跃值: 活跃值 (332)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
cydian 活跃值 2019-11-25 23:34
20
0
mark
雪    币: 18
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
Denny Chen 活跃值 2020-4-28 20:17
21
0
您好,大佬,请问一下包含replaceDalvikImplementation的js文件是在frida-server的代码嘛?好像没找到 frida-server 的对应代码
雪    币: 998
活跃值: 活跃值 (1330)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
爱吃菠菜 活跃值 1 2020-5-17 19:05
22
0
 
雪    币: 313
活跃值: 活跃值 (378)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
ychangeol 活跃值 2020-7-5 10:47
23
0
mark
雪    币: 4092
活跃值: 活跃值 (227)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
kinghzking 活跃值 2020-11-13 10:08
24
0
YerikK Frida在腾讯手游助手这个模拟器上,会导致蓝屏
很明显,模拟器有保护,TP保护
游客
登录 | 注册 方可回帖
返回