Remove parse folder because is no longer need it

This commit is contained in:
2022-09-13 02:44:04 +08:00
parent c0cfeb972b
commit b98e175f99
4 changed files with 0 additions and 580 deletions

View File

@@ -1,115 +0,0 @@
/*
* YukiHookAPI - An efficient Kotlin version of the Xposed Hook API.
* Copyright (C) 2019-2022 HighCapable
* https://github.com/fankes/YukiHookAPI
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This file is Created by fankes on 2022/5/24.
*/
@file:Suppress("unused")
package com.highcapable.yukihookapi.hook.core.reflex.parse
import android.content.pm.ApplicationInfo
import com.highcapable.yukihookapi.hook.utils.parallelForEach
import java.io.Closeable
import java.io.File
import java.nio.ByteBuffer
import java.util.zip.ZipEntry
import java.util.zip.ZipFile
/**
* 封装对 APK 文件的解析操作
*
* 参考了 dongliu 的 [apk-parser](https://github.com/hsiafan/apk-parser) 项目
*
* Contributed from [conan](https://github.com/meowool-catnip/conan)
* @param apkFile APK 文件
*/
internal class ApkFile private constructor(apkFile: File) : Closeable {
internal companion object {
private const val DEX_FILE = "classes.dex"
private const val DEX_ADDITIONAL = "classes%d.dex"
/**
* 获取 [ApkFile] 实例
* @param appInfo 当前 APP 的 [ApplicationInfo]
* @return [ApkFile] or null
*/
internal fun from(appInfo: ApplicationInfo?) = runCatching { ApkFile(File(appInfo!!.sourceDir)) }.getOrNull()
}
override fun close() = zipFile.close()
/**
* 当前 APK 文件
* @return [ZipFile]
*/
private val zipFile = ZipFile(apkFile)
/**
* 读取 Entry
* @param entry 压缩文件 Entry
* @return [ByteArray]
*/
private fun readEntry(entry: ZipEntry) = zipFile.getInputStream(entry).use { it.readBytes() }
/**
* 读取 DEX 文件路径
* @param idx 字节序号
* @return [String]
*/
private fun readDexFilePath(idx: Int) = if (idx == 1) DEX_FILE else String.format(DEX_ADDITIONAL, idx)
/**
* DEX 文件是否存在
* @param idx 字节序号
* @return [Boolean]
*/
private fun isDexFileExist(idx: Int) = zipFile.getEntry(readDexFilePath(idx)) != null
/**
* 读取 DEX 文件字节流
* @param idx 字节序号
* @return [ByteArray]
*/
private fun readDexFile(idx: Int) = readEntry(zipFile.getEntry(readDexFilePath(idx)))
/**
* 获取当前 DEX 的 package 结构实例
* @return [ClassTrie]
*/
internal val classTypes by lazy {
var end = 2
while (isDexFileExist(end)) end++
val ret = ClassTrie()
(1 until end).parallelForEach { idx ->
val data = readDexFile(idx)
val buffer = ByteBuffer.wrap(data)
val parser = DexParser(buffer)
ret += parser.parseClassTypes()
}
return@lazy ret.apply { mutable = false }
}
}

View File

