unidbg第三讲 com.github.unidbg.android.AndroidTest

讲解例子


类似的例子还有

com.github.unidbg.android.Android64Test

学习内容


  1. 手动调用native方法
  2. 手动调用JNI_OnLoad方法
  3. 手动调用模拟器入口方法
  4. 对jni里的env调用callStaticFloatMethod、newObject、setFloatField、SetDoubleField、
    getStaticBooleanField等方法进行hook

课前准备及了解的知识:


  1.  从源码中知道test文件和libnative.so文件的生成分别对应test.cpp和native.c
  2. 模拟器入口对应test.cpp里面的main方法
  3. JNI_OnLoad在native.c里定义
  4. native方法的实现也在native.c里实现

代码实现及备注:


package com.github.unidbg.android;

import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Emulator;
import com.github.unidbg.Module;
import com.github.unidbg.arm.backend.Backend;
import com.github.unidbg.arm.backend.BackendFactory;
import com.github.unidbg.arm.backend.Unicorn2Factory;
import com.github.unidbg.file.linux.AndroidFileIO;
import com.github.unidbg.hook.hookzz.HookZz;
import com.github.unidbg.linux.ARM32SyscallHandler;
import com.github.unidbg.linux.android.AndroidARMEmulator;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.AbstractJni;
import com.github.unidbg.linux.android.dvm.BaseVM;
import com.github.unidbg.linux.android.dvm.DalvikModule;
import com.github.unidbg.linux.android.dvm.DvmClass;
import com.github.unidbg.linux.android.dvm.DvmObject;
import com.github.unidbg.linux.android.dvm.VM;
import com.github.unidbg.linux.android.dvm.VarArg;
import com.github.unidbg.linux.file.Stdout;
import com.github.unidbg.linux.struct.Dirent;
import com.github.unidbg.linux.thread.ThreadJoinVisitor;
import com.github.unidbg.memory.Memory;
import com.github.unidbg.memory.SvcMemory;
import com.github.unidbg.unix.UnixSyscallHandler;
import com.sun.jna.Pointer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;

import java.io.File;
import java.io.IOException;
import java.util.Collections;

public class AndroidTest extends AbstractJni {
    private static final Log log = LogFactory.getLog(AndroidTest.class);
//    函数入口
    public static void main(String[] args) throws IOException {
        new AndroidTest().test();
    }

    private final AndroidEmulator emulator;
    private final Module module;
    private final DvmClass cJniTest;

    private static class MyARMSyscallHandler extends ARM32SyscallHandler {
        private MyARMSyscallHandler(SvcMemory svcMemory) {
            super(svcMemory);
        }
        @Override
        protected int fork(Emulator<?> emulator) {
            //    获取线程id
            return emulator.getPid();
        }
    }

    private AndroidTest() {
        final File executable = new File("unidbg-android/src/test/native/android/libs/armeabi-v7a/test");
//        创建模拟器
        emulator = new AndroidARMEmulator(executable.getName(),
                new File("target/rootfs"),
                Collections.<BackendFactory>singleton(new Unicorn2Factory(true))) {
            @Override
            protected UnixSyscallHandler<AndroidFileIO> createSyscallHandler(SvcMemory svcMemory) {
//                todo1  这个的作用我暂时也不知道
                return new MyARMSyscallHandler(svcMemory);
            }
        };
//        获取模拟器内存对象
        Memory memory = emulator.getMemory();

        // 设置是否打印Jni调用细节
        emulator.getSyscallHandler().setVerbose(false);
        AndroidResolver resolver = new AndroidResolver(23);
        memory.setLibraryResolver(resolver);

// todo ,推测patchThread表示对某个线程进行hook
        resolver.patchThread(emulator, HookZz.getInstance(emulator), new ThreadJoinVisitor() {
            @Override
            public boolean canJoin(Pointer start_routine, int threadId) {
                log.info("canJoin start_routine=" + start_routine + ", threadId=" + threadId);
                return true;
            }
        });
//加载模块
        module = emulator.loadLibrary(executable, true);
//创建虚拟机
        VM vm = emulator.createDalvikVM();
        // 设置是否打印Jni调用细节
        vm.setVerbose(true);
        vm.setJni(this);

//加载模块libnative.so
        DalvikModule dm = vm.loadLibrary(new File("unidbg-android/src/test/native/android/libs/armeabi-v7a/libnative.so"), true);
//手动调用JNI_OnLoad
        dm.callJNI_OnLoad(emulator);
//        需要模拟的类
        this.cJniTest = vm.resolveClass("com/github/unidbg/android/JniTest");

        {
//   动态分配栈
            Pointer pointer = memory.allocateStack(0x100);
//   todo : Dirent -> UnidbgStructure ->Structure
            System.out.println(new Dirent(pointer));
        }
    }

