plunder 2.0.0a

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bbebd78c8c112b0e33711b45fa10d1e6eabb4de4
4
+ data.tar.gz: 8acf065be1107b051e3434db977f03bd3e4074c1
5
+ SHA512:
6
+ metadata.gz: 232c90294a83f26e97de70ab32fb2f301592d1ef19656fb10a0a0a0c3d6482153c956905d2f1fe591b7837ab7d07425926d43b3cecc00c0324d5e010d1a212b2
7
+ data.tar.gz: 928179b760f52ece7f2a6883adf2a5fbd6b82530bc9eb31bb664c2158fc6a926e7e93aaf507c089b58a9b2e24ce180ea45df7f4e52e11d0be7cbb05d22dc6770
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- mode: ruby; -*-
3
+ #
4
+ # Plunder - SMB scanning and auditing tool
5
+ # Copyright (C) 2017 Joshua Stone
6
+ #
7
+ # This program is free software; you can redistribute it and/or
8
+ # modify it under the terms of the GNU General Public License
9
+ # as published by the Free Software Foundation; either version 2
10
+ # of the License, or (at your option) any later version.
11
+ #
12
+ # This program is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU General Public License
18
+ # along with this program; if not, write to the Free Software
19
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
+ #
21
+
22
+ require_relative '../ext/smbclient/smbclient.so'
23
+
24
+ domain = STDIN.readline.chomp
25
+ user = STDIN.readline.chomp
26
+ pass = STDIN.readline.chomp
27
+
28
+ client = SMBClient.new(domain, user, pass)
29
+
30
+ STDIN.each_line do |line|
31
+ begin
32
+ listing = client.list(line.chomp)
33
+ if listing == nil
34
+ STDOUT.puts "E failure"
35
+ else
36
+ (dirs, files) = client.list(line.chomp)
37
+ dirs.each { |dir| STDOUT.puts "D #{dir}" }
38
+ files.each { |file| STDOUT.puts "F #{file}" }
39
+ end
40
+ rescue Exception => e
41
+ log = open("agent.log", "a")
42
+ log.puts "Agent exception: #{e.class}:#{e.message}"
43
+ log.close
44
+ ensure
45
+ STDOUT.puts "C done"
46
+ STDOUT.flush
47
+ end
48
+ end
@@ -0,0 +1,158 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- mode: ruby; -*-
3
+ #
4
+ # Plunder - SMB scanning and auditing tool
5
+ # Copyright (C) 2017 Joshua Stone
6
+ #
7
+ # This program is free software; you can redistribute it and/or
8
+ # modify it under the terms of the GNU General Public License
9
+ # as published by the Free Software Foundation; either version 2
10
+ # of the License, or (at your option) any later version.
11
+ #
12
+ # This program is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU General Public License
18
+ # along with this program; if not, write to the Free Software
19
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
+ #
21
+
22
+ $pry = false
23
+
24
+ require 'time'
25
+ require 'set'
26
+ require 'pry'
27
+ require 'yaml'
28
+ require 'uri'
29
+
30
+ require_relative '../lib/core/io.rb'
31
+ require_relative '../lib/core/commands.rb'
32
+ require_relative '../lib/core/plunder.rb'
33
+ require_relative '../lib/core/config.rb'
34
+ require_relative '../lib/core/client.rb'
35
+
36
+ begin
37
+ require 'pry'
38
+ $pry = true
39
+ rescue LoadError
40
+ puts
41
+ Plunder::Report.error("'pry' gem not found, debugging will be less fun!")
42
+ end
43
+
44
+ Plunder::PlunderIO.banner
45
+
46
+ if ARGV.length == 0
47
+ Plunder::PlunderIO.usage
48
+ exit 1
49
+ end
50
+
51
+ cmd = Plunder::Commands.new do
52
+ command("init") do
53
+ name = next_arg
54
+ path = name + ".yaml"
55
+ default = Plunder::Config.default(name)
56
+ open(path, "w") { |file| file.write(default.to_yaml) }
57
+ puts " [+] wrote default config to file '\x1b[32;1m#{path}\x1b[0m'"
58
+ end
59
+
60
+ command("scan") do
61
+ plunder = Plunder::Plunder.new(next_arg)
62
+ Plunder::Report.init(plunder.name)
63
+ begin
64
+ Plunder::Report.notify("<mag>#{Time::now.to_s}<rst> : Starting scan")
65
+ plunder.scan(next_arg.to_i)
66
+ ensure
67
+ Plunder::Report.notify("<mag>#{Time::now.to_s}<rst> : Completed scan")
68
+ plunder.save
69
+ end
70
+ end
71
+
72
+ command("creds") do
73
+ config = Plunder::Config.new(next_arg + ".yaml")
74
+ config[:domain] = next_arg.strip
75
+ config[:user] = next_arg.strip
76
+ config[:pass] = next_arg.strip
77
+ Plunder::Report.notify("Saved creds")
78
+ config.save
79
+ end
80
+
81
+ command("summary") do
82
+ plunder = Plunder::Plunder.new(next_arg)
83
+ plunder.load
84
+ domain = plunder.config[:domain]
85
+ user = plunder.config[:user]
86
+ pass = plunder.config[:pass]
87
+ Plunder::Report.notify("Credentials: '<cya>#{domain}<gra>\\<cya>#{user}<gra>'%'<cya>#{pass}<gra>'<rst>")
88
+ Plunder::Report.notify("Target Count: #{plunder.config[:targets].length}")
89
+ Plunder::Report.notify("Files indexed: #{plunder.fsdb.length}")
90
+ end
91
+
92
+ command("target") do
93
+ config = Plunder::Config.new(next_arg + ".yaml")
94
+ url = "smb://#{next_arg}/"
95
+ config.add_target(url)
96
+ end
97
+
98
+ command("targets") do
99
+ config = Plunder::Config.new(next_arg + ".yaml")
100
+ stream = STDIN
101
+ stream = open(next_arg) if @args.length > 0
102
+ stream.each_line do |line|
103
+ config.add_target("smb://#{line.chomp}/")
104
+ end
105
+ end
106
+
107
+ command("search") do
108
+ plunder = Plunder::Plunder.new(next_arg)
109
+ plunder.load
110
+ plunder.select_files(next_arg) do |file, id|
111
+ printf("FILE %-8d %s\n", id, URI::decode(file))
112
+ end
113
+ end
114
+
115
+ command("mirror") do
116
+ plunder = Plunder::Plunder.new(next_arg)
117
+ plunder.load
118
+ loaded = Set.new
119
+ stream = STDIN
120
+ stream = open(next_arg) if @args.length > 0
121
+ stream.each_line do |line|
122
+ url = plunder.fsdb[line.to_i]
123
+ unless loaded.member? url
124
+ plunder.mirror(url)
125
+ puts " [-] Mirrored '\x1b[32;1m#{url}\x1b[0m'"
126
+ loaded << url
127
+ end
128
+ end
129
+ end
130
+
131
+ command("listing") do
132
+ plunder = Plunder::Plunder.new(next_arg)
133
+ plunder.load
134
+ 0.upto(plunder.fsdb.length - 1) do |index|
135
+ printf("FILE %-8d %s\n", index, plunder.fsdb[index])
136
+ end
137
+ end
138
+
139
+ command("client") do
140
+ plunder = Plunder::Plunder.new(next_arg)
141
+ plunder.load
142
+ client = Plunder::Client.new(plunder)
143
+ puts ""
144
+ client.repl
145
+ end
146
+
147
+ if $pry
148
+ command("debug") do
149
+ plunder = Plunder::Plunder.new(next_arg)
150
+ plunder.load
151
+ binding.pry
152
+ end
153
+ end
154
+ end
155
+
156
+ cmd.run ARGV
157
+
158
+ puts ""
@@ -0,0 +1,13 @@
1
+ # Loads mkmf which is used to make makefiles for Ruby extensions
2
+ require 'mkmf'
3
+
4
+ $CFLAGS << ' -Wno-unused-result '
5
+
6
+ # Give it a name
7
+ extension_name = 'fsdb'
8
+
9
+ # The destination
10
+ dir_config(extension_name)
11
+
12
+ # Do the work
13
+ create_makefile(extension_name)
@@ -0,0 +1,134 @@
1
+ //
2
+ // Plunder - SMB scanning and auditing tool
3
+ // Copyright (C) 2017 Joshua Stone
4
+ //
5
+ // This program is free software; you can redistribute it and/or
6
+ // modify it under the terms of the GNU General Public License
7
+ // as published by the Free Software Foundation; either version 2
8
+ // of the License, or (at your option) any later version.
9
+ //
10
+ // This program is distributed in the hope that it will be useful,
11
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ // GNU General Public License for more details.
14
+ //
15
+ // You should have received a copy of the GNU General Public License
16
+ // along with this program; if not, write to the Free Software
17
+ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
+ //
19
+
20
+ #include "fsdb-c.h"
21
+
22
+ fsdb fsdb_init(int bins) {
23
+ fsdb f;
24
+
25
+ f.strings = vault_init(1024);
26
+ f.paths = vault_init(1024);
27
+ f.index = vault_init(1024);
28
+ f.hash = hash_init(bins);
29
+ f.count = 0;
30
+
31
+ return f;
32
+ }
33
+
34
+ uint32_t fsdb_insert_path(fsdb *f, char *path) {
35
+ uint32_t ret;
36
+ uint32_t indices[MAXPATHLEN];
37
+ char *cursor = path + 6;
38
+ char *base = cursor;
39
+ int pindex = 0;
40
+ uint32_t value = 0;
41
+
42
+ while(*cursor) {
43
+ if(*cursor == '/') {
44
+ *cursor = 0;
45
+ if(!match(f->hash, base, f->strings, &value)) {
46
+ value = vault_insert_string(&f->strings, base);
47
+ hash_put(&f->hash, base, value);
48
+ }
49
+ indices[pindex++] = value;
50
+ base = cursor + 1;
51
+ }
52
+ cursor++;
53
+ }
54
+
55
+ indices[pindex] = 0x48544150;
56
+
57
+ value = vault_insert_bytes(&f->paths, indices, (pindex + 1) * 4);
58
+ ret = vault_insert_bytes(&f->index, &value, 4);
59
+ f->count++;
60
+ return ret;
61
+ }
62
+
63
+ char *fsdb_get_id(fsdb f, int id) {
64
+ char *name;
65
+ int offset;
66
+ int len;
67
+
68
+ len = DEF_NAME_LEN;
69
+ name = (char *) malloc(len + 1);
70
+ offset = 0;
71
+
72
+ uint32_t path = *((uint32_t *)vault_get(f.index, id * 4));
73
+ uint32_t *cursor = (uint32_t *)vault_get(f.paths, path);
74
+
75
+ offset += snprintf(name, len - offset, "smb:/");
76
+ while(*cursor != 0x48544150) {
77
+ uint8_t *elt = vault_get(f.strings, *cursor++);
78
+ int bytes = strlen((char *)elt);
79
+
80
+ while(offset + bytes + 2 > len) {
81
+ len = (len << 1) - (len >> 1);
82
+ name = realloc(name, len + 1);
83
+ }
84
+
85
+ name[offset++] = '/';
86
+ memcpy(name + offset, elt, bytes);
87
+ offset += bytes;
88
+ }
89
+
90
+ name[offset] = 0;
91
+
92
+ return name;
93
+ }
94
+
95
+ uint32_t fsdb_intern(fsdb *f, char *s) {
96
+ uint32_t value = 0;
97
+
98
+ if(!match(f->hash, s, f->strings, &value)) {
99
+ value = vault_insert_string(&f->strings, s);
100
+ hash_put(&f->hash, s, value);
101
+ }
102
+
103
+ return value;
104
+ }
105
+
106
+ int match(hash h, char *s, vault v, uint32_t *val) {
107
+ int len = strlen(s);
108
+ cons *c;
109
+
110
+ if((c = hash_get(h, s))) {
111
+ while(c) {
112
+ if(strncmp(s, (char *)vault_get(v, c->index), len) == 0) {
113
+ *val = c->index;
114
+ return 1;
115
+ }
116
+ c = c->next;
117
+ }
118
+ }
119
+
120
+ // note that the above may fail if there are already colliding
121
+ // entries in the hash, but none of them are the same as the
122
+ // current target. So we need to fall through here to make
123
+ // sure "false positives" get handled appropriately.
124
+
125
+ return 0;
126
+ }
127
+
128
+ void fsdb_free(fsdb *f) {
129
+ vault_free(f->strings);
130
+ vault_free(f->paths);
131
+ vault_free(f->index);
132
+ hash_free(f->hash);
133
+ free(f);
134
+ }
@@ -0,0 +1,49 @@
1
+ //
2
+ // Plunder - SMB scanning and auditing tool
3
+ // Copyright (C) 2017 Joshua Stone
4
+ //
5
+ // This program is free software; you can redistribute it and/or
6
+ // modify it under the terms of the GNU General Public License
7
+ // as published by the Free Software Foundation; either version 2
8
+ // of the License, or (at your option) any later version.
9
+ //
10
+ // This program is distributed in the hope that it will be useful,
11
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ // GNU General Public License for more details.
14
+ //
15
+ // You should have received a copy of the GNU General Public License
16
+ // along with this program; if not, write to the Free Software
17
+ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
+ //
19
+
20
+ #ifndef FSDB_C_H
21
+ #define FSDB_C_H
22
+
23
+ #define MAXPATHLEN 256
24
+ #define DEF_NAME_LEN 128
25
+
26
+ #include <stdio.h>
27
+ #include <stdlib.h>
28
+ #include <stdint.h>
29
+
30
+ #include "vault.h"
31
+ #include "hash.h"
32
+ #include "utilities.h"
33
+
34
+ typedef struct {
35
+ vault strings;
36
+ vault paths;
37
+ vault index;
38
+ hash hash;
39
+ uint32_t count;
40
+ } fsdb;
41
+
42
+ fsdb fsdb_init(int bins);
43
+ uint32_t fsdb_insert_path(fsdb *f, char *path);
44
+ void fsdb_free(fsdb *f);
45
+ uint32_t fsdb_intern(fsdb *f, char *s);
46
+ int match(hash h, char *s, vault v, uint32_t *val);
47
+ char *fsdb_get_id(fsdb f, int id);
48
+
49
+ #endif
@@ -0,0 +1,267 @@
1
+ //
2
+ // Plunder - SMB scanning and auditing tool
3
+ // Copyright (C) 2017 Joshua Stone
4
+ //
5
+ // This program is free software; you can redistribute it and/or
6
+ // modify it under the terms of the GNU General Public License
7
+ // as published by the Free Software Foundation; either version 2
8
+ // of the License, or (at your option) any later version.
9
+ //
10
+ // This program is distributed in the hope that it will be useful,
11
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ // GNU General Public License for more details.
14
+ //
15
+ // You should have received a copy of the GNU General Public License
16
+ // along with this program; if not, write to the Free Software
17
+ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
+ //
19
+
20
+ #include <ruby.h>
21
+ #include <ctype.h>
22
+ #include "fsdb-c.h"
23
+
24
+ VALUE fsdb_klass = Qnil;
25
+
26
+ void Init_fsdb();
27
+ VALUE method_init(VALUE self);
28
+ VALUE method_setup(VALUE self);
29
+ VALUE method_put(VALUE self, VALUE string);
30
+ VALUE method_debug(VALUE self);
31
+ VALUE method_get(VALUE self, VALUE num);
32
+ VALUE method_length(VALUE self);
33
+ VALUE method_contains(VALUE self, VALUE string);
34
+ VALUE method_intern(VALUE self, VALUE string);
35
+ VALUE method_lookup(VALUE self, VALUE num);
36
+ VALUE method_write(VALUE self, VALUE path);
37
+ VALUE method_read(VALUE self, VALUE path);
38
+ VALUE method_each_name(VALUE self);
39
+ VALUE method_select_index(VALUE self, VALUE target);
40
+
41
+ void Init_fsdb() {
42
+ fsdb_klass = rb_define_class("FSDB", rb_cObject);
43
+
44
+ rb_define_singleton_method(fsdb_klass, "new", method_setup, 0);
45
+ rb_define_singleton_method(fsdb_klass, "read", method_read, 1);
46
+
47
+ rb_define_method(fsdb_klass, "put", method_put, 1);
48
+ rb_define_method(fsdb_klass, "[]", method_get, 1);
49
+ rb_define_method(fsdb_klass, "debug", method_debug, 0);
50
+ rb_define_method(fsdb_klass, "length", method_length, 0);
51
+ rb_define_method(fsdb_klass, "contains", method_contains, 1);
52
+ rb_define_method(fsdb_klass, "intern", method_intern, 1);
53
+ rb_define_method(fsdb_klass, "lookup", method_lookup, 1);
54
+ rb_define_method(fsdb_klass, "write", method_write, 1);
55
+ rb_define_method(fsdb_klass, "each_name", method_each_name, 0);
56
+ rb_define_method(fsdb_klass, "select_index", method_select_index, 1);
57
+ }
58
+
59
+ VALUE method_setup(VALUE self) {
60
+ fsdb *f;
61
+ f = (fsdb *) malloc(sizeof(fsdb));
62
+ *f = fsdb_init(1 << 19);
63
+ return Data_Wrap_Struct(fsdb_klass, NULL, fsdb_free, f);
64
+ }
65
+
66
+ VALUE method_put(VALUE self, VALUE string) {
67
+ char *s = StringValueCStr(string);
68
+ fsdb *f;
69
+ Data_Get_Struct(self, fsdb, f);
70
+ return UINT2NUM((fsdb_insert_path(f, s) / sizeof(uint32_t)) - 1);
71
+ }
72
+
73
+ VALUE method_debug(VALUE self) {
74
+ fsdb *f;
75
+ Data_Get_Struct(self, fsdb, f);
76
+ printf(" # Count: %d\n", f->count);
77
+ vault_info(f->strings, "Strings");
78
+ hexdump(f->strings.base, 256);
79
+
80
+ vault_info(f->paths, "Paths");
81
+ hexdump(f->paths.base, 256);
82
+
83
+ vault_info(f->index, "Index");
84
+ hexdump(f->index.base, 256);
85
+
86
+ hash_info(f->hash);
87
+ return Qtrue;
88
+ }
89
+
90
+ VALUE method_get(VALUE self, VALUE num) {
91
+ fsdb *f;
92
+ VALUE ret;
93
+ unsigned int i;
94
+
95
+ i = NUM2UINT(num) + 1;
96
+ Data_Get_Struct(self, fsdb, f);
97
+
98
+ if(i > 0 && i <= f->count) {
99
+ char *name = fsdb_get_id(*f, i);
100
+ ret = rb_str_new_cstr(name);
101
+ free(name);
102
+ return ret;
103
+ } else {
104
+ return Qnil;
105
+ }
106
+ }
107
+
108
+ VALUE method_contains(VALUE self, VALUE string) {
109
+ char *s = StringValueCStr(string);
110
+ fsdb *f;
111
+ int i;
112
+ VALUE ret = rb_eval_string_protect("[]", &i);
113
+ char *buffer;
114
+ int buflen;
115
+
116
+ buflen = 1024;
117
+ buffer = (char *)malloc(buflen);
118
+
119
+ Data_Get_Struct(self, fsdb, f);
120
+ for(i = 1; i <= f->count; i++) {
121
+ char *name = fsdb_get_id(*f, i);
122
+ int len = strlen(name);
123
+
124
+ while(len + 1 > buflen) {
125
+ buflen = buflen * 2;
126
+ buffer = realloc(buffer, buflen + 1);
127
+ }
128
+
129
+ strncpy(buffer, name, len + 1);
130
+ for(char *p = buffer; *p; p++)
131
+ *p = tolower(*p);
132
+
133
+ if(strstr(buffer, s)) {
134
+ rb_funcall(ret, rb_intern("<<"), 1, rb_str_new_cstr(name));
135
+ }
136
+
137
+ free(name);
138
+ }
139
+
140
+ return ret;
141
+ }
142
+
143
+ VALUE method_length(VALUE self) {
144
+ fsdb *f;
145
+ Data_Get_Struct(self, fsdb, f);
146
+ return UINT2NUM(f->count);
147
+ }
148
+
149
+ VALUE method_intern(VALUE self, VALUE string) {
150
+ char *s;
151
+ fsdb *f;
152
+
153
+ s = StringValueCStr(string);
154
+ Data_Get_Struct(self, fsdb, f);
155
+
156
+ return UINT2NUM(fsdb_intern(f, s));
157
+ }
158
+
159
+ VALUE method_lookup(VALUE self, VALUE num) {
160
+ fsdb *f;
161
+ char *s;
162
+
163
+ Data_Get_Struct(self, fsdb, f);
164
+ s = (char *)vault_get(f->strings, NUM2UINT(num));
165
+
166
+ return rb_str_new_cstr(s);
167
+ }
168
+
169
+ VALUE method_write(VALUE self, VALUE path) {
170
+ char *p = StringValueCStr(path);
171
+ fsdb *f;
172
+ FILE *out;
173
+ Data_Get_Struct(self, fsdb, f);
174
+
175
+ if(!(out = fopen(p, "wb"))) {
176
+ return Qnil;
177
+ }
178
+
179
+ fwrite(f, sizeof(fsdb), 1, out);
180
+ fwrite(f->strings.base, 1, f->strings.size, out);
181
+ fwrite(f->paths.base, 1, f->paths.size, out);
182
+ fwrite(f->index.base, 1, f->index.size, out);
183
+ hash_write(f->hash, out);
184
+
185
+ fclose(out);
186
+
187
+ return Qtrue;
188
+ }
189
+
190
+ VALUE method_read(VALUE self, VALUE path) {
191
+ char *p = StringValueCStr(path);
192
+ fsdb *f;
193
+ FILE *in;
194
+
195
+ f = (fsdb *) malloc(sizeof(fsdb));
196
+
197
+ if(!(in = fopen(p, "rb"))) {
198
+ return Qnil;
199
+ }
200
+
201
+ fread(f, sizeof(fsdb), 1, in);
202
+
203
+ f->strings.base = (uint8_t *) malloc(f->strings.size);
204
+ f->paths.base = (uint8_t *) malloc(f->paths.size);
205
+ f->index.base = (uint8_t *) malloc(f->index.size);
206
+
207
+ fread(f->strings.base, 1, f->strings.size, in);
208
+ fread(f->paths.base, 1, f->paths.size, in);
209
+ fread(f->index.base, 1, f->index.size, in);
210
+ f->hash = hash_read(in);
211
+
212
+ fclose(in);
213
+
214
+ return Data_Wrap_Struct(fsdb_klass, NULL, fsdb_free, f);
215
+ }
216
+
217
+ VALUE method_each_name(VALUE self) {
218
+ if(rb_block_given_p()) {
219
+ fsdb *f;
220
+ char *top, *cursor;
221
+
222
+ Data_Get_Struct(self, fsdb, f);
223
+ cursor = (char *)(f->strings.base + 4);
224
+ top = f->strings.top + ((char *)f->strings.base);
225
+
226
+ while(cursor < top) {
227
+ int len = strlen(cursor);
228
+ VALUE name = rb_str_new(cursor, len);
229
+ VALUE num = UINT2NUM(cursor - ((char *)f->strings.base));
230
+ rb_yield_values(2, name, num);
231
+ cursor += len + 1;
232
+ }
233
+ return Qtrue;
234
+ }
235
+ return Qnil;
236
+ }
237
+
238
+ VALUE method_select_index(VALUE self, VALUE target) {
239
+ uint32_t index = 0;
240
+ uint32_t value = NUM2UINT(target);
241
+ uint32_t sep = 0x48544150;
242
+
243
+ if(rb_block_given_p()) {
244
+ fsdb *f;
245
+ uint32_t *top, *cursor;
246
+
247
+ Data_Get_Struct(self, fsdb, f);
248
+
249
+ cursor = ((uint32_t *)(f->paths.base)) + 1;
250
+ top = (uint32_t *)(f->paths.top + ((char *)f->paths.base));
251
+
252
+ while(cursor < top) {
253
+ fflush(stdout);
254
+ while(*cursor != sep) {
255
+ if(*cursor == value && *(cursor+1) == sep) {
256
+ rb_yield(UINT2NUM(index));
257
+ }
258
+ cursor++;
259
+ }
260
+ cursor++;
261
+ index++;
262
+ }
263
+
264
+ return Qtrue;
265
+ }
266
+ return Qnil;
267
+ }