forked from projectdiscovery/nuclei
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathhexdump.go
130 lines (110 loc) · 4.17 KB
/
hexdump.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
127
128
129
130
package responsehighlighter
import (
"errors"
"fmt"
"regexp"
"strings"
"unicode"
"github.com/projectdiscovery/gologger"
)
// [0-9a-fA-F]{8} {2} - hexdump indexes (8 character hex value followed by two spaces)
// [0-9a-fA-F]{2} + - 2 character long hex values followed by one or two space (potentially wrapped with an ASCII color code, see below)
// \x1b\[(\d;?)+m - ASCII color code pattern
// \x1b\[0m - ASCII color code reset
// \|(.*)\|\n - ASCII representation of the input delimited by pipe characters
var hexDumpParsePattern = regexp.MustCompile(`([0-9a-fA-F]{8} {2})((?:(?:\x1b\[(?:\d;?)+m)?[0-9a-fA-F]{2}(?:\x1b\[0m)? +)+)\|(.*)\|\n`)
var hexValuePattern = regexp.MustCompile(`([a-fA-F0-9]{2})`)
type HighlightableHexDump struct {
index []string
hex []string
ascii []string
}
func NewHighlightableHexDump(rowSize int) HighlightableHexDump {
return HighlightableHexDump{index: make([]string, 0, rowSize), hex: make([]string, 0, rowSize), ascii: make([]string, 0, rowSize)}
}
func (hexDump HighlightableHexDump) len() int {
return len(hexDump.index)
}
func (hexDump HighlightableHexDump) String() string {
var result string
for i := 0; i < hexDump.len(); i++ {
result += hexDump.index[i] + hexDump.hex[i] + "|" + hexDump.ascii[i] + "|\n"
}
return result
}
func toHighLightedHexDump(hexDump, snippetToHighlight string) (HighlightableHexDump, error) {
hexDumpRowValues := hexDumpParsePattern.FindAllStringSubmatch(hexDump, -1)
if hexDumpRowValues == nil || len(hexDumpRowValues) != strings.Count(hexDump, "\n") {
message := "could not parse hexdump"
gologger.Warning().Msgf(message)
return HighlightableHexDump{}, errors.New(message)
}
result := NewHighlightableHexDump(len(hexDumpRowValues))
for _, currentHexDumpRowValues := range hexDumpRowValues {
result.index = append(result.index, currentHexDumpRowValues[1])
result.hex = append(result.hex, currentHexDumpRowValues[2])
result.ascii = append(result.ascii, currentHexDumpRowValues[3])
}
return result.highlight(snippetToHighlight), nil
}
func (hexDump HighlightableHexDump) highlight(snippetToColor string) HighlightableHexDump {
return highlightAsciiSection(highlightHexSection(hexDump, snippetToColor), snippetToColor)
}
func highlightHexSection(hexDump HighlightableHexDump, snippetToColor string) HighlightableHexDump {
var snippetHexCharactersMatchPattern string
for _, char := range snippetToColor {
snippetHexCharactersMatchPattern += fmt.Sprintf(`(%02x[ \n]+)`, char)
}
hexDump.hex = highlight(hexDump.hex, snippetHexCharactersMatchPattern, func(v string) string {
return hexValuePattern.ReplaceAllString(v, addColor("$1"))
})
return hexDump
}
func highlightAsciiSection(hexDump HighlightableHexDump, snippetToColor string) HighlightableHexDump {
var snippetCharactersMatchPattern string
for _, v := range snippetToColor {
var value string
if IsASCIIPrintable(v) {
value = regexp.QuoteMeta(string(v))
} else {
value = "."
}
snippetCharactersMatchPattern += fmt.Sprintf(`(%s\n*)`, value)
}
hexDump.ascii = highlight(hexDump.ascii, snippetCharactersMatchPattern, func(v string) string {
if len(v) > 1 {
return addColor(string(v[0])) + v[1:] // do not color new line characters
}
return addColor(v)
})
return hexDump
}
func highlight(values []string, snippetCharactersMatchPattern string, replaceToFunc func(v string) string) []string {
rows := strings.Join(values, "\n")
compiledPattern := regexp.MustCompile(snippetCharactersMatchPattern)
for _, submatch := range compiledPattern.FindAllStringSubmatch(rows, -1) {
var replaceTo string
var replaceFrom string
for _, matchedValueWithSuffix := range submatch[1:] {
replaceFrom += matchedValueWithSuffix
replaceTo += replaceToFunc(matchedValueWithSuffix)
}
rows = strings.ReplaceAll(rows, replaceFrom, replaceTo)
}
return strings.Split(rows, "\n")
}
func HasBinaryContent(input string) bool {
return !IsASCII(input)
}
// IsASCII tests whether a string consists only of ASCII characters or not
func IsASCII(input string) bool {
for i := 0; i < len(input); i++ {
if input[i] > unicode.MaxASCII {
return false
}
}
return true
}
func IsASCIIPrintable(input rune) bool {
return input > 32 && input < unicode.MaxASCII
}