@@ -1,169 +0,0 @@
/*
* YukiHookAPI - An efficient Kotlin version of the Xposed Hook API.
* Copyright (C) 2019-2022 HighCapable
* https://github.com/fankes/YukiHookAPI
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This file is Created by fankes on 2022/5/24.
*/
@file:Suppress("unused")
package com.highcapable.yukihookapi.hook.core.reflex.parse
import java.util.concurrent.ConcurrentHashMap
/**
* 用来储存一个 APK 的 package 结构
*
* 出于性能考虑 - 这个类不支持读线程和写线程同时操作 - 但支持同类型的线程同时操作
*
* Contributed from [conan](https://github.com/meowool-catnip/conan)
*/
internal class ClassTrie internal constructor() {
private companion object {
/**
* 用来将 JVM 格式的类型标识符转换为类名
*
* Example: String 的类型标识符为 "Ljava/lang/String;"
*
* [Refer](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3)
* @return [String]
*/
private fun convertJVMTypeToClassName(type: String) = type.substring(1, type.length - 1).replace(oldChar = '/', newChar = '.')
}
/**
* 读写开关 - 用于增强线程间的安全性
*
* 只有开关设为 true 的时候 - 写操作才会被执行
*
* 只有开关设为 false 的时候 - 读操作才会返回有效数据
*/
@Volatile
internal var mutable = true
/**
* package 结构的根结点
* @return [TrieNode]
*/
private val root = TrieNode()
/**
* 插入一个单独的 JVM 格式的类型标识符
* @param type 类型
*/
internal operator fun plusAssign(type: String) {
if (mutable) root.add(convertJVMTypeToClassName(type))
}
/**
* 插入一组 JVM 格式的类型标识符
* @param types 类型数组
*/
internal operator fun plusAssign(types: Array<String>) = types.forEach { this += it }
/**
* 查找指定包里指定深度的所有类
*
* 出于性能方面的考虑 - 只有深度相等的类才会被返回 - 比如查找深度为 0 的时候 - 就只返回这个包自己拥有的类 - 不包括它里面其他包拥有的类
* @param packageName 包名 - 默认为根包名
* @param depth 深度
* @return [List] 查找到的类名数组
*/
internal fun search(packageName: String = "root", depth: Int): List<String> {
if (mutable) return emptyList()
if (packageName == "root") return root.classes
return root.search(packageName, depth)
}
/**
* 私有的节点结构
*/
inner class TrieNode {
/** 当前的 Class 实例数组 */
internal val classes: MutableList<String> = ArrayList(50)
/** 当前的 Class 子实例数组 */
private val children: MutableMap<String, TrieNode> = ConcurrentHashMap()
/**
* 添加节点
* @param className 类名
*/
internal fun add(className: String) = add(className, pos = 0)
/**
* 获取节点下的类名数组
* @param depth 深度
* @return [List]
*/
internal fun get(depth: Int = 0): List<String> {
if (depth == 0) return classes
return children.flatMap { it.value.get(depth - 1) }
}
/**
* 查找当前包里指定深度的所有类
* @param packageName 包名 - 默认为根包名
* @param depth 深度
* @return [List] 查找到的类名数组
*/
internal fun search(packageName: String, depth: Int) = search(packageName, depth, pos = 0)
/**
* 添加节点
* @param className 类名
* @param pos 下标
*/
private fun add(className: String, pos: Int) {
val delimiterAt = className.indexOf(char = '.', pos)
if (delimiterAt == -1) {
synchronized(this) { classes.add(className) }
return
}
val pkg = className.substring(pos, delimiterAt)
if (pkg !in children) children[pkg] = TrieNode()
children[pkg]?.add(className, pos = delimiterAt + 1)
}
/**
* 查找当前包里指定深度的所有类
* @param packageName 包名 - 默认为根包名
* @param depth 深度
* @param pos 下标
* @return [List] 查找到的类名数组
*/
private fun search(packageName: String, depth: Int, pos: Int): List<String> {
val delimiterAt = packageName.indexOf(char = '.', pos)
if (delimiterAt == -1) {
val pkg = packageName.substring(pos)
return children[pkg]?.get(depth) ?: emptyList()
}
val pkg = packageName.substring(pos, delimiterAt)
val next = children[pkg] ?: return emptyList()
return next.search(packageName, depth, pos = delimiterAt + 1)
}
}
}

View File

@@ -1,70 +0,0 @@
/*
* YukiHookAPI - An efficient Kotlin version of the Xposed Hook API.
* Copyright (C) 2019-2022 HighCapable
* https://github.com/fankes/YukiHookAPI
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This file is Created by fankes on 2022/5/24.
*/
@file:Suppress("unused")
package com.highcapable.yukihookapi.hook.core.reflex.parse
/**
* DEX 格式的文件头
*
* 参考来源 [Dex Format](https://source.android.com/devices/tech/dalvik/dex-format)
*
* Contributed from [conan](https://github.com/meowool-catnip/conan)
*/
internal class DexHeader internal constructor() {
internal var version = 0
internal var checksum = 0u
internal var signature = ByteArray(kSHA1DigestLen)
internal var fileSize = 0u
internal var headerSize = 0u
internal var endianTag = 0u
internal var linkSize = 0u
internal var linkOff = 0u
internal var mapOff = 0u
internal var stringIdsSize = 0
internal var stringIdsOff = 0u
internal var typeIdsSize = 0
internal var typeIdsOff = 0u
internal var protoIdsSize = 0
internal var protoIdsOff = 0u
internal var fieldIdsSize = 0
internal var fieldIdsOff = 0u
internal var methodIdsSize = 0
internal var methodIdsOff = 0u
internal var classDefsSize = 0
internal var classDefsOff = 0u
internal var dataSize = 0
internal var dataOff = 0u
internal companion object {
internal const val kSHA1DigestLen = 20
internal const val kSHA1DigestOutputLen = kSHA1DigestLen * 2 + 1
}
}

View File

