require 'spec_helper' require 'ronin/exploits/mixins/nops' require 'ronin/exploits/exploit' require 'ronin/exploits/metadata/arch' describe Ronin::Exploits::Mixins::NOPS do describe "NOPS" do subject { described_class::NOPS } describe ":x86" do subject { super()[:x86] } it "must return \"\\x90\"" do expect(subject).to eq("\x90".b) end end describe ":x86_64" do subject { super()[:x86_64] } it "must return \"\\x90\"" do expect(subject).to eq("\x90".b) end end describe ":arm" do subject { super()[:arm] } it "must return \"\\x05P\\xa0\\xe1\"" do expect(subject).to eq("\x05P\xa0\xe1".b) end end describe ":arm64" do subject { super()[:arm64] } it "must return \"\\xe5\\x03\\x05\\xaa\"" do expect(subject).to eq("\xe5\x03\x05\xaa".b) end end end module TestNOPSMixin class ExploitWithArchSet < Ronin::Exploits::Exploit include Ronin::Exploits::Metadata::Arch include Ronin::Exploits::Mixins::NOPS arch :x86 end class ExploitWithMultiByteNopArchSet < Ronin::Exploits::Exploit include Ronin::Exploits::Metadata::Arch include Ronin::Exploits::Mixins::NOPS arch :arm end class ExploitWithoutArch < Ronin::Exploits::Exploit include Ronin::Exploits::Mixins::NOPS end class ExploitWithoutArchSet < Ronin::Exploits::Exploit include Ronin::Exploits::Metadata::Arch include Ronin::Exploits::Mixins::NOPS end class ExploitWithUnsupportedArch < Ronin::Exploits::Exploit include Ronin::Exploits::Metadata::Arch include Ronin::Exploits::Mixins::NOPS arch :mips end end subject { exploit_class.new } describe "#perform_validate" do context "when the exploit class does not define an #arch method" do let(:exploit_class) { TestNOPSMixin::ExploitWithoutArch } it do expect { subject.perform_validate }.to raise_error(Ronin::Exploits::ValidationError,"exploit #{exploit_class} did not include Ronin::Exploits::Metadata::Arch or Ronin::Exploits::Mixins::HasTargets") end end context "when the exploit class's #arch method returns nil" do let(:exploit_class) { TestNOPSMixin::ExploitWithoutArchSet } it do expect { subject.perform_validate }.to raise_error(Ronin::Exploits::ValidationError,"exploit #{exploit_class} did not include define an architecture") end end context "when the exploit class defines an architecture" do let(:exploit_class) { TestNOPSMixin::ExploitWithArchSet } it do expect { subject.perform_validate }.to_not raise_error end end end describe "#nop" do context "when #arch returns an architecture name" do context "and it's supported" do let(:exploit_class) { TestNOPSMixin::ExploitWithArchSet } it "must return the String from #{described_class}::NOPS for the #arch" do expect(subject.nop).to eq(described_class::NOPS.fetch(subject.arch)) end end context "but it's not supported" do let(:exploit_class) { TestNOPSMixin::ExploitWithUnsupportedArch } it do expect { subject.nop }.to raise_error(NotImplementedError,"no NOP string is currently defined for the architecture: #{subject.arch.inspect}") end end end end describe "#nops" do let(:size) { 100 } context "when #arch returns an architecture name" do context "and it's supported" do let(:exploit_class) { TestNOPSMixin::ExploitWithArchSet } let(:nop) { described_class::NOPS.fetch(subject.arch) } it "must return a String of the NOP instruction for the #arch repeated size times" do expect(subject.nops(size)).to eq(nop * size) end context "but the NOP instruction for the architecture is more than one byte" do let(:exploit_class) { TestNOPSMixin::ExploitWithMultiByteNopArchSet } it "must return a String of the desired length containing as many of the NOP instructions as possible" do expect(subject.nops(size)).to eq(nop * (size / nop.bytesize)) end end end context "but it's not supported" do let(:exploit_class) { TestNOPSMixin::ExploitWithUnsupportedArch } it do expect { subject.nops(size) }.to raise_error(NotImplementedError,"no NOP string is currently defined for the architecture: #{subject.arch.inspect}") end end end end end