Android作假大作戰之你真的相信魯大師、安兔兔評測跑分嗎?
前言:本文僅針對少部分中低端Android(山寨)機,請勿對各大廠商對號入座~不是鼓勵大家作假,只是讓大家對手機評測的水分有更深的了解~
現在國內Android市場如火如荼,Android機的價格從幾百到幾千不等,差異還是比較大的。我們經常能聽到有人巴拉巴拉說自己幾百買了個多好多好的手機,CPU xxx,內存 xxx,像素 xxx,跑分完爆某米幾條街,比某米實惠強大太多了。那么我們今天就來扒一拔這些數據一定是真的嗎?這些跑分排名一定準確嗎?
小白型作假
先從我們最關心的CPU信號來看:
一般可以從我們手機的設置--關于手機中選項中查看到當前的cpu型號、主頻、核數等信息,如下所示:
這部分的作假有一種最簡單愚蠢的方法,直接在當前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也能"掩護"我們作假呢?其實有了思路就會發現非常簡單。因為作假一般都是在rom層開發的時候考慮的,所以我們可以直接修改framework框架層的東西。最終顯示在魯大師、安兔兔等跑分軟件上的信息本質肯定也是一個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中的源碼!這樣的話當第三方APP運行在我們的系統中時就能"掩護"我們了~但是,這種方案也有一個致命的缺點,萬一用戶不用魯大師呢?而是用360、騰訊或者其他第三方評測應用呢?難道我們還要一個一個包名類名的添加至 setText() 中?這顯然不符和設計代碼的原理。
終極作假
這里以手機內置存儲空間為例,作假讓其在任何時候都能向外界提供"假信息"。手機的存儲空間并不是直接在系統上層(這里指application、framework層)上報的,而是從底層(kernel、hal、jni層)傳遞給上層處理。所以為了一勞永逸,我們直接在底層動手!在其向上層傳遞的時候,我們就改變它的部分信息,不必再考慮上層使用什么第三方app。
觀察系統源碼libcore/luni/src/main/native/libcore_io_Posix.cpp,我們可以找到此函數:
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) 函數,將此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("ro.bdfun.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 替換成我們作假的大小和數量。看一下效果圖:
作假前
作假后
除了這些,用戶肯定還關心像素吧?這其實也沒什么難度。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);
}
最后在此說明本文并不是作假教學,也沒針對任何手機!只是想讓大家謹慎購機,讓大家明白,良辰有一百種作假的方法,而你卻無可奈何~~~
來自:http://www.jianshu.com/p/0368128423ba