    @Override
    public DvmObject<?> newObject(BaseVM vm, DvmClass dvmClass, String signature, VarArg varArg) {
        if ("com/github/unidbg/android/AndroidTest-><init>()V".equals(signature)) {
            return dvmClass.newObject(null);
        }
        return super.newObject(vm, dvmClass, signature, varArg);
    }

    @Override
    public void setFloatField(BaseVM vm, DvmObject<?> dvmObject, String signature, float value) {
        if ("com/github/unidbg/android/AndroidTest->floatField:F".equals(signature)) {
            System.out.println("floatField value=" + value);
            return;
        }
        super.setFloatField(vm, dvmObject, signature, value);
    }

    @Override
    public void setDoubleField(BaseVM vm, DvmObject<?> dvmObject, String signature, double value) {
        if ("com/github/unidbg/android/AndroidTest->doubleField:D".equals(signature)) {
            System.out.println("doubleField value=" + value);
            return;
        }
        super.setDoubleField(vm, dvmObject, signature, value);
    }

    @Override
    public float callStaticFloatMethod(BaseVM vm, DvmClass dvmClass, String signature, VarArg varArg) {
        if ("com/github/unidbg/android/AndroidTest->testStaticFloat(FD)F".equals(signature)) {
            float f1 = varArg.getFloatArg(0);
            double d2 = varArg.getDoubleArg(1);
            System.out.printf("callStaticFloatMethod f1=%s, d2=%s%n", f1, d2);
            return 0.0033942017F;
        }

        return super.callStaticFloatMethod(vm, dvmClass, signature, varArg);
    }

    @Override
    public double callStaticDoubleMethod(BaseVM vm, DvmClass dvmClass, String signature, VarArg varArg) {
        if ("com/github/unidbg/android/AndroidTest->testStaticDouble(FD)D".equals(signature)) {
            return 0.0023942017D;
        }
        return super.callStaticDoubleMethod(vm, dvmClass, signature, varArg);
    }

    @Override
    public boolean getStaticBooleanField(BaseVM vm, DvmClass dvmClass, String signature) {
        if ("com/github/unidbg/android/AndroidTest->staticBooleanField:Z".equals(signature)) {
            return true;
        }

        return super.getStaticBooleanField(vm, dvmClass, signature);
    }

    @Override
    public void setStaticDoubleField(BaseVM vm, DvmClass dvmClass, String signature, double value) {
        if ("com/github/unidbg/android/AndroidTest->staticDoubleField:D".equals(signature)) {
            System.out.println("staticDoubleField value=" + value);
            return;
        }

        super.setStaticDoubleField(vm, dvmClass, signature, value);
    }

    @Override
    public void setStaticFloatField(BaseVM vm, DvmClass dvmClass, String signature, float value) {
        if ("com/github/unidbg/android/AndroidTest->staticFloatField:F".equals(signature)) {
            System.out.println("staticFloatField value=" + value);
            return;
        }

        super.setStaticFloatField(vm, dvmClass, signature, value);
    }

    private void test() {
//        模拟调用native函数
        cJniTest.callStaticJniMethod(emulator, "testJni(Ljava/lang/String;JIDZSFDBJF)V",
                getClass().getName(), 0x123456789abcdefL,
                0x789a, 0.12345D, true, 0x123, 0.456f, 0.789123D, (byte) 0x7f,
                0x89abcdefL, 0.123f);

//        Logger.getLogger(Stdout.class).setLevel(Level.WARN);
//
//        调用入口函数,这里指的是test.cpp里的main方法
        int exitCode = module.callEntry(emulator);
//        按任意键后打印下面的信息
        Backend backend = emulator.getBackend();
        System.err.println("exit code: " + exitCode + ", backend=" + backend);
    }

}
test.cpp
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <net/if.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/statfs.h>
#include <signal.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/system_properties.h>

#include <linux/if.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>

#include <iostream>
#include <exception>

#include <sched.h>
#include <link.h>

#include "test.h"

static int sdk_int = 0;

