首页 > 编程语言 >Fart脱壳-源码分析

Fart脱壳-源码分析

时间:2023-05-05 15:01:10浏览次数:43  
标签:脱壳 dexfilepath item int dexfilefp Fart 源码 method size

源码分析

首先看java代码,在APP启动时候反射了DexFile.java中三个方法,分别是

  1. getClassNameList

  2. defineClassNative

  3. dumpMethodCode

其中前面两个方法是android自带的,dumpMethodCode方法是fart自己添加的

// frameworks/base/core/java/android/app/ActivityThread.java
public static void fart() {
        ...
        Class DexFileClazz = null;
        try {
            DexFileClazz = appClassloader.loadClass("dalvik.system.DexFile");
        } catch (Exception e) {
            e.printStackTrace();
        }
        Method getClassNameList_method = null;
        Method defineClass_method = null;
        Method dumpDexFile_method = null;
        Method dumpMethodCode_method = null;

        for (Method field : DexFileClazz.getDeclaredMethods()) {
            if (field.getName().equals("getClassNameList")) {
                getClassNameList_method = field;
                getClassNameList_method.setAccessible(true);
            }
            if (field.getName().equals("defineClassNative")) {
                defineClass_method = field;
                defineClass_method.setAccessible(true);
            }
            if (field.getName().equals("dumpMethodCode")) {
                dumpMethodCode_method = field;
                dumpMethodCode_method.setAccessible(true);
            }
        }
}

重点: ArtMethod::FromReflectedMethod 获取 ArtMethod 指针

static void DexFile_dumpMethodCode(JNIEnv* env, jclass,jobject method) {
ScopedFastNativeObjectAccess soa(env);
  if(method!=nullptr)
  {
      ArtMethod* artmethod = ArtMethod::FromReflectedMethod(soa, method);
      myfartInvoke(artmethod);
  }

  return;
}



    extern "C" void myfartInvoke(ArtMethod * artmethod)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
        JValue *result = nullptr;
        Thread *self = nullptr;
        uint32_t temp = 6;
        uint32_t *args = &temp;
        uint32_t args_size = 6;
        artmethod->Invoke(self, args, args_size, result, "fart");
    }

注意第一个参数self,这里为null,会进入到dumpArtMethod中,也是fart添加的

    void ArtMethod::Invoke(Thread * self, uint32_t * args,
                   uint32_t args_size, JValue * result,
                   const char *shorty) {
 

        if (self == nullptr) {
            dumpArtMethod(this);
            return;
        }
        ....
     }

重点
artmethod->GetDexFile() 获取 DexFile
dex_file->Begin() 对应dex在内存中的起点
dex_file->size() 对应dex文件大小

DexFile::CodeItem 是什么目前还不清楚

    extern "C" void dumpArtMethod(ArtMethod * artmethod)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
        char *dexfilepath = (char *) malloc(sizeof(char) * 2000);
        if (dexfilepath == nullptr) {
            LOG(INFO) <<
                "ArtMethod::dumpArtMethodinvoked,methodname:"
                << PrettyMethod(artmethod).
                c_str() << "malloc 2000 byte failed";
            return;
        }
        int fcmdline = -1;
        char szCmdline[64] = { 0 };
        char szProcName[256] = { 0 };
        int procid = getpid();
        sprintf(szCmdline, "/proc/%d/cmdline", procid);
        fcmdline = open(szCmdline, O_RDONLY, 0644);
        if (fcmdline > 0) {
            read(fcmdline, szProcName, 256);
            close(fcmdline);
        }

        if (szProcName[0]) {

            const DexFile *dex_file = artmethod->GetDexFile();
            const char *methodname = PrettyMethod(artmethod).c_str();
            const uint8_t *begin_ = dex_file->Begin();
            size_t size_ = dex_file->Size();

            memset(dexfilepath, 0, 2000);
            int size_int_ = (int) size_;

            memset(dexfilepath, 0, 2000);
            sprintf(dexfilepath, "%s", "/sdcard/fart");
            mkdir(dexfilepath, 0777);

            memset(dexfilepath, 0, 2000);
            sprintf(dexfilepath, "/sdcard/fart/%s", szProcName);
            mkdir(dexfilepath, 0777);

            memset(dexfilepath, 0, 2000);
            sprintf(dexfilepath, "/sdcard/fart/%s/%d_dexfile.dex", szProcName, size_int_);
            int dexfilefp = open(dexfilepath, O_RDONLY, 0666);
            if (dexfilefp > 0) {
                close(dexfilefp);
                dexfilefp = 0;
            } else {
                dexfilefp = open(dexfilepath, O_CREAT | O_RDWR, 0666);
                if (dexfilefp > 0) {
                    write(dexfilefp, (void *) begin_, size_);
                    fsync(dexfilefp);
                    close(dexfilefp);
                }
            }
            const DexFile::CodeItem * code_item = artmethod->GetCodeItem();
            if (LIKELY(code_item != nullptr)) {
                int code_item_len = 0;
                uint8_t *item = (uint8_t *) code_item;
                if (code_item->tries_size_ > 0) {
                    const uint8_t *handler_data = (const uint8_t *) (DexFile::GetTryItems(*code_item, code_item->tries_size_));
                    uint8_t *tail = codeitem_end(&handler_data);
                    code_item_len = (int) (tail - item);
                } else {
                    code_item_len = 16 + code_item->insns_size_in_code_units_ * 2;
                }
                memset(dexfilepath, 0, 2000);
                int size_int = (int) dex_file->Size();  // Length of data
                uint32_t method_idx = artmethod->get_method_idx();
                sprintf(dexfilepath, "/sdcard/fart/%s/%d_%ld.bin", szProcName, size_int, gettidv1());
                int fp2 = open(dexfilepath, O_CREAT | O_APPEND | O_RDWR, 0666);
                if (fp2 > 0) {
                    lseek(fp2, 0, SEEK_END);
                    memset(dexfilepath, 0, 2000);
                    int offset = (int) (item - begin_);
                    sprintf(dexfilepath, "{name:%s, method_idx:%d, offset:%d, code_item_len:%d, ins:",
                        methodname, method_idx, offset, code_item_len);
                    int contentlength = 0;
                    while (dexfilepath[contentlength] != 0)
                        contentlength++;
                    write(fp2, (void *) dexfilepath, contentlength);
                    long outlen = 0;
                    char *base64result = base64_encode((char *) item, (long)code_item_len, &outlen);
                    write(fp2, base64result, outlen);
                    write(fp2, "};", 2);
                    fsync(fp2);
                    close(fp2);
                    if (base64result != nullptr) {
                        free(base64result);
                        base64result = nullptr;
                    }
                }
            }
        }

        if (dexfilepath != nullptr) {
            free(dexfilepath);
            dexfilepath = nullptr;
        }

    }

