前言:本文僅針對少部分中低端Android(山寨)機蝴乔,請勿對各大廠商對號入座~不是鼓勵大家作假,只是讓大家對手機評測的水分有更深的了解~
現(xiàn)在國內(nèi)Android市場如火如荼驮樊,Android機的價格從幾百到幾千不等薇正,差異還是比較大的。我們經(jīng)常能聽到有人巴拉巴拉說自己幾百買了個多好多好的手機囚衔,CPU xxx挖腰,內(nèi)存 xxx,像素 xxx,跑分完爆某米幾條街佳魔,比某米實惠強大太多了曙聂。那么我們今天就來扒一拔這些數(shù)據(jù)一定是真的嗎?這些跑分排名一定準確嗎鞠鲜?
小白型作假
先從我們最關心的CPU信號來看:
一般可以從我們手機的設置--關于手機中選項中查看到當前的cpu型號宁脊、主頻、核數(shù)等信息贤姆,如下所示:
這部分的作假有一種最簡單愚蠢的方法榆苞,直接在當前Activity找到該String將其修改掉,設置中的這些菜單項一般都是
Preference
的子類霞捡,我們可以在xml文件中找到其相應summary
坐漏、title
的字符即可,如下:
android:summary="@string/cpu_setting_summary"
android:title="@string/cp_setting_title"
修改后的效果圖:
這很簡單吧碧信?相信剛接觸Android一天的同學都能明白赊琳。但是為什么又說愚蠢呢?很明顯砰碴,這要修改的話只能修改掉當前Activity的字符躏筏,萬一其他地方也有讀取顯示cpu信息,就會造成顯示不同信息的沖突呈枉,另外當用戶使用第三方apk評測的時候也會瞬間原形畢露趁尼,所以這樣的修改方法可以直接pass。
進階型作假
上面提及了第三APK評測時的作假問題猖辫,那我們怎樣才能修改使得第三方的APK也能"掩護"我們作假呢酥泞?其實有了思路就會發(fā)現(xiàn)非常簡單。因為作假一般都是在rom層開發(fā)的時候考慮的啃憎,所以我們可以直接修改framework框架層的東西芝囤。最終顯示在魯大師、安兔兔等跑分軟件上的信息本質(zhì)肯定也是一個TextView,但我們又不能去修改魯大師、安兔兔等代碼凡人,所以退而求其次名党,我們修改framework層中的TextView.java(frameworks/base/core/java/android/widget/TextView.java),大致思路可以參考下面的代碼:
private void setText(CharSequence text, BufferType type,
boolean notifyBefore, int oldlen) {
if (text == null) {
text = "";
}
String packageName = getContext().getPackageName();
if (packageName.equals("com.antutu.ABenchMark")
|| packageName.equals("com.cpuid.cpu_z")
|| packageName.equals("com.primatelabs.geekbench")) {
String str1 = text.toString();
if (str1.contains("hahaha")) {
text = "lalalala";
}
}
}
}
我們直接在框架層TextView的setText方法最前面添加了一段邏輯,判斷一下當前應用包名的及顯示的字符名是否符合我們需要作假的評測軟件挠轴,如果滿足直接替換作假信息的字符传睹,當然這里只是最間的字符替換,其他作假情況也完全可以按以上思路直接修改framework中的源碼岸晦!這樣的話當?shù)谌紸PP運行在我們的系統(tǒng)中時就能"掩護"我們了~但是欧啤,這種方案也有一個致命的缺點,萬一用戶不用魯大師呢启上?而是用360邢隧、騰訊或者其他第三方評測應用呢?難道我們還要一個一個包名類名的添加至setText()
中冈在?這顯然不符和設計代碼的原理倒慧。
終極作假
這里以手機內(nèi)置存儲空間為例,作假讓其在任何時候都能向外界提供"假信息"包券。手機的存儲空間并不是直接在系統(tǒng)上層(這里指application纫谅、framework層)上報的,而是從底層(kernel溅固、hal付秕、jni層)傳遞給上層處理。所以為了一勞永逸侍郭,我們直接在底層動手询吴!在其向上層傳遞的時候,我們就改變它的部分信息亮元,不必再考慮上層使用什么第三方app猛计。
觀察系統(tǒng)源碼libcore/luni/src/main/native/libcore_io_Posix.cpp,我們可以找到此函數(shù):
static jobject Posix_statvfs(JNIEnv* env, jobject, jstring javaPath) {
ScopedUtfChars path(env, javaPath);
if (path.c_str() == NULL) {
return NULL;
}
struct statvfs sb;
int rc = TEMP_FAILURE_RETRY(statvfs(path.c_str(), &sb));
if (rc == -1) {
throwErrnoException(env, "statvfs");
return NULL;
}
//return makeStructStatVfs_fake(env, sb, false);
return makeStructStatVfs(env, sb);
}
最后的return makeStructStatVfs(env, sb);
便是向上層傳遞的存儲空間信息爆捞,因此我們直接模仿makeStructStatVfs(env, sb)
自己寫一個makeStructStatVfs_fake(env, sb, false)
函數(shù)奉瘤,將此return給上層:
static jobject makeStructStatVfs_fake(JNIEnv* env, const struct statvfs& sb, bool internal) {
jlong f_blocks;
jlong f_bfree;
jlong f_bavail;
int value = 0;
jlong f_blocks_temp ;
int size =0 ;
//[CDS]Libcore_io_Posix bsize:4096
//[CDS]Libcore_io_Posix frsize:4096
//[CDS]Libcore_io_Posix blocks:207369
//[CDS]Libcore_io_Posix bfree:189725
//[CDS]Libcore_io_Posix bavail:189725
size = property_getInt("fake_system_rom_size", size);
if(internal) { //internal storage
value = property_getInt("internal_fake_rom_size", 0);
} else { //phone storage
value = property_getInt("phone_fake_rom_size", 0);
}
if(value == 0) {
f_blocks = sb.f_blocks;
f_bfree = sb.f_bfree;
f_bavail = sb.f_bavail;
} else {
f_blocks = (jlong)(((jlong)value * 256 * 4096) / sb.f_bsize);
f_blocks_temp = (jlong)(((jlong)(value - size) * 256 * 4096) / sb.f_bsize);
f_bfree = (jlong)((jfloat)((jfloat) f_blocks_temp / sb.f_blocks ) * sb.f_bfree );
f_bavail = (jlong)((jfloat)((jfloat) f_blocks_temp / sb.f_blocks) * sb.f_bavail);
}
static jmethodID ctor = env->GetMethodID(JniConstants::structStatVfsClass, "<init>",
"(JJJJJJJJJJJ)V");
return env->NewObject(JniConstants::structStatVfsClass, ctor,
static_cast<jlong>(sb.f_bsize),
static_cast<jlong>(sb.f_frsize),
static_cast<jlong>(f_blocks),
static_cast<jlong>(f_bfree),
static_cast<jlong>(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),
max_name_length);
}
看似一長段代碼,其實就只是將sb.f_bsize
嵌削、sb.f_bfree
毛好、sb.f_bavail
替換成我們作假的大小和數(shù)量望艺】溜酰看一下效果圖:
作假前
作假后
除了這些,用戶肯定還關心像素吧找默?這其實也沒什么難度艇劫。camera像素作假一般會做到二千萬像素,五千萬也不是不可能惩激,如果是僅僅針對工具檢測推薦修改的地方為:frameworks\base\core\java\android\hardware\Camera.java中的getSupportedPictureSizes()方法:
public List<Size> getSupportedPictureSizes() {
String str = get((mStereo3DMode ? KEY_STEREO3D_PRE : "") + KEY_PICTURE_SIZE + SUPPORTED_VALUES_SUFFIX);
if(DisplayManagerGlobal.getCurrentFakeProcess()){
ArrayList<Size> sizeList = splitSize(str);
Size large_size = sizeList.get(sizeList.size() - 1);
if(large_size.width * large_size.height > 2560 * 1920) str += ",4608x3456";
}
return splitSize(str);
}
最后在此說明本文并不是作假教學店煞,也沒針對任何手機蟹演!只是想讓大家謹慎購機,讓大家明白顷蟀,良辰有一百種作假的方法酒请,而你卻無可奈何~~~