[转载] 3. JebAPI 之 jeb.api.ast
本文转载自: https://www.zybuluo.com/oro-oro/note/143651
0. 序
Jeb 本身是支持变量重命名的,所以,混淆了的变量名、类名可以修改。
实际上,它还可以做到这种效果 Decompiled Java Code Manipulation using JEB API – Part 2: Decrypting Strings。
例子中的脚本在这:ASTDecryptStrings.py。
整体的逻辑:
1. 破解解密算法。
2. 遍历类里面的所有方法
3. 如果方法为解密方法,则提取所有的参数出来,给解密方法。
4. 计算出解密的字符串,最终用replaceSubElement
替换掉整个函数调用。
而这些都需要去了解 jeb.api.ast。
1. AST 整体结构简介
AST是Abstract Syntax Tree的简称,也就是抽象语法树,这是用来解析源码的。
源代码有各种各样的结构和语句,譬如类、方法、变量、表达式、常量、For语句、Break语句等等。
这些东西AST都会有对应的类一一对应。
整个jeb.api.ast整体结构如下:
所有的类都直接或间接实现了 IElement。
它有2个重要的方法:
方法 | 说明 |
---|---|
getSubElements() | 获取该元素的子元素列表。 |
replaceSubElement(IElement old_elt, IElement new_elt) | 用另外一个元素替换一个元素。 |
2. NonStateMent 部分
2.1 Class, Method, Field
Class:表示一个Java类。类则包含了内部类、方法(Method)、变量(Field)等。
Method:表示一个Java方法。可以用JebInstance.getDecompiledMethodTree
来获得一个方法,可以通过Method.Builder
创建方法。
Field:表示一个Java变量。可以通过Field.Builder
创建变量。
这3类元素都是只读元素,而不是表达式(Expression),跟其他类是有区别的。
import jeb.api.IScript; import jeb.api.JebInstance; import jeb.api.ast.Field; import jeb.api.ast.Method; import jeb.api.dex.Dex; import java.util.List; public class TestASTClass implements IScript { @Override public void run(JebInstance jebInstance) { Dex dex = jebInstance.getDex(); List<String> classSignatures = dex.getClassSignatures(true); for (String classSignature : classSignatures) { if (!classSignature.contains("MainActivity")) { continue; } jebInstance.print(classSignature); jeb.api.ast.Class decompiledClassTree = jebInstance.getDecompiledClassTree(classSignature); if (decompiledClassTree == null) { continue; } jebInstance.print("\nField : "); List<Field> fields = decompiledClassTree.getFields(); for (Field field : fields) { jebInstance.print(field.getSignature()); } jebInstance.print("\nMethod : "); List<Method> methods = decompiledClassTree.getMethods(); for (Method method : methods) { jebInstance.print(method.getSignature()); } jebInstance.print("\nInnerClass : "); List<jeb.api.ast.Class> innerClasses = decompiledClassTree.getInnerClasses(); for (jeb.api.ast.Class cls : innerClasses) { jebInstance.print(cls.getType()); } String type = decompiledClassTree.getType(); jebInstance.print("\nType : " + type); } } }
2.2 ArrayElt, Identifier, InstanceField, StaticField
ArrayElt : 表示一个数组的元素,如array[index]。
Identifier:表示一个Java标识符或变量。
InstanceField:表示非静态变量,这是一个左值表达式,不要跟jeb.api.ast.Field混淆。
StaticField:表示静态变量,不要跟jeb.api.ast.Field混淆。
这3个都实现了ILeftExpression
。
下面代码是有问题的,Field不是表达式,因为变量可能用在任何地方,而具体使用的地方,才是表达式。
if (field instanceof InstanceField) { }
2.3 ConditionalExpression, Constant, Expression, TypeReference
ConditionalExpression:表示条件表达式,如a ? b : c。
Constant:表示一个常量值,类型支持8个主要类型 (boolean, byte, char, short, int, long, float, double) 和字符串。
通过Constant.Builder.
可创建一个Constant
。
Constant constant = new Constant.Builder(jebInstance).buildString("Hello World!");
Expression:算术或逻辑表达式。
一个表达式,包含1个或2个成员(左成员和右成员)和一个操作符(Operator),其中左成员是可选的。
如:
a + 1
a * ((int)b - foo())
!x
x ^ y | z
TypeReference : 表示一个类型引用,用在instanceof
表达式中。
如:if(pet instanceof Dog) { ... }
3. Statement 部分
3.1 Assignment, Break, Continue, Goto, Label, Monitor, Return, Throw
这些类都是直接继承了 Statement,一看类名就知道什么意思了,这里单单看Assignment
。
Assignment : 表示赋值语句,如 left = right。
方法 | 说明 |
---|---|
getLeft() | 获得赋值语句的左边表达式 |
getRight() | 获得赋值语句的右边表达式 |
setRight() | 直接修改右边语句 |
3.2 Compound
Compound :混合语句,包含了更多的语句,基于一个或多个语句块。
下面的子类有:Block, DoWhileStm, ForStm, IfStm, SwitchStm, TryStm, WhileStm。
Block : 表示语句块,是最基本的混合语句,里面包含多个语句。
如:
{
stm0;
stm1;
stm2;
}
其他语句块,则类似。
3.3 Definition, New
Definition : 声明语句。
New: 表示New了一个非数组对象。
3.4 Call, NewArray
Call:表示一个方法调用,如foo(0, 1, "bar")
。
NewArray:表示New了一个数组对象。
4. 解密demo
准备一个helloworld项目,随便写个简单的加密算法。
package com.test.helloworld; import android.app.Activity; import android.os.Bundle; public class MainActivity extends Activity { public static final byte[] bytes = new byte[]{'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); System.out.println(decode(0, 6)); } String decode(int a, int b) { byte[] ab = new byte[]{bytes[a], bytes[b]}; return new String(ab); } }
Jeb 显示为:
package com.test.helloworld; import android.app.Activity; import android.os.Bundle; public class MainActivity extends Activity { public static final byte[] bytes; static { MainActivity.bytes = new byte[]{72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33}; } public MainActivity() { super(); } String decode(int a, int b) { return new String(new byte[]{MainActivity.bytes[a], MainActivity.bytes[b]}); } protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.setContentView(2130968601); System.out.println(this.decode(0, 6)); } }
接下来,我们参考ASTDecryptStrings.py
,将所有出现decode解密方法的地方,都替换成解密的字符串。
因为有python的例子了,这里用Java实现。
import jeb.api.IScript; import jeb.api.JebInstance; import jeb.api.ast.*; import jeb.api.dex.Dex; import jeb.api.dex.DexMethod; import java.util.ArrayList; import java.util.List; public class TestASTDecode implements IScript { public static final byte[] bytes = new byte[]{'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'}; @Override public void run(JebInstance jebInstance) { Dex dex = jebInstance.getDex(); List<String> classSignatures = dex.getClassSignatures(true); Constant.Builder cstBuilder = new Constant.Builder(jebInstance); // 获得decode方法的sig int methodCount = dex.getMethodCount(); String decodeMtdSig; for (int i = 0; i < methodCount; i++) { DexMethod dexMethod = dex.getMethod(i); int index = dexMethod.getIndex(); decodeMtdSig = dex.getMethod(i).getSignature(true); if (decodeMtdSig.contains("Lcom/test/helloworld/MainActivity;->decode")) { // 找出所有使用了该方法的地方 List<Integer> methodReferences = dex.getMethodReferences(index); for (Integer refIdx : methodReferences) { DexMethod refDexMethod = dex.getMethod(refIdx); // 找到AST中对应的Method Method decompiledMethodTree = jebInstance.getDecompiledMethodTree(refDexMethod.getSignature(true)); // 拿到语句块,遍历所有语句 Block block = decompiledMethodTree.getBody(); int size = block.size(); for (int j = 0; j < size; j++) { Statement statement = block.get(j); jebInstance.print(statement.toString()); if (statement instanceof Call) { Call call = (Call) statement; Method method = call.getMethod(); jebInstance.print("Call : " + method.getSignature()); List<IElement> subElements = call.getSubElements(); for (IElement element : subElements) { jebInstance.print("Sub Element : " + element.toString()); if (element instanceof Call) { Call c = (Call) element; Method m = c.getMethod(); if (m.getSignature().equals(decodeMtdSig)) { jebInstance.print(">>> " + decodeMtdSig); List<IExpression> arguments = c.getArguments(); ArrayList<Integer> arrayList = new ArrayList<Integer>(); for (IExpression expression : arguments) { if (expression instanceof Constant) { arrayList.add(((Constant) expression).getInt()); } } String str = decode(arrayList.get(0), arrayList.get(1)); jebInstance.print("解密后的字符串 : " + str); // 将当前语句Call的子元素,替换为解密后的字符串 call.replaceSubElement(element, cstBuilder.buildString(str)); } } } } } } } } } String decode(int a, int b) { byte[] ab = new byte[]{bytes[a], bytes[b]}; return new String(ab); } }
执行完后,需要手工刷新, 反编译的代码,就可以看到解密的字符串了。
package com.test.helloworld; import android.app.Activity; import android.os.Bundle; public class MainActivity extends Activity { public static final byte[] bytes; static { MainActivity.bytes = new byte[]{72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33}; } public MainActivity() { super(); } String decode(int a, int b) { return new String(new byte[]{MainActivity.bytes[a], MainActivity.bytes[b]}); } protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.setContentView(2130968601); System.out.println("HW"); } }
如果想让脚本解密后,自动刷新UI的话,需要调用UI的相关接口。
另外,Jeb使用Jython和Java作为脚本,而dex文件,又可以反编译为jar文件,这意味着可以直接加载jar包,调用解密方法来解密了。
HelloWorld的APK载地址:http://yunpan.cn/cdjW2su55qjR9 访问密码 aff9
[转载] 3. JebAPI 之 jeb.api.ast的更多相关文章
- [转载] 4. JebAPI 之 jeb.api.ui
本文转载自: https://www.zybuluo.com/oro-oro/note/145250 JebInstance可以通过getUI()方法来获得jeb.api.ui.JebUI. JebU ...
- [转载] 1. JebAPI 之 jeb.api
本文转载自: https://www.zybuluo.com/oro-oro/note/142707 JEB API 官方地址:https://www.pnfsoftware.com/apidoc/ ...
- [转载] 2. JebAPI 之 jeb.api.dex
本文转载自: https://www.zybuluo.com/oro-oro/note/142842 1. jeb.api.dex.Dex 这个类代表正在被JEB处理的DEX文件. 要想更好的了解这个 ...
- [转载] ZooKeeper的Java客户端API
转载自 http://www.cnblogs.com/ggjucheng/p/3370359.html http://zookeeper.apache.org/doc/trunk/javaExampl ...
- [转载]Java 8 日期&时间 API
Java 8 日期和时间 声明 本文转自http://www.journaldev.com/2800/java-8-date-localdate-localdatetime-instant,以mark ...
- (转载) ASP.NET(C#) Web Api 通过文件流下载文件到本地实例
下载文件到本地是很多项目开发中需要实现的一个很简单的功能.说简单,是从具体的代码实现上来说的,.NET的文件下载方式有很多种,本示例给大家介绍的是ASP.NET Web Api方式返回HttpResp ...
- (转载)Java8新的日期API LocalDate, LocalTime
前言 由于Java Date的各种问题,Java8推出了新的日期API,很受一拨人的追捧. 为什么我们需要新的Java日期/时间API? 在开始研究Java 8日期/时间API之前,让我们先来看一下为 ...
- 转载LoadRunner的常用Java API
Java API是访问Vuser函数的基础,通过LoadRunner的Java API可以在脚本中很容易地创建事务与并发点.获取用户信息等功能. 1. 事务函数(Transaction Functio ...
- 【转载】Asp .Net Web Api路由路径问题
原文章地址:https://www.cnblogs.com/devtester/p/8897302.html MVC也好,WebAPI也好,据我所知,有部分人是因为复杂的路由,而不想去学的.曾经见过一 ...
随机推荐
- JAVA 编码中文简述
中文编码问题虽然是个老问题,但对不熟悉的人来说还是不好处理的.不过Java中已经有了一套比较成熟的解决方案. 首先对中文编码格式予以简单介绍:中文编码有三套国标:GB2312,GBK,GB18030, ...
- 【转】Jquery ajax方法解析返回的json数据
转自http://blog.csdn.net/haiqiao_2010/article/details/12653555 最近在用jQuery的ajax方法传递接收json数据时发现一个问题,那就是返 ...
- 使用样式“clear”和“overflow”消除浮动元素对环绕行框的影响
为元素设置“float”样式之后,元素会脱离标准文档流,不再占据原来的空间.后续元素会向前移动,占据这个新的空间.后续的文本会围绕着浮动元素分布,形成一种环绕布局的现象. 示例代码: <!DOC ...
- ps通道磨皮
1.Ctrl+J 复制一个新图层2.进入通道面板,复制一个噪点最多的通道3.滤镜--其他--高反差保留 (我一般设数值13)4.图像--计算 (混合模式选择强光) 计算3次,得到Alpha3 5.按住 ...
- [转]MYSQL远程登录权限设置
Mysql默认关闭远程登录权限,如下操作允许用户在任意地点登录: 1. 进入mysql,GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED B ...
- 处理畅捷通的T+ 12.0版,web服务无故自动停止的问题
用了几个月的畅捷通T+ 12.0版,一直都挺正常,但最近这两周,出现了好几次web服务自动停止的情况,今天抽空仔细看了Windows的日志,发现在半夜2点左右,TPlusProWebService12 ...
- IOS开发-CALayer和UIView详细汇总
1. CALayer和UIView之间的关系: 在iOS系统中,你能看得见摸得着的东西基本上都是UIView,比如UI控件.图标等等,都是UIView. 其实UIView之所以能显示在屏幕上,完 ...
- 严格模式use strict
严格模式主要有以下限制: 变量必须声明后再使用函数的参数不能有同名属性,否则报错不能使用with语句不能对只读属性赋值,否则报错不能使用前缀0表示八进制数,否则报错不能删除不可删除的属性,否则报错不能 ...
- Spring MVC小结
Spring MVC项目搭建 添加依赖 (省略) Spring MVC配置类 @Configuration @EnableWebMvc @ComponentScan("com.sjx.spr ...
- [MySQL] 关系型数据库的设计范式 1NF 2NF 3NF BCNF
一.缘由: 要做好DBA,就要更好地理解数据库设计范式.数据库范式总结概览: 为了更好地理解数据库的设计范式,这里借用一下知乎刘慰老师的解释,很通俗易懂.非常感谢! 二.具体说明: 首先要明白”范 ...