Mr.Nubility進階記——安卓如何修改3rd App(某兔兔、某大師、CPU-Z)等檢測信息

這種作假的東西其實我是很反感的,有些無良客戶居然提要求把1G的改成2G的,2G的改成4G的,

導致我現在都不相信現在手機顯示出來的數據了,但是沒辦法,爲了能混口飯吃,唉...

本文提供2種方法,並已Ram Rom爲例

1.在TextView.java(frameworks/base/core/java/android/widget/TextView.java),因爲三方軟件我們沒辦法直接修改,但是從顯示上來看肯定是textview,因而我們可以直接在SetText()的方法中去修改

private void setText(CharSequence text, BufferType type,
                        boolean notifyBefore, int oldlen) {
    mTextSetFromXmlOrResourceId = false;
    if (text == null) {
        text = "";
    }
    String packageName = getContext().getPackageName();
    if (packageName.equals("com.antutu.ABenchMark")
                || packageName.equals("com.cpuid.cpu_z")
                || packageName.equals("com.ludashi.benchmark")) {
        //這兩個是我們在frameworks/base/core/res/res/valuess/configs.xml中寫死的值
        String fakeRamSize = getContext().getResources().getString(com.android.internal.R.string.custom_ram_size);
        String fakeRomSize = getContext().getResources().getString(com.android.internal.R.string.custom_rom_size);
        //然後就是用我們自己定義的字符串去替換,三方的字符串
        if (fakeRamSize != null && !fakeRamSize.equals("") && s.startsWith("Total:") && s.endsWith("MB")) {
                String totals = s.substring(s.indexOf(":") + 1, s.indexOf("B") + 1);
                text = s.replace(totals, fakeRamSize);
        }
        if (fakeRomSize != null && !fakeRomSize.equals("") && s.startsWith("Total:") && s.endsWith("GB")) {
                String totals = s.substring(s.indexOf(":") + 1, s.indexOf("B") + 1);
                text = s.replace(totals, fakeRomSize);
        }
        if (fakeRamSize != null && !fakeRamSize.equals("") && s.contains("/") && s.endsWith("MB")) {
                String totals = s.substring(s.lastIndexOf("/") + 1, s.lastIndexOf("B") + 1);
                text = s.replace(totals, fakeRamSize);
        }
        if (fakeRomSize != null && !fakeRomSize.equals("") && s.contains("/") && s.endsWith("GB")) {
                String totals = s.substring(s.lastIndexOf("/") + 1, s.lastIndexOf("B") + 1);
                text = s.replace(totals, fakeRomSize);
        }
    }   
}

通過上面的方法,我們就可以把ram rom,替換成我們想要的大小,並且肯定是整數。

2. 大家都看到了,用TextView改的方法很low,對不對?這上面只是3個應用就寫了這麼多代碼,有這麼多判斷,那如果市面上又出來其他主流檢測工具呢???

另外,從性能上面講,系統裏有多少Textview,每個顯示之前都要判斷是不是三方應用,如果是三方應用,每個TextView還要判斷已什麼開頭,我的天!如果說這不影響性能,鬼才信啊!因此,我們的第二種方法會解決這些問題。

思路是這樣的,先考慮三方應用是如何獲取系統的ram rom的,至於如何獲取,在這裏不再詳述,大家可以自行百度,經過調試最後發現,這些主流的App獲取Rom、Ram的方式是:

//ROM
String path = Environment.getDataDirectory().getPath();
StatFs statFs = new StatFs(path);
long blockCount = statFs.getBlockCountLong();
long blockSize = statFs.getBlockSizeLong();
long availableBlocks = statFs.getAvailableBlocksLong();
long totalBytes = statFs.getTotalBytes();
long freeBytes = statFs.getFreeBytes();