static void *start_routine(void *arg) {
  void *ret = &sdk_int;
  printf("test_pthread start_routine arg=%p, ret=%p\n", arg, ret);
  return ret;
}

static void test_pthread() {
  pthread_t thread = 0;
  void *arg = &thread;
  int ret = pthread_create(&thread, NULL, start_routine, arg);
  void *value = NULL;
  int join_ret = pthread_join(thread, &value);
  printf("test_pthread arg=%p, ret=%d, thread=0x%lx, join_ret=%d, value=%p\n", arg, ret, thread, join_ret, value);
}

#define INFINITY_LIFE_TIME      0xFFFFFFFFU
#define NIPQUAD(addr) \
    ((unsigned char *)&addr)[0], \
    ((unsigned char *)&addr)[1], \
    ((unsigned char *)&addr)[2], \
    ((unsigned char *)&addr)[3]

static void test_netlink() {
  static __u32 seq = 0;
  struct rtattr *rta;
  int fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
  if(fd == -1) {
    printf("test_netlink code=%d, msg=%s\n", errno, strerror(errno));
    return;
  }
  struct {
    struct nlmsghdr n;
    struct ifaddrmsg r;
    int pad[4];
  } req;
  memset(&req, 0, sizeof(req));
  req.n.nlmsg_len = sizeof(req);
  req.n.nlmsg_type = RTM_GETADDR;
  req.n.nlmsg_flags = NLM_F_MATCH | NLM_F_REQUEST;
  req.n.nlmsg_pid = 0;
  req.n.nlmsg_seq = seq;
  req.r.ifa_family = AF_UNSPEC;

  /* Fill up all the attributes for the rtnetlink header. The code is pretty easy
         to understand. The lenght is very important. We use 16 to signify the ipv6
         address. If the user chooses to use AF_INET (ipv4) the length has to be
         RTA_LENGTH(4) */
  rta = (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.n.nlmsg_len));
  rta->rta_len = RTA_LENGTH(4);

  char buf[16384];
  hex(buf, &req, sizeof(req));
  int ret = sendto(fd, (void *)&req, sizeof(req), 0, NULL, 0);
  printf("test_netlink fd=%d, sizeof(req)=%zu, buf=%s, ret=%d\n", fd, sizeof(req), buf, ret);

  memset(buf, 0, sizeof(buf));
  int status = recv(fd, buf, sizeof(buf), 0);
  if (status < 0) {
      perror("test_netlink");
      return;
  }
  if(status == 0) {
      printf("test_netlink EOF\n");
      return;
  }
  char str[16384];
  hex(str, buf, status);
  printf("test_netlink status=%d, buf=%s\n", status, str);

  struct nlmsghdr *nlmp;
  struct ifaddrmsg *rtmp;
  struct rtattr *rtatp;
  int rtattrlen;
  struct in_addr *inp;
  struct ifa_cacheinfo *cache_info;

  /* Typically the message is stored in buf, so we need to parse the message to *
          * get the required data for our display. */

  next_nlmp:
      for(nlmp = (struct nlmsghdr *)buf; status > sizeof(*nlmp);){
          int len = nlmp->nlmsg_len;
          int req_len = len - sizeof(*nlmp);

          if (req_len<0 || len>status) {
              printf("test_netlink error\n");
              return;
          }

          if (!NLMSG_OK(nlmp, status)) {
              printf("test_netlink NLMSG not OK\n");
              return;
          }

          rtmp = (struct ifaddrmsg *)NLMSG_DATA(nlmp);
          rtatp = (struct rtattr *)IFA_RTA(rtmp);

          /* Start displaying the index of the interface */

          int ctl_sock = socket(AF_INET, SOCK_DGRAM, 0);
          struct ifreq ifr;
          memset(&ifr, 0, sizeof(ifr));
          ifr.ifr_ifindex = rtmp->ifa_index;
          ioctl(ctl_sock, SIOCGIFNAME, &ifr);
          ioctl(ctl_sock, SIOCGIFFLAGS, &ifr);
          printf("Index Of Iface: %d, name=%s, flags=0x%x\n", rtmp->ifa_index, ifr.ifr_name, ifr.ifr_flags);
          close(ctl_sock);

          rtattrlen = IFA_PAYLOAD(nlmp);

          for (; RTA_OK(rtatp, rtattrlen); rtatp = RTA_NEXT(rtatp, rtattrlen)) {

              /* Here we hit the fist chunk of the message. Time to validate the    *
                   * the type. For more info on the different types see man(7) rtnetlink*
                   * The table below is taken from man pages.                           *
                   * Attributes                                                         *
                   * rta_type        value type             description                 *
                   * -------------------------------------------------------------      *
                   * IFA_UNSPEC      -                      unspecified.                *
                   * IFA_ADDRESS     raw protocol address   interface address           *
                   * IFA_LOCAL       raw protocol address   local address               *
                   * IFA_LABEL       asciiz string          name of the interface       *
                   * IFA_BROADCAST   raw protocol address   broadcast address.          *
                   * IFA_ANYCAST     raw protocol address   anycast address             *
                   * IFA_CACHEINFO   struct ifa_cacheinfo   Address information.        */

              if(rtatp->rta_type == IFA_LABEL){
                  const char *label = (const char *)RTA_DATA(rtatp);
                  printf("  label: %s\n", label);
              }

              if(rtatp->rta_type == IFA_CACHEINFO){
                  cache_info = (struct ifa_cacheinfo *)RTA_DATA(rtatp);
                  if (cache_info->ifa_valid == INFINITY_LIFE_TIME)
                      printf("  valid_lft forever\n");
                  else
                      printf("  valid_lft %usec\n", cache_info->ifa_valid);

                  if (cache_info->ifa_prefered == INFINITY_LIFE_TIME)
                      printf("  preferred_lft forever\n");
                  else
                      printf("  preferred_lft %usec\n",cache_info->ifa_prefered);
              }

              /* NOTE: All the commented code below can be used as it is for ipv4 table */

              if(rtatp->rta_type == IFA_ADDRESS){
                  inp = (struct in_addr *)RTA_DATA(rtatp);
                  //  in6p = (struct in6_addr *)RTA_DATA(rtatp);
                  //  printf("addr0: " NIP6_FMT "\n",NIP6(*in6p));
                  printf("  addr0: %u.%u.%u.%u\n",NIPQUAD(*inp));
              }

              if(rtatp->rta_type == IFA_LOCAL){
                  inp = (struct in_addr *)RTA_DATA(rtatp);
                  //  in6p = (struct in6_addr *)RTA_DATA(rtatp);
                  //  printf("addr1: " NIP6_FMT "\n",NIP6(*in6p));
                  printf("  addr1: %u.%u.%u.%u\n",NIPQUAD(*inp));
              }

              if(rtatp->rta_type == IFA_BROADCAST){
                  inp = (struct in_addr *)RTA_DATA(rtatp);
                  //  in6p = (struct in6_addr *)RTA_DATA(rtatp);
                  //  printf("bcataddr: " NIP6_FMT "\n",NIP6(*in6p));
                  printf("  Bcast addr: %u.%u.%u.%u\n",NIPQUAD(*inp));
              }

              if(rtatp->rta_type == IFA_ANYCAST){
                  inp = (struct in_addr *)RTA_DATA(rtatp);
                  //  in6p = (struct in6_addr *)RTA_DATA(rtatp);
                  //  printf("anycastaddr: "NIP6_FMT"\n",NIP6(*in6p));
                  printf("  anycast addr: %u.%u.%u.%u\n",NIPQUAD(*inp));
              }

          }
          status -= NLMSG_ALIGN(len);
          nlmp = (struct nlmsghdr*)((char*)nlmp + NLMSG_ALIGN(len));

      }

  status = recv(fd, buf, sizeof(buf), 0);
  printf("test_netlink status=%d\n", status);
  if(status > 0) {
    goto next_nlmp;
  }
  close(fd);
}

