asmrepl 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,3 @@
1
+ module ASMREPL
2
+ VERSION = '1.0.0'
3
+ end
data/lib/asmrepl.rb ADDED
@@ -0,0 +1,3 @@
1
+ require "asmrepl/parser"
2
+ require "asmrepl/assembler"
3
+ require "asmrepl/repl"
@@ -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