Module: MemoryIO::Util

Defined in:
lib/memory_io/util.rb

Overview

Defines utility methods.

Class Method Summary collapse

Class Method Details

.file_permission(file) ⇒ #readable?, ...

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns Struct with two boolean method. nil for file not exists or is inaccessible.

Parameters:

  • file (String)

    File name.

Returns:

  • (#readable?, #writable?, nil)

    Struct with two boolean method. nil for file not exists or is inaccessible.


42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/memory_io/util.rb', line 42

def file_permission(file)
  return nil unless File.file?(file)
  stat = File.stat(file)
  # we do a trick here because /proc/[pid]/mem might be marked as readable but fails at sysopen.
  os = OpenStruct.new(readable?: stat.readable_real?, writable?: stat.writable_real?)
  begin
    os.readable? && File.open(file, 'rb').close
  rescue Errno::EACCES
    os[:readable?] = false
  end
  begin
    os.writable? && File.open(file, 'wb').close
  rescue Errno::EACCES
    os[:writable?] = false
  end
  os
end

.pack(val, b) ⇒ String

Pack an integer into b bytes. Little endian is used.

Examples:

Util.pack(0x123, 4)
#=> "\x23\x01\x00\x00"

Parameters:

  • val (Integer)

    The integer to pack. If val contains more than b bytes, only lower b bytes in val will be packed.

  • b (Integer)

Returns:

  • (String)

    Packing result with length b.


114
115
116
# File 'lib/memory_io/util.rb', line 114

def pack(val, b)
  Array.new(b) { |i| (val >> (i * 8)) & 0xff }.pack('C*')
end

.safe_eval(str, **vars) ⇒ Integer

Evaluate string safely.

Examples:

Util.safe_eval('heap + 0x10 * pp', heap: 0xde00, pp: 8)
#=> 56960 # 0xde80

Parameters:

  • str (String)

    String to be evaluated.

  • vars ({Symbol => Integer})

    Predefined variables

Returns:

  • (Integer)

    Result.


73
74
75
76
77
78
# File 'lib/memory_io/util.rb', line 73

def safe_eval(str, **vars)
  return str if str.is_a?(Integer)
  # dentaku 2 doesn't support hex
  str = str.gsub(/0x[0-9a-zA-Z]+/) { |c| c.to_i(16) }
  Dentaku::Calculator.new.store(vars).evaluate(str)
end

.trim_libname(name) ⇒ String

Remove extension name (.so) and version in library name.

Examples:

Util.trim_libname('libc-2.24.so')
#=> 'libc'
Util.trim_libname('libcrypto.so.1.0.0')
#=> 'libcrypto'
Util.trim_libname('not_a_so')
#=> 'not_a_so'

Parameters:

  • name (String)

    Original library filename.

Returns:

  • (String)

    Name without version and '.so'.


133
134
135
136
137
# File 'lib/memory_io/util.rb', line 133

def trim_libname(name)
  type1 = '(-[\d.]+)?\.so$'
  type2 = '\.so.\d+[\d.]+$'
  name.sub(/#{type1}|#{type2}/, '')
end

.underscore(str) ⇒ String

Convert input into snake-case.

This method also converts '::' to '/'.

Examples:

Util.underscore('MemoryIO')
#=> 'memory_io'

Util.underscore('MyModule::MyClass')
#=> 'my_module/my_class'

Parameters:

  • str (String)

    String to be converted.

Returns:

  • (String)

    Converted string.


25
26
27
28
29
30
31
32
# File 'lib/memory_io/util.rb', line 25

def underscore(str)
  return '' if str.empty?
  str = str.gsub('::', '/')
  str.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
  str.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
  str.downcase!
  str
end

.unpack(str) ⇒ Integer

Unpack a string into an integer. Little endian is used.

Examples:

Util.unpack("\xff")
#=> 255
Util.unpack("@\xE2\x01\x00")
#=> 123456

Parameters:

  • str (String)

    String.

Returns:

  • (Integer)

    Result.


94
95
96
# File 'lib/memory_io/util.rb', line 94

def unpack(str)
  str.bytes.reverse.reduce(0) { |s, c| s * 256 + c }
end