frida 0.1.0 → 0.1.1

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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/CODE_OF_CONDUCT.md +84 -0
  3. data/Gemfile +12 -0
  4. data/Gemfile.lock +25 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +64 -0
  7. data/Rakefile +20 -0
  8. data/exe/frida +3 -0
  9. data/ext/c_frida/Application.c +79 -0
  10. data/ext/c_frida/Bus.c +91 -0
  11. data/ext/c_frida/Child.c +134 -0
  12. data/ext/c_frida/Compiler.c +208 -0
  13. data/ext/c_frida/Crash.c +92 -0
  14. data/ext/c_frida/Device.c +955 -0
  15. data/ext/c_frida/DeviceManager.c +260 -0
  16. data/ext/c_frida/EndpointParameters.c +189 -0
  17. data/ext/c_frida/FileMonitor.c +67 -0
  18. data/ext/c_frida/GObject.c +138 -0
  19. data/ext/c_frida/IOStream.c +228 -0
  20. data/ext/c_frida/PortalMembership.c +43 -0
  21. data/ext/c_frida/PortalService.c +413 -0
  22. data/ext/c_frida/Process.c +67 -0
  23. data/ext/c_frida/Relay.c +121 -0
  24. data/ext/c_frida/Script.c +221 -0
  25. data/ext/c_frida/Session.c +626 -0
  26. data/ext/c_frida/Spawn.c +53 -0
  27. data/ext/c_frida/c_frida.c +68 -0
  28. data/ext/c_frida/extconf.rb +26 -25
  29. data/ext/c_frida/gutils.c +498 -0
  30. data/ext/c_frida/gvl_bridge.c +131 -0
  31. data/ext/c_frida/inc/Application.h +9 -0
  32. data/ext/c_frida/inc/Bus.h +15 -0
  33. data/ext/c_frida/inc/Child.h +9 -0
  34. data/ext/c_frida/inc/Compiler.h +21 -0
  35. data/ext/c_frida/inc/Crash.h +9 -0
  36. data/ext/c_frida/inc/Device.h +71 -0
  37. data/ext/c_frida/inc/DeviceManager.h +20 -0
  38. data/ext/c_frida/inc/EndpointParameters.h +15 -0
  39. data/ext/c_frida/inc/FileMonitor.h +9 -0
  40. data/ext/c_frida/inc/GObject.h +10 -0
  41. data/ext/c_frida/inc/IOStream.h +29 -0
  42. data/ext/c_frida/inc/PortalMembership.h +9 -0
  43. data/ext/c_frida/inc/PortalService.h +47 -0
  44. data/ext/c_frida/inc/Process.h +9 -0
  45. data/ext/c_frida/inc/Relay.h +9 -0
  46. data/ext/c_frida/inc/Script.h +21 -0
  47. data/ext/c_frida/inc/Session.h +40 -0
  48. data/ext/c_frida/inc/Spawn.h +9 -0
  49. data/ext/c_frida/inc/c_frida.h +129 -0
  50. data/ext/c_frida/inc/gutils.h +21 -0
  51. data/ext/c_frida/inc/gvl_bridge.h +42 -0
  52. data/frida.gemspec +39 -0
  53. data/lib/frida/version.rb +5 -0
  54. data/lib/frida.rb +8 -0
  55. metadata +55 -3
