ByteCodeDL 学习

系列 - 静态软件分析

ByteCodeDL也是一款java字节码静态分析工具,它借助了soot-fact-generator + Souffle 两个工具实现了一款声明式的静态分析工具。

声明式和命令式概念参见 https://www.aqee.net/post/imperative-vs-declarative/

其中soot-fact-generator的作用在于为souffle生成fact事实,也就是生成数据集。

souffle根据facts以及我们给定的规则语句(以.dl为后缀的文件)来进行查询。

ByteCodeDL为我们编写了一些已经写好的规则,比如callgraph/cha(Class hierarchy analysis)/PTA指针分析及P/Taint污点分析等,可以根据自己需求编写相应dl文件实现静态分析。规则文件移步 https://github.com/BytecodeDL/ByteCodeDL/tree/main/logic

关于Datalog-Based Program Analysis这部分的原理应该先看李樾和谭添老师的ppt https://pascal-group.bitbucket.io/lectures/Datalog.pdf

本文只是根据文档过一遍,带读者简单了解bytecodedl。

环境

安装souffle 见https://souffle-lang.github.io/install

1
2
3
4
sudo wget https://souffle-lang.github.io/ppa/souffle-key.public -O /usr/share/keyrings/souffle-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/souffle-archive-keyring.gpg] https://souffle-lang.github.io/ppa/ubuntu/ stable main" | sudo tee /etc/apt/sources.list.d/souffle.list
sudo apt update
sudo apt install souffle

然后下载BytecodeDL打包好的soot-fact-generator.jar

souffle demo

以官方给的例子来看 https://souffle-lang.github.io/simple

给定一个edge.facts如下

1
2
1	2
2	3

再给定一个example.dl

1
2
3
4
5
6
7
8
.decl edge(x:number, y:number)
.input edge

.decl path(x:number, y:number)
.output path

path(x, y) :- edge(x, y).
path(x, y) :- path(x, z), edge(z, y).

其中两个.decl分别表示input、output传入传出关系,这表示从磁盘读入edge.facts并将path.csv结果集写入磁盘。

path(x, y) :- edge(x, y).表示:如果存在x->y的一条edge边,那么就存在x->y的一条path路径。

path(x, y) :- path(x, z), edge(z, y).则表示:如果x到z有条路径,并且z到y有条边,那么就可以推理出x到y也有路径。

我们使用souffle查询一下看看结果。

1
2
3
4
5
6
7
8
ubuntu@ubuntu:~$ cat edge.facts
1       2
2       3
ubuntu@ubuntu:~$ souffle -F. -D. example.dl
ubuntu@ubuntu:~$ cat path.csv
1	2
2	3
1	3

输出了三条路径

这是最简单的一个demo,而soot-fact-generator则是用来生成facts的。

soot-fact-generator

ByteCodeDL提供的soot-fact-generator是来自于另一个静态分析框架 https://bitbucket.org/yanniss/doop/src/master/generators/

doop本身就是使用souffle来做Java Pointer and Taint Analysis的工具,并且其本身有一些分析规则https://bitbucket.org/yanniss/doop/src/master/souffle-logic/

ByteCodeDL将doop的generator提取了出来,用doop的代码来生成facts。

然后自己写规则实现功能。

这节我们用 https://github.com/BytecodeDL/Benchmark 来生成facts数据集。

下载https://github.com/BytecodeDL/Benchmark 然后maven package。

运行soot-fact-generator

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
ubuntu@ubuntu:~$ java -jar soot-fact-generator.jar -i Benchmark-1.0-SNAPSHOT.jar -l /usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/rt.jar --generate-jimple --allow-phantom --full -d out
No logs directory set, using: out/logs
Logging initialized, using directory: out/logs
WARNING: 'file.encoding' property missing or not UTF8, please pass: -Dfile.encoding=UTF-8
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
WARNING: SSA not enabled, generating Jimple instead of Shimple
Preprocessing application: Benchmark-1.0-SNAPSHOT.jar
Preprocessing platform library: /usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/rt.jar
Adding archive: Benchmark-1.0-SNAPSHOT.jar
Adding archive for resolving: /usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/rt.jar
Classes in input (application) jar(s): 85
Total classes in Scene: 3695
Retrieved all bodies (time: 11)
Fact generation cores: 16
WARNING: some classes were not resolved, consider using thorough fact generation or adding them manually via --also-resolve: [sun.util.locale.provider.HostLocaleProviderAdapterImpl, java.lang.annotation.Inherited]
Found 74 phantom references. Rerun with '--report-phantoms' for more details.
Total classes (application, dependencies and SDK) to generate Jimple for: 3695
Soot: hierarchy_dirs set.
Methods without active bodies encountered (and reset): 0