static void test_stat() {
  struct stat st;
  printf("st_nlink=0x%lx, st_blocks=0x%lx, st_rdev=0x%lx, st_uid=0x%lx, st_mtime=0x%lx, size=%lu\n", (long) &st.st_nlink - (long) &st, (long) &st.st_blocks - (long) &st, (long) &st.st_rdev - (long) &st, (long) &st.st_uid - (long) &st, (long) &st.st_mtime - (long) &st, (unsigned long) sizeof(st));
}

static void test_dirent() {
/**
dirent,LINUX系统下的一个头文件,在这个目录下/usr/include,为了获取某文件夹目录内容,所使用的结构体。
**/
  struct dirent dt;
  fprintf(stdout, "dirent size=%lu\n", (unsigned long) sizeof(dt));
}

static void test_ioctl() {
  struct ifconf ifc;
  struct ifreq ibuf[256];
  ifc.ifc_len = sizeof ibuf;
  ifc.ifc_buf = (caddr_t)ibuf;
  int fd = socket(AF_INET, SOCK_DGRAM, 0);
  ioctl(fd, SIOCGIFCONF, (char *)&ifc);

  printf("sizeof ifconf=%lu, ifreq=%lu\n", (unsigned long) sizeof(struct ifconf), (unsigned long) sizeof(struct ifreq));
  int i = 0;
  for (; i < ifc.ifc_len / sizeof(*ifc.ifc_ifcu.ifcu_req); ++i) {
    printf("ioctl %d  %zu  %s %d\n", i, strlen(ibuf[i].ifr_name), ibuf[i].ifr_name, ibuf[i].ifr_addr.sa_family);
  }
  close(fd);
}

