混淆技术研究笔记(六)如何基于yGuard实现?

logo
确定参考 <adjust> 作为入口后,就需要详细了解这部分代码的逻辑。

需要看yguard源码了,你会如何阅读一个完全不了解的源码?

我通常的策略都是找一个目标,添加代码依赖,写好demo,debug跟踪代码看。如果漫无目的的看,很难串起来整个流程,范围太大也容易迷失。

先在配置中增加 <adjust> 配置:

<adjust replacePathPolicy="lenient"><include name="**.*"/>
</adjust>

最快定位代码位置的方式就是搜索,可以搜 adjust,也可以搜 replacePathPolicy,搜索后发现了 AdjustSection 内部类(IDEA用ctrl+shift+num1标记),在 ObfuscatorTask 中,从名字来看这个是混淆的任务,对应的就是 <rename> 标签。在这个类中发现了 List<AdjustSection> adjustSections,然后搜索 adjustSections,发现几处使用的地方:

try {for (AdjustSection section : adjustSections) {section.prepare(this);}
} catch (BuildException be) {throw new BuildException(be.getMessage(), be.getLocation());
}

这是在准备什么东西,还没到关键的位置,继续往下找:

for (AdjustSection as : adjustSections)
{as.createEntries(inFilesList);
}

从这里看到,<adjust>会根据配置的 include 配置找到要处理的类,这个方法有用,我可以使用他来匹配要需要签名的类,顺手打个标记(ctrl+shitf+num2),再继续找:

public boolean filterName( final String inName, final StringBuffer outName ) {for(AdjustSection as : adjustSections) {if (as.contains(inName)) {filterNameImpl(inName, outName, as);return true;}}return false;
}

这里似乎在处理文件名,如果是前面要处理的文件,这里通过 StringBuffer outName 处理的文件名,鼠标滚轮点击该方法,追踪到调用的位置,在 GuardDB 中的 remapTo 方法里面:

if(resourceHandler != null && resourceHandler.filterName(inName, outNameBuffer))
{outName = outNameBuffer.toString();if(!outName.equals(inName)){replaceNameLog.append("  <resource name=\"");replaceNameLog.append(ClassTree.toUtf8XmlString(inName));replaceNameLog.append("\" map=\"");replaceNameLog.append(ClassTree.toUtf8XmlString(outName));replaceNameLog.append("\"/>\n");}
}
else
{outName = classTree.getOutName(inName);
}

这里会使用改后的文件名,那么改后文件名的生效肯定是在这里,这里可能会有写入jar的操作,这非常关键,但是我们先回到前面继续查找 adjustSections,发现了最后一处:

public boolean filterContent(InputStream in, OutputStream out, String resourceName) throws IOException
{for(AdjustSection as : adjustSections){if(filterContentImpl(in, out, resourceName, as)){return true;}}return false;
}

这里是修改文件内容的地方,滚轮点击找调用位置,发现在 GuardDB 中的 remapTo 中的代码:

if(resourceHandler == null || !resourceHandler.filterContent(inStream, dataOutputStream, inName))
{byte[] bytes = new byte[(int)size];inStream.readFully(bytes);// outName = classTree.getOutName(inName);// Dump the data, while creating the digestsdataOutputStream.write(bytes, 0, bytes.length);
}
else
{replaceContentsLog.append("  <resource name=\"");replaceContentsLog.append(ClassTree.toUtf8XmlString(inName));replaceContentsLog.append("\"/>\n");
}

这里修改的文件内容,修改的内容最后会写入jar,继续往下看,就发现了下面代码:

jarEntries.add(new Object[]{outEntry, baos.toByteArray()});

往下搜索 jarEntries 发现了下面代码:

for (int j = 0; j < jarEntries.size(); j++){Object[] array = (Object[]) jarEntries.get(j);JarEntry entry = (JarEntry) array[0];String name = entry.getName();// make sure the directory entries are written to the jar fileif (!entry.isDirectory()){int index = 0;while ((index = name.indexOf("/", index + 1))>= 0){String directory = name.substring(0, index+1);if (!directoriesWritten.contains(directory)){directoriesWritten.add(directory);outJar.addDirectory(directory);}}}// write the entry itselfoutJar.addFile(entry.getName(), (byte[]) array[1]);
}

