ragweed 0.2.0-java
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.
- data/History.txt +32 -0
- data/README.rdoc +60 -0
- data/README.txt +9 -0
- data/Rakefile +86 -0
- data/VERSION +1 -0
- data/examples/hittracertux.rb +45 -0
- data/examples/hittracerx.rb +63 -0
- data/examples/hook_notepad.rb +9 -0
- data/examples/snicker.rb +183 -0
- data/examples/tux-example.rb +24 -0
- data/lib/ragweed/arena.rb +55 -0
- data/lib/ragweed/blocks.rb +128 -0
- data/lib/ragweed/debugger32.rb +400 -0
- data/lib/ragweed/debuggerosx.rb +456 -0
- data/lib/ragweed/debuggertux.rb +502 -0
- data/lib/ragweed/detour.rb +223 -0
- data/lib/ragweed/ptr.rb +48 -0
- data/lib/ragweed/rasm/bblock.rb +73 -0
- data/lib/ragweed/rasm/isa.rb +1115 -0
- data/lib/ragweed/rasm.rb +59 -0
- data/lib/ragweed/sbuf.rb +197 -0
- data/lib/ragweed/trampoline.rb +103 -0
- data/lib/ragweed/utils.rb +182 -0
- data/lib/ragweed/wrap32/debugging.rb +401 -0
- data/lib/ragweed/wrap32/device.rb +49 -0
- data/lib/ragweed/wrap32/event.rb +50 -0
- data/lib/ragweed/wrap32/hooks.rb +39 -0
- data/lib/ragweed/wrap32/overlapped.rb +46 -0
- data/lib/ragweed/wrap32/process.rb +613 -0
- data/lib/ragweed/wrap32/process_token.rb +75 -0
- data/lib/ragweed/wrap32/thread_context.rb +142 -0
- data/lib/ragweed/wrap32/winx.rb +16 -0
- data/lib/ragweed/wrap32/wrap32.rb +583 -0
- data/lib/ragweed/wrap32.rb +59 -0
- data/lib/ragweed/wraposx/constants.rb +114 -0
- data/lib/ragweed/wraposx/kernelerrorx.rb +147 -0
- data/lib/ragweed/wraposx/region_info.rb +275 -0
- data/lib/ragweed/wraposx/structs.rb +102 -0
- data/lib/ragweed/wraposx/thread_context.rb +902 -0
- data/lib/ragweed/wraposx/thread_info.rb +160 -0
- data/lib/ragweed/wraposx/thread_info.rb.old +121 -0
- data/lib/ragweed/wraposx/wraposx.rb +356 -0
- data/lib/ragweed/wraposx.rb +60 -0
- data/lib/ragweed/wraptux/constants.rb +101 -0
- data/lib/ragweed/wraptux/process.rb +35 -0
- data/lib/ragweed/wraptux/threads.rb +7 -0
- data/lib/ragweed/wraptux/wraptux.rb +72 -0
- data/lib/ragweed/wraptux.rb +57 -0
- data/lib/ragweed.rb +112 -0
- data/ragweed.gemspec +102 -0
- data/spec/ragweed_spec.rb +7 -0
- data/spec/spec_helper.rb +16 -0
- data/test/test_ragweed.rb +0 -0
- metadata +121 -0
data/lib/ragweed/rasm.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# Dir[File.expand_path("#{File.dirname(__FILE__)}/rasm/*.rb")].each do |file|
|
2
|
+
# require file
|
3
|
+
# end
|
4
|
+
module Ragweed; end
|
5
|
+
module Ragweed::Rasm
|
6
|
+
|
7
|
+
# :stopdoc:
|
8
|
+
VERSION = File.read(File.join(File.dirname(__FILE__),"..","..","VERSION")).strip
|
9
|
+
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
|
10
|
+
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
11
|
+
# :startdoc:
|
12
|
+
|
13
|
+
# Returns the version string for the library.
|
14
|
+
#
|
15
|
+
def self.version
|
16
|
+
VERSION
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns the library path for the module. If any arguments are given,
|
20
|
+
# they will be joined to the end of the libray path using
|
21
|
+
# <tt>File.join</tt>.
|
22
|
+
#
|
23
|
+
def self.libpath( *args )
|
24
|
+
args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the lpath for the module. If any arguments are given,
|
28
|
+
# they will be joined to the end of the path using
|
29
|
+
# <tt>File.join</tt>.
|
30
|
+
#
|
31
|
+
def self.path( *args )
|
32
|
+
args.empty? ? PATH : ::File.join(PATH, args.flatten)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Utility function to load utility classes and extensions
|
36
|
+
def self.require_utils
|
37
|
+
%w{utils sbuf}.each{|r| require self.libpath(r)+'.rb'}
|
38
|
+
end
|
39
|
+
|
40
|
+
# Utility method used to require all files ending in .rb that lie in the
|
41
|
+
# directory below this file that has the same name as the filename passed
|
42
|
+
# in. Optionally, a specific _directory_ name can be passed in such that
|
43
|
+
# the _filename_ does not have to be equivalent to the directory.
|
44
|
+
#
|
45
|
+
def self.require_all_libs_relative_to( fname, dir = nil )
|
46
|
+
self.require_utils
|
47
|
+
dir ||= ::File.basename(fname, '.*')
|
48
|
+
search_me = ::File.expand_path(
|
49
|
+
::File.join(::File.dirname(fname), dir, '**', '*.rb'))
|
50
|
+
|
51
|
+
Dir.glob(search_me).sort.each {|rb| require rb}
|
52
|
+
# require File.dirname(File.basename(__FILE__)) + "/#{x}"
|
53
|
+
|
54
|
+
end
|
55
|
+
end # module Ragweed::Rasm
|
56
|
+
|
57
|
+
Ragweed::Rasm.require_all_libs_relative_to(__FILE__)
|
58
|
+
|
59
|
+
# EOF
|
data/lib/ragweed/sbuf.rb
ADDED
@@ -0,0 +1,197 @@
|
|
1
|
+
# Stolen (mostly) from Net::SSH
|
2
|
+
|
3
|
+
# a* string a10 string 10 bytes A* string trimmed
|
4
|
+
# C uchar
|
5
|
+
# L native u32, l signed
|
6
|
+
# N BE u32, n 16
|
7
|
+
# Qq quad
|
8
|
+
# Ss native u16
|
9
|
+
# Vv LE u32
|
10
|
+
|
11
|
+
# Encapsulate a buffer of data with structured data accessors
|
12
|
+
class Ragweed::Sbuf
|
13
|
+
attr_reader :content
|
14
|
+
attr_accessor :position
|
15
|
+
|
16
|
+
def self.from(*args)
|
17
|
+
raise ArgumentError, "odd argument count" if args.length.odd?
|
18
|
+
|
19
|
+
b = self.new
|
20
|
+
while not args.empty?
|
21
|
+
t = args.shift; v = args.shift
|
22
|
+
if t == :raw
|
23
|
+
b.straw(v)
|
24
|
+
elsif v.kind_of? Array
|
25
|
+
b.st t, *v
|
26
|
+
else
|
27
|
+
b.st t, v
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
return b
|
32
|
+
end
|
33
|
+
|
34
|
+
def st(t, *args)
|
35
|
+
send "st#{ t }", *args
|
36
|
+
end
|
37
|
+
|
38
|
+
def straw(*args)
|
39
|
+
args.each do |raw|
|
40
|
+
@content << raw.to_s
|
41
|
+
end
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
def initialize(opts={})
|
46
|
+
@content = opts[:content] || ""
|
47
|
+
@position = 0
|
48
|
+
end
|
49
|
+
|
50
|
+
def consume!(n=position)
|
51
|
+
if(n >= length); clear!
|
52
|
+
elsif n > 0
|
53
|
+
@content = remainder(n)
|
54
|
+
@position -= n
|
55
|
+
@position = 0 if @position < 0
|
56
|
+
end
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
60
|
+
def ldraw(n=length)
|
61
|
+
n = ((self.length) - position) if(position + n > length)
|
62
|
+
@position += n
|
63
|
+
@content[position-n, n]
|
64
|
+
end
|
65
|
+
|
66
|
+
def ld(t, *args)
|
67
|
+
return ldraw(t) if t.kind_of? Numeric
|
68
|
+
|
69
|
+
begin
|
70
|
+
send "ld#{ t }", *args
|
71
|
+
rescue => e
|
72
|
+
case t.to_s
|
73
|
+
when /^strz(\d+)?/
|
74
|
+
n = $1.to_i if not $1.empty?
|
75
|
+
n ||= 0
|
76
|
+
ldsz(n)
|
77
|
+
when /^strs(\d+)?/
|
78
|
+
n = $1.to_i if not $1.empty?
|
79
|
+
n ||= 0
|
80
|
+
ldss(n)
|
81
|
+
else
|
82
|
+
raise e
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def sz(t, *args); self.class.sz(t, *args); end
|
88
|
+
def self.sz(t, *args)
|
89
|
+
begin
|
90
|
+
send "sz#{ t }", *args
|
91
|
+
rescue => e
|
92
|
+
case t.to_s
|
93
|
+
when /^strz(\d+)/
|
94
|
+
$1.to_i
|
95
|
+
when /^strs(\d+)/
|
96
|
+
$1.to_i
|
97
|
+
when /^str.*/
|
98
|
+
raise Exception, "can't take size of unbounded string"
|
99
|
+
else
|
100
|
+
raise e
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def shraw(n=length)
|
106
|
+
ret = ldraw(n)
|
107
|
+
consume!
|
108
|
+
return ret
|
109
|
+
end
|
110
|
+
|
111
|
+
def sh(t, *args)
|
112
|
+
return shraw(t) if t.kind_of? Numeric
|
113
|
+
ret = send "ld#{ t }", *args
|
114
|
+
consume!
|
115
|
+
return ret
|
116
|
+
end
|
117
|
+
|
118
|
+
def ldsz(n=0)
|
119
|
+
n = @content.size - @position if n == 0
|
120
|
+
ld(n).unpack("a#{ n }").first
|
121
|
+
end
|
122
|
+
|
123
|
+
def ldss(n=0)
|
124
|
+
n = @content.size - @position if n == 0
|
125
|
+
ld(n).unpack("A#{ n }").first
|
126
|
+
end
|
127
|
+
|
128
|
+
def length; @content.length; end
|
129
|
+
def size; @content.size; end
|
130
|
+
def empty?; @content.empty?; end
|
131
|
+
|
132
|
+
def available; length - position; end
|
133
|
+
alias_method :remaining, :available
|
134
|
+
|
135
|
+
def to_s; @content.dup; end
|
136
|
+
def ==(b); to_s == b.to_s; end
|
137
|
+
def reset; @position = 0; end
|
138
|
+
def eof?; @position >= length; end
|
139
|
+
def clear!; @content = "" and reset; end
|
140
|
+
def remainder(n = position); @content[n..-1] || ""; end
|
141
|
+
def remainder_as_buffer(t=Ragweed::Sbuf); t.new(:content => remainder); end
|
142
|
+
|
143
|
+
def self.szl64; 8; end
|
144
|
+
def self.szb64; 8; end
|
145
|
+
def self.szn64; 8; end
|
146
|
+
|
147
|
+
def ldl64; ld(8).unpack("Q").first; end
|
148
|
+
def ldb64; ld(8).reverse.unpack("Q").first; end
|
149
|
+
alias_method :ldn64, :ldb64
|
150
|
+
|
151
|
+
def stl64(v); straw([v].pack("Q")); end
|
152
|
+
def stb64(v); straw([v].pack("Q").reverse); end
|
153
|
+
alias_method :stn64, :stb64
|
154
|
+
|
155
|
+
def self.szl32; 4; end
|
156
|
+
def self.szb32; 4; end
|
157
|
+
def self.szn32; 4; end
|
158
|
+
|
159
|
+
def ldl32; ld(4).unpack("L").first; end
|
160
|
+
def ldb32; ld(4).unpack("N").first; end
|
161
|
+
alias_method :ldn32, :ldb32
|
162
|
+
|
163
|
+
def stl32(v); straw([v].pack("L")); end
|
164
|
+
def stb32(v); straw([v].pack("N")); end
|
165
|
+
alias_method :stn32, :stb32
|
166
|
+
|
167
|
+
def self.szl16; 2; end
|
168
|
+
def self.szb16; 2; end
|
169
|
+
def self.szn16; 2; end
|
170
|
+
|
171
|
+
def ldl16; ld(2).unpack("v").first; end
|
172
|
+
def ldb16; ld(2).unpack("n").first; end
|
173
|
+
alias_method :ldn16, :ldb16
|
174
|
+
|
175
|
+
def stl16(v); straw([v].pack("v")); end
|
176
|
+
def stb16(v); straw([v].pack("n")); end
|
177
|
+
alias_method :stn16, :stb16
|
178
|
+
|
179
|
+
def self.szl8; 1; end;
|
180
|
+
def self.szb8; 1; end;
|
181
|
+
def self.szn8; 1; end;
|
182
|
+
|
183
|
+
def ldl8; ld(1)[0]; end
|
184
|
+
def ldb8; ldl8; end
|
185
|
+
alias_method :ldn8, :ldb8
|
186
|
+
|
187
|
+
def stl8(v)
|
188
|
+
if v.kind_of? String
|
189
|
+
straw(v[0].chr)
|
190
|
+
else
|
191
|
+
straw([v].pack("c"))
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def stb8(v); stl8(v); end
|
196
|
+
alias_method :stn8, :stb8
|
197
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
class Ragweed::Trampoline
|
2
|
+
|
3
|
+
# Normally called through WinProcess#remote_call, but, for
|
4
|
+
# what it's worth: needs a WinProcess instance and a location,
|
5
|
+
# which can be a string module!function or a pointer.
|
6
|
+
def initialize(p, loc, opts={})
|
7
|
+
@p = p
|
8
|
+
@loc = @p.get_proc loc
|
9
|
+
@argc = opts[:argc]
|
10
|
+
@a = @p.arena
|
11
|
+
@mem = @a.alloc(1024)
|
12
|
+
@arg_mem = @mem + 512
|
13
|
+
@wait = opts[:wait] || true
|
14
|
+
@chicken = opts[:chicken]
|
15
|
+
@opts = opts
|
16
|
+
end
|
17
|
+
|
18
|
+
# Call the remote function. Returns the 32 bit EAX return value provided
|
19
|
+
# by stdcall.
|
20
|
+
def call(*args)
|
21
|
+
raise "Insufficient Arguments" if @argc and @argc != args.size
|
22
|
+
|
23
|
+
@shim = Ragweed::Blocks::remote_trampoline(args.size, @opts)
|
24
|
+
|
25
|
+
# Won't leak memory.
|
26
|
+
@p.arena do |a|
|
27
|
+
# 1024 is a SWAG. Divide it in half, one for the trampoline
|
28
|
+
# (which is unrolled, because I am lazy and dumb) and the other
|
29
|
+
# for the call stack.
|
30
|
+
base = @p.ptr(a.alloc(1024))
|
31
|
+
|
32
|
+
argm = base + 512
|
33
|
+
cur = argm
|
34
|
+
|
35
|
+
# Write the location for the tramp to call
|
36
|
+
cur.write(@loc)
|
37
|
+
cur += 4
|
38
|
+
|
39
|
+
# Write the function arguments into the call stack.
|
40
|
+
(0...args.size).each_backwards do |i|
|
41
|
+
if args[i].kind_of? Integer
|
42
|
+
val = args[i].to_l32
|
43
|
+
elsif args[i].kind_of? String
|
44
|
+
stash = a.copy(args[i])
|
45
|
+
val = stash.to_l32
|
46
|
+
else
|
47
|
+
val = args[i].to_s
|
48
|
+
end
|
49
|
+
cur.write(val)
|
50
|
+
cur += 4
|
51
|
+
end if args.size.nonzero?
|
52
|
+
|
53
|
+
# Write a placeholder for the return value
|
54
|
+
cur.write(0xDEADBEEF.to_l32)
|
55
|
+
|
56
|
+
# Write the tramp
|
57
|
+
s = @shim.assemble
|
58
|
+
base.write(s)
|
59
|
+
|
60
|
+
th = Ragweed::Wrap32::create_remote_thread(@p.handle, base, argm)
|
61
|
+
Ragweed::Wrap32::wait_for_single_object(th) if @wait
|
62
|
+
Ragweed::Wrap32::close_handle(th)
|
63
|
+
ret = @p.read32(cur)
|
64
|
+
if ret == 0xDEADBEEF
|
65
|
+
ret = nil
|
66
|
+
end
|
67
|
+
ret
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class Trevil
|
73
|
+
def initialize(p)
|
74
|
+
@p = p
|
75
|
+
@ev1, @ev2 = [WinEvent.new, WinEvent.new]
|
76
|
+
@a = @p.arena
|
77
|
+
end
|
78
|
+
|
79
|
+
def clear!
|
80
|
+
@a.release
|
81
|
+
end
|
82
|
+
|
83
|
+
def go
|
84
|
+
mem = @a.alloc(1024)
|
85
|
+
base = @p.ptr(mem)
|
86
|
+
data = base + 512
|
87
|
+
swch = ["OpenProcess",
|
88
|
+
"DuplicateHandle",
|
89
|
+
"ResetEvent",
|
90
|
+
"SetEvent",
|
91
|
+
"WaitForSingleObject"].
|
92
|
+
map {|x| @p.get_proc("kernel32!#{x}").to_i}.
|
93
|
+
pack("LLLLL")
|
94
|
+
state = [Ragweed::Wrap32::get_current_process_id, @ev1.handle, @ev2.handle].
|
95
|
+
pack("LLL")
|
96
|
+
|
97
|
+
data.write(swch + state)
|
98
|
+
base.write(event_pair_stub(:debug => false).assemble)
|
99
|
+
Ragweed::Wrap32::create_remote_thread(@p.handle, base, data)
|
100
|
+
@ev1.wait
|
101
|
+
@ev2
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,182 @@
|
|
1
|
+
require 'iconv'
|
2
|
+
|
3
|
+
#do not rely on this extension to range. it'll be removed at some point.
|
4
|
+
class Range
|
5
|
+
module RangeExtensions
|
6
|
+
def each_backwards
|
7
|
+
max.to_i.downto(min) {|i| yield i}
|
8
|
+
end
|
9
|
+
end
|
10
|
+
include RangeExtensions
|
11
|
+
end
|
12
|
+
|
13
|
+
class Array
|
14
|
+
module ArrayExtensions
|
15
|
+
# Convert to hash
|
16
|
+
##
|
17
|
+
def to_hash
|
18
|
+
# too clever.
|
19
|
+
# Hash[*self.flatten]
|
20
|
+
|
21
|
+
h = Hash.new
|
22
|
+
each do |k,v|
|
23
|
+
h[k] = v
|
24
|
+
end
|
25
|
+
h
|
26
|
+
end
|
27
|
+
end
|
28
|
+
include ArrayExtensions
|
29
|
+
end
|
30
|
+
|
31
|
+
# These should probably be extensions to Module since that's the location of instance_eval and friends.
|
32
|
+
class Object
|
33
|
+
module ObjectExtensions
|
34
|
+
# Every object has a "singleton" class, which you can think
|
35
|
+
# of as the class (ie, 1.metaclass =~ Fixnum) --- but that you
|
36
|
+
# can modify and extend without fucking up the actual class.
|
37
|
+
def metaclass; class << self; self; end; end
|
38
|
+
def meta_eval(&blk) metaclass.instance_eval &blk; end
|
39
|
+
def meta_def(name, &blk) meta_eval { define_method name, &blk }; end
|
40
|
+
def try(meth, *args); send(meth, *args) if respond_to? meth; end
|
41
|
+
|
42
|
+
def through(meth, *args)
|
43
|
+
if respond_to? meth
|
44
|
+
send(meth, *args)
|
45
|
+
else
|
46
|
+
self
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
## This is from Topher Cyll's Stupd IRB tricks
|
51
|
+
def mymethods
|
52
|
+
(self.methods - self.class.superclass.methods).sort
|
53
|
+
end
|
54
|
+
# self-evident
|
55
|
+
def callable?; respond_to? :call; end
|
56
|
+
def number?; kind_of? Numeric; end
|
57
|
+
|
58
|
+
# while X remains callable, keep calling it to get its value
|
59
|
+
def derive
|
60
|
+
# also, don't drink and derive
|
61
|
+
x = self
|
62
|
+
while x.callable?
|
63
|
+
x = x()
|
64
|
+
end
|
65
|
+
return x
|
66
|
+
end
|
67
|
+
end
|
68
|
+
include ObjectExtensions
|
69
|
+
end
|
70
|
+
|
71
|
+
class String
|
72
|
+
def to_l32; unpack("L").first; end
|
73
|
+
def to_b32; unpack("N").first; end
|
74
|
+
def to_l16; unpack("v").first; end
|
75
|
+
def to_b16; unpack("n").first; end
|
76
|
+
def to_u8; self[0]; end
|
77
|
+
def shift_l32; shift(4).to_l32; end
|
78
|
+
def shift_b32; shift(4).to_b32; end
|
79
|
+
def shift_l16; shift(2).to_l16; end
|
80
|
+
def shift_b16; shift(2).to_b16; end
|
81
|
+
def shift_u8; shift(1).to_u8; end
|
82
|
+
def to_utf16
|
83
|
+
Iconv.iconv("utf-16LE", "utf-8", self).first + "\x00\x00"
|
84
|
+
end
|
85
|
+
def from_utf16
|
86
|
+
ret = Iconv.iconv("utf-8", "utf-16le", self).first
|
87
|
+
if ret[-1] == 0
|
88
|
+
ret = ret[0..-2]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
alias_method :to_utf8, :from_utf16
|
92
|
+
alias_method :to_ascii, :from_utf16
|
93
|
+
def from_utf16_buffer
|
94
|
+
self[0..index("\0\0\0")+2].from_utf16
|
95
|
+
end
|
96
|
+
|
97
|
+
def shift(count=1)
|
98
|
+
return self if count == 0
|
99
|
+
slice! 0..(count-1)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Sometimes string buffers passed through Win32 interfaces come with
|
103
|
+
# garbage after the trailing NUL; this method gets rid of that, like
|
104
|
+
# String#trim
|
105
|
+
def asciiz
|
106
|
+
begin
|
107
|
+
self[0..self.index("\x00")-1]
|
108
|
+
rescue
|
109
|
+
self
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def asciiz!; replace asciiz; end
|
114
|
+
|
115
|
+
# Convert a string into hex characters
|
116
|
+
def hexify
|
117
|
+
self.unpack("H*").first
|
118
|
+
end
|
119
|
+
|
120
|
+
# Convert a string of raw hex characters (no %'s or anything) into binary
|
121
|
+
def dehexify
|
122
|
+
[self].pack("H*")
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
class Integer
|
127
|
+
module IntegerExtensions
|
128
|
+
# Convert integers to binary strings
|
129
|
+
def to_l32; [self].pack "L"; end
|
130
|
+
def to_b32; [self].pack "N"; end
|
131
|
+
def to_l16; [self].pack "v"; end
|
132
|
+
def to_b16; [self].pack "n"; end
|
133
|
+
def to_u8; [self].pack "C"; end
|
134
|
+
|
135
|
+
# sign extend
|
136
|
+
def sx8; ([self].pack "c").unpack("C").first; end
|
137
|
+
def sx16; ([self].pack "s").unpack("S").first; end
|
138
|
+
def sx32; ([self].pack "l").unpack("L").first; end
|
139
|
+
|
140
|
+
def ffs
|
141
|
+
i = 0
|
142
|
+
v = self
|
143
|
+
while((v >>= 1) != 0)
|
144
|
+
i += 1
|
145
|
+
end
|
146
|
+
return i
|
147
|
+
end
|
148
|
+
end
|
149
|
+
include IntegerExtensions
|
150
|
+
end
|
151
|
+
|
152
|
+
class Module
|
153
|
+
def to_name_hash
|
154
|
+
@name_hash ||= constants.map {|k| [k.intern, const_get(k.intern)]}.to_hash
|
155
|
+
end
|
156
|
+
|
157
|
+
def to_key_hash
|
158
|
+
@key_hash ||= constants.map {|k| [const_get(k.intern), k.intern]}.to_hash
|
159
|
+
end
|
160
|
+
|
161
|
+
def flag_dump(i)
|
162
|
+
@bit_map ||= constants.map do |k|
|
163
|
+
[k, const_get(k.intern).ffs]
|
164
|
+
end.sort {|x, y| x[1] <=> y[1]}
|
165
|
+
|
166
|
+
last = 0
|
167
|
+
r = ""
|
168
|
+
@bit_map.each do |tup|
|
169
|
+
if((v = (tup[1] - last)) > 1)
|
170
|
+
r << ("." * (v-1))
|
171
|
+
end
|
172
|
+
|
173
|
+
if((i & (1 << tup[1])) != 0)
|
174
|
+
r << tup[0][0].chr
|
175
|
+
else
|
176
|
+
r << tup[0][0].chr.downcase
|
177
|
+
end
|
178
|
+
last = tup[1]
|
179
|
+
end
|
180
|
+
return r.reverse
|
181
|
+
end
|
182
|
+
end
|