dumpDexFileByExecute 是在Execute中被调用, 也就是是执行指令的时候

// art/runtime/interpreter/interpreter.cc
static inline JValue Execute(Thread* self, const DexFile::CodeItem* code_item,
                             ShadowFrame& shadow_frame, JValue result_register) {

  if(strstr(PrettyMethod(shadow_frame.GetMethod()).c_str(),"<clinit>") != nullptr)
  {
    dumpDexFileByExecute(shadow_frame.GetMethod());
  }
  ...

    extern "C" void dumpDexFileByExecute(ArtMethod * artmethod)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
        char *dexfilepath = (char *) malloc(sizeof(char) * 2000);
        if (dexfilepath == nullptr) {
            LOG(INFO) <<
                "ArtMethod::dumpDexFileByExecute,methodname:"
                << PrettyMethod(artmethod).
                c_str() << "malloc 2000 byte failed";
            return;
        }
        int fcmdline = -1;
        char szCmdline[64] = { 0 };
        char szProcName[256] = { 0 };
        int procid = getpid();
        sprintf(szCmdline, "/proc/%d/cmdline", procid);
        fcmdline = open(szCmdline, O_RDONLY, 0644);
        if (fcmdline > 0) {
            read(fcmdline, szProcName, 256);
            close(fcmdline);
        }

        if (szProcName[0]) {

            const DexFile *dex_file = artmethod->GetDexFile();
            const uint8_t *begin_ = dex_file->Begin();  // Start of data.
            size_t size_ = dex_file->Size();    // Length of data.

            memset(dexfilepath, 0, 2000);
            int size_int_ = (int) size_;

            memset(dexfilepath, 0, 2000);
            sprintf(dexfilepath, "%s", "/sdcard/fart");
            mkdir(dexfilepath, 0777);

            memset(dexfilepath, 0, 2000);
            sprintf(dexfilepath, "/sdcard/fart/%s",
                szProcName);
            mkdir(dexfilepath, 0777);

            memset(dexfilepath, 0, 2000);
            sprintf(dexfilepath,
                "/sdcard/fart/%s/%d_dexfile_execute.dex",
                szProcName, size_int_);
            int dexfilefp = open(dexfilepath, O_RDONLY, 0666);
            if (dexfilefp > 0) {
                close(dexfilefp);
                dexfilefp = 0;
                
            } else {
                dexfilefp =
                    open(dexfilepath, O_CREAT | O_RDWR,
                     0666);
                if (dexfilefp > 0) {
                    write(dexfilefp, (void *) begin_,
                          size_);
                    fsync(dexfilefp);
                    close(dexfilefp);
                }
            }
        }
        
        if (dexfilepath != nullptr) {
            free(dexfilepath);
            dexfilepath = nullptr;
        }
    }

