Fart修改源碼注釋

libcore\dalvik\src\main\java\dalvik\system\DexFile.java

    //增加dumpMethodCode纺铭,對(duì)應(yīng) art\runtime\native\dalvik_system_DexFile.cc  DexFile_dumpMethodCode
    private static native void dumpMethodCode(Object m);
    

frameworks\base\core\java\android\app\ActivityThread.java

  • 主要是增加了在Activity OnCreate時(shí)虽画,遍歷所有dex并且遍歷所有類,遍歷所有方法朽砰,然后dump method
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        //在Activity ONCREATE 后 增加了調(diào)用
        fartthread();
        //add    
    }
    
    public static void fartthread() {
        new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    Log.e("ActivityThread", "start sleep,wait for fartthread start......");
                    Thread.sleep(1 * 60 * 1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Log.e("ActivityThread", "sleep over and start fartthread");
                fart();
                Log.e("ActivityThread", "fart run over");

            }
        }).start();
    }
    
    public static void fart() {
        ClassLoader appClassloader = getClassloader();
        List<Object> dexFilesArray = new ArrayList<Object>();
        Field pathList_Field = (Field) getClassField(appClassloader, "dalvik.system.BaseDexClassLoader", "pathList");
        Object pathList_object = getFieldOjbect("dalvik.system.BaseDexClassLoader", appClassloader, "pathList");
        Object[] ElementsArray = (Object[]) getFieldOjbect("dalvik.system.DexPathList", pathList_object, "dexElements");
        Field dexFile_fileField = null;
        try {
            dexFile_fileField = (Field) getClassField(appClassloader, "dalvik.system.DexPathList$Element", "dexFile");
        } catch (Exception e) {
            e.printStackTrace();
        }
        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);
            }
        }
        Field mCookiefield = getClassField(appClassloader, "dalvik.system.DexFile", "mCookie");
        for (int j = 0; j < ElementsArray.length; j++) {
            Object element = ElementsArray[j];
            Object dexfile = null;
            try {
                dexfile = (Object) dexFile_fileField.get(element);
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (dexfile == null) {
                continue;
            }
            if (dexfile != null) {
                dexFilesArray.add(dexfile);
                Object mcookie = getClassFieldObject(appClassloader, "dalvik.system.DexFile", dexfile, "mCookie");
                if (mcookie == null) {
                    continue;
                }
                String[] classnames = null;
                try {
                    //獲取dex中所有的類名
                    classnames = (String[]) getClassNameList_method.invoke(dexfile, mcookie);
                } catch (Exception e) {
                    e.printStackTrace();
                    continue;
                } catch (Error e) {
                    e.printStackTrace();
                    continue;
                }
                if (classnames != null) {
                    for (String eachclassname : classnames) {
                        //遍歷所有的類扔傅,并且調(diào)用新增的dumpMethodCode_method
                        loadClassAndInvoke(appClassloader, eachclassname, dumpMethodCode_method);
                    }
                }

            }
        }
        return;
    }
    //遍歷類,并且調(diào)用方法的dumpMethodCode_method
    public static void loadClassAndInvoke(ClassLoader appClassloader, String eachclassname, Method dumpMethodCode_method) {
        Log.i("ActivityThread", "go into loadClassAndInvoke->" + "classname:" + eachclassname);
        Class resultclass = null;
        try {
            resultclass = appClassloader.loadClass(eachclassname);
        } catch (Exception e) {
            e.printStackTrace();
            return;
        } catch (Error e) {
            e.printStackTrace();
            return;
        } 
        if (resultclass != null) {
            try {
                Constructor<?> cons[] = resultclass.getDeclaredConstructors();
                for (Constructor<?> constructor : cons) {
                    if (dumpMethodCode_method != null) {
                        try {
                            dumpMethodCode_method.invoke(null, constructor);
                        } catch (Exception e) {
                            e.printStackTrace();
                            continue;
                        } catch (Error e) {
                            e.printStackTrace();
                            continue;
                        } 
                    } else {
                        Log.e("ActivityThread", "dumpMethodCode_method is null ");
                    }

                }
            } catch (Exception e) {
                e.printStackTrace();
            } catch (Error e) {
                e.printStackTrace();
            } 
            try {
                Method[] methods = resultclass.getDeclaredMethods();
                if (methods != null) {
                    for (Method m : methods) {
                        if (dumpMethodCode_method != null) {
                            try {
                               dumpMethodCode_method.invoke(null, m);
                             } catch (Exception e) {
                                e.printStackTrace();
                                continue;
                            } catch (Error e) {
                                e.printStackTrace();
                                continue;
                            } 
                        } else {
                            Log.e("ActivityThread", "dumpMethodCode_method is null ");
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            } catch (Error e) {
                e.printStackTrace();
            } 
        }
    }
    

art\runtime\interpreter\interpreter.cc

  • 解釋執(zhí)行時(shí)dump 整體的dex
static inline JValue Execute(Thread* self, const DexFile::CodeItem* code_item,
                             ShadowFrame& shadow_frame, JValue result_register) {
                                 
            
    //ADD END 這里是解釋執(zhí)行模式苗傅,art虛擬機(jī)的clinit方法一定會(huì)走這里捺球,但是其他的oat優(yōu)化的方法 不一定會(huì)走這里缸浦。
  if(strstr(PrettyMethod(shadow_frame.GetMethod()).c_str(),"<clinit>")!=nullptr)
  {
  //在執(zhí)行類初始化方法的時(shí)候 整體dump , 由于類加載的多氮兵,所以這里應(yīng)該會(huì)dump多次
      dumpDexFileByExecute(shadow_frame.GetMethod());
      }
    //ADD END
    *******

}
      

art\runtime\native\dalvik_system_DexFile.cc

  • 增加DexFile_dumpMethodCode 裂逐,在ACtivity oncreate時(shí),主動(dòng)遍歷所有方法泣栈,調(diào)用此方法dump
  • dumpDexFileByExecute 實(shí)現(xiàn)卜高,在解釋執(zhí)行時(shí)整體的dump
//addfunction
static void DexFile_dumpMethodCode(JNIEnv* env, jclass,jobject method) {
ScopedFastNativeObjectAccess soa(env);
  if(method!=nullptr)
  {
          ArtMethod* artmethod = ArtMethod::FromReflectedMethod(soa, method);
          myfartInvoke(artmethod);
      }   


  return;
}

//addfunction

art\runtime\art_method.cc 主要邏輯

  • ArtMethod::Invoke 時(shí),根據(jù)標(biāo)示Thread=null南片, dumpArtMethod
  • 主動(dòng)調(diào)用 myfartInvoke 實(shí)現(xiàn)掺涛,主要進(jìn)行ArtMethod的Invoke調(diào)用,但是在invoke的時(shí)候根據(jù)標(biāo)示Thread *self = nullptr; 進(jìn)行dump
  • 在dumpArtMethod時(shí)疼进,再次整體dump了dex薪缆,雖然dump了整體的dex,但是抽取殼伞广,可能函數(shù)體還是空的拣帽,所以會(huì)進(jìn)行codeitem的dump
  • dumpArtMethod生成bin文件
    void ArtMethod::Invoke(Thread * self, uint32_t * args,
                   1. uint32_t args_size, JValue * result,
                   const char *shorty) {

        //ADD self等于null的時(shí)候 是自己調(diào)用的,dump方法
        if (self == nullptr) {
            dumpArtMethod(this);
            return;
        }
        //ADD END
        *******
    }
    
    //導(dǎo)出 myfartInvoke 在DexFile_dumpMethodCode 調(diào)用
    extern "C" void myfartInvoke(ArtMethod * artmethod)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
        JValue *result = nullptr;
        Thread *self = nullptr;//nullptr 標(biāo)示 主動(dòng)調(diào)用 不執(zhí)行代碼邏輯嚼锄,只進(jìn)行方法的dump
        uint32_t temp = 6;
        uint32_t *args = &temp;
        uint32_t args_size = 6;
        artmethod->Invoke(self, args, args_size, result, "fart");
    }
    
    //計(jì)算有異常的codeitem長(zhǎng)度
    uint8_t *codeitem_end(const uint8_t ** pData) {
        uint32_t num_of_list = DecodeUnsignedLeb128(pData);
        for (; num_of_list > 0; num_of_list--) {
            int32_t num_of_handlers =
                DecodeSignedLeb128(pData);
            int num = num_of_handlers;
            if (num_of_handlers <= 0) {
                num = -num_of_handlers;
            }
            for (; num > 0; num--) {
                DecodeUnsignedLeb128(pData);
                DecodeUnsignedLeb128(pData);
            }
            if (num_of_handlers <= 0) {
                DecodeUnsignedLeb128(pData);
            }
        }
        return (uint8_t *) (*pData);
    }

    //將code item 進(jìn)行base64的輸出减拭,方便閱讀
    extern "C" char *base64_encode(char *str, long str_len,
                       long *outlen) {
        long len;
        char *res;
        int i, j;
        const char *base64_table =
            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        if (str_len % 3 == 0)
            len = str_len / 3 * 4;
        else
            len = (str_len / 3 + 1) * 4;

        res = (char *) malloc(sizeof(char) * (len + 1));
        res[len] = '\0';
        *outlen = len;
        for (i = 0, j = 0; i < len - 2; j += 3, i += 4) {
            res[i] = base64_table[str[j] >> 2];
            res[i + 1] =
                base64_table[(str[j] & 0x3) << 4 |
                     (str[j + 1] >> 4)];
            res[i + 2] =
                base64_table[(str[j + 1] & 0xf) << 2 |
                     (str[j + 2] >> 6)];
            res[i + 3] = base64_table[str[j + 2] & 0x3f];
        }

        switch (str_len % 3) {
        case 1:
            res[i - 2] = '=';
            res[i - 1] = '=';
            break;
        case 2:
            res[i - 1] = '=';
            break;
        }

        return res;
    }
    
    //整體dump d_dexfile_execute.dex 調(diào)用時(shí)機(jī)在解釋器解釋執(zhí)行類cliniT的時(shí)候
    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;
        }

    }
    //主動(dòng)調(diào)用了invoke,如果殼在這個(gè)時(shí)機(jī)区丑,將代碼還原拧粪,那么將可以dumP出method
    //方法的code-item dump
    //在這里進(jìn)行了_dexfile.dex的dump
    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",//dump整體的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;//這里計(jì)算code item的長(zhǎng)度
                uint8_t *item = (uint8_t *) code_item;
                if (code_item->tries_size_ > 0) {//有異常的計(jì)算方式要加上try catch的長(zhǎng)度
                    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 {//沒(méi)有try catch 
                    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",//生成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;
        }

    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末沧侥,一起剝皮案震驚了整個(gè)濱河市可霎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌正什,老刑警劉巖啥纸,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異婴氮,居然都是意外死亡斯棒,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門主经,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)荣暮,“玉大人,你說(shuō)我怎么就攤上這事罩驻∷胨郑” “怎么了?”我有些...
    開封第一講書人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)砾跃。 經(jīng)常有香客問(wèn)我骏啰,道長(zhǎng),這世上最難降的妖魔是什么抽高? 我笑而不...
    開封第一講書人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任判耕,我火速辦了婚禮,結(jié)果婚禮上翘骂,老公的妹妹穿的比我還像新娘壁熄。我一直安慰自己,他們只是感情好碳竟,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開白布草丧。 她就那樣靜靜地躺著,像睡著了一般莹桅。 火紅的嫁衣襯著肌膚如雪昌执。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,079評(píng)論 1 285
  • 那天统翩,我揣著相機(jī)與錄音仙蚜,去河邊找鬼。 笑死厂汗,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的呜师。 我是一名探鬼主播娶桦,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼汁汗!你這毒婦竟也來(lái)了衷畦?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤知牌,失蹤者是張志新(化名)和其女友劉穎祈争,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體角寸,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡菩混,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了扁藕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片沮峡。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖亿柑,靈堂內(nèi)的尸體忽然破棺而出邢疙,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布疟游,位于F島的核電站呼畸,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏颁虐。R本人自食惡果不足惜役耕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望聪廉。 院中可真熱鬧瞬痘,春花似錦、人聲如沸板熊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)干签。三九已至津辩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間容劳,已是汗流浹背喘沿。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留竭贩,地道東北人蚜印。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像留量,于是被迫代替她去往敵國(guó)和親窄赋。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容