###########################################
指令
###########################################
mount -o remount,rw /system /system
mkdir /system/usr/myadm
chmod 001 /system/usr/myadm
cat /system/xbin/su > /system/usr/myadm/admin
chmod 06755 /system/usr/myadm/admin
mount -o remount,ro /system /system
#/data/data/myadm/admin
#/system/usr/myadm/admin
###########################################
原理
###########################################
Android OTA 後如何保留 root
以電子郵件傳送這篇文章
BlogThis!
分享至 Twitter
分享至 Facebook
不少人會有這種問題, root 後不能更新 ,
萬一能更新,在更新後不一定能夠保留 root 權限
而偏偏很多廠商 OTA 之後會把漏洞修掉,所以之前提到的
TF101 才需要用到 RootKeeper 來保留 root 權限。
重點就在這個 OTARootKeeper 是怎麼運作的,我從之前學長教的
Linux 「漏洞」(應該算是挖坑給 root 跳的動作吧XD )中想到的方法
PS : 這個漏洞是挖洞給懶人管理者跳,所以基本上並沒有甚麼威脅XD
隨後也去看了一下 RootKeeper 的 source code , 果然是用這種方式XD
Linux 在給予系統檔案權限的時候會用到三個數字,分別代表
Owner , Group , Other 的存取權限,但其實 Linux 還可以有
第四位數字用來給予一些特殊的權限,放在 Owner 之前
SUID = 4
SGID = 2
SBIT = 1
這部分可以參考鳥哥私房菜
重點就在於:SUID 是表示『該檔案在執行的時候,具有檔案擁有者的權限』
因為其實 root 就只是把 su 這隻程式裝進去,所以要是我們可以把 su 先
備份到「OTA 不會動到的地方」,那基本上就 OK 了。
這也就是為什麼 OTA RootKeeper 會提到
「Upgrades not formatting or overwriting completely the /system partition.」
1.將 su 備份到某個地方,並 chown 0:0 ((使用者和群組皆為 roo
2.將這個 su 給予權限: chomd 6755 ((執行身分為 root , 並大家都可執行
這樣一來,更新後既使 /system/bin 裡面的 su 被拿掉了,只要這個備份檔案還在
那麼執行這個備分的 su 還可以切換成 root 身分(以 root 切換 root 權限也OK)
當取得 root 身分之後,就可以再把這個備份 su 放回 /system/bin 裡面了
是說從 OTA Root Keeper 的 source code 裡面還看到幾個比較特別的
指令,不太清楚是不是這麼簡單就可以做到,上面這個方法理論上一般
的 linux 系統應該是OK,但不知道 embedded 是不是也一樣...
另外就是如果要避免 /system 整個被 format掉,為什麼不選擇在 /data 呢...
難道有些機器沒辦法再 /data 裡面設定 SUID ? (就像 /sdcard/ 裡面不能設定一樣)
或者是還有其他權限上的問題呢?這就不太清楚了
chattr [+-=][ASacdistu] 檔案或目錄名稱
選項與參數:
+ :增加某一個特殊參數,其他原本存在參數則不動。
- :移除某一個特殊參數,其他原本存在參數則不動。
= :設定一定,且僅有後面接的參數
A :當設定了 A 這個屬性時,若你有存取此檔案(或目錄)時,他的存取時間 atime將不會被修改,可避免I/O較
慢的機器過度的存取磁碟。這對速度較慢的電腦有幫助
S :一般檔案是非同步寫入磁碟的(原理請參考第五章sync的說明),如果加上 S 這個屬性時,當你進行任何檔案
的修改,該更動會『同步』寫入磁碟中。
a :當設定 a 之後,這個檔案將只能增加資料,而不能刪除也不能修改資料,只有root才能設定這個屬性。
c :這個屬性設定之後,將會自動的將此檔案『壓縮』,在讀取的時候將會自動解壓縮,但是在儲存的時候,將
會先進行壓縮後再儲存(看來對於大檔案似乎蠻有用的!)
d :當 dump 程序被執行的時候,設定 d 屬性將可使該檔案(或目錄)不會被 dump 備份
i :這個 i 可就很厲害了!他可以讓一個檔案『不能被刪除、改名、設定連結也無法寫入或新增資料!』對於系
統安全性有相當大的助益!只有 root 能設定此屬性
s :當檔案設定了 s 屬性時,如果這個檔案被刪除,他將會被完全的移除出這個硬碟空間,所以如果誤刪了,完
全無法救回來了喔!
u :與 s 相反的,當使用 u 來設定檔案時,如果該檔案被刪除了,則資料內容其實還存在磁碟中,可以使用來
救援該檔案喔!
注意:屬性設定常見的是 a 與 i 的設定值,而且很多設定值必須要身為 root 才能設定
###########################################
參考程式
###########################################
public class SuOperations {
private Context mContext;
private Device mDevice;
private static final String TAG = "Voodoo OTA RootKeeper ProtectedSuOperation";
public static final String SU_PATH = "/system/bin/su";
public static final String SU_BACKUP_BASE_DIR = "/system/usr";
public static final String SU_BACKUP_DIR = SU_BACKUP_BASE_DIR + "/we-need-root";
public static final String SU_BACKUP_FILENAME = "su-backup";
public static final String SU_BACKUP_PATH = SU_BACKUP_DIR + "/" + SU_BACKUP_FILENAME;
public static final String SU_BACKUP_PATH_OLD = "/system/" + SU_BACKUP_FILENAME;
public static final String CMD_REMOUNT_RW = "mount -o remount,rw /system /system";
public static final String CMD_REMOUNT_RO = "mount -o remount,ro /system /system";
public SuOperations(Context context, Device device) {
mContext = context;
mDevice = device;
}
public final void backup() {
Log.i(TAG, "Backup to protected su");
String suSource = "/system/xbin/su";
ArrayList<String> commands = new ArrayList<String>();
commands.add(CMD_REMOUNT_RW);
// de-protect
if (mDevice.mFileSystem == FileSystem.EXTFS)
commands.add(mContext.getFilesDir().getAbsolutePath()
+ "/chattr -i " + SU_BACKUP_PATH);
if (Utils.isSuid(mContext, SU_PATH))
suSource = SU_PATH;
commands.add("mkdir " + SU_BACKUP_BASE_DIR);
commands.add("mkdir " + SU_BACKUP_DIR);
commands.add("chmod 001 " + SU_BACKUP_DIR);
commands.add("cat " + suSource + " > " + SU_BACKUP_PATH);
commands.add("chmod 06755 " + SU_BACKUP_PATH);
// protect
if (mDevice.mFileSystem == FileSystem.EXTFS)
commands.add(mContext.getFilesDir().getAbsolutePath()
+ "/chattr +i " + SU_BACKUP_PATH);
commands.add(CMD_REMOUNT_RO);
Utils.run("su", commands);
int toastText;
if (mDevice.mFileSystem == FileSystem.EXTFS)
toastText = R.string.toast_su_protected;
else
toastText = R.string.toast_su_backup;
Toast.makeText(mContext, toastText, Toast.LENGTH_LONG).show();
}
public final void restore() {
String[] commands = {
CMD_REMOUNT_RW,
// restore su binary to /system/bin/su
// choose bin over xbin to avoid confusion
"cat " + mDevice.validSuPath + " > " + SU_PATH,
"chown 0:0 " + SU_PATH,
"chmod 06755 " + SU_PATH,
"rm /system/xbin/su",
CMD_REMOUNT_RO,
};
Utils.run(mDevice.validSuPath, commands);
upgradeSuBackup();
Toast.makeText(mContext, R.string.toast_su_restore, Toast.LENGTH_LONG).show();
}
public final void deleteBackup() {
Log.i(TAG, "Delete protected or backup su");
ArrayList<String> commands = new ArrayList<String>();
commands.add(CMD_REMOUNT_RW);
// de-protect
if (mDevice.mFileSystem == FileSystem.EXTFS)
commands.add(mContext.getFilesDir().getAbsolutePath()
+ "/chattr -i " + mDevice.validSuPath);
commands.add("rm " + mDevice.validSuPath);
commands.add("rm -r " + SU_BACKUP_DIR);
commands.add(CMD_REMOUNT_RO);
Utils.run("su", commands);
Toast.makeText(mContext, R.string.toast_su_delete_backup, Toast.LENGTH_LONG).show();
}
public final void unRoot() {
Log.i(TAG, "Unroot device but keep su backup");
upgradeSuBackup();
if (!mDevice.isSuProtected) {
Toast.makeText(mContext, R.string.toast_su_protection_error, Toast.LENGTH_LONG).show();
return;
}
String[] commands = new String[] {
CMD_REMOUNT_RW,
"rm /system/*bin/su",
CMD_REMOUNT_RO,
};
Utils.run("su", commands);
Toast.makeText(mContext, R.string.toast_unroot, Toast.LENGTH_LONG).show();
}
private void upgradeSuBackup() {
if (!mDevice.needSuBackupUpgrade)
return;
Log.i(TAG, "Upgrade su backup");
deleteBackup();
backup();
mDevice.analyzeSu();
}
}
看一下mount指令的輸出可以發現,/data被設定成nosuid了。所以有suid也沒用
回覆刪除