在out目录下会生成facts文件

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
ubuntu@ubuntu:~$ find out/*.facts
out/Activity.facts
out/ActualParam.facts
out/AndroidApplication.facts
out/AndroidCallbackMethodName.facts
out/AndroidEntryPoint.facts
out/AndroidId.facts
out/AndroidIncludeXML.facts
out/AnnotationElement.facts
out/ApplicationClass.facts
out/ApplicationPackage.facts
out/ArrayAllocationConstSize.facts
out/ArrayAllocation.facts
out/ArrayInitialValueFromConst.facts
out/ArrayInitialValueFromLocal.facts
out/ArrayInsnIndex.facts
out/ArrayNumIndex.facts
out/ArrayType.facts
out/AssignBinop.facts
out/AssignCast.facts
out/AssignCastNull.facts
out/AssignCastNumConstant.facts
out/AssignHeapAllocation.facts
out/AssignInstanceOf.facts
out/AssignLocal.facts
out/AssignNull.facts
out/AssignNumConstant.facts
out/AssignOperFromConstant.facts
out/AssignOperFrom.facts
out/AssignPhantomInvoke.facts
out/AssignReturnValue.facts
out/AssignUnop.facts
out/BootstrapParam.facts
out/BreakpointStmt.facts
out/BroadcastReceiver.facts
out/Class-Artifact.facts
out/ClassHeap.facts
out/ClassModifier.facts
out/ClassType.facts
out/ComponentType.facts
out/ContentProvider.facts
out/DexInstructionAddressMap.facts
out/DirectSuperclass.facts
out/DirectSuperinterface.facts
out/DummyIfVar.facts
out/DynamicMethodInvocation.facts
out/DynamicMethodInvocation-ParamType.facts
out/EmptyArray.facts
out/EnterMonitor.facts
out/ExceptionHandler.facts
out/ExceptionHandler-FormalParam.facts
out/ExceptionHandler-Previous.facts
out/ExitMonitor.facts
out/Field-Annotation.facts
out/Field.facts
out/FieldInitialValue.facts
out/Field-Modifier.facts
out/FormalParam.facts
out/GenericField.facts
out/GenericType-ErasedType.facts
out/GenericTypeParameters.facts
out/Goto.facts
out/IfConstant.facts
out/If.facts
out/IfVar.facts
out/InterfaceType.facts
out/LayoutControl.facts
out/LoadArrayIndex.facts
out/LoadInstanceField.facts
out/LoadStaticField.facts
out/LookupSwitch-Default.facts
out/LookupSwitch.facts
out/LookupSwitch-Target.facts
out/Method-Annotation.facts
out/Method-DeclaresException.facts
out/Method.facts
out/MethodHandleConstant.facts
out/MethodInvocation-Line.facts
out/Method-Modifier.facts
out/MethodTypeConstant.facts
out/MethodTypeConstantParam.facts
out/NativeLibEntryPoint.facts
out/NativeMethodId.facts
out/NativeMethodTypeCandidate.facts
out/NativeNameCandidate.facts
out/NativeReturnVar.facts
out/NativeXRef.facts
out/NormalHeap.facts
out/NumConstantRaw.facts
out/OperatorAt.facts
out/Param-Annotation.facts
out/PhantomBasedMethod.facts
out/PhantomMethod.facts
out/PhantomType.facts
out/PolymorphicInvocation.facts
out/Properties.facts
out/Return.facts
out/ReturnVoid.facts
out/SensitiveLayoutControl.facts
out/Service.facts
out/SpecialMethodInvocation.facts
out/StatementType.facts
out/StaticMethodInvocation.facts
out/StoreArrayIndex.facts
out/StoreInstanceField.facts
out/StoreStaticField.facts
out/StringConstant.facts
out/StringRaw.facts
out/SuperMethodInvocation.facts
out/TableSwitch-Default.facts
out/TableSwitch.facts
out/TableSwitch-Target.facts
out/ThisVar.facts
out/Throw.facts
out/ThrowNull.facts
out/Type-Annotation.facts
out/Type-SimpleName.facts
out/UnsupportedInstruction.facts
out/Var-DeclaringMethod.facts
out/Var-SimpleName.facts
out/Var-Type.facts
out/VirtualMethodInvocation.facts
out/XMLNodeAttribute.facts
out/XMLNodeData.facts
out/XMLNode.facts

其中每个facts文件对应了不同的关系,比如Method.facts

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
ubuntu@ubuntu:~$ cat out/Method.facts|head -10
<java.net.ProxySelector: void <init>()> <init>          java.net.ProxySelector  void    ()V     0
<java.lang.invoke.MethodHandleImpl$CountingWrapper: void <init>(java.lang.invoke.MethodHandle,java.lang.invoke.LambdaForm,java.util.function.Function,java.util.function.Function,int)> <init>  java.lang.invoke.MethodHandle,java.lang.invoke.LambdaForm,java.util.function.Function,java.util.function.Function,int    java.lang.invoke.MethodHandleImpl$CountingWrapper       void    (Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/LambdaForm;Ljava/util/function/Function;Ljava/util/function/Function;I)V       5
<sun.text.normalizer.UBiDiProps$IsAcceptable: void <init>(sun.text.normalizer.UBiDiProps)>      <init>  sun.text.normalizer.UBiDiProps  sun.text.normalizer.UBiDiProps$IsAcceptable     void    (Lsun/text/normalizer/UBiDiProps;)V      1
<java.lang.UNIXProcess$Platform: java.lang.UNIXProcess$Platform[] values()>     values          java.lang.UNIXProcess$Platform  java.lang.UNIXProcess$Platform[]        ()[Ljava/lang/UNIXProcess$Platform;     0
<sun.invoke.util.VerifyAccess: void <init>()>   <init>          sun.invoke.util.VerifyAccess    void    ()V     0
<java.util.WeakHashMap$KeySpliterator: void <init>(java.util.WeakHashMap,int,int,int,int)>      <init>  java.util.WeakHashMap,int,int,int,int   java.util.WeakHashMap$KeySpliterator    void    (Ljava/util/WeakHashMap;IIII)V   5
<java.util.stream.Tripwire: void <init>()>      <init>          java.util.stream.Tripwire       void    ()V     0
<java.util.BitSet: int wordIndex(int)>  wordIndex       int     java.util.BitSet        int     (I)I    1
<sun.invoke.util.VerifyAccess: boolean isMemberAccessible(java.lang.Class,java.lang.Class,int,java.lang.Class,int)>     isMemberAccessible      java.lang.Class,java.lang.Class,int,java.lang.Class,int sun.invoke.util.VerifyAccess     boolean (Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class;I)Z        5
<java.net.ProxySelector: java.net.ProxySelector getDefault()>   getDefault              java.net.ProxySelector  java.net.ProxySelector  ()Ljava/net/ProxySelector;      0

facts默认用\t做分隔符,抽出一行来看

1
<sun.invoke.util.VerifyAccess: boolean isMemberAccessible(java.lang.Class,java.lang.Class,int,java.lang.Class,int)>     isMemberAccessible      java.lang.Class,java.lang.Class,int,java.lang.Class,int sun.invoke.util.VerifyAccess     boolean (Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class;I)Z        5

这行对应sun.invoke.util.VerifyAccess#isMemberAccessible,以\t分隔每一列又对应到函数的不同属性。

再者说MethodInvocation-Line.facts

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
ubuntu@ubuntu:~$ cat out/MethodInvocation-Line.facts |head -10
<sun.invoke.util.VerifyAccess: void <init>()>/java.lang.Object.<init>/0 38
<java.net.ProxySelector: void <init>()>/java.lang.Object.<init>/0       60
<java.util.stream.Tripwire: void <init>()>/java.lang.Object.<init>/0    55
<java.util.WeakHashMap$KeySpliterator: void <init>(java.util.WeakHashMap,int,int,int,int)>/java.util.WeakHashMap$WeakHashMapSpliterator.<init>/0        1102
<sun.text.normalizer.UBiDiProps$IsAcceptable: void <init>(sun.text.normalizer.UBiDiProps)>/java.lang.Object.<init>/0    107
<java.lang.UNIXProcess$Platform: java.lang.UNIXProcess$Platform[] values()>/java.lang.Object.clone/0    81
<java.net.ProxySelector: java.net.ProxySelector getDefault()>/java.lang.System.getSecurityManager/0     92
<java.lang.invoke.MethodHandleImpl$CountingWrapper: void <init>(java.lang.invoke.MethodHandle,java.lang.invoke.LambdaForm,java.util.function.Function,java.util.function.Function,int)>/java.lang.invoke.MethodHandle.type/0     810
<java.lang.invoke.MethodHandleImpl$CountingWrapper: void <init>(java.lang.invoke.MethodHandle,java.lang.invoke.LambdaForm,java.util.function.Function,java.util.function.Function,int)>/java.lang.invoke.DelegatingMethodHandle.<init>/0 810
<java.net.ProxySelector: java.net.ProxySelector getDefault()>/java.lang.SecurityManager.checkPermission/0       94

记录了method call的行号。

那么通过facts文件我们就有了静态软件分析中所需要的东西。

写规则

soot-fact-generator.jar 为我们提供了各种所需要的结果集

https://y4er.com/img/uploads/bytecodedl/1.png

我们一步一步来实现静态分析。

从基本的Class Hierarchy开始,我们需要构建一个类型层次图,用于寻找某个类的子类、父类,或者用于判断两个类之间是否有继承关系。

generator为我们生成了facts结果集

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
ubuntu@ubuntu:~$ cat out/DirectSuperclass.facts |head -10
java.lang.UNIXProcess$Platform  java.lang.Enum
sun.text.normalizer.UBiDiProps$IsAcceptable     java.lang.Object
java.net.ProxySelector  java.lang.Object
java.lang.invoke.MethodHandleImpl$CountingWrapper       java.lang.invoke.DelegatingMethodHandle
java.util.WeakHashMap$KeySpliterator    java.util.WeakHashMap$WeakHashMapSpliterator
java.util.BitSet        java.lang.Object
sun.invoke.util.VerifyAccess    java.lang.Object
java.util.stream.Tripwire       java.lang.Object
sun.text.normalizer.ReplaceableString   java.lang.Object
java.net.StandardSocketOptions  java.lang.Object

可以看到具体的继承关系。extend对应的是DirectSuperclass.facts,implement对应的是DirectSuperinterface.facts。

1
2
3
4
5
6
7
.type Class <: symbol

.decl DirectSuperclass(child:Class, parent:Class)
.input DirectSuperclass

.decl DirectSuperinterface(child:Class, parent:Class)
.input DirectSuperinterface

递归判断子类关系

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
.type Class <: symbol

.decl ClassModifier(mod:symbol, class:Class)
.input ClassModifier

.decl ClassType(class:Class)
.input ClassType

.decl InterfaceType(interface:Class)
.input InterfaceType

.decl DirectSuperclass(child:Class, parent:Class)
.input DirectSuperclass

.decl DirectSuperinterface(child:Class, parent:Class)
.input DirectSuperinterface

.decl SubClass(subclass:Class, class:Class)
.output SubClass


SubClass(subclass, class) :- DirectSuperclass(subclass, class).
SubClass(subclass, class) :- DirectSuperinterface(subclass, class).
SubClass(subclass, class) :-
    (
        DirectSuperclass(subclass, tmp);
        DirectSuperinterface(subclass, tmp)
    ),
    SubClass(tmp, class).

运行并且查看输出结果

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
ubuntu@ubuntu:~$ souffle -F out/ -D . example.dl  ; cat SubClass.csv |head -n 10
java.lang.UNIXProcess$Platform  java.lang.Enum
java.lang.UNIXProcess$Platform  java.lang.Object
java.lang.UNIXProcess$Platform  java.io.Serializable
java.lang.UNIXProcess$Platform  java.lang.Comparable
java.lang.Enum  java.lang.Object
java.lang.Enum  java.io.Serializable
java.lang.Enum  java.lang.Comparable
sun.text.normalizer.UBiDiProps$IsAcceptable     java.lang.Object
sun.text.normalizer.UBiDiProps$IsAcceptable     sun.text.normalizer.ICUBinary$Authenticate
java.net.ProxySelector  java.lang.Object

https://y4er.com/img/uploads/bytecodedl/2.png

对于static call和special call都是在编译时就确定调用者的具体类型的,而virtual call需要在实际运行时根据obj的实际类型判断函数调用。由此一来如何确定obj的运行时类型,成为了调用图构造的关键。

对于cha算法而言

https://y4er.com/img/uploads/bytecodedl/3.png

receiver在实际运行的过程中的类型可以是其声明类型的任意非abstract子类。所以我们需要一个Dispatch来进行method dispatch。

这里直接贴ByteCodeDL的文档 https://github.com/BytecodeDL/ByteCodeDL/blob/main/docs/utils.md#method-dispatch

1
2
3
4
5
6
7
8
9
Dispatch(simplename, descriptor, class, method) :-
    MethodInfo(method, simplename, _, class, _, descriptor, _),
    !MethodModifier("abstract", method).

Dispatch(simplename, descriptor, class, method) :-
    !MethodInfo(_, simplename, _, class, _, descriptor, _),
    DirectSuperclass(class, superclass),
    Dispatch(simplename, descriptor, superclass, method),
    !MethodModifier("abstract", method).

第一个Dispatch表示如果class中有签名相对并且修饰符不为abstract的method则返回method,第二个Dispatch表示如果没从当前class中找到method则去从该class的superclass中寻找对应签名并且不是abstract的method。

有了dispatch之后就可以实现cha调用图了,代码还是直接看https://github.com/BytecodeDL/ByteCodeDL/blob/main/logic/cha.dl

还有一个rta算法,不在这里写了,直接看文档,ByteCodeDL也实现了。

针对不同的需求,我们需要找特定类,那么这个时候cha调用图就比较有用了。

官方文档以ezchain hfctf2022为例,讲解了cha的实际使用。该ctf给了一个getter,禁用已知链,让自己找getter来rce。

那么有了如下代码

用SinkDesc声明我们要的sink

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#define MAXSTEP 5
#define CHAO 2

#include "../logic/cha.dl"


.decl NonParamPublicMethod(method:Method, class:Class)
.output NonParamPublicMethod

SinkDesc("exec", "java.lang.Runtime").
SinkDesc("<init>", "java.lang.ProcessBuilder").
SinkDesc("start", "java.lang.ProcessImpl").
SinkDesc("loadClass", "java.lang.ClassLoader").
SinkDesc("defineClass", "java.lang.ClassLoader").
SinkDesc("readObject", "java.io.ObjectInputStream").
SinkDesc("readExternal", "java.io.ObjectInputStream").


EntryMethod(method),
Reachable(method, 0),
NonParamPublicMethod(method, class) :- 
    MethodInfo(method, simplename, _, class, _, _, arity),
    MethodModifier("public", method),
    contains("get", simplename),
    arity = 0.

.output SinkMethod

https://y4er.com/img/uploads/bytecodedl/4.png

找到entry为<java.security.SignedObject: java.lang.Object getObject()>的method

可以将结果导入到neo4j中进行可视化。

1
bash importOutput2Neo4j.sh neoImportCall.sh dbname

不演示了

这里提一嘴,相对tabby来讲,ByteCodeDL使用souffle减少了输入源,更快。用了指针分析,更准。

缺点也很明显,语法更变态,自定义规则头发直接掉完,文档少、规则库不够完善,门槛比tabby高太多。

这里算法我讲不明白了,直接看ByteCodeDL文档把。

指针分析的一个简单例子

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#include "inputDeclaration.dl"
#include "utils.dl"
#include "pt-noctx.dl"

// 实例化 component
.init cipt = ContextInsensitivePt

// 初始化readchable
cipt.Reachable(method) :-
    MethodInfo(method, simplename, _, _, _, descriptor, _),
    simplename = "main",
    descriptor = "([Ljava/lang/String;)V".

.output cipt.VarPointsTo

这样可以查询出method name为main并且函数签名是([Ljava/lang/String;)V的函数,可以传播到的点结果集。

截出一部分结果集来看

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<com.bytecodedl.benchmark.demo.TaintDemo1: void main(java.lang.String[])>/new com.bytecodedl.benchmark.demo.TaintDemo1/0        <com.bytecodedl.benchmark.demo.TaintDemo1: void <init>()>/@this
<com.bytecodedl.benchmark.demo.TaintDemo1: void main(java.lang.String[])>/new com.bytecodedl.benchmark.demo.TaintDemo1/0        <com.bytecodedl.benchmark.demo.TaintDemo1: void <init>()>/this#_0
<com.bytecodedl.benchmark.demo.TaintDemo1: void main(java.lang.String[])>/new com.bytecodedl.benchmark.demo.TaintDemo1/0        <com.bytecodedl.benchmark.demo.TaintDemo1: void main(java.lang.String[])>/demo#_8
<com.bytecodedl.benchmark.demo.TaintDemo1: void main(java.lang.String[])>/new com.bytecodedl.benchmark.demo.TaintDemo1/0        <com.bytecodedl.benchmark.demo.TaintDemo1: void test1(java.lang.String)>/@this
<com.bytecodedl.benchmark.demo.TaintDemo1: void main(java.lang.String[])>/new com.bytecodedl.benchmark.demo.TaintDemo1/0        <com.bytecodedl.benchmark.demo.TaintDemo1: void test1(java.lang.String)>/this#_0
<com.bytecodedl.benchmark.demo.TaintDemo1: void main(java.lang.String[])>/new com.bytecodedl.benchmark.demo.TaintDemo1/0        <com.bytecodedl.benchmark.demo.TaintDemo1: void Sink(java.lang.String)>/@this
<com.bytecodedl.benchmark.demo.TaintDemo1: void main(java.lang.String[])>/new com.bytecodedl.benchmark.demo.TaintDemo1/0        <com.bytecodedl.benchmark.demo.TaintDemo1: void Sink(java.lang.String)>/this#_0
<com.bytecodedl.benchmark.demo.TaintDemo1: void Sink(java.lang.String)>/new java.lang.StringBuilder/0   <com.bytecodedl.benchmark.demo.TaintDemo1: void Sink(java.lang.String)>/builder#_19
<com.bytecodedl.benchmark.demo.TaintDemo1: void main(java.lang.String[])>/new com.bytecodedl.benchmark.demo.TaintDemo1/0        <com.bytecodedl.benchmark.demo.TaintDemo1: java.lang.String Source()>/@this
<com.bytecodedl.benchmark.demo.TaintDemo1: void main(java.lang.String[])>/new com.bytecodedl.benchmark.demo.TaintDemo1/0        <com.bytecodedl.benchmark.demo.TaintDemo1: java.lang.String Source()>/this#_0

对应的代码为

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.bytecodedl.benchmark.demo;

public class TaintDemo1 {
    public static void main(String[] args) {
        TaintDemo1 demo = new TaintDemo1();
        String name = demo.Source();
        demo.test1(name);
    }

    public void test1(String name){
        String sql = "select * from user where name='" + name + "'";
        Sink(sql);
    }

    public void Sink(String param){
        StringBuilder builder = new StringBuilder();
        builder.append(param);
    }

    public String Source(){
        return "tainted name";
    }
}

没啥问题。

这里不详细写了,直接贴我在官方GitHub的discussions

  1. 使用ByteCodeDL分析长城杯CTF b4bycoffee

我只是给官方作者提需求,规则还是作者写的。

文笔垃圾,措辞轻浮,内容浅显,操作生疏。不足之处欢迎大师傅们指点和纠正,感激不尽。