@@ -1,226 +0,0 @@
/*
* YukiHookAPI - An efficient Kotlin version of the Xposed Hook API.
* Copyright (C) 2019-2022 HighCapable
* https://github.com/fankes/YukiHookAPI
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This file is Created by fankes on 2022/5/24.
*/
@file:Suppress("unused")
package com.highcapable.yukihookapi.hook.core.reflex.parse
import java.io.UTFDataFormatException
import java.nio.Buffer
import java.nio.ByteBuffer
import java.nio.ByteOrder
/**
* 封装对 DEX 格式数据的解析操作
*
* 参考了 dongliu 的 [apk-parser](https://github.com/hsiafan/apk-parser) 项目
*
* Contributed from [conan](https://github.com/meowool-catnip/conan)
* @param buffer DEX 字节流
*/
internal class DexParser internal constructor(buffer: ByteBuffer) {
/**
* 当前字节流
* @return [ByteBuffer]
*/
private val buffer = buffer.duplicate().apply { order(ByteOrder.LITTLE_ENDIAN) }
/**
* 读取 Bytes
* @param size 大小
* @return [ByteArray]
*/
private fun ByteBuffer.readBytes(size: Int) = ByteArray(size).also { get(it) }
/**
* 获取当前 package 下全部的类名
* @return [Array]
*/
internal fun parseClassTypes(): Array<String> {
// read magic
val magic = String(buffer.readBytes(8))
if (magic.startsWith(prefix = "dex\n").not()) return arrayOf()
val version = magic.substring(4, 7).toInt()
// now the version is 035
if (version < 35) {
// version 009 was used for the M3 releases of the Android platform (NovemberDecember 2007),
// and version 013 was used for the M5 releases of the Android platform (FebruaryMarch 2008)
error("Dex file version: $version is not supported")
}
// read header
val header = readDexHeader()
header.version = version
// read string offsets
val stringOffsets = readStringOffsets(header.stringIdsOff, header.stringIdsSize)
// read type ids
val typeIds = readTypeIds(header.typeIdsOff, header.typeIdsSize)
// read class ids
val classIds = readClassIds(header.classDefsOff, header.classDefsSize)
// read class types
return Array(classIds.size) { i ->
val classId = classIds[i]
val typeId = typeIds[classId]
val offset = stringOffsets[typeId]
readStringAtOffset(offset)
}
}
/**
* 获取 DEX 文件头
* @return [DexHeader]
*/
private fun readDexHeader() = DexHeader().apply {
checksum = buffer.int.toUInt()
buffer.get(signature)
fileSize = buffer.int.toUInt()
headerSize = buffer.int.toUInt()
endianTag = buffer.int.toUInt()
linkSize = buffer.int.toUInt()
linkOff = buffer.int.toUInt()
mapOff = buffer.int.toUInt()
stringIdsSize = buffer.int
stringIdsOff = buffer.int.toUInt()
typeIdsSize = buffer.int
typeIdsOff = buffer.int.toUInt()
protoIdsSize = buffer.int
protoIdsOff = buffer.int.toUInt()
fieldIdsSize = buffer.int
fieldIdsOff = buffer.int.toUInt()
methodIdsSize = buffer.int
methodIdsOff = buffer.int.toUInt()
classDefsSize = buffer.int
classDefsOff = buffer.int.toUInt()
dataSize = buffer.int
dataOff = buffer.int.toUInt()
}
/**
* 读取字符串偏移量
* @param stringIdsOff 偏移量
* @param stringIdsSize 偏移大小
* @return [IntArray]
*/
private fun readStringOffsets(stringIdsOff: UInt, stringIdsSize: Int): IntArray {
(buffer as Buffer).position(stringIdsOff.toInt())
return IntArray(stringIdsSize) { buffer.int }
}
/**
* 读取 Ids 类型偏移量
* @param typeIdsOff 偏移量
* @param typeIdsSize 偏移大小
* @return [IntArray]
*/
private fun readTypeIds(typeIdsOff: UInt, typeIdsSize: Int): IntArray {
(buffer as Buffer).position(typeIdsOff.toInt())
return IntArray(typeIdsSize) { buffer.int }
}
/**
* 读取 Class Ids 偏移量
* @param classDefsOff 偏移量
* @param classDefsSize 偏移大小
* @return [Array]
*/
private fun readClassIds(classDefsOff: UInt, classDefsSize: Int): Array<Int> {
(buffer as Buffer).position(classDefsOff.toInt())
return Array(classDefsSize) {
val classIdx = buffer.int
// access_flags, skip
buffer.int
// superclass_idx, skip
buffer.int
// interfaces_off, skip
buffer.int
// source_file_idx, skip
buffer.int
// annotations_off, skip
buffer.int
// class_data_off, skip
buffer.int
// static_values_off, skip
buffer.int
classIdx
}
}
/**
* 读取偏移量的字符串
* @param offset 偏移量
* @return [String]
*/
private fun readStringAtOffset(offset: Int): String {
(buffer as Buffer).position(offset)
return readString(readULEB128Int())
}
/**
* 读取 ULEB128 整型
* @return [Int]
*/
private fun readULEB128Int(): Int {
var ret = 0
var count = 0
var byte: Int
do {
if (count > 4) error("read varints error.")
byte = buffer.get().toInt()
ret = ret or (byte and 0x7f shl count * 7)
count++
} while (byte and 0x80 != 0)
return ret
}
/**
* 读取字符串
* @param len 长度
* @return [String]
*/
private fun readString(len: Int): String {
val chars = CharArray(len)
for (i in 0 until len) {
val byte = buffer.get().toInt()
when {
// ascii char
byte and 0x80 == 0 -> chars[i] = byte.toChar()
// read one more
byte and 0xe0 == 0xc0 -> {
val b = buffer.get().toInt()
chars[i] = (byte and 0x1F shl 6 or (b and 0x3F)).toChar()
}
byte and 0xf0 == 0xe0 -> {
val b = buffer.get().toInt()
val c = buffer.get().toInt()
chars[i] = (byte and 0x0F shl 12 or (b and 0x3F shl 6) or (c and 0x3F)).toChar()
}
else -> throw UTFDataFormatException()
}
}
return String(chars)
}
}