mirror of
https://github.com/HighCapable/YukiHookAPI.git
synced 2025-09-05 18:25:28 +08:00
Remove parse folder because is no longer need it
This commit is contained in:
@@ -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 }
|
|
||||||
}
|
|
||||||
}
|
|
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
@@ -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 (November–December 2007),
|
|
||||||
// and version 013 was used for the M5 releases of the Android platform (February–March 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)
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user