我目前正在开发一款可在驾车时读取短信/电子邮件的应用。许多用户都希望得到WhatsApp / KakaoTalk的支持。
但是,由于没有“官方”方式接收他们的消息,因此只有三个选项,都需要root:
在给定的intervall中扫描数据库的更简单方法。
另一种方法是运行具有root权限的服务并注册侦听其推送通知的接收器。这必须使用root来完成,因为两个软件包都需要基于签名的权限才能接收其推送通知。
我还想到了另一件事:安装后是否可以手动为APK添加权限?在这种情况下,我可以将c2dm权限添加到我的包中。
问题是,完全如何运行具有root权限的服务(实际上是否可行)? 我知道如何使用root 运行shell命令或二进制文件,但我不知道如何以root身份启动APK的一部分。
此外,是否可以将BroadcastReceiver集成到二进制文件中?我实际上没有使用C / C ++的经验,尤其是在Android环境中。
你可以帮帮我吗? 谢谢。编辑:就像我在评论中所说,我不想使用AccesibilityService ,因为它不符合我的需要(例如,如果超过一个,它会给我“2条未读消息”是未读的,也不包括完整的身体。
edit2:只是为了澄清一些事情:我知道如何用root运行命令。我需要知道的是如何注册接收特定广播“普通”接收器的广播接收器,因为广播本身需要我没有的基于签名的许可。
答案 0 :(得分:3)
这远非微不足道,但是当您要监控的应用程序使用sqlite数据库时,或者更一般地,当它们到达时将消息写入文件时,它应该起作用。
您确实需要拥有该设备的root访问权限,因为这违反了Android安全系统:
编写一个本机进程,它使用NDK作为守护进程运行,并在以root身份启动后生成一次。您现在有3个主要问题需要解决:
如何判断某些内容是否有变化?
这很容易。您需要使用Linux inotify接口,该接口应该可以在每个Android手机上访问,因为SDK自API 1以来具有FileObserver,因此您在这里是安全的。
另一种有趣的方法可能是捕获C2DM消息。我找到了一个名为BroadcastReceiver的NDK类,因此NDK可以捕获它们。但我个人不会这样做,因为窃取意图感觉不对。此外,你必须重新分配它们或让它们前往真正的收件人,所以我不会在这里详细描述。它可能有用,但可能更难,只应该是后备。
所以,当你解决了这个问题后,就会出现下一个问题:
如何以安全的方式阅读更改?
你有一个问题,一个大问题,在这里。该文件不属于客户端,客户端甚至无权知道它(通常)的位置。因此受监控的应用程序不知道客户端,并且将像文件仅由其自身独占。如果他们使用一些普通的旧文本文件来写消息,你必须找到一种方法来安全地读取它,因为它可能随时被覆盖或扩展。但是当你使用sqlite时,你可能会很幸运,根据this它有一个以上的同时阅读器,只有一个作家是完全有效的。我们在规格中,一切都很好。当您现在已经读出新数据时,需要解决更多问题:
如何将新数据恢复到主应用程序?
你应该只在这个C / C ++程序中做到最低限度,因为它以root身份运行。您还应该保护您的应用用户免受安全漏洞的影响,因此请在编写程序时牢记这一点。我不知道这可能真的很好用,但这里有一些想法:
如上文所述,编写此守护程序时请小心,因为它可能存在安全隐患。如果您根本不了解C / C ++,可能很难做到这一点,即使您编写了简单的程序,这应该是一项非常重要的任务。
在我通过网络搜索时,我找到了上面提到的NDK C ++类。它可以在Google code找到。我既没有使用NDK也没有C ++包装器的经验,但是当你打算写这个时,它可能值得一看。
答案 1 :(得分:2)
答案 2 :(得分:2)
强制,我必须告诉你, Android服务不需要root访问,而是某些操作(即访问,读取,写入系统资源)需要Root权限。 Android SDK中提供的每个Android服务都可以在没有ROOT ACCESS的情况下运行。
您可以借助shell命令使用root权限执行操作。
我创建了一个抽象类来帮助你
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import android.util.Log;
public abstract class RootAccess {
private static final String TAG = "RootAccess";
protected abstract ArrayList<String> runCommandsWithRootAccess();
//Check for Root Access
public static boolean hasRootAccess() {
boolean rootBoolean = false;
Process suProcess;
try {
suProcess = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(suProcess.getOutputStream());
DataInputStream is = new DataInputStream(suProcess.getInputStream());
if (os != null && is != null) {
// Getting current user's UID to check for Root Access
os.writeBytes("id\n");
os.flush();
String outputSTR = is.readLine();
boolean exitSu = false;
if (outputSTR == null) {
rootBoolean = false;
exitSu = false;
Log.d(TAG, "Can't get Root Access or Root Access deneid by user");
} else if (outputSTR.contains("uid=0")) {
//If is contains uid=0, It means Root Access is granted
rootBoolean = true;
exitSu = true;
Log.d(TAG, "Root Access Granted");
} else {
rootBoolean = false;
exitSu = true;
Log.d(TAG, "Root Access Rejected: " + is.readLine());
}
if (exitSu) {
os.writeBytes("exit\n");
os.flush();
}
}
} catch (Exception e) {
rootBoolean = false;
Log.d(TAG, "Root access rejected [" + e.getClass().getName() + "] : " + e.getMessage());
}
return rootBoolean;
}
//Execute commands with ROOT Permission
public final boolean execute() {
boolean rootBoolean = false;
try {
ArrayList<String> commands = runCommandsWithRootAccess();
if ( commands != null && commands.size() > 0) {
Process suProcess = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(suProcess.getOutputStream());
// Execute commands with ROOT Permission
for (String currentCommand : commands) {
os.writeBytes(currentCommand + "\n");
os.flush();
}
os.writeBytes("exit\n");
os.flush();
try {
int suProcessRetval = suProcess.waitFor();
if ( suProcessRetval != 255) {
// Root Access granted
rootBoolean = true;
} else {
// Root Access denied
rootBoolean = false;
}
} catch (Exception ex) {
Log.e(TAG, "Error executing Root Action", ex);
}
}
} catch (IOException ex) {
Log.w(TAG, "Can't get Root Access", ex);
} catch (SecurityException ex) {
Log.w(TAG, "Can't get Root Access", ex);
} catch (Exception ex) {
Log.w(TAG, "Error executing operation", ex);
}
return rootBoolean;
}
}
使用RootAccess扩展您的类或创建RootAccess类的实例并覆盖runCommandsWithRootAccess()方法。
答案 3 :(得分:1)
如果您要定位未经更改的非root设备,则无法以root用户身份运行服务(或任何其他应用程序组件)。允许这样做会使Android中的所有安全机制毫无意义。
也无法在运行时更改APK的权限。在APK安装时始终授予或拒绝权限。有关此主题的更多信息,请参阅http://developer.android.com/guide/topics/security/security.html。
答案 4 :(得分:1)
“我需要知道的是如何注册广播接收器,接收特定广播”普通“接收器无法获得,因为广播本身需要我没有的基于签名的许可。”
你做不到。期。故事结局。并且感谢ghod。
是的,如果你使用可怕的有根设备设施让一些代码以root身份运行,理论上你可以做任何你想做的事情。在实践中,可能很难绕过这个限制,并且平台通常被设计成这样。您至少需要处理由程序包管理器维护和/或存储的状态,并且可能需要使用户重新启动设备以获取您作为root所做的更改才能实际产生影响。当然,您正在深入讨论该平台的深层内部实现细节,这意味着跨平台的不同版本和来自不同制造商的不同构建将其遍布各处。
答案 5 :(得分:-1)
你可以使用
pm grant your.permission
作为shell命令,为您的应用授予其他权限。 我认为该命令最近才被添加,所以如果您定位旧版本,则可能需要直接更改'packages.xml'。
可以使用app_process命令以root身份执行app / dex文件,但我还没有弄清楚如何获取有效的上下文(使用此方法,您可以使用java.io.File api访问所有文件,但像bindService等非静态android方法将失败,因为你在没有应用程序上下文的情况下运行。)
答案 6 :(得分:-2)
当然,您可以更改应用程序的权限。如果权限将被更改,则用户只需手动更新应用程序,新的权限将显示给用户。但我不知道如何更改您的应用程序权限将帮助您解决此问题。
我可以告诉你的另一件事是,你不能只在root设备上运行Service
或root
,并且通过你的设备生成设备并不是一件容易的事。应用程序,也不会是许多用户想要的东西。
您目前如何访问SMS
?
如果您有BroadcastReceiver
,则可以为MAX_PRIORITY
设置receiver
,也许它会在其他应用程序之前截取消息。这可以按如下方式完成:
<receiver android:name=".SmsReceiver" >
<intent-filter android:priority="100" >
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
你也可以使用现在不公开的SMS Provider
,但是如果你以给定的间隔查询这个Provider
,你可以查看新的消息。您还可以查看此主题:Android SMS Provider如果您尚未完成此操作。