Class: Nitro::CodeBin
- Inherits:
-
Object
- Object
- Nitro::CodeBin
- Includes:
- NitroBind
- Defined in:
- lib/ncpp/utils.rb,
lib/nitro/nitro.rb
Overview
Various utility methods tying Nitro to the Unarm module
Direct Known Subclasses
Instance Attribute Summary collapse
-
#functions ⇒ Object
readonly
Returns the value of attribute functions.
Instance Method Summary collapse
- #bounds ⇒ Object
-
#disasm_function(addr) ⇒ Object
(also: #disasm_func)
TODO: rewrite in Rust?.
- #each_arm_instruction(range = bounds) ⇒ Object (also: #each_arm_ins, #each_ins)
- #each_byte(range = bounds) ⇒ Object
- #each_char(range = bounds) ⇒ Object
- #each_dword(range = bounds) ⇒ Object
- #each_hword(range = bounds) ⇒ Object
- #each_thumb_instruction(range = bounds) ⇒ Object (also: #each_thumb_ins)
- #each_word(range = bounds) ⇒ Object
- #end_address ⇒ Object (also: #end_addr)
- #find_hex(hex_str) ⇒ Object
-
#get_function(addr) ⇒ Object
TODO: rewrite in Rust?.
- #get_location ⇒ Object (also: #get_loc)
- #get_section_ptr(addr, sect_size) ⇒ Object (also: #get_sect_ptr)
- #read(range = bounds, step = 4) ⇒ Object
- #read16(addr) ⇒ Object (also: #read_hword)
- #read32(addr) ⇒ Object (also: #read_word)
- #read64(addr) ⇒ Object (also: #read_dword)
- #read8(addr) ⇒ Object (also: #read_byte)
- #read_arm_instruction(addr) ⇒ Object (also: #read_arm_ins, #read_ins)
- #read_cstring(addr) ⇒ Object (also: #read_cstr)
- #read_thumb_instruction(addr) ⇒ Object (also: #read_thumb_ins)
- #reloc_function(addr) ⇒ Object (also: #reloc_func)
- #size ⇒ Object
- #start_address ⇒ Object (also: #start_addr)
Instance Attribute Details
#functions ⇒ Object (readonly)
Returns the value of attribute functions.
591 592 593 |
# File 'lib/ncpp/utils.rb', line 591 def functions @functions end |
Instance Method Details
#bounds ⇒ Object
175 176 177 |
# File 'lib/nitro/nitro.rb', line 175 def bounds start_addr..end_addr end |
#disasm_function(addr) ⇒ Object Also known as: disasm_func
TODO: rewrite in Rust?
625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 |
# File 'lib/ncpp/utils.rb', line 625 def disasm_function(addr) is_thumb = addr & 1 != 0 addr -= 1 if is_thumb instructions = [] # [Unarm::Ins] labels = {} # key: addr, val: [xrefs] pool = {} # key: addr, val: Unarm::Data send(:"each_#{is_thumb ? 'thumb' : 'arm'}_ins", addr..) do |ins| next if pool.keys.include? ins.addr raise "Illegal instruction found at #{ins.addr.to_hex}; this is likely not a function." if ins.illegal? instructions << ins if target = ins.target_addr # if target addr not nil pool[target] ||= Unarm::Data.new(read_word(target), addr: target, loc: get_loc) end if ins.opcode == :b && (label_addr = ins.branch_dest) labels[label_addr] = [] if labels[label_addr].nil? labels[label_addr] << ins.addr # add xref break if ins.unconditional? && ins.addr > labels.keys.max elsif ins.function_end? && (labels.empty? || ins.addr > labels.keys.max) break end if instructions.length > 2500 # TODO: is this a good threshold? raise "Function at #{addr.to_hex} is growing exceptionally large; it is likely not a function." end end if !instance_variable_defined? :@functions instance_variable_set(:@functions, {}) end @functions[addr] = { thumb?: is_thumb, instructions: instructions, labels: labels, literal_pool: pool, } end |
#each_arm_instruction(range = bounds) ⇒ Object Also known as: each_arm_ins, each_ins
609 610 611 612 613 |
# File 'lib/ncpp/utils.rb', line 609 def each_arm_instruction(range = bounds) each_word(range) do |word, addr| yield Unarm::ArmIns.disasm(word, addr, get_loc) end end |
#each_byte(range = bounds) ⇒ Object
206 207 208 209 210 |
# File 'lib/nitro/nitro.rb', line 206 def each_byte(range = bounds) read(range,1).each do |byte, addr| yield byte, addr end end |
#each_char(range = bounds) ⇒ Object
212 213 214 215 216 |
# File 'lib/nitro/nitro.rb', line 212 def each_char(range = bounds) each_byte(range) do |char, addr| yield char.chr, addr end end |
#each_dword(range = bounds) ⇒ Object
194 195 196 197 198 |
# File 'lib/nitro/nitro.rb', line 194 def each_dword(range = bounds) read(range,8).each do |dword, addr| yield dword, addr end end |
#each_hword(range = bounds) ⇒ Object
200 201 202 203 204 |
# File 'lib/nitro/nitro.rb', line 200 def each_hword(range = bounds) read(range,2).each do |hword, addr| yield hword, addr end end |
#each_thumb_instruction(range = bounds) ⇒ Object Also known as: each_thumb_ins
617 618 619 620 621 |
# File 'lib/ncpp/utils.rb', line 617 def each_thumb_instruction(range = bounds) each_hword(range) do |hword, addr| yield Unarm::ThumbIns.disasm(hword, addr, get_loc) end end |
#each_word(range = bounds) ⇒ Object
188 189 190 191 192 |
# File 'lib/nitro/nitro.rb', line 188 def each_word(range = bounds) read(range).each do |word, addr| yield word, addr end end |
#end_address ⇒ Object Also known as: end_addr
170 171 172 |
# File 'lib/nitro/nitro.rb', line 170 def end_address start_address + size end |
#find_hex(hex_str) ⇒ Object
719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 |
# File 'lib/ncpp/utils.rb', line 719 def find_hex(hex_str) target_bytes = [hex_str].pack('H*').unpack('C*') target_len = target_bytes.length found = 0 found_addr = nil each_byte do |byte, addr| if byte == target_bytes[found] found += 1 found_addr = addr break if found == target_len else found = 0 end end raise 'Could not find hex byte string in binary.' if found != target_len found_addr - (target_len - 1) * 4 end |
#get_function(addr) ⇒ Object
TODO: rewrite in Rust?
672 673 674 675 676 677 678 679 |
# File 'lib/ncpp/utils.rb', line 672 def get_function(addr) func = @functions.nil? ? nil : @functions[addr] if func.nil? disasm_func(addr) func = @functions[addr] end func end |
#get_location ⇒ Object Also known as: get_loc
593 594 595 |
# File 'lib/ncpp/utils.rb', line 593 def get_location respond_to?(:id) ? "ov#{id}" : Unarm.cpu.to_s end |
#get_section_ptr(addr, sect_size) ⇒ Object Also known as: get_sect_ptr
223 224 225 226 227 228 |
# File 'lib/nitro/nitro.rb', line 223 def get_section_ptr(addr, sect_size) ptr = FFI::MemoryPointer.new(:pointer, 1) ptr.write_pointer(codeBin_getSectPtr(@ptr, addr, sect_size)) raise "Could not read #{sect_size} bytes from address #{addr.to_hex}" if ptr.read_pointer == FFI::Pointer::NULL ptr.read_pointer end |
#read(range = bounds, step = 4) ⇒ Object
179 180 181 182 183 184 185 186 |
# File 'lib/nitro/nitro.rb', line 179 def read(range = bounds, step = 4) raise ArgumentError, 'step must be 1, 2, 4, or 8 (bytes)' unless [1,2,4,8].include? step raise ArgumentError, 'range must be a Range' unless range.is_a? Range clamped = Range.new(range.begin || start_addr, [range.end || end_addr, end_addr].min) clamped.step(step).map { |addr| [send(:"read#{step * 8}", addr), addr] } end |
#read16(addr) ⇒ Object Also known as: read_hword
151 152 153 |
# File 'lib/nitro/nitro.rb', line 151 def read16(addr) codeBin_read16(@ptr, addr) end |
#read32(addr) ⇒ Object Also known as: read_word
146 147 148 |
# File 'lib/nitro/nitro.rb', line 146 def read32(addr) codeBin_read32(@ptr, addr) end |
#read64(addr) ⇒ Object Also known as: read_dword
141 142 143 |
# File 'lib/nitro/nitro.rb', line 141 def read64(addr) codeBin_read64(@ptr, addr) end |
#read8(addr) ⇒ Object Also known as: read_byte
156 157 158 |
# File 'lib/nitro/nitro.rb', line 156 def read8(addr) codeBin_read8(@ptr, addr) end |
#read_arm_instruction(addr) ⇒ Object Also known as: read_arm_ins, read_ins
598 599 600 |
# File 'lib/ncpp/utils.rb', line 598 def read_arm_instruction(addr) Unarm::ArmIns.disasm(read32(addr), addr, get_loc) end |
#read_cstring(addr) ⇒ Object Also known as: read_cstr
218 219 220 |
# File 'lib/nitro/nitro.rb', line 218 def read_cstring(addr) codeBin_readCString(@ptr, addr) end |
#read_thumb_instruction(addr) ⇒ Object Also known as: read_thumb_ins
604 605 606 |
# File 'lib/ncpp/utils.rb', line 604 def read_thumb_instruction(addr) Unarm::ThumbIns.disasm(read16(addr), addr, get_loc) end |
#reloc_function(addr) ⇒ Object Also known as: reloc_func
681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 |
# File 'lib/ncpp/utils.rb', line 681 def reloc_function(addr) if !instance_variable_defined? :@functions instance_variable_set(:@functions, {}) end func = get_function(addr) out = "" labels = func[:labels].keys func[:instructions].each do |ins| if label = labels.index(ins.addr) out << "#{label+1}:\n" end if target = ins.target_addr out << "#{ins.str[..ins.str.index(',')]} =#{(func[:literal_pool][target]).value}" elsif ins.opcode == :b && (label = labels.index(ins.branch_dest)) out << ins.str[..ins.str.index('#')-1] << "#{label+1}f" elsif (branch = ins.branch_dest) && ins.str.include?('#') && (dest = ins.str[ins.str.index('#')+1..].hex) && dest != branch && (dest += ins.addr) && (dest < func[:instructions][0].addr || dest > func[:instructions][-1].addr) out << ins.str[..ins.str.index('#')] << dest.to_hex else out << ins.str end out << "\n" end out end |
#size ⇒ Object
161 162 163 |
# File 'lib/nitro/nitro.rb', line 161 def size codeBin_getSize(@ptr) end |
#start_address ⇒ Object Also known as: start_addr
165 166 167 |
# File 'lib/nitro/nitro.rb', line 165 def start_address codeBin_getStartAddress(@ptr) end |