设计
- 设计思路
可读接口->不可读接口
- Android 创建一个新的Lib
目录结构
--src
--main
--java com.tool.hwtools
--CheckRoot
--Hw.Tools
--SignatureUtil
--proguard-rules.pro
未加密代码
package com.tool.hwtools;
import android.content.Context;
import android.content.pm.Signature;
public class HwTools {
public static boolean CachedValue = false;
public static boolean IsDeviceRooted() {
CachedValue = CheckRoot.isDeviceRooted();
return CheckRoot.isDeviceRooted();
}
public static String getSignatureInfo256(Context context, String packageName) {
return SignatureUtil.getSignatureInfo256(context, packageName);
}
public static String getSignatureInfo1(Context context, String packageName) {
return SignatureUtil.getSignatureInfo1(context, packageName);
}
public static String getSignatureInfo256(Signature[] signatures) {
return SignatureUtil.getSignatureInfo256(signatures);
}
public static String getSignatureInfo1(Signature[] signatures) {
return SignatureUtil.getSignatureInfo1(signatures);
}
public static String getApkHash(Context context, String packageName) {
return SignatureUtil.getApkHash(context, packageName);
}
}
package com.tool.hwtools;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import android.util.Log;
public class CheckRoot {
// 定义TAG常量
private static String TAG = CheckRoot.class.getName();
public static boolean isDeviceRooted() {
if (checkDeviceDebuggable()) {
return true;
}//check buildTags
if (checkSuperuserApk()) {
return true;
}//Superuser.apk
if (checkRootPathSU()) {
return true;
}//find su in some path
if (checkRootWhichSU()) {
return true;
}//find su use 'which'
if (checkBusybox()) {
return true;
}//find su use 'which'
if (checkAccessRootData()) {
return true;
}//find su use 'which'
if (checkGetRootAuth()) {
return true;
}//exec su
return false;
}
// 检查判断是否存在SuperSU.apk文件,存在的话就是root
private static boolean checkSuperuserApk() {
try {
File file = new File("/system/app/SuperSU/SuperSU.apk");
if (file.exists()) {
Log.w(TAG, "/system/app/SuperSU/SuperSU.apk exist");
return true;
}
} catch (Exception e) {
}
return false;
}
private static boolean checkDeviceDebuggable() {
String buildTags = android.os.Build.TAGS;
if (buildTags != null && buildTags.contains("test-keys")) {
Log.i(TAG, "buildTags=" + buildTags);
return true;
}
return false;
}
private static boolean checkRootPathSU() {
File f = null;
final String kSuSearchPaths[] = {"/system/bin/", "/system/xbin/", "/system/sbin/", "/sbin/", "/vendor/bin/"};
try {
for (int i = 0; i < kSuSearchPaths.length; i++) {
f = new File(kSuSearchPaths[i] + "su");
if (f != null && f.exists()) {
Log.i(TAG, "find su in : " + kSuSearchPaths[i]);
return true;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
private static boolean checkRootWhichSU() {
String[] strCmd = new String[]{"/system/xbin/which", "su"};
ArrayList<String> execResult = executeCommand(strCmd);
if (execResult != null) {
Log.i(TAG, "execResult=" + execResult.toString());
return true;
} else {
Log.i(TAG, "execResult=null");
return false;
}
}
private static ArrayList<String> executeCommand(String[] shellCmd) {
String line = null;
ArrayList<String> fullResponse = new ArrayList<String>();
Process localProcess = null;
try {
Log.i(TAG, "to shell exec which for find su :");
localProcess = Runtime.getRuntime().exec(shellCmd);
} catch (Exception e) {
return null;
}
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(localProcess.getOutputStream()));
BufferedReader in = new BufferedReader(new InputStreamReader(localProcess.getInputStream()));
try {
while ((line = in.readLine()) != null) {
Log.i(TAG, "–> Line received: " + line);
fullResponse.add(line);
}
} catch (Exception e) {
e.printStackTrace();
}
Log.i(TAG, "–> Full response was: " + fullResponse);
return fullResponse;
}
private static synchronized boolean checkGetRootAuth() {
Process process = null;
DataOutputStream os = null;
try {
Log.i(TAG, "to exec su");
process = Runtime.getRuntime().exec("su");
os = new DataOutputStream(process.getOutputStream());
os.writeBytes("exit\n");
os.flush();
int exitValue = process.waitFor();
Log.i(TAG, "exitValue=" + exitValue);
if (exitValue == 0) {
return true;
} else {
return false;
}
} catch (Exception e) {
Log.i(TAG, "Unexpected error - Here is what I know: "
+ e.getMessage());
return false;
} finally {
try {
if (os != null) {
os.close();
}
process.destroy();
} catch (Exception e) {
e.printStackTrace();
}
}
}
private static synchronized boolean checkBusybox() {
try {
Log.i(TAG, "to exec busybox df");
String[] strCmd = new String[]{"busybox", "df"};
ArrayList<String> execResult = executeCommand(strCmd);
if (execResult != null) {
Log.i(TAG, "execResult=" + execResult.toString());
return true;
} else {
Log.i(TAG, "execResult=null");
return false;
}
} catch (Exception e) {
Log.i(TAG, "Unexpected error - Here is what I know: "
+ e.getMessage());
return false;
}
}
private static synchronized boolean checkAccessRootData() {
try {
Log.i(TAG, "to write /data");
String fileContent = "test_ok";
Boolean writeFlag = writeFile("/data/su_test", fileContent);
if (writeFlag) {
Log.i(TAG, "write ok");
} else {
Log.i(TAG, "write failed");
}
Log.i(TAG, "to read /data");
String strRead = readFile("/data/su_test");
Log.i(TAG, "strRead=" + strRead);
if (fileContent.equals(strRead)) {
return true;
} else {
return false;
}
} catch (Exception e) {
Log.i(TAG, "Unexpected error - Here is what I know: "
+ e.getMessage());
return false;
}
}
//写文件
private static Boolean writeFile(String fileName, String message) {
try {
FileOutputStream fout = new FileOutputStream(fileName);
byte[] bytes = message.getBytes();
fout.write(bytes);
fout.close();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
//读文件
private static String readFile(String fileName) {
File file = new File(fileName);
try {
FileInputStream fis = new FileInputStream(file);
byte[] bytes = new byte[1024];
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int len;
while ((len = fis.read(bytes)) > 0) {
bos.write(bytes, 0, len);
}
String result = new String(bos.toByteArray());
Log.i(TAG, result);
return result;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
package com.tool.hwtools;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.util.Log;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class SignatureUtil {
private static final String TAG = "SignatureUtil";
public static String getSignatureInfo256(Context context, String packageName) {
try {
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
return getSignatureInfo256(packageInfo.signatures);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
public static String getSignatureInfo1(Context context, String packageName) {
try {
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
return getSignatureInfo1(packageInfo.signatures);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
public static String getSignatureInfo256(Signature[] signatures) {
if (null == signatures) return "Null";
StringBuilder sb = new StringBuilder();
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
for (Signature signature : signatures) {
byte[] signatureBytes = signature.toByteArray();
byte[] hashBytes = md.digest(signatureBytes);
String hash = bytesToHex(hashBytes);
sb.append("Signature Hash 256: ").append(hash).append("\n\n");
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return sb.toString();
}
public static String getSignatureInfo1(Signature[] signatures) {
if (null == signatures) return "Null";
StringBuilder sb = new StringBuilder();
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
for (Signature signature : signatures) {
byte[] signatureBytes = signature.toByteArray();
byte[] hashBytes = md.digest(signatureBytes);
String hash = bytesToHex(hashBytes);
sb.append("Signature Hash 1: ").append(hash).append("\n\n");
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return sb.toString();
}
private static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x:", b));
}
// 删除最后一个冒号
sb.deleteCharAt(sb.length() - 1);
return sb.toString();
}
public static String getApkHash(Context context, String packageName) {
try {
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
String apkFilePath = packageInfo.applicationInfo.sourceDir;
return calculateHash(apkFilePath);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
} catch (IOException | NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
return null;
}
private static String calculateHash(String filePath) throws IOException, NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA-256");
try (FileInputStream fis = new FileInputStream(filePath)) {
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
md.update(buffer, 0, bytesRead);
}
}
byte[] hashBytes = md.digest();
StringBuilder sb = new StringBuilder();
for (byte hashByte : hashBytes) {
sb.append(Integer.toString((hashByte & 0xff) + 0x100, 16).substring(1));
}
return sb.toString();
}
public static String convertFormattedHashToHex(String formattedHash) {
// 去除冒号
// formattedHash = formattedHash.replaceAll(":", "");
// 转换为十六进制表示
StringBuilder hexHash = new StringBuilder();
for (int i = 0; i < formattedHash.length(); i += 2) {
String hexByte = formattedHash.substring(i, i + 2);
int decimal = Integer.parseInt(hexByte, 16);
String hex = Integer.toHexString(decimal);
hexHash.append(hex);
}
return hexHash.toString();
}
}
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-keep class com.tool.hwtools.HwTools {
*;
}
-keepnames class com.tool.hwtools.HwTools {
*;
}
Jar生成位置
build/.transforms..../out/jars/classes.jar
评论