Skip to content

Commit

Permalink
1.1
Browse files Browse the repository at this point in the history
  • Loading branch information
keven1z committed Nov 29, 2021
1 parent c97b8de commit 747dacb
Show file tree
Hide file tree
Showing 22 changed files with 584 additions and 513 deletions.
37 changes: 28 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# DHook ![1.0 (shields.io)](https://img.shields.io/badge/1.1-brightgreen.svg)
DHook是一个自定义动态hook的工具。通过`javaagent`+`ASM`技术对运行时的java应用进行字节码修改,并可以配置文件的方式来增加hook点,修改执行方法的返回值等
DHook是一个自定义动态hook的工具。通过`javaagent`+`ASM`技术对运行时的java应用进行字节码修改,并可以配置文件的方式来增加hook点,修改执行方法的返回值以及参数等

## 兼容性
* java 8-11
Expand Down Expand Up @@ -42,17 +42,36 @@ public class Test {
该类存在三个分别是string,boolean,int为参数和返回值的方法,通过配置`hookClass.csv`文件,更改对应的返回值。此文件内容如下:

```csv
className,method,desc,return
com/keven1z/Test,test1,(Ljava/lang/String;)Ljava/lang/String;,keven1z
com/keven1z/Test,test2,(I)I,111
com/keven1z/Test,test3,(Z)Z,true
className,method,desc,return,parameter
com/keven1z/Test,test1,(Ljava/lang/String;)Ljava/lang/String;,keven1z,
com/keven1z/Test,test2,(I)I,111,
com/keven1z/Test,test3,(Z)Z,true,
```
文件参数如下:

该配置文件由className,method,desc,return组成,分别为类名,方法名,方法的描述符,以及返回值组成,配置文件路径固定为运行应用的当前路径。
| name | description |
| :-------: | :----------------------------------------------------------: |
| className | 类的全路径,以`/`分割,示例:`com/keven1z/Test`|
| method | 方法名,示例:`test1` |
| desc | 方法描述,示例:`(Ljava/lang/String;)Ljava/lang/String;` |
| return | 待修改的返回值 |
| parameter | 待修改的参数,以`;`分割多个参数,以`-`分割位置和值,前者为位置,后者为值,静态方法位置以0为起始值,非静态方法以1为起始值,示例:0-aa;1-bb |

运行`java -javaagent:agent -jar test.jar`.运行结果如下:

![image-20211123135028361](https://typora-1253484559.cos.ap-shanghai.myqcloud.com/img/image-20211123135028361.png)

运行`java -javaagent:dHook.jar -jar test.jar`.运行结果如下:

![image-20211129204730815](https://typora-1253484559.cos.ap-shanghai.myqcloud.com/img/image-20211129204730815.png)

### 辅助参数

#### 反编译源代码

需在`className`前添加`+`,会在运行目录下生成一个文件,若该类可以被反编译,则生成java文件,否则生成class文件。

#### 打印类的所有方法

可以通过将method设置为`*`,则`Dhook`会打印该类的所有方法。

## 更新
### 1.0版本
Expand All @@ -63,5 +82,5 @@ com/keven1z/Test,test3,(Z)Z,true
### 1.1版本
* 增加通过`*`打印该类的所有方法
* 支持打印返回值
* 支持反编译代码,将hook代码生成文件写入当前目录
* 支持反编译代码
* 支持修改参数
8 changes: 4 additions & 4 deletions hookClass.csv
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
className,method,desc,return,parameter,
com/keven1z/Test,test1,(Ljava/lang/String;)Ljava/lang/String;,keven1z
com/keven1z/Test,test2,(I)I,111
com/keven1z/Test,test3,(Z)Z,true
com/keven1z/Test,*,*
com/keven1z/Test,test1,(Ljava/lang/String;)Ljava/lang/String;,keven1z,
com/keven1z/Test,test2,(I)I,111,
com/keven1z/Test,test3,(Z)Z,true,
com/keven1z/Test,test4,(Ljava/lang/String;I)Ljava/lang/String;,,0-keven1z;1-777
13 changes: 7 additions & 6 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@
<artifactId>commons-csv</artifactId>
<version>1.9.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.9</version>
</dependency>

<!-- https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api -->
<dependency>
<groupId>javax.xml.bind</groupId>
Expand All @@ -51,12 +58,6 @@
<artifactId>procyon-compilertools</artifactId>
<version>0.5.36</version>
</dependency>
<dependency>
<groupId>org.jvnet.sorcerer</groupId>
<artifactId>sorcerer-javac</artifactId>
<version>0.8</version>
</dependency>
<!-- Thanks for using https://jar-download.com -->

</dependencies>
<build>
Expand Down
10 changes: 4 additions & 6 deletions src/main/java/cn/com/x1001/Agent.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package cn.com.x1001;


import cn.com.x1001.hook.BpCrack;
import cn.com.x1001.hook.HookTransformer;
import cn.com.x1001.watch.ClassFileWatch;
import cn.com.x1001.watch.HookWatch;
Expand All @@ -21,16 +20,15 @@ public static void premain(String args, Instrumentation inst){
}

private static void start(Instrumentation inst) {
out.println("********************************************************************");
out.println("* Run Success *");
out.println("********************************************************************");
inst.addTransformer(new BpCrack());
inst.addTransformer(new HookTransformer(), true);
try {
new ClassFileWatch().start();
} catch (IOException e) {
e.printStackTrace();
}
out.println("********************************************************************");
out.println("* Run Success *");
out.println("********************************************************************");
inst.addTransformer(new HookTransformer(), true);
new HookWatch(inst).start();
}
}
169 changes: 117 additions & 52 deletions src/main/java/cn/com/x1001/InstrumentationContext.java
Original file line number Diff line number Diff line change
@@ -1,40 +1,37 @@
package cn.com.x1001;

import cn.com.x1001.classmap.ClassInfo;
import cn.com.x1001.classmap.Edge;
import cn.com.x1001.classmap.GraphNode;
import cn.com.x1001.classmap.HookGraph;
import cn.com.x1001.classmap.*;
import cn.com.x1001.util.ClassUtil;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

/**
* @author keven1z
* @Date 2021/6/17
* @author keven1z
* @Date 2021/6/17
* @Description hook 的上下文信息
*/
*/
public class InstrumentationContext {

/**
* 类的图集合
*/
private HookGraph classMap = new HookGraph();
/*
* 存储hook的接口或类
*/
private Set<ClassInfo> hookClasses = new CopyOnWriteArraySet();
* 存储hook的接口或类
*/
private CopyOnWriteArraySet<HookClass> hookClasses = new CopyOnWriteArraySet<>();


public Set<ClassInfo> getClassHashSet() {
public CopyOnWriteArraySet<HookClass> getClassHashSet() {
return hookClasses;
}

public void addHook(ClassInfo classInfo) {
this.getClassHashSet().add(classInfo);
public void addHook(HookClass hookClass) {
this.getClassHashSet().add(hookClass);
}

public HookGraph getClassMap() {
return classMap;
}
Expand All @@ -43,68 +40,136 @@ public HookGraph getClassMap() {
* 是否为hook点
*/
public boolean isHookClass(String className) {
for (ClassInfo hookClassInfo : getClassHashSet()) {
String hookClassName = hookClassInfo.getClassName();
for (HookClass hookHookClass : getClassHashSet()) {
String hookClassName = hookHookClass.getClassName();
if (hookClassName.equals(className)) {
return true;
}
}
return false;
}
public void setHooked(String className){
GraphNode node = this.getClassMap().getNode(className);
node.hooked();

public boolean isHookClass(String className, String method, String desc) {
for (HookClass hookHookClass : getClassHashSet()) {
String hookClassName = hookHookClass.getClassName();
String m = hookHookClass.getMethod();
String d = hookHookClass.getDesc();
if (hookClassName.equals(className) && m.equals(method) && d.equals(desc)) {
return true;
}
}
return false;
}
public ClassInfo getHookClass(String className) {
for (ClassInfo hookClassInfo : getClassHashSet()) {
String hookClassName = hookClassInfo.getClassName();
if (hookClassName.equals(className)) {
return hookClassInfo;

public HookClass getHookClass(Set<HookClass> hookClasses, String method, String desc) {

for (HookClass hookClass : hookClasses) {
String m = hookClass.getMethod();
String d = hookClass.getDesc();
if (m.equals(method) && d.equals(desc)) {
return hookClass;
}
}
return null;
}
public void addHooKClass(String className,ClassInfo hookClass){
ClassInfo vertex = getClassMap().getVertex(className);
vertex.setMethodDesc(hookClass.getMethodDesc());
getClassHashSet().add(vertex);

public HookClass getHookClass(String className, String method, String desc) {
Set<HookClass> hookClasses = getHookClasses(className);
for (HookClass hookClass : hookClasses) {
String m = hookClass.getMethod();
String d = hookClass.getDesc();
if (m.equals(method) && d.equals(desc)) {
return hookClass;
}
}
return null;
}

/**
* 設置已hook
*/
public void setHooked(String className) {
Set<HookClass> hookClasses = getHookClasses(className);
for (HookClass hookClass : hookClasses) {
hookClass.setHooked(true);
}
}

public Set<HookClass> getHookClasses(String className) {
HashSet<HookClass> hashSet = new HashSet<>();
for (HookClass hookHookClass : getClassHashSet()) {
String hookClassName = hookHookClass.getClassName();
if (hookClassName.equals(className)) {
hashSet.add(hookHookClass);
}
}
return hashSet;
}

public boolean containAction(String className, int action) {
Set<HookClass> hookClasses = getHookClasses(className);
for (HookClass hookClass : hookClasses) {
Set<Integer> actions = hookClass.getActions();
if (actions.contains(action)) return true;
}
return false;
}

/**
* 通过父类增加hook点
*
* @param className
* @param superClassName
*/
public void addHooKClass(String className, String superClassName) {
Set<HookClass> superHookClasses = getHookClasses(superClassName);
for (HookClass hookClass : superHookClasses) {
HookClass hc = new HookClass(className, hookClass.getMethod(), hookClass.getDesc(), hookClass.getReturnValue(), hookClass.getParameters(), hookClass.getActions());
getClassHashSet().add(hc);
}
}
public void addHooKClass(Set<ClassInfo> classInfoHashSet,ClassInfo hookClass){
for (ClassInfo classInfo :classInfoHashSet){
classInfo.setMethodDesc(hookClass.getMethodDesc());

public void addHooKClass(String className, Set<ClassVertex> childClasses) {
Set<HookClass> hookClasses = getHookClasses(className);

for (HookClass hookClass : hookClasses) {
for (ClassVertex classVertex : childClasses) {
HookClass hc = new HookClass(classVertex.getClassName(), hookClass.getMethod(), hookClass.getDesc(), hookClass.getReturnValue(), hookClass.getParameters(), hookClass.getActions());
getClassHashSet().add(hc);
}
}
getClassHashSet().addAll(classInfoHashSet);
}

/**
* 判断该节点的父类是否在hook表中
*
* @param className 待hook的className
*/
public Set<ClassInfo> getChildHookClasses(String className){
ClassInfo superClassInfo = getClassMap().getVertex(className);
HashSet<Edge> toEdges = getClassMap().getToEdges(superClassInfo);
HashSet<ClassInfo> classInfos = new HashSet<>();
for(Edge edge:toEdges){
ClassInfo from = edge.getFrom();
if (!ClassUtil.isInterface(from.getAccess())){
classInfos.add(from);
}
else classInfos.addAll(getChildHookClasses(from.getClassName()));
public Set<ClassVertex> getChildClasses(String className) {
ClassVertex vertex = classMap.getVertex(className);
HashSet<Edge> toEdges = getClassMap().getToEdges(vertex);
HashSet<ClassVertex> classVertices = new HashSet<>();
for (Edge edge : toEdges) {
ClassVertex from = edge.getFrom();
if (!ClassUtil.isInterface(from.getAccess())) {
classVertices.add(from);
} else classVertices.addAll(getChildClasses(from.getClassName()));
}
return classInfos;
return classVertices;
}
public ClassInfo getSuperHookClasses(String className){
ClassInfo classInfo = getClassMap().getVertex(className);

public ClassVertex getSuperClasses(String className) {
ClassVertex classVertex = getClassMap().getVertex(className);
/*如果为接口则不加入hook点*/
if (ClassUtil.isInterface(classInfo.getAccess())){
if (ClassUtil.isInterface(classVertex.getAccess())) {
return null;
}
HashSet<Edge> fromEdges = getClassMap().getFromEdges(classInfo);
for(Edge edge:fromEdges){
ClassInfo to = edge.getTo();
if (isHookClass(to.getClassName())){
HashSet<Edge> fromEdges = getClassMap().getFromEdges(classVertex);
for (Edge edge : fromEdges) {
ClassVertex to = edge.getTo();
if (isHookClass(to.getClassName())) {
return to;
}
else getSuperHookClasses(to.getClassName());
} else getSuperClasses(to.getClassName());
}
return null;
}
Expand Down
Loading

0 comments on commit 747dacb

Please sign in to comment.