new Runnable的方式创建启动线程
线程启动的开端实际上是.start()之后
然后走/art/runtime/native/java_lang_Thread.cc
1 | static void Thread_nativeCreate(JNIEnv* env, jclass, jobject java_thread, jlong stack_size, |
/art/runtime/thread.cc
1 | void Thread::CreateNativeThread(JNIEnv* env, jobject java_peer, size_t stack_size, bool is_daemon) { |
以上代码在pthread_create
函数执行之前,线程还是没有得到创建。其中,pthread_create函数的三个参数Thread::CreateCallback,
1 | void* Thread::CreateCallback(void* arg) { |
该方法实际上是在初始化和执行java.lang.Thread这个对象的run方法,也就是我们重写的run方法。从注释// Invoke the 'run' method of our java.lang.Thread.
也能看出来。
由此我们可以得知,java的线程依附于JNI的线程来执行,并且run()函数实际上是在JNI层面上进行执行的,所以打印调用栈时,java.lang.Thread.run()总在调用栈的最开头,因为打印的调用栈是子线程的,子线程的执行的也就是run()函数。但是大部分时候我们也需要知道这个子线程执行的run()方法在哪个位置,然而这部分是在主线程创建Java的Thread对象附近,所以我们需要hook Thread的构造函数的地方来实现。
我们现在来看看Thread类的构造函数。
有若干个,但是最终都会调用private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc)
1 | private void init(ThreadGroup g, Runnable target, String name, |
pthread_create的具体执行线程函数实际上是这一块
找到相应函数所在位置看看这函数是啥意思
是通过汇编来调用CreateCallBack这个函数的,也就是说hook pthread_create是拿不到子线程的ThreadID而只要hook CreateCallBack这个函数即可拿到子线程的线程ID,而且该函数此时正在执行,Hook这个函数肯定比Socket收发点更快的拿到线程ID,然后等到Socket收发时就可以通过子线程ID来拿到具体的调用栈。
所以我们是不是只要hook这个函数就可以拿到具体的调用栈?let us try!
找到某被大佬们反复胖揍的违法APP