原来这里通过 outJar 就可以写入文件,而且也不必存在已有的文件,直接加个新的也可以,在 outJar.addFile 这行加个断点,clean 代码,然后在 package 上右键 debug(注意,需要在 pom.xml的dependencies中添加yguard依赖,然后定位到上面位置加断点):

在这里插入图片描述

这种方式是可以调试maven插件的,debug进入这里后,在表达式中执行代码,添加一个文件试试是否生效:

在这里插入图片描述

直接关闭断点执行完成,然后打开当时处理的module-b的jar包:

在这里插入图片描述
很容易就成功了,比预想的要顺利一些。

在后续的处理过程中,我写代码还有一个特点,不考虑太多(说明考虑了一点)的设计,先用最直接的手段实现功能,等功能完成后再去全局设计进行重构调整。如果一上来就想着如何设计,万一最后行不通就白费了,而且设计没有尽头,想要完美的设计可能需要纠结很久才有结果,在这种重构调整比较容易的情况下,先动手,后设计。

上面解决了最难的写入jar包的问题,再次查看 outJar 的上下文时,关注到了对应的 inJar,查看 remapTo 方法发现下面的代码:

if (inName.endsWith(CLASS_EXT))
{if (fileFilter == null || fileFilter.accepts(inName)){// Write the obfuscated version of the class to the output JarClassFile cf = ClassFile.create(inStream);fireObfuscatingClass(Conversion.toJavaClass(cf.getName()));cf.remap(classTree, replaceClassNameStrings, log);String outName = createClassFileName(inName, cf) + CLASS_EXT;JarEntry outEntry = new JarEntry(outName);DataOutputStream classOutputStream;if (digestStrings == null){digestStrings = new String[]{"SHA-1", "MD5"};}MessageDigest[] digests = new MessageDigest[digestStrings.length];// Create an OutputStream piped through a number of digest generators for the manifestclassOutputStream = fillDigests(baos, digestStrings, digests);// Dump the classfile, while creating the digestscf.write(classOutputStream);classOutputStream.flush();Object[] entry = {outEntry, baos.toByteArray()};jarEntries.add(entry);baos.reset();// Now update the manifest entry for the class with new name and new digestsupdateManifest(i, inName, outName, digests);}
}

这段代码中可以看到 inName 是原始的名字,outName 是经过混淆处理后的名字(没混淆类名就不变,混淆就变),后面还有 classOutputStream是类的字节码内容,是我们想要加密的内容。这个方法的位置太好了,这就是我想要匹配文件,获取字节码内容的地方。

接下来要考虑的是如何配置要对哪些内容进行签名,一开始我想参考 <adjust> 中的 <include> 实现,上面提到过的 as.createEntries(inFilesList) 是一种可行的方式,但是我最后选择了参考 <class> 中的 <patternset>,这也是一种获取匹配类的方式。

准备工作都已经好了,接下来就该动手实现了,此时我还有一个问题,yguard中是如何创建对象的,xml和类是如何结合的,于是我找到了 ant 开发者文档,我们下篇先简单翻译下文档看看ant中的基本规则,磨刀不误砍柴工说的就是现在。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/133144.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Maven系列第3篇:详解maven解决依赖问题

maven系列目标&#xff1a;从入门开始开始掌握一个高级开发所需要的maven技能。 这是maven系列第3篇。 我们先来回顾一下什么是maven&#xff1f; maven是apache软件基金会组织维护的一款自动化构件工具&#xff0c;专注服务于java平台的项目构件和依赖管理。 本文主要内容…

数据库基础篇一

MySQL数据模型 关系型数据库通过表来存储数据的数据库 SQL分类 数据库操作 进入数据库 mysql -u root -p #输入密码即可在cmd命令行窗口使用mysql 1.查询 2.创建 create database test; create database if not exists test; #如果test数据库不存在&#xff0c;则创建tes…

对比纯软开与嵌入式硬件开发谁更好呢?

对比纯软开与嵌入式硬件开发谁更好呢&#xff1f; 你的纠结和犹豫是理解的&#xff0c;职业选择确实是一个重要的决策。我明白你在嵌入式和软件开发之间犹豫不决的原因。让我给你提供一些建议&#xff0c;帮助你做出更明智的决定。最近很多小伙伴找我&#xff0c;说想要一些嵌入…

idea怎么设置作者信息(详细)

目录 一&#xff1a;在Java类的开头自动注释作者名字和日期等信息 二&#xff1a;给Java的方法注释作者名字和日期等信息 1. 不可修改的模板&#xff1a;Postfix Completion 2. 可修改的模板&#xff1a;Live Templates tips&#xff1a;首先给大家推荐两款好用的免费软件&…

Web知识:markupsafe.escape() 函数的作用

1、markupsafe.escape() 函数是 MarkupSafe 库中的一个函数&#xff0c;它的作用是对字符串进行 HTML 转义&#xff0c;以防止在 HTML 文档中引起意外的解析结果或安全漏洞。 2、在 Web 开发中&#xff0c;如果用户提供的数据直接插入到 HTML 页面中&#xff0c;而没有经过转义…

四.镜头知识之放大倍率

四.镜头知识之放大倍率 文章目录 四.镜头知识之放大倍率4.0 前言4.1 镜头的光学放大倍率的计算方法4.2 显示器的电子放大倍率4.2.1 智能硬件产品的显示放大倍率计算案例 4.3 系统放大倍率4.4 智能硬件产品的系统放大倍率计算案例4.4 智能硬件产品的系统放大倍率计算案例 4.0 前…

很烦的Node报错积累

目录 1. 卡在sill idealTree buildDeps2、Node Sass老是安装不上的问题3、unable to resolve dependency tree4、nvm相关命令5、设置淘宝镜像等基操5.1 镜像 5.2 npm清理缓存6、Browserslist: caniuse-lite is outdated loader 1. 卡在sill idealTree buildDeps 参考&#xf…

银河麒麟安装arm架构mysql8

1. 准备工作 2. 查看麒麟系统版本 使用命令 Linux version 4.19.90-25.21.v2101.ky10.aarch64 (KYLINSOFTlocalhost.localdomain) (gcc version 7.3.0 (GCC)) #1 SMP Wed Sep 28 16:37:42 CST 2022可以看出这是麒麟 v10 &#xff0c;aarch64 &#xff08;ARM 架构的&#xff…

NginxWebUI runCmd 远程命令执行漏洞复现 [附POC]

文章目录 NginxWebUI runCmd 远程命令执行漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 0x06 修复建议 NginxWebUI runCmd 远程命令执行漏洞复现 [附POC] 0x01 前言 免责声明&#xff1a;请勿利用文章内的相…

vue实现一个简单导航栏

Vue之简单导航栏 在vue中&#xff0c;想要实现导航栏的功能&#xff0c;除了用传统的a标签以外&#xff0c;还可以使用路由——vue-router来实现&#xff0c;前端小白在此记录一下学习过程&#xff08;默认已经搭建好vue的脚手架环境&#xff09;&#xff1a; 建立项目并安装…

jupyter 切换虚拟环境

当前只有两个环kernel 我已经创建了很多虚拟环境&#xff0c;如何在notebook中使用这些虚拟环境呢&#xff1f;请看下面 比如说我要添加nlp 这个虚拟环境到notebook中 1. 切换到nlp环境 2. 安装如下模块 pip install ipykernel 3. 执行如下命令 python -m ipykernel install …

个人财务预算系统BudgetBee

什么是 BudgetBee &#xff1f; BudgetBee 是一个个人财务预算系统。通过 BudgetBee&#xff0c;您可以轻松管理您的个人财务。它可以帮助您跟踪您的支出和收入&#xff0c;以便您可以减少支出并增加储蓄。 镜像下载 官方没有在 docker hub 上发布镜像&#xff0c;而是采用了自…