测试实际效果

某平台加固后


fart之后

总结

Hook点有2个:

  1. 是app启动时候,在ActivityThread中利用反射,拿到ArtMethod,再通过ArtMethod->GetDexFile()拿到DexFile
  2. 在安卓虚拟机执行指令时候Execute中进行dump出DexFile,相较于早期的DexFile::OpenCommon(const uint8_t* base, size_t size, ...)中进行脱壳更加底层

标签:脱壳,dexfilepath,item,int,dexfilefp,Fart,源码,method,size
From: https://www.cnblogs.com/tangshunhui/p/17373570.html

相关文章

  • 从源码深入理解读写锁(golang-RWMutex)
    环境:go1.19.8在读多写少的情况下,即使一段时间内没有写操作,大量并发的读访问也不得不在Mutex的保护下变成串行访问,这种情况下,使用Mutex,对性能影响比较大。所以就要区分读写操作。如果某个读操作的g持有了锁,其他读操作的g就不必等待了,可以并发的访问共享变量,这样就可以将串行的......
  • OpenHarmony 资源调度之智能感知调度源码分析
    作者:张守忠1WPA_supplicant简介WPA是WiFiProtectedAccess的缩写,中文含义为“WiFi网络安全存取”。WPA是一种基于标准的可互操作的WLAN安全性增强解决方案,可大大增强现有以及未来无线局域网络的数据保护和访问控制水平。wpa_supplicant是开源项目源码,支持Linux,Windows以及很多......
  • Opal 教程之二 SipIM 例子源码分析
    在互联网上.极少有关于Opal的中文教程.因此敝人决定把学习Opal的过程记录下来勉励自己.抑或给后来者留下一些入门的资料.最近感觉学习Opal已经慢慢摸出了门道.前几个星期.摸索在VS2005编译Opal花了我好多天的时间.把我的耐心都磨得差不多快要放弃研究Opal.作为初学者.学习的难度......
  • java基于springboot+vue的宿舍管理系统、学生宿舍管理系统、高校宿舍管理系统,附源码+
    1、项目介绍java基于springboot+vue的宿舍管理系统、学生宿舍管理系统、高校宿舍管理系统,实现管理员:首页、个人中心、公告信息管理、院系管理、班级管理、学生管理、宿舍信息管理、宿舍安排管理、卫生检查管理、报修信息管理、报修处理管理、缴费信息管理,学生;首页、个人中心、公......
  • Spring源码:Bean生命周期(三)
    前言在之前的文章中,我们已经对bean的准备工作进行了讲解,包括bean定义和FactoryBean判断等。在这个基础上,我们可以更加深入地理解getBean方法的实现逻辑,并在后续的学习中更好地掌握createBean方法的实现细节。getBean用法讲解getBean方法之前,我们先来看看他有几种常见......
  • STL源码分析读书笔记
    主要是关于标准库容器的整理空间配置器主要看SGI的实现,有两个空间配置器_malloc_alloc_template<0>__default_alloc_template<...>用户可以选择单独使用第一个分配器,或者一起使用两个分配器。当用户选择使用两个分配器时,编译器会分别将上述两个分配器typedef成malloc_a......
  • springboot 分析源码欢迎页和图标-> thymeleaf模板引擎常用语法->扩展
    欢迎页: icon: 注意点: thymeleaf模板引擎1.使用thymeleaf模板引擎前要导入对应依赖包2.阅读源码:根据源码说明我们可以将html文件放置在templates目录下,然后通过controller进行跳转即可 controller类://在templates下的东西需要通过controller类来跳转,//需要导入......
  • 从案例中详解go-errgroup-源码
    一、背景某次会议上发表了errorgroup包,一个g失败,其他的g会同时失败的错误言论(看了一下源码中的一句话Thefirstcalltoreturnanon-nilerrorcancelsthegroup,没进一步看其他源码,片面理解了)。//Thefirstcalltoreturnanon-nilerrorcancelsthegroup'scontext......
  • JUC并发编程原理精讲(源码分析)
    1.JUC前言知识JUC即java.util.concurrent涉及三个包:java.util.concurrentjava.util.concurrent.atomicjava.util.concurrent.locks普通的线程代码:ThreadRunnable没有返回值、效率相比入Callable相对较低!Callable有返回值!【工作常用】1.1进程和线程进程:是......
  • 互联网医院系统源码:数据安全与隐私保护问题如何解决?
    当下,互联网医院系统源码已经走进了很多人的视野中,它的作用和好处小编就不用强调了,今天我们来聊另一个话题——隐私与数据安全。在智慧医疗行业,安全问题更是重中之重,这也自然而然成为了老生常谈的一个问题。本文小编将从互联网医院系统源码的数据安全与隐私保护的意义、当前面临的挑......