asmrepl 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CODE_OF_CONDUCT.md +78 -0
- data/Gemfile +3 -0
- data/LICENSE +201 -0
- data/README.md +83 -0
- data/Rakefile +23 -0
- data/asmrepl.gemspec +24 -0
- data/bin/asmrepl +5 -0
- data/lib/asmrepl/assembler.rb +49 -0
- data/lib/asmrepl/linux.rb +186 -0
- data/lib/asmrepl/macos.rb +205 -0
- data/lib/asmrepl/parser.rb +101 -0
- data/lib/asmrepl/parser.tab.rb +297 -0
- data/lib/asmrepl/parser.y +44 -0
- data/lib/asmrepl/repl.rb +105 -0
- data/lib/asmrepl/version.rb +3 -0
- data/lib/asmrepl.rb +3 -0
- data/test/asmrepl_test.rb +116 -0
- data/test/helper.rb +20 -0
- metadata +120 -0
data/lib/asmrepl/repl.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
require "fiddle"
|
2
|
+
require "fisk/helpers"
|
3
|
+
require "crabstone"
|
4
|
+
require "reline"
|
5
|
+
|
6
|
+
if RUBY_PLATFORM =~ /darwin/
|
7
|
+
require "asmrepl/macos"
|
8
|
+
else
|
9
|
+
require "asmrepl/linux"
|
10
|
+
end
|
11
|
+
|
12
|
+
class Crabstone::Binding::Instruction
|
13
|
+
class << self
|
14
|
+
alias :old_release :release
|
15
|
+
end
|
16
|
+
|
17
|
+
# Squelch error in crabstone
|
18
|
+
def self.release obj
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module ASMREPL
|
24
|
+
class REPL
|
25
|
+
include Fiddle
|
26
|
+
|
27
|
+
if RUBY_PLATFORM =~ /darwin/
|
28
|
+
CFuncs = MacOS
|
29
|
+
else
|
30
|
+
CFuncs = Linux
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize
|
34
|
+
size = 1024 * 16 # 16k is enough for anyone!
|
35
|
+
@buffer = CFuncs.jitbuffer(size)
|
36
|
+
CFuncs.memset(@buffer.memory, 0xCC, size)
|
37
|
+
@parser = ASMREPL::Parser.new
|
38
|
+
@assembler = ASMREPL::Assembler.new
|
39
|
+
end
|
40
|
+
|
41
|
+
def display_state state
|
42
|
+
puts " CPU STATE ".center(48, "=")
|
43
|
+
puts state
|
44
|
+
puts
|
45
|
+
puts "FLAGS: #{state.flags.inspect}"
|
46
|
+
puts
|
47
|
+
end
|
48
|
+
|
49
|
+
def start
|
50
|
+
pid = fork {
|
51
|
+
CFuncs.traceme
|
52
|
+
@buffer.to_function([], TYPE_INT).call
|
53
|
+
}
|
54
|
+
|
55
|
+
tracer = CFuncs::Tracer.new pid
|
56
|
+
should_cpu = true
|
57
|
+
while tracer.wait
|
58
|
+
state = tracer.state
|
59
|
+
|
60
|
+
# Show CPU state once on boot
|
61
|
+
if should_cpu
|
62
|
+
display_state state
|
63
|
+
should_cpu = false
|
64
|
+
end
|
65
|
+
|
66
|
+
# Move the JIT buffer to the current instruction pointer
|
67
|
+
pos = (state.rip - @buffer.memory.to_i)
|
68
|
+
@buffer.seek pos
|
69
|
+
use_history = true
|
70
|
+
loop do
|
71
|
+
cmd = nil
|
72
|
+
text = Reline.readmultiline(">> ", use_history) do |multiline_input|
|
73
|
+
if multiline_input =~ /\A\s*(\w+)\s*\Z/
|
74
|
+
register = $1
|
75
|
+
cmd = [:read, register]
|
76
|
+
else
|
77
|
+
cmd = :run
|
78
|
+
end
|
79
|
+
true
|
80
|
+
end
|
81
|
+
|
82
|
+
case cmd
|
83
|
+
in :run
|
84
|
+
break if text.chomp.empty?
|
85
|
+
binary = @assembler.assemble @parser.parse text.chomp
|
86
|
+
binary.bytes.each { |byte| @buffer.putc byte }
|
87
|
+
break
|
88
|
+
in [:read, "cpu"]
|
89
|
+
display_state state
|
90
|
+
in [:read, reg]
|
91
|
+
val = state[reg]
|
92
|
+
if val
|
93
|
+
puts sprintf("%#018x", state[reg])
|
94
|
+
else
|
95
|
+
puts "Unknown command: "
|
96
|
+
puts " " + text
|
97
|
+
end
|
98
|
+
else
|
99
|
+
end
|
100
|
+
end
|
101
|
+
tracer.continue
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
data/lib/asmrepl.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
require "helper"
|
2
|
+
|
3
|
+
class ParserTest < ASMREPL::Test
|
4
|
+
def setup
|
5
|
+
super
|
6
|
+
@parser = ASMREPL::Parser.new
|
7
|
+
@assembler = ASMREPL::Assembler.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_int3
|
11
|
+
assert_round_trip "int3 "
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_and
|
15
|
+
assert_round_trip "and r9, 0xffff"
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_negative
|
19
|
+
assert_round_trip "test qword ptr [r15], -9"
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_mem_lhs
|
23
|
+
asm = disasm_for "mov [r15], r9"
|
24
|
+
assert_equal "mov qword ptr [r15], r9", asm
|
25
|
+
assert_round_trip "mov qword ptr [r15], r9"
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_inc
|
29
|
+
assert_round_trip "inc r10"
|
30
|
+
assert_round_trip "inc qword ptr [r10]"
|
31
|
+
assert_round_trip "inc qword ptr [r10 + 8]"
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_movabs
|
35
|
+
assert_round_trip "movabs r10, 0x6000014b1ae0"
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_ret
|
39
|
+
assert_round_trip "ret "
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_lea_rip
|
43
|
+
if RUBY_PLATFORM =~ /darwin/
|
44
|
+
assert_round_trip "lea rax, [rip]"
|
45
|
+
assert_round_trip "lea rax, [rip + 9]"
|
46
|
+
else
|
47
|
+
assert_round_trip "lea rax, qword ptr [rip]"
|
48
|
+
assert_round_trip "lea rax, qword ptr [rip + 9]"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_push_reg
|
53
|
+
assert_round_trip "push r13"
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_int_4
|
57
|
+
assert_round_trip "int 4"
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_shl_1
|
61
|
+
assert_round_trip "shl rax, 1"
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_simple
|
65
|
+
assert_round_trip "mov rax, 0xff"
|
66
|
+
assert_round_trip "mov r8, 0xff"
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_2_regs
|
70
|
+
assert_round_trip "mov r8, rax"
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_memory_offset
|
74
|
+
assert_round_trip "mov r8, qword ptr [rax + 0x7b]"
|
75
|
+
assert_round_trip "mov r8, qword ptr [rax - 0x7b]"
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_memory_defaults_64_offset
|
79
|
+
asm = disasm_for "mov rax, [rax + 0x7b]"
|
80
|
+
assert_equal "mov rax, qword ptr [rax + 0x7b]", asm
|
81
|
+
|
82
|
+
asm = disasm_for "mov rax, [rax - 0x7b]"
|
83
|
+
assert_equal "mov rax, qword ptr [rax - 0x7b]", asm
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_memory_defaults_64
|
87
|
+
asm = disasm_for "mov rax, [rax]"
|
88
|
+
assert_equal "mov rax, qword ptr [rax]", asm
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_memory_specify_width
|
92
|
+
assert_round_trip "mov r8, qword ptr [rax]"
|
93
|
+
assert_round_trip "mov r8d, dword ptr [r8]"
|
94
|
+
assert_round_trip "mov r8w, word ptr [r8]"
|
95
|
+
assert_round_trip "mov r8b, byte ptr [r8]"
|
96
|
+
end
|
97
|
+
|
98
|
+
def assert_round_trip asm
|
99
|
+
ast = @parser.parse asm
|
100
|
+
binary = @assembler.assemble ast
|
101
|
+
assert_equal asm, disasm(binary)
|
102
|
+
end
|
103
|
+
|
104
|
+
def disasm_for asm
|
105
|
+
ast = @parser.parse asm
|
106
|
+
binary = @assembler.assemble ast
|
107
|
+
disasm(binary)
|
108
|
+
end
|
109
|
+
|
110
|
+
def disasm binary
|
111
|
+
cs = Crabstone::Disassembler.new(Crabstone::ARCH_X86, Crabstone::MODE_64)
|
112
|
+
cs.disasm(binary, 0x0000).each {|i|
|
113
|
+
return "%s %s" % [i.mnemonic, i.op_str]
|
114
|
+
}
|
115
|
+
end
|
116
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require "asmrepl"
|
2
|
+
require "minitest"
|
3
|
+
require "minitest/autorun"
|
4
|
+
require "crabstone"
|
5
|
+
|
6
|
+
class Crabstone::Binding::Instruction
|
7
|
+
class << self
|
8
|
+
alias :old_release :release
|
9
|
+
end
|
10
|
+
|
11
|
+
# Squelch error in crabstone
|
12
|
+
def self.release obj
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module ASMREPL
|
18
|
+
class Test < Minitest::Test
|
19
|
+
end
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: asmrepl
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Aaron Patterson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-11-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: minitest
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '5.14'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '5.14'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: crabstone
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '4.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '4.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '13.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '13.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: fisk
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2'
|
69
|
+
description: Tired of writing assembly and them assembling it? Now you can write assembly
|
70
|
+
and evaluate it!
|
71
|
+
email: tenderlove@ruby-lang.org
|
72
|
+
executables:
|
73
|
+
- asmrepl
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- CODE_OF_CONDUCT.md
|
78
|
+
- Gemfile
|
79
|
+
- LICENSE
|
80
|
+
- README.md
|
81
|
+
- Rakefile
|
82
|
+
- asmrepl.gemspec
|
83
|
+
- bin/asmrepl
|
84
|
+
- lib/asmrepl.rb
|
85
|
+
- lib/asmrepl/assembler.rb
|
86
|
+
- lib/asmrepl/linux.rb
|
87
|
+
- lib/asmrepl/macos.rb
|
88
|
+
- lib/asmrepl/parser.rb
|
89
|
+
- lib/asmrepl/parser.tab.rb
|
90
|
+
- lib/asmrepl/parser.y
|
91
|
+
- lib/asmrepl/repl.rb
|
92
|
+
- lib/asmrepl/version.rb
|
93
|
+
- test/asmrepl_test.rb
|
94
|
+
- test/helper.rb
|
95
|
+
homepage: https://github.com/tenderlove/asmrepl
|
96
|
+
licenses:
|
97
|
+
- Apache-2.0
|
98
|
+
metadata: {}
|
99
|
+
post_install_message:
|
100
|
+
rdoc_options: []
|
101
|
+
require_paths:
|
102
|
+
- lib
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
requirements: []
|
114
|
+
rubygems_version: 3.3.0.dev
|
115
|
+
signing_key:
|
116
|
+
specification_version: 4
|
117
|
+
summary: Write assembly in a REPL!
|
118
|
+
test_files:
|
119
|
+
- test/asmrepl_test.rb
|
120
|
+
- test/helper.rb
|