frida 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ }