應廣大網友的要求,筆者近期對樂安全的軟件鎖進行了分析,下面簡單就一篇博文向大家介紹一下樂安全軟件鎖的實現原理。測試的樂安全版本爲V4.2.4。
先說下結論,如果有興趣的同學可以繼續往下看分析。樂安全在本地進程得到了AMS的Bp,直接調用其getTasks方法,每隔一秒檢測一下當前topActivity是否是需要被鎖定的,如果是的話,就彈出一個解鎖界面蓋住本該啓動的APP。
下面進行分析
首先要爆料的是,樂安全做的實在是有點不小心,打了些對於破解有用的log出來,降低了破解的難度。比如下面的:
這是在觸發軟件鎖的時候打出的log,給了我們啓發,通過反編譯APK文件後,我們很快定位到了相關的代碼。
while (AppCheck.isRun)
try
{
Thread.sleep(1000L);
List localList1 = AppCheck.a(AppCheck.this).getTasks(1, 0, null);
if (localList1.size() > 0)
{
AppCheck.a(AppCheck.this, ((ActivityManager.RunningTaskInfo)localList1.get(0)).topActivity.getPackageName());
if (!AppCheck.c(AppCheck.this).equals(AppCheck.b(AppCheck.this)))
{
Log.i("AppCheck", "old" + AppCheck.c(AppCheck.this) + "------------new:" + AppCheck.b(AppCheck.this));
String[] arrayOfString3 = new String[3];
arrayOfString3[0] = "runningTask";
arrayOfString3[1] = AppCheck.b(AppCheck.this);
arrayOfString3[2] = AppCheck.c(AppCheck.this);
a(arrayOfString3);
AppCheck.b(AppCheck.this, AppCheck.b(AppCheck.this));
}
}
可以看到,樂安全在這裏做了一個循環操作,首先sleep一秒,然後直接調用getTasks()方法得到一個List。我們先看下AppCheck.a(AppCheck.this)返回的是什麼。由於jd反編譯的不全面,下面要po上一個smali的代碼片段。
.method static synthetic a(Lcom/lenovo/safecenter/utils/AppCheck;)Landroid/app/IActivityManager;
.locals 1
.parameter "x0"
.prologue
.line 21
iget-object v0, p0, Lcom/lenovo/safecenter/utils/AppCheck;->a:Landroid/app/IActivityManager;
return-object v0
.end method
這裏可以看到a(AppCheck.this)返回的是一個IActivityManager的對象。這裏可能大家會有一個疑問,IActivityManager是hide的,爲什麼可以在這裏被調用。@安卓安全小分隊的大牛講師認爲樂安全很有可能自己編譯了一套framework.jar使得樂安全在編譯階段順利通過,並且在手機上也能正常運行,關於這一部分的機理,如果大家覺得有必要,我們可以在以後的時間作爲一個專題來講解。
在這裏筆者對之前的猜測做下更正,樂安全並不是通過注入方式來調用AMS的一個方法,而是簡單的在本地得到了AMS的Bp,也就是這個IActivityManager的對象。下面再po一個smali的代碼段來說明這個IActivityManager是如何得到的。
.line 38
invoke-static {}, Landroid/app/ActivityManagerNative;->getDefault()Landroid/app/IActivityManager;
move-result-object v0
iput-object v0, p0, Lcom/lenovo/safecenter/utils/AppCheck;->a:Landroid/app/IActivityManager;
通過直接調用ActivityManagerNative的getDefault靜態方法就獲得了這個IActivityManager對象,很簡單。
好,回到前面的分析階段。我們已經知道了,樂安全通過調用AMS的getTasks方法得到了tasks的list,到了第一if分支(參考前面貼出的代碼)。
首先檢查的是新啓動的activity是否與前一個activity屬於同一包。說白了就是如果用戶已經在使用敏感APP了,樂安全就不要再去搞軟件鎖了,不然用戶啓動一個activity就有一鎖出來不的把人煩死。
但是如果不屬於同一個包,就進入了這個分支,先打了個被我們抓住尾巴的log,然後把old的包名和new的報名放進數組交給了a()方法。我們看看a()裏都做了什麼
private void a(Object[] paramArrayOfObject)
{
if (paramArrayOfObject[0].equals("runningTask"));
for (String str = "com.lenovo.safecenter.activityswitch"; ; str = "com.lenovo.safecenter.activityswitch2")
{
Log.i("AppCheck", paramArrayOfObject[0] + "------------action:" + str + " " + paramArrayOfObject[1] + " " + paramArrayOfObject[2]);
Intent localIntent = new Intent(str);
localIntent.putExtra("newPkg", (String)paramArrayOfObject[1]);
localIntent.putExtra("oldPkg", (String)paramArrayOfObject[2]);
AppCheck.g(AppCheck.this).sendBroadcast(localIntent);
Settings.System.putString(AppCheck.g(AppCheck.this).getContentResolver(), "safe_input_method", "com.android.inputmethod.latin/.LatinIME");
Log.i("AppCheck", paramArrayOfObject[0] + "------------end");
return;
}
}
很簡單,把old package和new package用廣播給發出去了。我們到接收端看一下如何處理。
樂安全的assets包裏有一個LenovoSafeBox429.apk,打開後在裏面發現一個MonitorAppService的類,他在onCreate的時候註冊了一個BroadcastReceiver,接收名爲com.lenovo.safecenter.activityswitch的action如下。
public void onCreate()
{
this.getBroadcast = false;
this.mContext = this;
this.pattern = Pattern.compile("(.*)(\\={1})(.*)(//*)");
this.runtime = Runtime.getRuntime();
this.filter = new IntentFilter();
this.filter.addAction("android.intent.action.SCREEN_OFF");
this.filter.addAction("android.intent.action.SCREEN_ON");
this.filter.addAction("com.lenovo.safecenter.activityswitch");
this.filter.addAction("com.lenovo.safebox.lockscreen");
this.lastPkg = "";
registerReceiver(this.receiver, this.filter);
if (canGetPassword())
{
if (!this.watchAppOpen)
watchAppStart();
if (!this.getBroadcast)
{
this.mTimer = new Timer(true);
restartTimer();
}
}
在receiver的onReceive函數裏,這個receiver做了下面的事情。我們撿主要的說
label498: if ((MonitorAppService.this.lastPkg == null) || (MonitorAppService.this.lastPkg.equals("com.lenovo.safebox")) || (MonitorAppService.this.lastPkg.equals(str)) || (!MonitorAppService.this.checkList.contains(str)) || (MonitorAppService.isLocked))
continue;
Intent localIntent = new Intent(MonitorAppService.this.mContext, LockScreenActivity.class);
localIntent.putExtra("pkg", str);
localIntent.addFlags(268435456);
if (MonitorAppService.DEBUG)
Log.i("MonitorAppService", "Lock in Broadcast TopTask :" + str);
MonitorAppService.this.mContext.startActivity(localIntent);
關鍵的位置就是到一個list裏查看當前啓動的package是不是我要鎖住的,如果是鎖住的,那就直接啓動一個activity蓋在上面,就是我們看到的效果了。
PS:有的網友提到樂安全阻止了程序的正常啓動,相關進程不會被啓動。但是通過我們的觀察,進程是已經被啓動了的 ,如下圖。
需要關注的是,AMS首先啓動了被鎖軟件。Start了它的activity以及process(最開始的兩條log),然後纔會執行我們之前分析的部分,然後LockScreenActivity才被啓動。這個時候可以通過ps命令查看當前進程。我們發現了被鎖軟件:
新浪微博@安卓安全小分隊