-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathmain.go
126 lines (120 loc) · 2.86 KB
/
main.go
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
126
package main
import (
"flag"
"fmt"
"github.com/4ra1n/accelerator/classfile"
"github.com/4ra1n/accelerator/core"
"github.com/4ra1n/accelerator/files"
"github.com/4ra1n/accelerator/global"
"github.com/4ra1n/accelerator/ref"
"github.com/4ra1n/accelerator/rule"
"io/ioutil"
"strings"
)
var (
ruleFile string
jarsDir string
)
func main() {
// resolve input
flag.StringVar(&ruleFile, "rule", "rule.txt", "rule file")
flag.StringVar(&jarsDir, "jars", ".", "your jars dir")
flag.Parse()
// delete temp dir
files.RemoveTempFiles()
// extract all jars to temp dir
files.UnzipJars(jarsDir)
// traverse to get all class files
classes := files.ReadAllClasses()
for _, c := range classes {
// analyze each class file separately
start(c)
}
files.RemoveTempFiles()
}
func start(class string) {
data, err := ioutil.ReadFile(class)
cf, err := classfile.Parse(data)
if err != nil {
panic(err)
}
cl := ref.NewClass(cf)
// constant pool cache
// refresh cp in each new class file
global.CP = cf.ConstantPool()
for _, method := range cf.Methods() {
codeAttr := method.CodeAttribute()
if codeAttr == nil {
// interface or abstract
continue
}
bytecode := codeAttr.Code()
// virtual thread
thread := core.Thread{}
reader := &core.BytecodeReader{}
// save all instructions to struct
instSet := core.InstructionSet{}
instSet.ClassName = cl.Name()
instSet.MethodName = method.Name()
instSet.Desc = method.Descriptor()
for {
// read finish
if thread.PC() >= len(bytecode) {
break
}
// offset
reader.Reset(bytecode, thread.PC())
// read instruction
opcode := reader.ReadUint8()
inst := core.NewInstruction(opcode)
// read operands of the instruction
inst.FetchOperands(reader)
ops := inst.GetOperands()
instEntry := core.InstructionEntry{
Instrument: getInstructionName(inst),
Operands: ops,
}
instSet.InstArray = append(instSet.InstArray, instEntry)
// offset++
thread.SetPC(reader.PC())
}
doAnalysis(instSet)
}
}
func getInstructionName(instruction core.Instruction) string {
// type name -> instruction name
i := fmt.Sprintf("%T", instruction)
return strings.Split(i, ".")[1]
}
func doAnalysis(instSet core.InstructionSet) {
analysisRule := rule.GetRule(ruleFile)
if len(analysisRule) == 0 {
panic("error rule file")
}
ruleLen := len(analysisRule)
var ruleLenState []bool
i := 0
for _, inst := range instSet.InstArray {
if inst.Instrument != analysisRule[i][0] {
continue
}
splits := strings.Split(inst.Operands[0], " ")
stdName := splits[0]
stdDesc := splits[1]
if analysisRule[i][1] != stdName {
continue
}
if analysisRule[i][2] == stdDesc ||
analysisRule[i][2] == "*" {
ruleLenState = append(ruleLenState, true)
if i != ruleLen-1 {
i++
} else {
break
}
}
}
if len(ruleLenState) == ruleLen {
fmt.Println(instSet.ClassName, instSet.MethodName)
}
}