// 3.不可靠信号的丢失
static void signal_handler(int signo) {
    printf("received a signal: %d\n", signo);
}

static void test_signal() {
    pid_t pid;
    sigset_t set;
    sigset_t oset;

    sigemptyset(&set);          //清空
    sigaddset(&set, SIGINT);          //添加2号信号
    sigaddset(&set, SIGRTMIN);         //添加34号信号
    sigprocmask(SIG_SETMASK, &set, &oset);     //将这个集合设置为这个进程的阻塞信号集

    //绑定信号
    signal(SIGINT, signal_handler);
    signal(SIGRTMIN, signal_handler);

    sigprocmask(SIG_SETMASK, &oset, NULL); //解除绑定
}

static void handler(int signo, siginfo_t *resdata, void *unknowp) {
    printf("signo=%d\n", signo);
    printf("return data: %d\n", resdata->si_value.sival_int);
}

static void test_signalaction() {
    pid_t pid = fork();
    if(pid == -1) {
        perror("create fork");
        return;
    } else if(pid == 0) { // 子进程
        sleep(1);
        //发送信号
        kill(getppid(), SIGINT);
        printf("send signal: %d success!\n", SIGINT);
        kill(getppid(), SIGRTMIN);
        printf("send signal: %d success!\n", SIGRTMIN);
        exit(0);
    } else {
        struct sigaction act;
        //初始化sa_mask
        sigemptyset(&act.sa_mask);
        act.sa_handler = signal_handler;
        act.sa_sigaction = handler;
        //一旦使用了sa_sigaction属性,那么必须设置sa_flags属性的值为SA_SIGINFO
        act.sa_flags = SA_SIGINFO;

        //注册信号
        sigaction(SIGINT, &act, NULL);
        sigaction(SIGRTMIN, &act, NULL);
    }
}

__attribute__((constructor))
void init() {
  char sdk[PROP_VALUE_MAX];
  __system_property_get("ro.build.version.sdk", sdk);
  sdk_int = atoi(sdk);
  printf("constructor sdk=%d\n", sdk_int);
}

static void test_backtrace() {
}

static void test_statfs() {
  struct statfs stb;
  int ret = statfs("/data/app", &stb);
  char buf[1024];
  hex(buf, &stb, sizeof(stb));
  printf("test_statfs size=%d, ret=%d, hex=%s\n", (int) sizeof(stb), ret, buf);
}

static float sFloat = 0.0023942017f;

static float* float_func() {
  return &sFloat;
}

static void test_float() {
  float *f = float_func();
  void *ptr = f;
  unsigned int *ip = (unsigned int *) ptr;
  printf("test_float size=%zu, ip=0x%x\n", sizeof(float), *ip);
}

static void test_jni_float() {
}

