duckyparser.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. package hid
  2. import (
  3. "fmt"
  4. "strconv"
  5. "strings"
  6. "github.com/evilsocket/islazy/fs"
  7. )
  8. type DuckyParser struct {
  9. mod *HIDRecon
  10. }
  11. func (p DuckyParser) parseLiteral(what string, kmap KeyMap) (*Command, error) {
  12. // get reference command from the layout
  13. ref, found := kmap[what]
  14. if found == false {
  15. return nil, fmt.Errorf("can't find '%s' in current keymap", what)
  16. }
  17. return &Command{
  18. HID: ref.HID,
  19. Mode: ref.Mode,
  20. }, nil
  21. }
  22. func (p DuckyParser) parseModifier(line string, kmap KeyMap, modMask byte) (*Command, error) {
  23. // get optional key after the modifier
  24. ch := ""
  25. if idx := strings.IndexRune(line, ' '); idx != -1 {
  26. ch = line[idx+1:]
  27. }
  28. cmd, err := p.parseLiteral(ch, kmap)
  29. if err != nil {
  30. return nil, err
  31. }
  32. // apply modifier mask
  33. cmd.Mode |= modMask
  34. return cmd, nil
  35. }
  36. func (p DuckyParser) parseNumber(from string) (int, error) {
  37. idx := strings.IndexRune(from, ' ')
  38. if idx == -1 {
  39. return 0, fmt.Errorf("can't parse number from '%s'", from)
  40. }
  41. num, err := strconv.Atoi(from[idx+1:])
  42. if err != nil {
  43. return 0, fmt.Errorf("can't parse number from '%s': %v", from, err)
  44. }
  45. return num, nil
  46. }
  47. func (p DuckyParser) parseString(from string) (string, error) {
  48. idx := strings.IndexRune(from, ' ')
  49. if idx == -1 {
  50. return "", fmt.Errorf("can't parse string from '%s'", from)
  51. }
  52. return from[idx+1:], nil
  53. }
  54. func (p DuckyParser) lineIs(line string, tokens ...string) bool {
  55. for _, tok := range tokens {
  56. if strings.HasPrefix(line, tok) {
  57. return true
  58. }
  59. }
  60. return false
  61. }
  62. func (p DuckyParser) Parse(kmap KeyMap, path string) (cmds []*Command, err error) {
  63. lines := []string{}
  64. source := []string{}
  65. reader := (chan string)(nil)
  66. if reader, err = fs.LineReader(path); err != nil {
  67. return
  68. } else {
  69. for line := range reader {
  70. lines = append(lines, line)
  71. }
  72. }
  73. // preprocessing
  74. for lineno, line := range lines {
  75. if p.lineIs(line, "REPEAT") {
  76. if lineno == 0 {
  77. err = fmt.Errorf("error on line %d: REPEAT instruction at the beginning of the script", lineno+1)
  78. return
  79. }
  80. times := 1
  81. times, err = p.parseNumber(line)
  82. if err != nil {
  83. return
  84. }
  85. for i := 0; i < times; i++ {
  86. source = append(source, lines[lineno-1])
  87. }
  88. } else {
  89. source = append(source, line)
  90. }
  91. }
  92. cmds = make([]*Command, 0)
  93. for _, line := range source {
  94. cmd := &Command{}
  95. if p.lineIs(line, "CTRL", "CONTROL") {
  96. if cmd, err = p.parseModifier(line, kmap, 1); err != nil {
  97. return
  98. }
  99. } else if p.lineIs(line, "SHIFT") {
  100. if cmd, err = p.parseModifier(line, kmap, 2); err != nil {
  101. return
  102. }
  103. } else if p.lineIs(line, "ALT") {
  104. if cmd, err = p.parseModifier(line, kmap, 4); err != nil {
  105. return
  106. }
  107. } else if p.lineIs(line, "GUI", "WINDOWS", "COMMAND") {
  108. if cmd, err = p.parseModifier(line, kmap, 8); err != nil {
  109. return
  110. }
  111. } else if p.lineIs(line, "CTRL-ALT", "CONTROL-ALT") {
  112. if cmd, err = p.parseModifier(line, kmap, 4|1); err != nil {
  113. return
  114. }
  115. } else if p.lineIs(line, "CTRL-SHIFT", "CONTROL-SHIFT") {
  116. if cmd, err = p.parseModifier(line, kmap, 1|2); err != nil {
  117. return
  118. }
  119. } else if p.lineIs(line, "ESC", "ESCAPE", "APP") {
  120. if cmd, err = p.parseLiteral("ESCAPE", kmap); err != nil {
  121. return
  122. }
  123. } else if p.lineIs(line, "ENTER") {
  124. if cmd, err = p.parseLiteral("ENTER", kmap); err != nil {
  125. return
  126. }
  127. } else if p.lineIs(line, "UP", "UPARROW") {
  128. if cmd, err = p.parseLiteral("UP", kmap); err != nil {
  129. return
  130. }
  131. } else if p.lineIs(line, "DOWN", "DOWNARROW") {
  132. if cmd, err = p.parseLiteral("DOWN", kmap); err != nil {
  133. return
  134. }
  135. } else if p.lineIs(line, "LEFT", "LEFTARROW") {
  136. if cmd, err = p.parseLiteral("LEFT", kmap); err != nil {
  137. return
  138. }
  139. } else if p.lineIs(line, "RIGHT", "RIGHTARROW") {
  140. if cmd, err = p.parseLiteral("RIGHT", kmap); err != nil {
  141. return
  142. }
  143. } else if p.lineIs(line, "DELAY", "SLEEP") {
  144. secs := 0
  145. if secs, err = p.parseNumber(line); err != nil {
  146. return
  147. }
  148. cmd = &Command{Sleep: secs}
  149. } else if p.lineIs(line, "STRING", "STR") {
  150. str := ""
  151. if str, err = p.parseString(line); err != nil {
  152. return
  153. }
  154. for _, c := range str {
  155. if cmd, err = p.parseLiteral(string(c), kmap); err != nil {
  156. return
  157. }
  158. cmds = append(cmds, cmd)
  159. }
  160. continue
  161. } else if cmd, err = p.parseLiteral(line, kmap); err != nil {
  162. err = fmt.Errorf("error parsing '%s': %s", line, err)
  163. return
  164. }
  165. cmds = append(cmds, cmd)
  166. }
  167. return
  168. }