最通俗易懂的字节码插桩实战(Gradle + ASM)

这篇博客详细介绍了如何使用Gradle和ASM库进行字节码插桩,包括处理jar和目录输入、字节码注入、BuryPointVisitor和BuryPointMethodVisitor的实现,以及如何在实际项目中应用和配置插件。
摘要由CSDN通过智能技术生成

input.jarInputs.each { JarInput jarInput ->

handleJarInput(jarInput, outputProvider)

}

}

}

/**

  • 处理文件目录下的class文件

*/

static void handleDirectoryInput(DirectoryInput directoryInput, TransformOutputProvider outputProvider) {

//是否是目录

if (directoryInput.file.isDirectory()) {

//列出目录所有文件(包含子文件夹,子文件夹内文件)

directoryInput.file.eachFileRecurse { File file ->

def name = file.name

if (filterClass(name)) {

ClassReader classReader = new ClassReader(file.bytes)

ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_MAXS)

ClassVisitor classVisitor = new BuryPointVisitor(classWriter)

classReader.accept(classVisitor, ClassReader.EXPAND_FRAMES)

byte[] code = classWriter.toByteArray()

FileOutputStream fos = new FileOutputStream(file.parentFile.absolutePath + File.separator + name)

fos.write(code)

fos.close()

}

}

}

//文件夹里面包含的是我们手写的类以及R.class、BuildConfig.class以及R$XXX.class等

// 获取output目录

def dest = outputProvider.getContentLocation(

directoryInput.name,

directoryInput.contentTypes,

directoryInput.scopes,

Format.DIRECTORY)

//这里执行字节码的注入,不操作字节码的话也要将输入路径拷贝到输出路径

FileUtils.copyDirectory(directoryInput.file, dest)

}

/**

  • 处理jar文件,一般是第三方依赖库jar文件

*/

static void handleJarInput(JarInput jarInput, TransformOutputProvider outputProvider) {

if (jarInput.file.getAbsolutePath().endsWith(“.jar”)) {

//重名名输出文件,因为可能同名,会覆盖

def jarName = jarInput.name

def md5Name = DigestUtils.md5Hex(jarInput.file.getAbsolutePath())

if (jarName.endsWith(“.jar”)) {

jarName = jarName.substring(0, jarName.length() - 4)

}

JarFile jarFile = new JarFile(jarInput.file)

Enumeration enumeration = jarFile.entries()

File tmpFile = new File(jarInput.file.getParent() + File.separator + “temp.jar”)

//避免上次的缓存被重复插入

if (tmpFile.exists()) {

tmpFile.delete()

}

JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(tmpFile))

//用于保存

while (enumeration.hasMoreElements()) {

JarEntry jarEntry = (JarEntry) enumeration.nextElement()

String entryName = jarEntry.getName()

ZipEntry zipEntry = new ZipEntry(entryName)

InputStream inputStream = jarFile.getInputStream(jarEntry)

//插桩class

if (filterClass(entryName)) {

//class文件处理

jarOutputStream.putNextEntry(zipEntry)

ClassReader classReader = new ClassReader(IOUtils.toByteArray(inputStream))

ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_MAXS)

ClassVisitor classVisitor = new BuryPointVisitor(classWriter)

classReader.accept(classVisitor, ClassReader.EXPAND_FRAMES)

byte[] bytes = classWriter.toByteArray()

jarOutputStream.write(bytes)

} else {

jarOutputStream.putNextEntry(zipEntry)

jarOutputStream.write(IOUtils.toByteArray(inputStream))

}

jarOutputStream.closeEntry()

}

//结束

jarOutputStream.close()

jarFile.close()

//生成输出路径 + md5Name

def dest = outputProvider.getContentLoc

  • 23
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值