static void test_sched() {
    int cpus = 0;
    int  i = 0;
    cpu_set_t mask;
    cpu_set_t get;
    int pid = gettid();

    cpus = sysconf(_SC_NPROCESSORS_ONLN);
    printf("cpus: %d, pid: %d\n", cpus, pid);

    CPU_ZERO(&get);
    if (sched_getaffinity(pid, sizeof(get), &get) != 0) {
        printf("Get CPU affinity failure, ERROR: %s\n", strerror(errno));
    } else {
        for(int i = 0; i < cpus; i++) {
            if(CPU_ISSET(i, &get)) {
                printf("Running processor : %d\n", i);
            }
        }
        char buf[1024];
        hex(buf, &get, sizeof(get));
        printf("Get CPU affinity success: buf=%s\n", buf);
    }

    CPU_ZERO(&mask);
    CPU_SET(cpus - 1, &mask);
    if (sched_setaffinity(pid, sizeof(mask), &mask) != 0) {
        printf("Set CPU affinity failure, ERROR: %s\n", strerror(errno));
    } else {
        char buf[1024];
        hex(buf, &mask, sizeof(mask));
        printf("Set CPU affinity success: buf=%s\n", buf);
    }

    CPU_ZERO(&get);
    if (sched_getaffinity(pid, sizeof(get), &get) != 0) {
        printf("Get CPU affinity failure, ERROR: %s\n", strerror(errno));
    } else {
        for(int i = 0; i < cpus; i++) {
            if(CPU_ISSET(i, &get)) {
                printf("Running processor : %d\n", i);
            }
        }
        char buf[1024];
        hex(buf, &get, sizeof(get));
        printf("Get CPU affinity success: buf=%s\n", buf);
    }
}

static int dl_iterate_phdr_callback(struct dl_phdr_info *info, size_t size, void *data) {
   const char *type;
   int p_type;

   printf("dl_iterate_phdr_callback Name: \"%s\" (%d segments) => %p\n", info->dlpi_name,
              info->dlpi_phnum, info->dlpi_name);

   if(!info->dlpi_name) {
     return 0;
   }

   for (int j = 0; j < info->dlpi_phnum; j++) {
       p_type = info->dlpi_phdr[j].p_type;
       type =  (p_type == PT_LOAD) ? "PT_LOAD" :
               (p_type == PT_DYNAMIC) ? "PT_DYNAMIC" :
               (p_type == PT_INTERP) ? "PT_INTERP" :
               (p_type == PT_NOTE) ? "PT_NOTE" :
               (p_type == PT_INTERP) ? "PT_INTERP" :
               (p_type == PT_PHDR) ? "PT_PHDR" :
               (p_type == PT_TLS) ? "PT_TLS" :
               (p_type == PT_GNU_EH_FRAME) ? "PT_GNU_EH_FRAME" :
               (p_type == PT_GNU_STACK) ? "PT_GNU_STACK" :
               (p_type == PT_GNU_RELRO) ? "PT_GNU_RELRO" : NULL;

       printf("    %2d: [%14p; memsz:%7jx] flags: %#jx; ", j,
               (void *) (info->dlpi_addr + info->dlpi_phdr[j].p_vaddr),
               (uintmax_t) info->dlpi_phdr[j].p_memsz,
               (uintmax_t) info->dlpi_phdr[j].p_flags);
       if (type != NULL)
           printf("%s\n", type);
       else
           printf("[other (%#x)]\n", p_type);
   }

   return strcmp("libnative.so", info->dlpi_name) == 0 ? size : 0;
}

static void test_dl_iterate_phdr() {
  int ret = dl_iterate_phdr(dl_iterate_phdr_callback, NULL);
  printf("test_dl_iterate_phdr sizeof(dl_phdr_info)=0x%x, sizeof(Phdr)=0x%x, ret=%d\n", (unsigned int) sizeof(struct dl_phdr_info), (unsigned int) sizeof(ElfW(Phdr)), ret);
}

int main() {
  setvbuf(stdout, NULL, _IONBF, 0);
  setvbuf(stderr, NULL, _IONBF, 0);
  fprintf(stderr, "Start test, stdin=%p, stdout=%p, stderr=%p, size=%lu\n", stdin, stdout, stderr, (unsigned long) sizeof(*stdout));
  test_stat();
  test_dirent();
  test_ioctl();
  if(sdk_int > 19) {
    test_signal();
    test_signalaction();
  }
  test_backtrace();
  test_statfs();
  test_sched();
  test_float();
  test_jni_float();
  char sdk[PROP_VALUE_MAX];
  __system_property_get("ro.build.version.sdk", sdk);
  test_dl_iterate_phdr();
  test_netlink();
  test_pthread();
  printf("Press any key to exit: cmp=%d\n", strcmp("23", sdk));
  getchar();
  return 0;
}

遗留问题:


  1. MyARMSyscallHandler起什么作用?
  2. new Dirent(pointer)起什么作用?
  3. resolver.patchThread(emulator, HookZz.getInstance(emulator), new ThreadJoinVisitor() 这个起什么作用?
  4. test.cpp里main函数执行的多个逻辑,还需要一个个的梳理
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值