Commit 437a6678 authored by steve's avatar steve

完成-适配 android 11 储存空间

parent 204240a5
...@@ -2,8 +2,10 @@ package com.go.hookNotify ...@@ -2,8 +2,10 @@ package com.go.hookNotify
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.go.hookNotify.databinding.ActivityMainBinding import com.go.hookNotify.databinding.ActivityMainBinding
import com.go.hookNotify.units.HookTestUnit
class MainActivity : AppCompatActivity(), View.OnClickListener { class MainActivity : AppCompatActivity(), View.OnClickListener {
...@@ -18,11 +20,12 @@ class MainActivity : AppCompatActivity(), View.OnClickListener { ...@@ -18,11 +20,12 @@ class MainActivity : AppCompatActivity(), View.OnClickListener {
override fun onClick(view: View?) { override fun onClick(view: View?) {
when (view) { when (view) {
mBinding.btnChange -> { mBinding.btnChange -> {
mBinding.tvTitle.text = "OK2"
if (HookTestUnit.toMessage())
Toast.makeText(this, getString(R.string.share_hook_suc), Toast.LENGTH_SHORT).show()
else
Toast.makeText(this, getString(R.string.share_hook_failure), Toast.LENGTH_SHORT).show()
mBinding.tvTitle.text = "OK"
} }
} }
} }
......
package com.go.hookNotify.units
import java.text.SimpleDateFormat
import java.util.*
object DateUnit {
fun getNowTime(sTimeFormat: String = "yyyy-MM-dd HH-mm-ss"): String {
val sdf = SimpleDateFormat(sTimeFormat, Locale.getDefault())
val calendar = Calendar.getInstance()
val data = calendar.time
return sdf.format(data)
}
}
\ No newline at end of file
package com.go.hookNotify.units package com.go.hookNotify.units
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.ContentValues
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Environment import android.os.Environment
import android.provider.MediaStore import android.provider.MediaStore
import android.text.TextUtils
import android.util.Log import android.util.Log
import java.io.* import java.io.*
import java.lang.StringBuilder
import java.text.SimpleDateFormat
import java.util.*
object LogSaveUnit { object LogSaveUnit {
fun saveLogFile(documentPath: String, sContent: String) { val TAG = LogSaveUnit::class.java.simpleName.toString()
val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
val calendar = Calendar.getInstance()
val data = calendar.time
val sTime = sdf.format(data)
val fileName = "$sTime.txt" fun saveLogFile(context: Context, documentPath: String, fileName: String, sContent: String) {
XPoseDebugUnit.xPoseLogDebug("$TAG-start saveLogFile")
when (Build.VERSION.SDK_INT) {
in 0..28 -> {
val destFile = File(
"${Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)}/$documentPath/",
fileName
)
save(destFile, sContent)
}
29 -> {
val destFile = File( }
"${Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)}/$documentPath/", else -> {
fileName //val isHaveFile = checkFileHigherAndroidQ(context, fileName, sContent) ?: false
) //if (!isHaveFile) saveFileHigherAndroidQ(context, documentPath, fileName, sContent)
saveFileHigherAndroidQ(context, documentPath, fileName, sContent)
}
}
}
save(destFile, sContent) /**
* android 版本 0..28(小於29)
* 檢查文件是否存在
*/
private fun checkFileLTAndroidQ(context: Context, saveFileName: String): String {
var getSaveContent = ""
val destFile = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), saveFileName)
val uri: Uri?
if (destFile.exists()) uri = Uri.parse("file://" + destFile.absoluteFile) else return ""
try {
val fileDescriptor = uri?.let { context.contentResolver.openFileDescriptor(it, "r", null) }
val inputStream = FileInputStream(fileDescriptor?.fileDescriptor)
getSaveContent = inputStreamToString(inputStream)
} catch (e: FileNotFoundException) {
e.printStackTrace()
}
return getSaveContent
} }
// /** /**
// * android 版本 0..28(小於29) * android 版本 大於 29
// * 檢查文件是否存在 * 檢查文件是否存在
// */ */
// private fun checkFileLTAndroidQ(context: Context, saveFileName: String): String { @SuppressLint("Range")
// var getSaveContent = "" private fun checkFileHigherAndroidQ(context: Context, saveFileName: String, content: String): Boolean? {
// val destFile = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), saveFileName) val cr = context.contentResolver
// val uri: Uri? val contentUri = MediaStore.Files.getContentUri("external")
// if (destFile.exists()) uri = Uri.parse("file://" + destFile.absoluteFile) else return ""
// try { val cursor = cr.query(contentUri, null, null, null, null)
// val fileDescriptor = uri?.let { context.contentResolver.openFileDescriptor(it, "r", null) } var uri: Uri? = null
// val inputStream = FileInputStream(fileDescriptor?.fileDescriptor) val columnIndexID: Int
// getSaveContent = inputStreamToString(inputStream) if (cursor?.count == 0) {
// } catch (e: FileNotFoundException) { XPoseDebugUnit.xPoseLogDebug("$TAG-no file")
// e.printStackTrace() return null
// } } else {
// return getSaveContent columnIndexID = cursor?.getColumnIndexOrThrow(MediaStore.Files.FileColumns._ID)!!
// } while (cursor.moveToNext()) {
val fileID = cursor.getLong(columnIndexID)
// /** val fileName = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME))
// * android 版本 29
// * 檢查文件是否存在 XPoseDebugUnit.xPoseLogDebug("$TAG-searchFileName=$fileName")
// */ XPoseDebugUnit.xPoseLogDebug("$TAG-saveFileName=$saveFileName")
// private fun checkFileAndroidQ(context: Context, saveFileName: String): String {
// val imageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI if (fileName == saveFileName) {
// val projection: Array<String> = arrayOf(MediaStore.Images.Media.DISPLAY_NAME, MediaStore.Images.Media._ID) uri = Uri.withAppendedPath(contentUri, fileID.toString())
// break
// //查詢 }
// val contentResolver = context.contentResolver }
// if (uri == null) {
// //添加篩選條件 XPoseDebugUnit.xPoseLogDebug("$TAG-no uri")
// val selection = "${MediaStore.Images.Media.DISPLAY_NAME}='$saveFileName'" return null
// val cursor = contentResolver.query(imageUri, projection, selection, null, null) } else {
// var outputStream: FileOutputStream? = null
// var getSaveContent = "" return try {
// if (cursor != null) { val fieldException = cr.openAssetFileDescriptor(uri, "r", null)
// while (cursor.moveToNext()) { outputStream = FileOutputStream(fieldException?.fileDescriptor)
// val fileIdIndex = cursor.getColumnIndex(MediaStore.Images.Media._ID) val byte = content.toByteArray()
// val thumbPath = MediaStore.Images.Media.EXTERNAL_CONTENT_URI.buildUpon().appendPath(cursor.getInt(fileIdIndex).toString()).build().toString()
// val fileUri = Uri.parse(thumbPath) outputStream.write(byte)
// outputStream.flush()
// try {
// val fileDescriptor = contentResolver.openAssetFileDescriptor(fileUri, "r", null)
// val inputStream = FileInputStream(fileDescriptor?.fileDescriptor)
// getSaveContent = inputStreamToString(inputStream)
// } catch (e: FileNotFoundException) {
// e.printStackTrace()
// }
//
// //只有在得到的唯一標示符
// if (!TextUtils.isEmpty(getSaveContent)) {
// break
// }
// }
// cursor.close()
// }
// return getSaveContent
// }
//
// /**
// * android 版本 大於 29
// * 檢查文件是否存在
// */
// @SuppressLint("Range")
// private fun checkFileGtAndroidQ(context: Context, saveFileName: String): String? {
// val cr = context.contentResolver
// val contentUri = MediaStore.Files.getContentUri("external")
// val projection: Array<String> = arrayOf(MediaStore.Files.FileColumns._ID, MediaStore.Files.FileColumns.DISPLAY_NAME)
// val selection = "${MediaStore.Files.FileColumns.MEDIA_TYPE}=${MediaStore.Files.FileColumns.MEDIA_TYPE_NONE}"
// val selectionArgs: Array<String>? = null
// val sortOrder = null
// val cursor = cr.query(contentUri, projection, selection, selectionArgs, sortOrder)
// var uri: Uri? = null
// val columnIndexID: Int
// if (cursor?.count == 0) {
// Log.d(TAG, "no file")
// return null
// } else {
// columnIndexID = cursor?.getColumnIndexOrThrow(MediaStore.Files.FileColumns._ID)!!
// while (cursor.moveToNext()) {
// val fileID = cursor.getLong(columnIndexID)
// val fileName = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME))
// if (fileName == saveFileName) {
// uri = Uri.withAppendedPath(contentUri, fileID.toString())
// break
// }
// }
// if (uri == null) {
// Log.d(TAG, "no uri")
// return null
// } else {
// return try {
// val fieldException = cr.openAssetFileDescriptor(uri, "r", null)
// val inputStream = FileInputStream(fieldException?.fileDescriptor) // val inputStream = FileInputStream(fieldException?.fileDescriptor)
// val sUUID = inputStreamToString(inputStream) // val sUUID = inputStreamToString(inputStream)
// inputStream.close() // inputStream.close()
// sUUID
// } catch (e: IOException) {
// Log.d(TAG, e.message.toString())
// null
// } finally {
// cursor.close()
// }
// }
// }
// }
//
// /**
// * 流 轉為 字符串
// * @param inputStream 流
// * @return 轉換完成的字符串
// */
// private fun inputStreamToString(inputStream: InputStream): String {
// val reader = BufferedReader(InputStreamReader(inputStream))
// val sb = StringBuilder()
// try {
// reader.use { r -> r.lineSequence().forEach { sb.append(it) } }
// } catch (e: IOException) {
// e.printStackTrace()
// } finally {
// try {
// inputStream.close()
// } catch (e: IOException) {
// e.printStackTrace()
// }
// }
// return sb.toString()
// }
true
} catch (e: IOException) {
XPoseDebugUnit.xPoseLogDebug("$TAG-${e.printStackTrace()}")
null
} finally {
cursor.close()
outputStream?.let { closeOutputStream(it) }
}
}
}
}
private fun closeOutputStream(vararg os: OutputStream) {
for (i in os.indices) {
try {
os[i].close()
} catch (e: IOException) {
e.printStackTrace()
}
}
}
/**
* android 0..28 版本
* 储存文件
*/
private fun save(file: File, content: String): Boolean { private fun save(file: File, content: String): Boolean {
if (!createFile(file, true)) { if (!createFile(file, true)) {
Log.e("FileSaveUtil", "create or delete file <\$file> failed.") Log.e("FileSaveUtil", "create or delete file <\$file> failed.")
...@@ -185,6 +152,63 @@ object LogSaveUnit { ...@@ -185,6 +152,63 @@ object LogSaveUnit {
return ret return ret
} }
/**
* android 版本大于29
* 储存 文件
*/
private fun saveFileHigherAndroidQ(context: Context, documentPath: String, fileName: String, content: String): Boolean {
XPoseDebugUnit.xPoseLogDebug("$TAG-init")
val resolver = context.contentResolver
val value = ContentValues()
value.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName)
value.put(MediaStore.MediaColumns.MIME_TYPE, "text/plain")
value.put(MediaStore.MediaColumns.RELATIVE_PATH, "${Environment.DIRECTORY_DOCUMENTS}/$documentPath/")
val uri = resolver.insert(MediaStore.Files.getContentUri("external"), value)
var outputStream: OutputStream? = null
XPoseDebugUnit.xPoseLogDebug("$TAG-start")
return try {
outputStream = uri?.let { context.contentResolver.openOutputStream(it) }
outputStream?.let {
it.write(content.toByteArray())
it.flush()
it.close()
}
XPoseDebugUnit.xPoseLogDebug("$TAG-true")
true
} catch (e: Exception) {
XPoseDebugUnit.xPoseLogDebug("$TAG-${e.message.toString()}")
false
}
}
/**
* 流 轉為 字符串
* @param inputStream 流
* @return 轉換完成的字符串
*/
private fun inputStreamToString(inputStream: InputStream): String {
val reader = BufferedReader(InputStreamReader(inputStream))
val sb = StringBuilder()
try {
reader.use { r -> r.lineSequence().forEach { sb.append(it) } }
} catch (e: IOException) {
e.printStackTrace()
} finally {
try {
inputStream.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
return sb.toString()
}
private fun createFile(file: File?, isDeleteOldFile: Boolean): Boolean { private fun createFile(file: File?, isDeleteOldFile: Boolean): Boolean {
if (file == null) return false if (file == null) return false
if (file.exists()) { if (file.exists()) {
......
...@@ -4,7 +4,6 @@ import com.go.hookNotify.units.XPoseDebugUnit ...@@ -4,7 +4,6 @@ import com.go.hookNotify.units.XPoseDebugUnit
import com.go.hookNotify.xp.code.HookGlobalNotify import com.go.hookNotify.xp.code.HookGlobalNotify
import com.go.hookNotify.xp.code.HookSimBoxNotify import com.go.hookNotify.xp.code.HookSimBoxNotify
import de.robv.android.xposed.IXposedHookLoadPackage import de.robv.android.xposed.IXposedHookLoadPackage
import de.robv.android.xposed.XposedBridge
import de.robv.android.xposed.callbacks.XC_LoadPackage import de.robv.android.xposed.callbacks.XC_LoadPackage
class Hook : IXposedHookLoadPackage { class Hook : IXposedHookLoadPackage {
...@@ -17,7 +16,7 @@ class Hook : IXposedHookLoadPackage { ...@@ -17,7 +16,7 @@ class Hook : IXposedHookLoadPackage {
xPosedHook(packageName, lpparam) xPosedHook(packageName, lpparam)
} }
private fun androidSystemHook(loadPackageParam: XC_LoadPackage.LoadPackageParam?){ private fun androidSystemHook(loadPackageParam: XC_LoadPackage.LoadPackageParam?) {
XPoseDebugUnit.xPoseLogDebug("android system start") XPoseDebugUnit.xPoseLogDebug("android system start")
HookGlobalNotify().handleLoadPackage(loadPackageParam) HookGlobalNotify().handleLoadPackage(loadPackageParam)
} }
......
...@@ -5,13 +5,18 @@ import android.app.Notification; ...@@ -5,13 +5,18 @@ import android.app.Notification;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import com.go.hookNotify.units.DateUnit;
import com.go.hookNotify.units.LogSaveUnit; import com.go.hookNotify.units.LogSaveUnit;
import com.go.hookNotify.units.XPoseDebugUnit; import com.go.hookNotify.units.XPoseDebugUnit;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import de.robv.android.xposed.IXposedHookLoadPackage; import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.IXposedHookZygoteInit;
import de.robv.android.xposed.XC_MethodHook; import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XSharedPreferences;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers; import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage; import de.robv.android.xposed.callbacks.XC_LoadPackage;
...@@ -48,9 +53,10 @@ public class HookGlobalNotify implements IXposedHookLoadPackage { ...@@ -48,9 +53,10 @@ public class HookGlobalNotify implements IXposedHookLoadPackage {
Notification notification = (Notification) param.args[2]; Notification notification = (Notification) param.args[2];
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("\n").append("==============================================================================").append("\n");
sb.append(DateUnit.INSTANCE.getNowTime("yyyy-MM-dd HH-mm-ss"));
sb.append("\n").append("object notification: ").append(notification.toString()).append("\n"); sb.append("\n").append("object notification: ").append(notification.toString()).append("\n");
sb.append("object bundle:").append("\n"); sb.append("object bundle:").append("\n");
Bundle bundle = notification.extras; Bundle bundle = notification.extras;
if (bundle != null) { if (bundle != null) {
Set<String> keys = bundle.keySet(); Set<String> keys = bundle.keySet();
...@@ -63,8 +69,11 @@ public class HookGlobalNotify implements IXposedHookLoadPackage { ...@@ -63,8 +69,11 @@ public class HookGlobalNotify implements IXposedHookLoadPackage {
String title = notification.extras.getString("android.title", "no Title"); String title = notification.extras.getString("android.title", "no Title");
// String content = notification.extras.getString("android.text", ""); // String content = notification.extras.getString("android.text", "");
String documentName = "log/" + title; String documentPath = "logGlobal/" + title;
// LogSaveUnit.INSTANCE.saveLogFile(documentName, sb.toString()); String fileName = "GlobalLog_" + DateUnit.INSTANCE.getNowTime("yyyy-MM-dd HH-mm-ss")+".txt";
LogSaveUnit.INSTANCE.saveLogFile(mContext, documentPath, fileName, sb.toString());
} }
}); });
} }
......
package com.go.hookNotify.xp.code; package com.go.hookNotify.xp.code;
import android.app.AndroidAppHelper; import android.app.AndroidAppHelper;
import android.app.Notification;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.Context;
import android.os.Bundle;
import com.go.hookNotify.units.DateUnit;
import com.go.hookNotify.units.LogSaveUnit; import com.go.hookNotify.units.LogSaveUnit;
import com.go.hookNotify.units.XPoseDebugUnit; import com.go.hookNotify.units.XPoseDebugUnit;
import com.go.hookNotify.xp.Constants; import com.go.hookNotify.xp.Constants;
import java.util.Map; import java.util.Map;
import java.util.Set;
import de.robv.android.xposed.IXposedHookLoadPackage; import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook; import de.robv.android.xposed.XC_MethodHook;
...@@ -34,10 +39,11 @@ public class HookSimBoxNotify implements IXposedHookLoadPackage { ...@@ -34,10 +39,11 @@ public class HookSimBoxNotify implements IXposedHookLoadPackage {
private final String mCountryCode = "countryCode"; private final String mCountryCode = "countryCode";
private final String mNormalizedNumber = "normalizedNumber"; private final String mNormalizedNumber = "normalizedNumber";
private Context mContext = null;
@Override @Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable { public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
if (!lpparam.processName.equals(Constants.SIMBOX_NAME)) return; if (!lpparam.processName.equals(Constants.SIMBOX_NAME)) return;
XPoseDebugUnit.xPoseLogInfo("simBox start init!!"); XPoseDebugUnit.xPoseLogInfo("simBox start init!!");
...@@ -46,6 +52,9 @@ public class HookSimBoxNotify implements IXposedHookLoadPackage { ...@@ -46,6 +52,9 @@ public class HookSimBoxNotify implements IXposedHookLoadPackage {
ContentValues.class, String.class, Map.class, String.class, boolean.class, boolean.class, boolean.class, new XC_MethodHook() { ContentValues.class, String.class, Map.class, String.class, boolean.class, boolean.class, boolean.class, new XC_MethodHook() {
@Override @Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable { protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
mContext = AndroidAppHelper.currentApplication();
XPoseDebugUnit.xPoseLogInfo("Success Hook Method"); XPoseDebugUnit.xPoseLogInfo("Success Hook Method");
ContentValues contentValues = (ContentValues) param.args[0]; ContentValues contentValues = (ContentValues) param.args[0];
...@@ -79,12 +88,13 @@ public class HookSimBoxNotify implements IXposedHookLoadPackage { ...@@ -79,12 +88,13 @@ public class HookSimBoxNotify implements IXposedHookLoadPackage {
mExt + ": " + ext + "\n" + mExt + ": " + ext + "\n" +
mCountryCode + ": " + countryCode + "\n" + mCountryCode + ": " + countryCode + "\n" +
mNormalizedNumber + ": " + normalizedNumber + "\n"; mNormalizedNumber + ": " + normalizedNumber + "\n";
XPoseDebugUnit.xPoseLogInfo(sMsg); XPoseDebugUnit.xPoseLogInfo(sMsg);
String documentName = "log2/" + number + "-" + imsi;
LogSaveUnit.INSTANCE.saveLogFile(documentName, sMsg); //存在手机的外部空间
super.beforeHookedMethod(param);
String documentPath = "logSimbox/" + number + "-" + imsi;
String fileName = "SimBoxLog_" + DateUnit.INSTANCE.getNowTime("yyyy-MM-dd HH-mm-ss") + ".txt";
LogSaveUnit.INSTANCE.saveLogFile(mContext, documentPath, fileName, sMsg); //存在手机外部空间
super.beforeHookedMethod(param);
} }
}); });
} }
......
<resources> <resources>
<string name="app_name">HookNotify</string> <string name="app_name">HookNotify</string>
<!--share-->
<string name="share_hook_test">Hook 測試</string>
<string name="share_hook_suc">Hook 成功</string>
<string name="share_hook_failure">Hook 失敗</string>
</resources> </resources>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment