android开发检测用户是否使用了虚拟定位
在應(yīng)用開發(fā)中,如果有簽到打卡之類的功能,你是否會(huì)遇到檢測(cè)用戶是否使用了虛擬定位軟件來(lái)進(jìn)行打卡?如果有,那么請(qǐng)仔細(xì)閱讀這篇文章。該文章會(huì)帶你認(rèn)識(shí)什么是虛擬定位、什么是應(yīng)用分身,以及如何通過(guò)代碼來(lái)檢測(cè)用戶是否使用了虛擬定位進(jìn)行打卡...在寫之前首先要感覺這位博主的分享https://blog.csdn.net/mawei7510/article/details/80250416;他主要寫的是應(yīng)用分身、應(yīng)用雙開之類的內(nèi)容,受他的影響,研究了一下虛擬定位,其實(shí)這兩者的原理是一樣的,虛擬定位也是通過(guò)一些第三方應(yīng)用,然后把你自己的應(yīng)用克隆了一個(gè)。啟動(dòng)的時(shí)候需要在第三方的應(yīng)用里面來(lái)啟動(dòng),這樣的話在私有文件里面生成的包名勢(shì)必會(huì)和直接啟動(dòng)自己的應(yīng)用有區(qū)別,知道了這些,我們將通過(guò)以下三個(gè)方法來(lái)一一檢測(cè);
首先介紹一些那些使用應(yīng)用分身雙開和虛擬定位的應(yīng)用和自己的應(yīng)用在私有目錄下生成的包名有什么區(qū)別:
我們知道App的私有目錄是/data/data/包名/或/data/user/用戶號(hào)/包名,通過(guò)Context.getFilesDir()方法可以拿到私有目錄下的files目錄。在多開環(huán)境下,獲取到目錄會(huì)變?yōu)?data/data/多開App的包名/xxxxxxxx或/data/user/用戶號(hào)/多開App的包名/xxxxxxxx。
舉個(gè)例子,在我手機(jī)上,正常使用App上面的代碼獲取到的路徑為/data/user/0/top.darkness463.virtualcheck/files。在多開分身的多開環(huán)境下,路徑為/data/user/0/dkmodel.zom.rxo/virtual/data/user/0/top.darkness463.virtualcheck/files。
當(dāng)然,多開軟件是可以hook處理讓你拿到正常的目錄,但截至寫這篇文章為止,市面上大部分多開App沒(méi)有繞過(guò)這項(xiàng)檢測(cè),僅有360家的分身大師可以繞過(guò)。
下面開始正式檢測(cè):
1.?ps檢測(cè)(詳見https://www.jianshu.com/p/216d65d9971e)
我們先通過(guò)執(zhí)行對(duì)uid進(jìn)行過(guò)濾,得到類似下面的結(jié)果
?
可以看到在多開環(huán)境下,會(huì)獲取到自己的包名和多開App的包名這2個(gè)包名,通過(guò)這些包名去/data/data/下找會(huì)找到2個(gè)目錄,而正常情況下只能在/data/data/下找到自己的App的目錄。看下具體代碼實(shí)現(xiàn);
public static boolean isRunInVirtual() {String filter = getUidStrFormat();String result = exec("ps");if (result == null || result.isEmpty()) {return false;}String[] lines = result.split("\n");if (lines == null || lines.length <= 0) {return false;}int exitDirCount = 0;for (int i = 0; i < lines.length; i++) {if (lines[i].contains(filter)) {int pkgStartIndex = lines[i].lastIndexOf(" ");String processName = lines[i].substring(pkgStartIndex <= 0? 0 : pkgStartIndex + 1, lines[i].length());File dataFile = new File(String.format("/data/data/%s",processName, Locale.CHINA));if (dataFile.exists()) {exitDirCount++;}}}return exitDirCount > 1; }2.應(yīng)用列表檢測(cè)
這里的應(yīng)用列表檢測(cè)不是指簡(jiǎn)單的遍歷應(yīng)用列表判斷是不是安裝了多開App,我們并不阻止用戶安裝多開App并多開其他App,我們只是不希望用戶多開我們自己的App,因此不能檢測(cè)到用戶安裝了多開App就把他干掉。
多開App都會(huì)對(duì)context.getPackageName()進(jìn)行處理,讓這個(gè)方法返回原始App的包名,因此在被多開的App看來(lái),多開App的包名和原始的那個(gè)App的包名一樣,因此在多開環(huán)境下遍歷應(yīng)用列表時(shí)會(huì)發(fā)現(xiàn)包名等于原始App的包名的應(yīng)用會(huì)有兩個(gè)。
private boolean checkPkg(Context context) {try {if (context == null) {return false;}int count = 0;String packageName = context.getPackageName();PackageManager pm = context.getPackageManager();List<PackageInfo> pkgs = pm.getInstalledPackages(0);for (PackageInfo info : pkgs) {if (packageName.equals(info.packageName)) {count++;}}return count > 1;} catch (Exception ignore) {}return false; }3.maps檢測(cè)
讀取/proc/self/maps,多開App會(huì)加載一些自己的so到內(nèi)存空間,舉個(gè)例子,360的分身大師加載了其目錄下的某個(gè)so,/data/app/com.qihoo.magic-gdEsg8KRAuJy0MuY18BlqQ==/lib/arm/libbreakpad-jni-1.5.so,通過(guò)對(duì)各種多開App的包名的匹配,如果maps中有多開App的包名的東西,那么當(dāng)前就是運(yùn)行在多開環(huán)境下。目前沒(méi)有發(fā)現(xiàn)多開App繞過(guò)該項(xiàng)檢測(cè),但缺點(diǎn)是需要收集所有多開App的包名,一旦多開App改個(gè)包名就失效了。
Set<String> virtualPkgs; // 多開第三方App包名列表 private boolean check() {BufferedReader bufr = null;try {bufr = new BufferedReader(new FileReader("/proc/self/maps"));String line;while ((line = bufr.readLine()) != null) {for (String pkg : virtualPkgs) {if (line.contains(pkg)) {return true;}}}} catch (Exception ignore) {} finally {if (bufr != null) {try {bufr.close();} catch (IOException e) {}}}return false; }以上三種檢測(cè)方法有的會(huì)被第三方虛擬定位軟件或者多開分身軟件躲避掉,有的則不會(huì),所以使用的時(shí)候建議三種方法全部用上。好了今天就寫到這里,再次感謝mawei7510的分享;
轉(zhuǎn)載于:https://www.cnblogs.com/yzssoft/p/9933522.html
總結(jié)
以上是生活随笔為你收集整理的android开发检测用户是否使用了虚拟定位的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: ML激活函数使用法则
- 下一篇: Linux—vim常用命令