android x86 su,android root and su

在android用管理员权限执行指令很简单,就像这样

public static void sudo(String cmd) {

Process su;

DataOutputStream outputStream = null;

try {

su = Runtime.getRuntime().exec("su");

outputStream = new DataOutputStream(su.getOutputStream());

outputStream.writeBytes(cmd + "\n");

outputStream.flush();

outputStream.writeBytes("exit\n");

outputStream.flush();

su.waitFor();

su.getInputStream().close();

su.getErrorStream().close();

} catch (IOException | InterruptedException e) {

e.printStackTrace();

} finally {

Closer.closeSilently(outputStream);

}

}

Runtime.exec 做了什么呢?

java.lang.ProcessManager

/** Executes a command in a child process. */

static pid_t ExecuteProcess(JNIEnv* env, char** commands, char** environment,

const char* workingDirectory, jobject inDescriptor,

jobject outDescriptor, jobject errDescriptor,

jboolean redirectErrorStream) {

//... ignore

pid_t childPid = fork();

//... ignore

// Execute process. By convention, the first argument in the arg array

// should be the command itself.

execvp(commands[0], commands);

//... ignore

}

所以是fork出一个进程来执行su的指令,获得root权限是执行su指令之后的事情,su指令fork出一个子进程。

接着看su指令是怎么做的

在android_x86中的目录是:external/koush/Superuser/Superuser/jni/su/su.c

简单介绍下背景好了

android的权限机制其实就是linux权限那一套东西,所以root账号是有的root权限也是有的,不过root权限的uid和gid都是0,android系统在init的时候就是用 0 起的。su指令提供了一个方法,可以切换过去。换句话说,只要能把进程的uid和gid变为 0 那么就获得了ROOT权限。指令是不是叫su其实没关系。

在android_x86中,su 和 superuser 是配套使用的,具体细节如下:

static __attribute__ ((noreturn)) void allow(struct su_context *ctx) {

char *arg0;

int argc, err;

umask(ctx->umask);

int send_to_app = 1;

// no need to log if called by root

if (ctx->from.uid == AID_ROOT)

send_to_app = 0;

// dumpstate (which logs to logcat/shell) will spam the crap out of the system with su calls

if (strcmp("/system/bin/dumpstate", ctx->from.bin) == 0)

send_to_app = 0;

if (send_to_app)

send_result(ctx, ALLOW);

char *binary;

argc = ctx->to.optind;

if (ctx->to.command) {

binary = ctx->to.shell;

ctx->to.argv[--argc] = ctx->to.command;

ctx->to.argv[--argc] = "-c";

}

else if (ctx->to.shell) {

binary = ctx->to.shell;

}

else {

if (ctx->to.argv[argc]) {

binary = ctx->to.argv[argc++];

}

else {

binary = DEFAULT_SHELL;

}

}

arg0 = strrchr (binary, '/');

arg0 = (arg0) ? arg0 + 1 : binary;

if (ctx->to.login) {

int s = strlen(arg0) + 2;

char *p = malloc(s);

if (!p)

exit(EXIT_FAILURE);

*p = '-';

strcpy(p + 1, arg0);

arg0 = p;

}

populate_environment(ctx);

set_identity(ctx->to.uid);

#define PARG(arg) \

(argc + (arg) < ctx->to.argc) ? " " : "", \

(argc + (arg) < ctx->to.argc) ? ctx->to.argv[argc + (arg)] : ""

LOGD("%u %s executing %u %s using binary %s : %s%s%s%s%s%s%s%s%s%s%s%s%s%s",

ctx->from.uid, ctx->from.bin,

ctx->to.uid, get_command(&ctx->to), binary,

arg0, PARG(0), PARG(1), PARG(2), PARG(3), PARG(4), PARG(5),

(ctx->to.optind + 6 < ctx->to.argc) ? " ..." : "");

ctx->to.argv[--argc] = arg0;

execvp(binary, ctx->to.argv + argc);

err = errno;

PLOGE("exec");

fprintf(stderr, "Cannot execute %s: %s\n", binary, strerror(err));

exit(EXIT_FAILURE);

}

执行是

execvp(binary, ctx->to.argv + argc);

在app里面binary默认就是走的sh(/system/bin/su),也就是,所以就和执行Runtime.getRuntime().exec("sh") 的效果是一致的,除了权限的不同。

sh是怎么做的呢,原理应该是每次监听输入,fork一个进程去执行指令,apue中有提供了一个类似的例子

#include "apue.h"

#include

int

main(int argc, char *argv[])

{

char buf[MAXLINE];

pid_t pid;

int status;

printf("%% ");

while(fgets(buf,MAXLINE,stdin) != NULL){

if(buf[strlen(buf) - 1 ] == '\n')

buf[strlen(buf) - 1 ] = 0;

if((pid = fork()) <0){

err_sys("fork error");

}else if(pid == 0){

execlp(buf,buf,(char *)0);

err_ret("couldn't excute: %s",buf);

exit(127);

}

if((pid = waitpid(pid,&status,0))<0)

err_sys("wait pid error");

printf("%% ");

}

exit(0);

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Android应用中实现防止DEX注入,可以采取以下措施: 1. 检测应用签名:在应用启动时,可以检查应用的签名是否与预期的签名一致。如果签名不匹配,可能意味着应用已被篡改。 ```java public static boolean isSignatureValid(Context context) { try { PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES); Signature[] signatures = packageInfo.signatures; // 验证签名与预期签名是否一致 // ... } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } return false; } ``` 2. 检测应用运行环境:可以检查应用是否在预期的运行环境中执行。例如,可以检测当前应用是否在模拟器或Root设备上运行。 ```java public static boolean isEmulator() { return Build.FINGERPRINT.startsWith("generic") || Build.FINGERPRINT.startsWith("unknown") || Build.MODEL.contains("google_sdk") || Build.MODEL.contains("Emulator") || Build.MODEL.contains("Android SDK built for x86") || Build.MANUFACTURER.contains("Genymotion") || (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")) || "google_sdk".equals(Build.PRODUCT); } public static boolean isRooted() { String[] paths = {"/system/bin/", "/system/xbin/", "/sbin/", "/system/sd/xbin/", "/system/bin/failsafe/", "/data/local/xbin/", "/data/local/bin/", "/data/local/"}; for (String path : paths) { if (new File(path + "su").exists()) { return true; } } return false; } ``` 3. 内存完整性检测:可以定期检查应用的内存完整性,以防止DEX文件被恶意注入。可以使用一些第三方库或自行实现内存完整性检测的算法。 4. 加密DEX文件:可以使用加密算法对DEX文件进行加密,然后在运行时解密并加载。这样可以增加DEX文件的安全性,防止被恶意注入。 5. 应用签名校验:可以在应用启动时,对APK文件进行签名校验,确保APK文件没有被篡改。 这些措施并不是绝对的,但可以提高应用的安全性,防止DEX注入攻击。需要根据具体场景和需求选择合适的措施来保护应用的安全。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值