@@ -0,0 +1,955 @@
1
+ #include "Device.h"
2
+
3
+ VALUE Device_from_FridaDevice(FridaDevice *device)
4
+ {
5
+ GVariant * icon;
6
+ VALUE self;
7
+
8
+ if (!device) return (Qnil);
9
+ self = rb_class_new_instance(0, NULL, cDevice);
10
+ GET_GOBJECT_DATA();
11
+ d->handle = device;
12
+ d->destroy = frida_unref;
13
+ rb_ivar_set(self, rb_intern("id"), rb_str_new_cstr(frida_device_get_id(d->handle)));
14
+ rb_ivar_set(self, rb_intern("name"), rb_str_new_cstr(frida_device_get_name(d->handle)));
15
+ rb_ivar_set(self, rb_intern("type"), rbGObject_marshal_enum(frida_device_get_dtype(d->handle), FRIDA_TYPE_DEVICE_TYPE));
16
+ rb_ivar_set(self, rb_intern("bus"), Bus_from_FridaBus(g_object_ref(frida_device_get_bus(d->handle))));
17
+ icon = frida_device_get_icon(d->handle);
18
+ rb_ivar_set(self, rb_intern("icon"), icon ? rbGObject_marshal_variant(icon) : Qnil);
19
+ return (self);
20
+ }
21
+
22
+ /*
23
+ call-seq:
24
+ #id() -> String
25
+ */
26
+ static VALUE Device_id(VALUE self)
27
+ {
28
+ return (rb_ivar_get(self, rb_intern("id")));
29
+ }
30
+
31
+ /*
32
+ call-seq:
33
+ #name() -> String
34
+ */
35
+ static VALUE Device_name(VALUE self)
36
+ {
37
+ return (rb_ivar_get(self, rb_intern("name")));
38
+ }
39
+
40
+ /*
41
+ call-seq:
42
+ #type() -> String
43
+ */
44
+ static VALUE Device_type(VALUE self)
45
+ {
46
+ return (rb_ivar_get(self, rb_intern("type")));
47
+ }
48
+
49
+ /*
50
+ call-seq:
51
+ #bus() -> Bus
52
+ */
53
+ static VALUE Device_bus(VALUE self)
54
+ {
55
+ return (rb_ivar_get(self, rb_intern("bus")));
56
+ }
57
+
58
+ /*
59
+ call-seq:
60
+ #icon() -> String
61
+ */
62
+ static VALUE Device_icon(VALUE self)
63
+ {
64
+ return (rb_ivar_get(self, rb_intern("icon")));
65
+ }
66
+
67
+ static VALUE Device_inspect(VALUE self)
68
+ {
69
+ VALUE s, id, name, type;
70
+
71
+ id = rb_funcall(self, rb_intern("id"), 0, NULL);
72
+ name = rb_funcall(self, rb_intern("name"), 0, NULL);
73
+ type = rb_funcall(self, rb_intern("type"), 0, NULL);
74
+ s = rb_sprintf("#<Device: id=%+"PRIsVALUE", name=%+"PRIsVALUE", type=%+"PRIsVALUE">", id, name, type);
75
+ return (s);
76
+ }
77
+
78
+ GVL_FREE_PROXY_FUNC(open_channel_sync, open_channel_proxy_args *args)
79
+ {
80
+ GError *gerr = NULL;
81
+ GIOStream *stream;
82
+
83
+ stream = frida_device_open_channel_sync(args->device_handle, args->address, NULL, &gerr);
84
+ RETURN_GVL_FREE_RESULT(stream);
85
+ }
86
+
87
+ /*
88
+ call-seq:
89
+ #open_channel(address) -> IOStream
90
+ */
91
+ static VALUE Device_open_channel(VALUE self, VALUE address)
92
+ {
93
+ GET_GOBJECT_DATA();
94
+ REQUIRE_GOBJECT_HANDLE();
95
+ if (!RB_TYPE_P(address, T_STRING)) {
96
+ raise_argerror("address should be a string.");
97
+ return (Qnil);
98
+ }
99
+ open_channel_proxy_args args = {
100
+ .device_handle = d->handle,
101
+ .address = StringValueCStr(address)
102
+ };
103
+ CALL_GVL_FREE_WITH_RET(GIOStream *stream, open_channel_sync, &args);
104
+ return (IOStream_from_GIOStream(stream));
105
+
106
+ GERROR_BLOCK
107
+ }
108
+
109
+ GVL_FREE_PROXY_FUNC(is_lost, void *device_handle)
110
+ {
111
+ GError *gerr = NULL;
112
+ void *is_lost = NULL;
113
+
114
+ is_lost += frida_device_is_lost(device_handle);
115
+ RETURN_GVL_FREE_RESULT(is_lost);
116
+ }
117
+
118
+ /*
119
+ call-seq:
120
+ #is_lost() -> [TrueClass, FalseClass]
121
+ */
122
+ static VALUE Device_is_lost(VALUE self)
123
+ {
124
+ GET_GOBJECT_DATA();
125
+ REQUIRE_GOBJECT_HANDLE();
126
+ CALL_GVL_FREE_WITH_RET(void *is_lost, is_lost, d->handle);
127
+ return (is_lost ? Qtrue : Qfalse);
128
+
129
+ UNREACHABLE_GERROR_BLOCK
130
+ }
131
+
132
+ GVL_FREE_PROXY_FUNC(query_system_parameters_sync, void *device_handle)
133
+ {
134
+ GError *gerr = NULL;
135
+ GHashTable *params;
136
+
137
+ params = frida_device_query_system_parameters_sync(device_handle, NULL, &gerr);
138
+ RETURN_GVL_FREE_RESULT(params);
139
+ }
140
+
141
+ /*
142
+ call-seq:
143
+ #query_system_parameters() -> Hash
144
+ */
145
+ static VALUE Device_query_system_parameters(VALUE self)
146
+ {
147
+ GET_GOBJECT_DATA();
148
+ REQUIRE_GOBJECT_HANDLE();
149
+ CALL_GVL_FREE_WITH_RET(void *params, query_system_parameters_sync, d->handle);
150
+ return (rbGObject_marshal_dict(params));
151
+
152
+ GERROR_BLOCK
153
+ }
154
+
155
+ GVL_FREE_PROXY_FUNC(get_frontmost_application_sync, get_frontmost_application_proxy_args *args)
156
+ {
157
+ GError *gerr = NULL;
158
+ void *app;
159
+
160
+ app = frida_device_get_frontmost_application_sync(args->device_handle, args->options, NULL, &gerr);
161
+ RETURN_GVL_FREE_RESULT(app);
162
+ }
163
+
164
+ /*
165
+ call-seq:
166
+ #get_frontmost_application(scope:) -> Application
167
+ */
168
+ static VALUE Device_get_frontmost_application(int argc, VALUE *argv, VALUE self)
169
+ {
170
+ GET_GOBJECT_DATA();
171
+ REQUIRE_GOBJECT_HANDLE();
172
+ FridaFrontmostQueryOptions *options;
173
+ VALUE scope = Qnil;
174
+ VALUE kws;
175
+
176
+ rb_scan_args(argc, argv, ":", &kws);
177
+ options = frida_frontmost_query_options_new();
178
+ if (!NIL_P(kws)) {
179
+ scope = rb_hash_aref(kws, ID2SYM(rb_intern("scope")));
180
+ if (!NIL_P(scope)) {
181
+ if (!RB_TYPE_P(scope, T_STRING)) {
182
+ raise_argerror("scope must be a string.");
183
+ return (Qnil);
184
+ }
185
+ FridaScope fscope;
186
+ if (!rbGObject_unmarshal_enum(StringValueCStr(scope), FRIDA_TYPE_SCOPE, &fscope))
187
+ goto invalid_argument;
188
+ frida_frontmost_query_options_set_scope(options, scope);
189
+ }
190
+ }
191
+ get_frontmost_application_proxy_args args = {
192
+ .device_handle = d->handle,
193
+ .options = options
194
+ };
195
+ CALL_GVL_FREE_WITH_RET(void *app, get_frontmost_application_sync, &args);
196
+ g_object_unref (options);
197
+ return (Application_from_FridaApplication(app));
198
+
199
+ invalid_argument:
200
+ g_object_unref(options);
201
+ return (Qnil);
202
+ gerror:
203
+ g_object_unref(options);
204
+ raise_rerror(NULL, _gerr);
205
+ return (Qnil);
206
+ }
207
+
208
+ int array_all_type(VALUE arr, VALUE rtype)
209
+ {
210
+ long len = RARRAY_LEN(arr);
211
+
212
+ for (uint i = 0; i < len; i++) {
213
+ if (!RB_TYPE_P(RARRAY_AREF(arr, i), rtype))
214
+ return (0);
215
+ }
216
+ return (1);
217
+ }
218
+
219
+ GVL_FREE_PROXY_FUNC(enumerate_processes_sync, enumerate_processes_proxy_args *args)
220
+ {
221
+ GError *gerr;
222
+ void *procs;
223
+
224
+ procs = frida_device_enumerate_processes_sync(args->device_handle, args->options, NULL, &gerr);
225
+ RETURN_GVL_FREE_RESULT(procs);
226
+ }
227
+
228
+ /*
229
+ call-seq:
230
+ #enumerate_processes(pids:, scope:) -> Array[Process]
231
+ */
232
+ static VALUE Device_enumerate_processes(int argc, VALUE *argv, VALUE self)
233
+ {
234
+ GET_GOBJECT_DATA();
235
+ REQUIRE_GOBJECT_HANDLE();
236
+ FridaProcessQueryOptions *options;
237
+ VALUE pids, scope = Qnil;
238
+ VALUE kws;
239
+
240
+ rb_scan_args(argc, argv, ":", &kws);
241
+ options = frida_process_query_options_new();
242
+ if (!NIL_P(kws)) {
243
+ pids = rb_hash_aref(kws, ID2SYM(rb_intern("pids")));
244
+ if (!NIL_P(pids)) {
245
+ if (!RB_TYPE_P(pids, T_ARRAY) || !array_all_type(pids, T_FIXNUM)) {
246
+ raise_argerror("pids must be an array of integers.");
247
+ return (Qnil);
248
+ }
249
+ long len = RARRAY_LEN(pids);
250
+ VALUE pid;
251
+ for (uint i = 0; i < len; i++) {
252
+ pid = RARRAY_AREF(pids, i);
253
+ frida_process_query_options_select_pid(options, NUM2UINT(pid));
254
+ }
255
+ }
256
+ scope = rb_hash_aref(kws, ID2SYM(rb_intern("scope")));
257
+ if (!NIL_P(scope)) {
258
+ if (!RB_TYPE_P(scope, T_STRING)) {
259
+ raise_argerror("scope must be a string.");
260
+ return (Qnil);
261
+ }
262
+ FridaScope frida_scope;
263
+ if (!rbGObject_unmarshal_enum(StringValueCStr(scope), FRIDA_TYPE_SCOPE, &frida_scope))
264
+ goto error;
265
+ frida_process_query_options_set_scope(options, frida_scope);
266
+ }
267
+ }
268
+ enumerate_processes_proxy_args args = {
269
+ .device_handle = d->handle,
270
+ .options = options
271
+ };
272
+ CALL_GVL_FREE_WITH_RET(FridaProcessList *procs, enumerate_processes_sync, &args);
273
+ g_object_unref(options);
274
+ int procs_count = frida_process_list_size(procs);
275
+ VALUE procs_arr = rb_ary_new_capa(procs_count);
276
+ for (gint i = 0; i < procs_count; i++) {
277
+ rb_ary_store(procs_arr, i, Process_from_FridaProcess(frida_process_list_get(procs, i)));
278
+ }
279
+ g_object_unref(procs);
280
+ return (procs_arr);
281
+
282
+ gerror:
283
+ raise_rerror(NULL, _gerr);
284
+ error:
285
+ g_object_unref(options);
286
+ return (Qnil);
287
+ }
288
+
289
+ GVL_FREE_PROXY_FUNC(enumerate_applications_sync, enumerate_applications_proxy_args *args)
290
+ {
291
+ GError *gerr;
292
+ void *apps;
293
+
294
+ apps = frida_device_enumerate_applications_sync(args->device_handle, args->options, NULL, &gerr);
295
+ RETURN_GVL_FREE_RESULT(apps);
296
+ }
297
+
298
+ /*
299
+ call-seq:
300
+ #enumerate_applications(identifiers:, scope:) -> Array[Application]
301
+ */
302
+ static VALUE Device_enumerate_applications(int argc, VALUE *argv, VALUE self)
303
+ {
304
+ GET_GOBJECT_DATA();
305
+ REQUIRE_GOBJECT_HANDLE();
306
+ FridaApplicationQueryOptions *options;
307
+ VALUE identifiers, scope = Qnil;
308
+ VALUE kws;
309
+
310
+ rb_scan_args(argc, argv, ":", &kws);
311
+ options = frida_application_query_options_new();
312
+ if (!NIL_P(kws)) {
313
+ identifiers = rb_hash_aref(kws, ID2SYM(rb_intern("identifiers")));
314
+ if (!NIL_P(identifiers)) {
315
+ if (!RB_TYPE_P(identifiers, T_ARRAY) || !array_all_type(identifiers, T_STRING)) {
316
+ raise_argerror("identifiers must be an array of strings.");
317
+ return (Qnil);
318
+ }
319
+ long len = RARRAY_LEN(identifiers);
320
+ VALUE id;
321
+ for (uint i = 0; i < len; i++) {
322
+ id = RARRAY_AREF(identifiers, i);
323
+ frida_application_query_options_select_identifier(options, StringValueCStr(id));
324
+ }
325
+ }
326
+ scope = rb_hash_aref(kws, ID2SYM(rb_intern("scope")));
327
+ if (!NIL_P(scope)) {
328
+ if (!RB_TYPE_P(scope, T_STRING)) {
329
+ raise_argerror("scope must be a string.");
330
+ return (Qnil);
331
+ }
332
+ FridaScope frida_scope;
333
+ if (!rbGObject_unmarshal_enum(StringValueCStr(scope), FRIDA_TYPE_SCOPE, &frida_scope))
334
+ goto error;
335
+ frida_application_query_options_set_scope(options, frida_scope);
336
+ }
337
+ }
338
+ enumerate_applications_proxy_args args = {
339
+ .device_handle = d->handle,
340
+ .options = options
341
+ };
342
+ CALL_GVL_FREE_WITH_RET(FridaApplicationList *apps, enumerate_applications_sync, &args);
343
+ g_object_unref(options);
344
+ int apps_count = frida_application_list_size(apps);
345
+ VALUE apps_arr = rb_ary_new_capa(apps_count);
346
+ for (gint i = 0; i < apps_count; i++) {
347
+ rb_ary_store(apps_arr, i, Application_from_FridaApplication(frida_application_list_get(apps, i)));
348
+ }
349
+ g_object_unref(apps);
350
+ return (apps_arr);
351
+
352
+ gerror:
353
+ raise_rerror(NULL, _gerr);
354
+ error:
355
+ g_object_unref(options);
356
+ return (Qnil);
357
+ }
358
+
359
+ GVL_FREE_PROXY_FUNC(enable_spawn_gating_sync, void *device_handle)
360
+ {
361
+ GError *gerr = NULL;
362
+
363
+ frida_device_enable_spawn_gating_sync(device_handle, NULL, &gerr);
364
+ RETURN_GVL_FREE_RESULT(NULL);
365
+ }
366
+
367
+ /*
368
+ call-seq:
369
+ #enable_spawn_gating() -> nil
370
+ */
371
+ static VALUE Device_enable_spawn_gating(VALUE self)
372
+ {
373
+ GET_GOBJECT_DATA();
374
+ REQUIRE_GOBJECT_HANDLE();
375
+
376
+ CALL_GVL_FREE_WITH_RET(void *dummy, enable_spawn_gating_sync, d->handle);
377
+ return (Qnil);
378
+
379
+ GERROR_BLOCK
380
+ }
381
+
382
+ GVL_FREE_PROXY_FUNC(disable_spawn_gating_sync, void *device_handle)
383
+ {
384
+ GError *gerr = NULL;
385
+
386
+ frida_device_disable_spawn_gating_sync(device_handle, NULL, &gerr);
387
+ RETURN_GVL_FREE_RESULT(NULL);
388
+ }
389
+
390
+ /*
391
+ call-seq:
392
+ #disable_spawn_gating() -> nil
393
+ */
394
+ static VALUE Device_disable_spawn_gating(VALUE self)
395
+ {
396
+ GET_GOBJECT_DATA();
397
+ REQUIRE_GOBJECT_HANDLE();
398
+
399
+ CALL_GVL_FREE_WITH_RET(void *dummy, disable_spawn_gating_sync, d->handle);
400
+ return (Qnil);
401
+
402
+ GERROR_BLOCK
403
+ }
404
+
405
+ static int hash_all_type(VALUE hash, VALUE rtype)
406
+ {
407
+ VALUE keys = rb_funcall(hash, rb_intern("keys"), 0);
408
+
409
+ long keys_count = RARRAY_LEN(keys);
410
+ for (uint i = 0; i < keys_count; i++) {
411
+ VALUE key = rb_ary_entry(keys, i);
412
+ VALUE value = rb_hash_aref(hash, key);
413
+ if (!RB_TYPE_P(key, rtype) || !RB_TYPE_P(value, rtype)) {
414
+ return 0;
415
+ }
416
+ }
417
+ return 1;
418
+ }
419
+
420
+ GVL_FREE_PROXY_FUNC(spawn_sync, spawn_sync_proxy_args *args)
421
+ {
422
+ GError *gerr;
423
+ char *pid = NULL;
424
+
425
+ pid += frida_device_spawn_sync(args->device_handle, args->program, args->options, NULL, &gerr);
426
+ RETURN_GVL_FREE_RESULT(pid);
427
+ }
428
+
429
+ static FridaSpawnOptions *parse_spwan_options(FridaSpawnOptions * options, VALUE kws)
430
+ {
431
+ VALUE argv, envp, env, cwd, rstdio, aux;
432
+
433
+ argv = rb_hash_aref(kws, ID2SYM(rb_intern("argv")));
434
+ if (!NIL_P(argv)) {
435
+ if (!RB_TYPE_P(argv, T_ARRAY) || !array_all_type(argv, T_STRING)) {
436
+ raise_argerror("argv must be an array of strings.");
437
+ return (NULL);
438
+ }
439
+ gchar **c_argv;
440
+ gint argv_count;
441
+ rbGObject_unmarshal_strv(argv, &c_argv, &argv_count);
442
+ frida_spawn_options_set_argv(options, c_argv, argv_count);
443
+ g_strfreev(c_argv);
444
+ }
445
+ envp = rb_hash_aref(kws, ID2SYM(rb_intern("envp")));
446
+ if (!NIL_P(envp)) {
447
+ if (!RB_TYPE_P(envp, T_HASH) || !hash_all_type(envp, T_STRING)) {
448
+ raise_argerror("envp must be a hash of keys and values as strings.");
449
+ return (NULL);
450
+ }
451
+ gchar **c_envp;
452
+ gint envp_count;
453
+ rbGObject_unmarshal_envp(envp, &c_envp, &envp_count);
454
+ frida_spawn_options_set_envp(options, c_envp, envp_count);
455
+ }
456
+ env = rb_hash_aref(kws, ID2SYM(rb_intern("env")));
457
+ if (!NIL_P(env)) {
458
+ if (!RB_TYPE_P(env, T_HASH) || !hash_all_type(env, T_STRING)) {
459
+ raise_argerror("env must be a hash of keys and values as strings.");
460
+ return (NULL);
461
+ }
462
+ gchar **c_env;
463
+ gint env_count;
464
+ rbGObject_unmarshal_envp(env, &c_env, &env_count);
465
+ frida_spawn_options_set_env(options, c_env, env_count);
466
+ }
467
+ cwd = rb_hash_aref(kws, ID2SYM(rb_intern("cwd")));
468
+ if (!NIL_P(cwd)) {
469
+ if (!RB_TYPE_P(cwd, T_STRING)) {
470
+ raise_argerror("cwd must be a string.");
471
+ return (NULL);
472
+ }
473
+ frida_spawn_options_set_cwd(options, StringValueCStr(cwd));
474
+ }
475
+ rstdio = rb_hash_aref(kws, ID2SYM(rb_intern("stdio")));
476
+ if (!NIL_P(rstdio)) {
477
+ if (!RB_TYPE_P(rstdio, T_STRING)) {
478
+ raise_argerror("stdio must be a string.");
479
+ return (NULL);
480
+ }
481
+ FridaStdio stdio;
482
+ if (!rbGObject_unmarshal_enum(StringValueCStr(rstdio), FRIDA_TYPE_STDIO, &stdio)) {
483
+ raise_argerror("stdio is invalid.");
484
+ return (NULL);
485
+ }
486
+ frida_spawn_options_set_stdio(options, stdio);
487
+ }
488
+ aux = rb_hash_aref(kws, ID2SYM(rb_intern("aux")));
489
+ if (!NIL_P(aux)) {
490
+ if (!RB_TYPE_P(aux, T_HASH)) {
491
+ raise_argerror("aux must be a hash.");
492
+ return (NULL);
493
+ }
494
+ VALUE keys = rb_funcall(aux, rb_intern("keys"), 0);
495
+ long keys_count = RARRAY_LEN(keys);
496
+ GHashTable *gaux = frida_spawn_options_get_aux(options);
497
+ GVariant *gvalue;
498
+ gchar *gkey;
499
+ for (uint i = 0; i < keys_count; i++) {
500
+ VALUE key = rb_ary_entry(keys, i);
501
+ if (!RB_TYPE_P(key, T_STRING)) {
502
+ raise_argerror("aux hash keys must be strings.");
503
+ return (NULL);
504
+ }
505
+ rbGObject_unmarshal_string(key, &gkey);
506
+ VALUE value = rb_hash_aref(aux, key);
507
+ if (!rbGObject_unmarshal_variant(value, &gvalue))
508
+ return (g_free(gkey), NULL);
509
+ g_hash_table_insert(gaux, gkey, g_variant_ref_sink(gvalue));
510
+ }
511
+ }
512
+ return (options);
513
+ }
514
+
515
+ /*
516
+ call-seq:
517
+ #spawn(program, argv:, envp:, env:, cwd:, stdio:, aux:) -> nil
518
+ */
519
+ static VALUE Device_spawn(int argc, VALUE *argv, VALUE self)
520
+ {
521
+ GET_GOBJECT_DATA();
522
+ REQUIRE_GOBJECT_HANDLE();
523
+ VALUE program, kws;
524
+
525
+ FridaSpawnOptions *options = frida_spawn_options_new();
526
+ rb_scan_args(argc, argv, "1:", &program, &kws);
527
+ if (!RB_TYPE_P(program, T_STRING)) {
528
+ raise_argerror("program must be a string.");
529
+ return (Qnil);
530
+ }
531
+ if (!NIL_P(kws)) {
532
+ options = parse_spwan_options(options, kws);
533
+ if (!options)
534
+ return (g_object_unref(options), Qnil);
535
+ }
536
+ spawn_sync_proxy_args args = {
537
+ .device_handle = d->handle,
538
+ .program = StringValueCStr(program),
539
+ .options = options
540
+ };
541
+ CALL_GVL_FREE_WITH_RET(void *pid, spawn_sync, &args);
542
+ g_object_unref(options);
543
+ return (UINT2NUM((unsigned long long)pid / sizeof(char)));
544
+
545
+ gerror:
546
+ g_object_unref(options);
547
+ raise_rerror(NULL, _gerr);
548
+ return (Qnil);
549
+ }
550
+
551
+ GVL_FREE_PROXY_FUNC(resume_sync, resume_sync_proxy_args *args)
552
+ {
553
+ GError *gerr = NULL;
554
+
555
+ frida_device_resume_sync(args->device_handle, args->pid, NULL, &gerr);
556
+ RETURN_GVL_FREE_RESULT(NULL);
557
+ }
558
+
559
+ /*
560
+ call-seq:
561
+ #resume(pid) -> nil
562
+ */
563
+ static VALUE Device_resume(VALUE self, VALUE pid)
564
+ {
565
+ GET_GOBJECT_DATA();
566
+ REQUIRE_GOBJECT_HANDLE();
567
+
568
+ if (!RB_TYPE_P(pid, T_FIXNUM)) {
569
+ raise_argerror("pid must be a number.");
570
+ return (Qnil);
571
+ }
572
+ resume_sync_proxy_args args = {
573
+ .device_handle = d->handle,
574
+ .pid = NUM2UINT(pid)
575
+ };
576
+ CALL_GVL_FREE_WITH_RET(void *dummy, resume_sync, &args);
577
+ return (Qnil);
578
+
579
+ GERROR_BLOCK
580
+ }
581
+
582
+ GVL_FREE_PROXY_FUNC(input_sync, input_sync_proxy_args *args)
583
+ {
584
+ GError *gerr = NULL;
585
+
586
+ frida_device_input_sync(args->device_handle, args->pid, args->data, NULL, &gerr);
587
+ RETURN_GVL_FREE_RESULT(NULL);
588
+ }
589
+
590
+ /*
591
+ call-seq:
592
+ #input(pid, buffer) -> nil
593
+ */
594
+ static VALUE Device_input(VALUE self, VALUE pid, VALUE buffer)
595
+ {
596
+ GET_GOBJECT_DATA();
597
+ REQUIRE_GOBJECT_HANDLE();
598
+
599
+ if (!RB_TYPE_P(pid, T_FIXNUM)) {
600
+ raise_argerror("pid must be a number.");
601
+ return (Qnil);
602
+ }
603
+ if (!RB_TYPE_P(buffer, T_STRING)) {
604
+ raise_argerror("buffer must be a string.");
605
+ return (Qnil);
606
+ }
607
+ GBytes *data;
608
+ data = g_bytes_new(RSTRING_PTR(buffer), RSTRING_LEN(buffer));
609
+ input_sync_proxy_args args = {
610
+ .device_handle = d->handle,
611
+ .pid = NUM2UINT(pid),
612
+ .data = data
613
+ };
614
+ CALL_GVL_FREE_WITH_RET(void *dummy, input_sync, &args);
615
+ goto done;
616
+
617
+ gerror:
618
+ raise_rerror(NULL, _gerr);
619
+ done:
620
+ g_bytes_unref(data);
621
+ return (Qnil);
622
+ }
623
+
624
+ GVL_FREE_PROXY_FUNC(kill_sync, kill_sync_proxy_args *args)
625
+ {
626
+ GError *gerr = NULL;
627
+
628
+ frida_device_kill_sync(args->device_handle, args->pid, NULL, &gerr);
629
+ RETURN_GVL_FREE_RESULT(NULL);
630
+ }
631
+
632
+ /*
633
+ call-seq:
634
+ #kill(pid) -> nil
635
+ */
636
+ static VALUE Device_kill(VALUE self, VALUE pid)
637
+ {
638
+ GET_GOBJECT_DATA();
639
+ REQUIRE_GOBJECT_HANDLE();
640
+
641
+ if (!RB_TYPE_P(pid, T_FIXNUM)) {
642
+ raise_argerror("pid must be a number.");
643
+ return (Qnil);
644
+ }
645
+ kill_sync_proxy_args args = {
646
+ .device_handle = d->handle,
647
+ .pid = NUM2UINT(pid)
648
+ };
649
+ CALL_GVL_FREE_WITH_RET(void *dummy, kill_sync, &args);
650
+ goto done;
651
+ gerror:
652
+ raise_rerror(NULL, _gerr);
653
+ done:
654
+ return (Qnil);
655
+ }
656
+
657
+ GVL_FREE_PROXY_FUNC(unpair_sync, void *device_handle)
658
+ {
659
+ GError *gerr = NULL;
660
+
661
+ frida_device_unpair_sync(device_handle, NULL, &gerr);
662
+ RETURN_GVL_FREE_RESULT(NULL);
663
+ }
664
+
665
+ /*
666
+ call-seq:
667
+ #unpair() -> nil
668
+ */
669
+ static VALUE Device_unpair(VALUE self)
670
+ {
671
+ GET_GOBJECT_DATA();
672
+ REQUIRE_GOBJECT_HANDLE();
673
+
674
+ CALL_GVL_FREE_WITH_RET(void *dummy, unpair_sync, d->handle);
675
+ goto done;
676
+
677
+ gerror:
678
+ raise_rerror(NULL, _gerr);
679
+ done:
680
+ return (Qnil);
681
+ }
682
+
683
+ GVL_FREE_PROXY_FUNC(inject_library_file_sync, inject_library_file_sync_proxy_args *args)
684
+ {
685
+ GError *gerr = NULL;
686
+ char *id = NULL;
687
+
688
+ id += frida_device_inject_library_file_sync(args->device_handle, args->pid, args->path, args->entrypoint, args->data, \
689
+ NULL, &gerr);
690
+ RETURN_GVL_FREE_RESULT(id);
691
+ }
692
+
693
+ /*
694
+ call-seq:
695
+ #inject_library_file(pid, path, entrypoint, data) -> Fixnum
696
+ */
697
+ static VALUE Device_inject_library_file(VALUE self, VALUE pid, VALUE path, VALUE entrypoint, VALUE data)
698
+ {
699
+ GET_GOBJECT_DATA();
700
+ REQUIRE_GOBJECT_HANDLE();
701
+
702
+ if (!RB_TYPE_P(pid, T_FIXNUM)) {
703
+ raise_argerror("pid must be a number.");
704
+ return (Qnil);
705
+ }
706
+ if (!RB_TYPE_P(path, T_STRING)) {
707
+ raise_argerror("path must be a string.");
708
+ return (Qnil);
709
+ }
710
+ if (!RB_TYPE_P(entrypoint, T_STRING)) {
711
+ raise_argerror("entrypoint must be a string.");
712
+ return (Qnil);
713
+ }
714
+ if (!RB_TYPE_P(data, T_STRING)) {
715
+ raise_argerror("data must be a string.");
716
+ return (Qnil);
717
+ }
718
+ inject_library_file_sync_proxy_args args = {
719
+ .device_handle = d->handle,
720
+ .pid = NUM2UINT(pid),
721
+ .path = StringValueCStr(path),
722
+ .entrypoint = StringValueCStr(entrypoint),
723
+ .data = StringValueCStr(data)
724
+ };
725
+ CALL_GVL_FREE_WITH_RET(void *id, inject_library_file_sync, &args);
726
+ return (UINT2NUM((unsigned long long)id / sizeof(char)));
727
+
728
+ GERROR_BLOCK
729
+ }
730
+
731
+ GVL_FREE_PROXY_FUNC(inject_library_blob_sync, inject_library_blob_sync_proxy_args *args)
732
+ {
733
+ GError *gerr = NULL;
734
+ char *id = NULL;
735
+
736
+ id += frida_device_inject_library_blob_sync(args->device_handle, args->pid, args->blob, args->entrypoint, args->data, \
737
+ NULL, &gerr);
738
+ RETURN_GVL_FREE_RESULT(id);
739
+ }
740
+
741
+ /*
742
+ call-seq:
743
+ #inject_library_blob(pid, blob, entrypoint, data) -> Fixnum
744
+ */
745
+ static VALUE Device_inject_library_blob(VALUE self, VALUE pid, VALUE blob, VALUE entrypoint, VALUE data)
746
+ {
747
+ GET_GOBJECT_DATA();
748
+ REQUIRE_GOBJECT_HANDLE();
749
+ GBytes *gblob;
750
+
751
+ if (!RB_TYPE_P(pid, T_FIXNUM)) {
752
+ raise_argerror("pid must be a number.");
753
+ return (Qnil);
754
+ }
755
+ if (!RB_TYPE_P(blob, T_STRING)) {
756
+ raise_argerror("blob must be a string.");
757
+ return (Qnil);
758
+ }
759
+ if (!RB_TYPE_P(entrypoint, T_STRING)) {
760
+ raise_argerror("entrypoint must be a string.");
761
+ return (Qnil);
762
+ }
763
+ if (!RB_TYPE_P(data, T_STRING)) {
764
+ raise_argerror("data must be a string.");
765
+ return (Qnil);
766
+ }
767
+ gblob = g_bytes_new(RSTRING_PTR(blob), RSTRING_LEN(blob));
768
+ inject_library_blob_sync_proxy_args args = {
769
+ .device_handle = d->handle,
770
+ .pid = NUM2UINT(pid),
771
+ .blob = gblob,
772
+ .entrypoint = StringValueCStr(entrypoint),
773
+ .data = StringValueCStr(data)
774
+ };
775
+ CALL_GVL_FREE_WITH_RET(void *id, inject_library_file_sync, &args);
776
+ g_bytes_unref(gblob);
777
+ return (UINT2NUM((unsigned long long)id / sizeof(char)));
778
+
779
+ gerror:
780
+ g_bytes_unref(gblob);
781
+ raise_rerror(NULL, _gerr);
782
+ return (Qnil);
783
+ }
784
+
785
+ GVL_FREE_PROXY_FUNC(enumerate_pending_spawn_sync, void *device_handle)
786
+ {
787
+ GError *gerr = NULL;
788
+ FridaSpawnList *spawn_list;
789
+
790
+ spawn_list = frida_device_enumerate_pending_spawn_sync(device_handle, NULL, &gerr);
791
+ RETURN_GVL_FREE_RESULT(spawn_list);
792
+ }
793
+
794
+ /*
795
+ call-seq:
796
+ #enumerate_pending_spawn() -> Array
797
+ */
798
+ static VALUE Device_enumerate_pending_spawn(VALUE self)
799
+ {
800
+ GET_GOBJECT_DATA();
801
+ REQUIRE_GOBJECT_HANDLE();
802
+ guint spawn_list_size;
803
+ VALUE spawn_list_array;
804
+
805
+ CALL_GVL_FREE_WITH_RET(FridaSpawnList *spawn_list, enumerate_pending_spawn_sync, d->handle);
806
+ spawn_list_size = frida_spawn_list_size(spawn_list);
807
+ spawn_list_array = rb_ary_new_capa(spawn_list_size);
808
+ for (uint i = 0; i < spawn_list_size; i++) {
809
+ rb_ary_store(spawn_list_array, i, Spawn_from_FridaSpawn(frida_spawn_list_get(spawn_list, i)));
810
+ }
811
+ g_object_unref(spawn_list);
812
+ goto done;
813
+
814
+ gerror:
815
+ raise_rerror(NULL, _gerr);
816
+ return (Qnil);
817
+ done:
818
+ return (spawn_list_array);
819
+ }
820
+
821
+ GVL_FREE_PROXY_FUNC(enumerate_pending_children_sync, void *device_handle)
822
+ {
823
+ GError *gerr = NULL;
824
+ FridaChildList *child_list;
825
+
826
+ child_list = frida_device_enumerate_pending_children_sync(device_handle, NULL, &gerr);
827
+ RETURN_GVL_FREE_RESULT(child_list);
828
+ }
829
+
830
+ /*
831
+ call-seq:
832
+ #enumerate_pending_children() -> Array
833
+ */
834
+ static VALUE Device_enumerate_pending_children(VALUE self)
835
+ {
836
+ GET_GOBJECT_DATA();
837
+ REQUIRE_GOBJECT_HANDLE();
838
+ guint child_list_size;
839
+ VALUE child_list_array;
840
+
841
+ CALL_GVL_FREE_WITH_RET(FridaChildList *child_list, enumerate_pending_children_sync, d->handle);
842
+ child_list_size = frida_child_list_size(child_list);
843
+ child_list_array = rb_ary_new_capa(child_list_size);
844
+ for (uint i = 0; i < child_list_size; i++) {
845
+ rb_ary_store(child_list_array, i, Child_from_FridaChild(frida_child_list_get(child_list, i)));
846
+ }
847
+ g_object_unref(child_list);
848
+ goto done;
849
+
850
+ gerror:
851
+ raise_rerror(NULL, _gerr);
852
+ return (Qnil);
853
+ done:
854
+ return (child_list_array);
855
+ }
856
+
857
+ GVL_FREE_PROXY_FUNC(attach_sync, attach_sync_proxy_args *args)
858
+ {
859
+ GError *gerr = NULL;
860
+ FridaSession *session;
861
+
862
+ session = frida_device_attach_sync(args->device_handle, args->pid, args->options, NULL, &gerr);
863
+ RETURN_GVL_FREE_RESULT(session);
864
+ }
865
+
866
+ /*
867
+ call-seq:
868
+ #attach(pid, realm:, persist_timeout:) -> Session
869
+ */
870
+ static VALUE Device_attach(int argc, VALUE *argv, VALUE self)
871
+ {
872
+ GET_GOBJECT_DATA();
873
+ REQUIRE_GOBJECT_HANDLE();
874
+ VALUE pid, kws;
875
+ FridaSessionOptions *options;
876
+
877
+ rb_scan_args(argc, argv, "1:", &pid, &kws);
878
+ options = frida_session_options_new();
879
+ if (!RB_TYPE_P(pid, T_FIXNUM)) {
880
+ raise_argerror("pid must be a number.");
881
+ return (Qnil);
882
+ }
883
+ if (!NIL_P(kws)) {
884
+ VALUE realm;
885
+ realm = rb_hash_aref(kws, ID2SYM(rb_intern("realm")));
886
+ if (!NIL_P(realm)) {
887
+ if (!RB_TYPE_P(realm, T_STRING)) {
888
+ raise_argerror("realm must be a string.");
889
+ return (Qnil);
890
+ }
891
+ FridaRealm grealm;
892
+ if (!rbGObject_unmarshal_enum(StringValueCStr(realm), FRIDA_TYPE_REALM, &grealm)) {
893
+ g_object_unref(options);
894
+ raise_argerror("invalid realm.");
895
+ return (Qnil);
896
+ }
897
+ frida_session_options_set_realm(options, grealm);
898
+ }
899
+
900
+ VALUE persist_timeout;
901
+ persist_timeout = rb_hash_aref(kws, ID2SYM(rb_intern("persist_timeout")));
902
+ if (!NIL_P(persist_timeout)) {
903
+ if (!RB_TYPE_P(persist_timeout, T_STRING)) {
904
+ raise_argerror("persist_timeout must be a number.");
905
+ return (Qnil);
906
+ }
907
+ }
908
+ frida_session_options_set_persist_timeout(options, NUM2UINT(persist_timeout));
909
+ }
910
+ attach_sync_proxy_args args = {
911
+ .device_handle = d->handle,
912
+ .pid = NUM2UINT(pid),
913
+ .options = options
914
+ };
915
+ CALL_GVL_FREE_WITH_RET(FridaSession *session, attach_sync, &args);
916
+ g_object_unref(options);
917
+ return (Session_from_FridaSession(session));
918
+
919
+ gerror:
920
+ g_object_unref(options);
921
+ raise_rerror(NULL, _gerr);
922
+ return (Qnil);
923
+ }
924
+
925
+ void define_Device()
926
+ {
927
+ cDevice = rb_define_class_under(mCFrida, "Device", cGObject);
928
+
929
+ rb_define_method(cDevice, "inspect", Device_inspect, 0);
930
+ rb_define_alias(cDevice, "to_s", "inspect");
931
+ rb_define_method(cDevice, "id", Device_id, 0);
932
+ rb_define_method(cDevice, "name", Device_name, 0);
933
+ rb_define_method(cDevice, "type", Device_type, 0);
934
+ rb_define_method(cDevice, "bus", Device_bus, 0);
935
+ rb_define_method(cDevice, "icon", Device_icon, 0);
936
+
937
+ rb_define_method(cDevice, "open_channel", Device_open_channel, 1);
938
+ rb_define_method(cDevice, "is_lost", Device_is_lost, 0);
939
+ rb_define_method(cDevice, "query_system_parameters", Device_query_system_parameters, 0);
940
+ rb_define_method(cDevice, "get_frontmost_application", Device_get_frontmost_application, -1);
941
+ rb_define_method(cDevice, "enumerate_applications", Device_enumerate_applications, -1);
942
+ rb_define_method(cDevice, "enumerate_processes", Device_enumerate_processes, -1);
943
+ rb_define_method(cDevice, "enable_spawn_gating", Device_enable_spawn_gating, 0);
944
+ rb_define_method(cDevice, "disable_spawn_gating", Device_disable_spawn_gating, 0);
945
+ rb_define_method(cDevice, "spawn", Device_spawn, -1);
946
+ rb_define_method(cDevice, "resume", Device_resume, 1);
947
+ rb_define_method(cDevice, "input", Device_input, 2);
948
+ rb_define_method(cDevice, "kill", Device_kill, 1);
949
+ rb_define_method(cDevice, "unpair", Device_unpair, 0);
950
+ rb_define_method(cDevice, "inject_library_file", Device_inject_library_file, 4);
951
+ rb_define_method(cDevice, "inject_library_blob", Device_inject_library_blob, 4);
952
+ rb_define_method(cDevice, "enumerate_pending_spawn", Device_enumerate_pending_spawn, 0);
953
+ rb_define_method(cDevice, "enumerate_pending_children", Device_enumerate_pending_children, 0);
954
+ rb_define_method(cDevice, "attach", Device_attach, -1);
955
+ }