//RAM
//RAM是保存在proc/meminfo文件裏面的,meminfo的大概結構式這樣的
/**
        MemTotal: 所有可用RAM大小。
        MemFree: LowFree與HighFree的總和,被系統留着未使用的內存。
        Buffers: 用來給文件做緩衝大小。
        Cached: 被高速緩衝存儲器(cache memory)用的內存的大小(等於diskcache minus SwapCache)。
        SwapCached:被高速緩衝存儲器(cache memory)用的交換空間的大小。已經被交換出來的內存,仍然被存放在swapfile中,用來在需要的時候很快的被替換而不需要再次打開I/O端口。
        Active: 在活躍使用中的緩衝或高速緩衝存儲器頁面文件的大小,除非非常必要,否則不會被移作他用。
        Inactive: 在不經常使用中的緩衝或高速緩衝存儲器頁面文件的大小,可能被用於其他途徑。
        SwapTotal: 交換空間的總大小。
        SwapFree: 未被使用交換空間的大小。
        Dirty: 等待被寫回到磁盤的內存大小。
        Writeback: 正在被寫回到磁盤的內存大小。
        AnonPages:未映射頁的內存大小。
        Mapped: 設備和文件等映射的大小。
        Slab: 內核數據結構緩存的大小,可以減少申請和釋放內存帶來的消耗。
        SReclaimable:可收回Slab的大小。
        SUnreclaim:不可收回Slab的大小(SUnreclaim+SReclaimable=Slab)。
        PageTables:管理內存分頁頁面的索引表的大小。
        NFS_Unstable:不穩定頁表的大小。
        要獲取android手機總內存大小,只需讀取”/proc/meminfo”文件的第1行,並進行簡單的字符串處理即可。*/

 public static String getMemInfoIype(Context context, String type) {
        try {
            FileReader fileReader = new FileReader("/proc/meminfo");
            BufferedReader bufferedReader = new BufferedReader(fileReader, 4 * 1024);
            String str = null;
            while ((str = bufferedReader.readLine()) != null) {
                if (str.contains(type)) {
                    break;
                }
            }
            bufferedReader.close();
            // \\s表示   空格,回車,換行等空白符
            // +號表示一個或多個的意思     
            String[] array = str.split("\\s+");
            // 獲得系統總內存,單位是KB,乘以1024轉換爲Byte
            int length = Integer.valueOf(array[1]).intValue() * 1024;
            return android.text.format.Formatter.formatFileSize(context, length);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

因此我們只需要在源頭改變數據的大小就OK,由於我對C不是太熟悉,所以開始時我採用的是修改java代碼達到目的。下面是修改Rom

// 剛纔已分析,ROM用的是BlockCount和blocksize的乘積,由於blocksize固定,所以我們用一下改法
// 在對應項目的system.prop文件中添加 ro.faker.rom.size = 8L
/*
擴展一下
屬性名稱以“ro.”開頭,那麼這個屬性被視爲只讀屬性。一旦設置,屬性值不能改變。
屬性名稱以“persist.”開頭,當設置這個屬性時,其值也將寫入/data/property。
屬性名稱以“net.”開頭,當設置這個屬性時,“net.change”屬性將會自動設置,以加入到最後修改的屬性名。(這是很巧妙的。 netresolve模塊的使用這個屬性來追蹤在net.*屬性上的任何變化。)
屬性“ ctrl.start ”和“ ctrl.stop ”是用來啓動和停止服務。每一項服務必須在/init.rc中定義.
*/

public long getBlockCountLong() {
        long fakerRomSize = SystemProperties.getLong("ro.faker.rom.size", 0L);
        return fakerRomSize == 0L
                ? (int) mStat.f_blocks
                : (int) (1024 * 1024 * 1024L * fakerRomSize / getBlockSizeLong());
    }

當然,getBlockCount()這個方法最好也改一下,這是過時的方法,但是仍可以使用

這個方法一般不會有問題,因爲大多數都是通過這種方法獲取的,但是如果想萬無一失,可以通過修改libcore\luni\src\main\native\libcore_io_Linux.cpp文件中的

static jobject makeStructStatVfs(JNIEnv* env, const struct statvfs& sb) {
    static jmethodID ctor = env->GetMethodID(JniConstants::structStatVfsClass, "<init>",
            "(JJJJJJJJJJJ)V");
    if (ctor == NULL) {
        return NULL;
    }
     return env->NewObject(JniConstants::structStatVfsClass, ctor,
                          static_cast<jlong>(sb.f_bsize),
                          static_cast<jlong>(sb.f_frsize),
                          static_cast<jlong>(sb.f_blocks),
                          static_cast<jlong>(sb.f_bfree),
                          static_cast<jlong>(sb.f_bavail),
                          static_cast<jlong>(sb.f_files),
                          static_cast<jlong>(sb.f_ffree),
                          static_cast<jlong>(sb.f_favail),
                          static_cast<jlong>(sb.f_fsid),
                          static_cast<jlong>(sb.f_flag),
                          static_cast<jlong>(sb.f_namemax));
}

這種改法大家有興趣自己實現吧,尷尬而不是禮貌的微笑

下面是修改RAM的,這個搞得我頭皮發麻,因爲之前沒搞過C和Kernel,提前說明一下,kernel層和framework層是相對獨立的,所以在安卓8.1 上之前的在項目的ProjectConfig.mk中定義一個宏,在kernel層通過Makefile編譯的方法不能再用了,廢話不說,上代碼

// 上面分析過meminfo文件了,這裏就不多說了,首先你要清楚項目用的內核版本是什麼,可以在手機設置裏面看到 ,kernel-4.9\fs\proc\meminfo.c,這個文件生成了meminfo
// 這個方法生成的KB
static int meminfo_proc_show(struct seq_file *m, void *v)
{
	struct sysinfo i;
	unsigned long committed;
	long cached;
......
    #if defined(CONFIG_FAKER_RAM_SIZE) && (CONFIG_FAKER_RAM_SIZE> 0)
        show_val_kb(m, "MemTotal:       ", CONFIG_FAKER_RAM_SIZE* 1024 * 256L);
    #else
       show_val_kb(m, "MemTotal:       ", i.totalram);
    #endif
    
	show_val_kb(m, "MemFree:        ", i.freeram);
	show_val_kb(m, "MemAvailable:   ", available);
	show_val_kb(m, "Buffers:        ", i.bufferram);
......
}

/*
通過這個CONFIG_FAKER_RAM_SIZE,我們就可以隨意改變RAM的大小了,這個東西的配置有講究,注意
首先在kernel-4.9\fs\proc\Kconfig中定義,格式如下 不能錯,bool string的寫法類似
config FAKER_RAM_SIZE    
    int FAKER_RAM_SIZE
    default 0

CONFIG_FAKER_RAM_SIZE這個就是,config FAKER_RAM_SIZE 合起來的,定義在對應的項目中
kernel-4.9\arch\arm64\configs\xoxo_debug_defconfig
kernel-4.9\arch\arm64\configs\xoxo_defconfig
兩個文件都添加如下配置,數值就是項目中需要的RAM大小1G 就是1
CONFIG_FAKER_RAM_SIZE = 1   錯誤寫法 不能留空格 不能留空格 不能留空格
CONFIG_FAKER_RAM_SIZE=1     正確寫法
*/

到此爲止,就已經實現要求了,Android O,Android P 測試OK,希望你像IG一樣,永不加班!

對了補充一句,能拒絕造假的,堅決拒絕,太特麼噁心了!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章