frida 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +25 -0
- data/LICENSE.txt +21 -0
- data/README.md +64 -0
- data/Rakefile +20 -0
- data/exe/frida +3 -0
- data/ext/c_frida/Application.c +79 -0
- data/ext/c_frida/Bus.c +91 -0
- data/ext/c_frida/Child.c +134 -0
- data/ext/c_frida/Compiler.c +208 -0
- data/ext/c_frida/Crash.c +92 -0
- data/ext/c_frida/Device.c +955 -0
- data/ext/c_frida/DeviceManager.c +260 -0
- data/ext/c_frida/EndpointParameters.c +189 -0
- data/ext/c_frida/FileMonitor.c +67 -0
- data/ext/c_frida/GObject.c +138 -0
- data/ext/c_frida/IOStream.c +228 -0
- data/ext/c_frida/PortalMembership.c +43 -0
- data/ext/c_frida/PortalService.c +413 -0
- data/ext/c_frida/Process.c +67 -0
- data/ext/c_frida/Relay.c +121 -0
- data/ext/c_frida/Script.c +221 -0
- data/ext/c_frida/Session.c +626 -0
- data/ext/c_frida/Spawn.c +53 -0
- data/ext/c_frida/c_frida.c +68 -0
- data/ext/c_frida/extconf.rb +26 -25
- data/ext/c_frida/gutils.c +498 -0
- data/ext/c_frida/gvl_bridge.c +131 -0
- data/ext/c_frida/inc/Application.h +9 -0
- data/ext/c_frida/inc/Bus.h +15 -0
- data/ext/c_frida/inc/Child.h +9 -0
- data/ext/c_frida/inc/Compiler.h +21 -0
- data/ext/c_frida/inc/Crash.h +9 -0
- data/ext/c_frida/inc/Device.h +71 -0
- data/ext/c_frida/inc/DeviceManager.h +20 -0
- data/ext/c_frida/inc/EndpointParameters.h +15 -0
- data/ext/c_frida/inc/FileMonitor.h +9 -0
- data/ext/c_frida/inc/GObject.h +10 -0
- data/ext/c_frida/inc/IOStream.h +29 -0
- data/ext/c_frida/inc/PortalMembership.h +9 -0
- data/ext/c_frida/inc/PortalService.h +47 -0
- data/ext/c_frida/inc/Process.h +9 -0
- data/ext/c_frida/inc/Relay.h +9 -0
- data/ext/c_frida/inc/Script.h +21 -0
- data/ext/c_frida/inc/Session.h +40 -0
- data/ext/c_frida/inc/Spawn.h +9 -0
- data/ext/c_frida/inc/c_frida.h +129 -0
- data/ext/c_frida/inc/gutils.h +21 -0
- data/ext/c_frida/inc/gvl_bridge.h +42 -0
- data/frida.gemspec +39 -0
- data/lib/frida/version.rb +5 -0
- data/lib/frida.rb +8 -0
- metadata +55 -3
@@ -0,0 +1,260 @@
|
|
1
|
+
#include "DeviceManager.h"
|
2
|
+
|
3
|
+
VALUE DeviceManager_from_FridaDeviceManager(FridaDeviceManager *handle)
|
4
|
+
{
|
5
|
+
VALUE self;
|
6
|
+
|
7
|
+
if (!handle)
|
8
|
+
return (Qnil);
|
9
|
+
self = rb_class_new_instance(0, NULL, cDeviceManager);
|
10
|
+
GET_GOBJECT_DATA();
|
11
|
+
d->destroy(d->handle);
|
12
|
+
d->handle = handle;
|
13
|
+
return (self);
|
14
|
+
}
|
15
|
+
|
16
|
+
GVL_FREE_PROXY_FUNC(close_device_manager_err, FridaDeviceManager *device_manager)
|
17
|
+
{
|
18
|
+
GError *gerr = NULL;
|
19
|
+
|
20
|
+
frida_device_manager_close_sync(device_manager, NULL, &gerr);
|
21
|
+
RETURN_GVL_FREE_RESULT(NULL);
|
22
|
+
}
|
23
|
+
|
24
|
+
GVL_FREE_PROXY_FUNC(close_device_manager, FridaDeviceManager *device_manager)
|
25
|
+
{
|
26
|
+
frida_device_manager_close_sync(device_manager, NULL, NULL);
|
27
|
+
return (NULL);
|
28
|
+
}
|
29
|
+
|
30
|
+
static void DeviceManager_destroy(void *handle)
|
31
|
+
{
|
32
|
+
CALL_GVL_FREE(close_device_manager, handle);
|
33
|
+
frida_unref(handle);
|
34
|
+
}
|
35
|
+
|
36
|
+
/*
|
37
|
+
call-seq:
|
38
|
+
#close() -> nil
|
39
|
+
*/
|
40
|
+
static VALUE DeviceManager_close(VALUE self)
|
41
|
+
{
|
42
|
+
GET_GOBJECT_DATA();
|
43
|
+
REQUIRE_GOBJECT_HANDLE();
|
44
|
+
CALL_GVL_FREE_WITH_RET(void *dummy, close_device_manager_err, d->handle);
|
45
|
+
return (Qnil);
|
46
|
+
|
47
|
+
GERROR_BLOCK
|
48
|
+
}
|
49
|
+
|
50
|
+
GVL_FREE_PROXY_FUNC(enumerate_devices_sync, FridaDeviceManager *device_manager)
|
51
|
+
{
|
52
|
+
GError *gerr = NULL;
|
53
|
+
FridaDeviceList * devices;
|
54
|
+
|
55
|
+
devices = frida_device_manager_enumerate_devices_sync(device_manager, NULL, &gerr);
|
56
|
+
RETURN_GVL_FREE_RESULT(devices);
|
57
|
+
}
|
58
|
+
|
59
|
+
/*
|
60
|
+
call-seq:
|
61
|
+
#enumerate_device() -> Array[Device]
|
62
|
+
*/
|
63
|
+
static VALUE DeviceManager_enumerate_devices(VALUE self)
|
64
|
+
{
|
65
|
+
GET_GOBJECT_DATA();
|
66
|
+
REQUIRE_GOBJECT_HANDLE();
|
67
|
+
FridaDeviceList * devices;
|
68
|
+
int devices_count;
|
69
|
+
VALUE Devices_arr;
|
70
|
+
|
71
|
+
CALL_GVL_FREE_WITH_RET(devices, enumerate_devices_sync, d->handle);
|
72
|
+
devices_count = frida_device_list_size(devices);
|
73
|
+
Devices_arr = rb_ary_new_capa(devices_count);
|
74
|
+
for (int i = 0; i < devices_count; i++)
|
75
|
+
rb_ary_store(Devices_arr, i, Device_from_FridaDevice(frida_device_list_get(devices, i)));
|
76
|
+
frida_unref(devices);
|
77
|
+
return (Devices_arr);
|
78
|
+
|
79
|
+
GERROR_BLOCK
|
80
|
+
}
|
81
|
+
|
82
|
+
/*
|
83
|
+
call-seq:
|
84
|
+
#get_device_matching() {} -> Device
|
85
|
+
*/
|
86
|
+
static VALUE DeviceManager_get_device_matching(VALUE self)
|
87
|
+
{
|
88
|
+
GET_GOBJECT_DATA();
|
89
|
+
REQUIRE_GOBJECT_HANDLE();
|
90
|
+
VALUE block;
|
91
|
+
VALUE devices, current_device, block_ret;
|
92
|
+
int devices_count;
|
93
|
+
|
94
|
+
if (!rb_block_given_p()) {
|
95
|
+
raise_argerror("a block argument is required");
|
96
|
+
return (Qnil);
|
97
|
+
}
|
98
|
+
block = rb_block_proc();
|
99
|
+
// NOTE: Ruby does not support (currently) setting up a non Ruby created thread to be able
|
100
|
+
// to call its C APIs, frida_device_manager_get_device_sync() would call our filtering predicate from a frida thread
|
101
|
+
// which is not created by Ruby, and GET_EC() call in the Ruby's C APIs would return NULL.
|
102
|
+
// so the filtering is done in this thread that currently holds the GVL, mimicking frida_device_manager_get_device_sync().
|
103
|
+
devices = rb_funcall(self, rb_intern("enumerate_devices"), 0, NULL);
|
104
|
+
devices_count = RARRAY_LEN(devices);
|
105
|
+
for (int i = 0; i < devices_count; i++) {
|
106
|
+
current_device = rb_ary_entry(devices, i);
|
107
|
+
block_ret = rb_funcall(block, rb_intern("call"), 1, current_device);
|
108
|
+
if (block_ret == Qtrue) return (current_device);
|
109
|
+
}
|
110
|
+
return (Qnil);
|
111
|
+
}
|
112
|
+
|
113
|
+
static FridaRemoteDeviceOptions *parse_add_rdevice_kws_to_options(VALUE kws)
|
114
|
+
{
|
115
|
+
FridaRemoteDeviceOptions *options;
|
116
|
+
VALUE cert, origin, token, keepalive_interval;
|
117
|
+
|
118
|
+
options = frida_remote_device_options_new();
|
119
|
+
cert = rb_hash_aref(kws, ID2SYM(rb_intern("certificate")));
|
120
|
+
if (!NIL_P(cert)) {
|
121
|
+
if (!RB_TYPE_P(cert, T_STRING)) {
|
122
|
+
raise_argerror("certificate should be a string.");
|
123
|
+
goto error;
|
124
|
+
}
|
125
|
+
GTlsCertificate * certificate;
|
126
|
+
if (!rbGObject_unmarshal_certificate(StringValueCStr(cert), &certificate))
|
127
|
+
goto error;
|
128
|
+
frida_remote_device_options_set_certificate(options, certificate);
|
129
|
+
g_object_unref(certificate);
|
130
|
+
}
|
131
|
+
origin = rb_hash_aref(kws, ID2SYM(rb_intern("origin")));
|
132
|
+
if (!NIL_P(origin)) {
|
133
|
+
if (!RB_TYPE_P(origin, T_STRING)) {
|
134
|
+
raise_argerror("origin should be a string.");
|
135
|
+
goto error;
|
136
|
+
}
|
137
|
+
frida_remote_device_options_set_origin(options, StringValueCStr(origin));
|
138
|
+
}
|
139
|
+
token = rb_hash_aref(kws, ID2SYM(rb_intern("token")));
|
140
|
+
if (!NIL_P(token)) {
|
141
|
+
if (!RB_TYPE_P(token, T_STRING)) {
|
142
|
+
raise_argerror("token should be a string.");
|
143
|
+
goto error;
|
144
|
+
}
|
145
|
+
frida_remote_device_options_set_token(options, StringValueCStr(token));
|
146
|
+
}
|
147
|
+
keepalive_interval = rb_hash_aref(kws, ID2SYM(rb_intern("keepalive_interval")));
|
148
|
+
if (!NIL_P(keepalive_interval)) {
|
149
|
+
if (!RB_TYPE_P(keepalive_interval, T_FIXNUM)) {
|
150
|
+
raise_argerror("keepalive_interval should be a number.");
|
151
|
+
goto error;
|
152
|
+
}
|
153
|
+
frida_remote_device_options_set_keepalive_interval(options, NUM2INT(keepalive_interval));
|
154
|
+
}
|
155
|
+
return (options);
|
156
|
+
|
157
|
+
error:
|
158
|
+
g_object_unref(options);
|
159
|
+
return (NULL);
|
160
|
+
}
|
161
|
+
|
162
|
+
GVL_FREE_PROXY_FUNC(add_remote_device_sync, add_remote_device_proxy_args *args)
|
163
|
+
{
|
164
|
+
GError *gerr = NULL;
|
165
|
+
FridaDevice *device;
|
166
|
+
|
167
|
+
device = frida_device_manager_add_remote_device_sync(args->device_manager, args->address, args->options, NULL, &gerr);
|
168
|
+
RETURN_GVL_FREE_RESULT(device);
|
169
|
+
}
|
170
|
+
|
171
|
+
/*
|
172
|
+
call-seq:
|
173
|
+
#add_remote_device(address, certificate:, origin:, token:, keepalive_interval:) -> Device
|
174
|
+
*/
|
175
|
+
static VALUE DeviceManager_add_remote_device(int argc, VALUE *argv, VALUE self)
|
176
|
+
{
|
177
|
+
GET_GOBJECT_DATA();
|
178
|
+
REQUIRE_GOBJECT_HANDLE();
|
179
|
+
VALUE address, kws;
|
180
|
+
FridaRemoteDeviceOptions *options;
|
181
|
+
FridaDevice *device;
|
182
|
+
|
183
|
+
rb_scan_args(argc, argv, "1:", &address, &kws);
|
184
|
+
if (!RB_TYPE_P(address, T_STRING))
|
185
|
+
return (raise_argerror("address must be a string."), Qnil);
|
186
|
+
if (NIL_P(kws)) kws = rb_hash_new();
|
187
|
+
options = parse_add_rdevice_kws_to_options(kws);
|
188
|
+
if (!options)
|
189
|
+
return (Qnil);
|
190
|
+
add_remote_device_proxy_args args = {
|
191
|
+
.device_manager = d->handle,
|
192
|
+
.options = options,
|
193
|
+
.address = StringValueCStr(address)
|
194
|
+
};
|
195
|
+
CALL_GVL_FREE_WITH_RET(device, add_remote_device_sync, &args);
|
196
|
+
g_object_unref(options);
|
197
|
+
return (Device_from_FridaDevice(device));
|
198
|
+
|
199
|
+
gerror:
|
200
|
+
g_object_unref(options);
|
201
|
+
raise_rerror(NULL, _gerr);
|
202
|
+
return (Qnil);
|
203
|
+
}
|
204
|
+
|
205
|
+
GVL_FREE_PROXY_FUNC(remove_remote_device_sync, remove_remote_devices_proxy_args *args)
|
206
|
+
{
|
207
|
+
GError *gerr = NULL;
|
208
|
+
|
209
|
+
frida_device_manager_remove_remote_device_sync(args->device_manager, args->address, NULL, &gerr);
|
210
|
+
RETURN_GVL_FREE_RESULT(NULL);
|
211
|
+
}
|
212
|
+
|
213
|
+
/*
|
214
|
+
call-seq:
|
215
|
+
#remove_remote_device(address) -> nil
|
216
|
+
*/
|
217
|
+
static VALUE DeviceManager_remove_remote_device(VALUE self, VALUE address)
|
218
|
+
{
|
219
|
+
GET_GOBJECT_DATA();
|
220
|
+
REQUIRE_GOBJECT_HANDLE();
|
221
|
+
|
222
|
+
if (!RB_TYPE_P(address, T_STRING)) {
|
223
|
+
raise_argerror("address should be a string.");
|
224
|
+
return (Qnil);
|
225
|
+
}
|
226
|
+
remove_remote_devices_proxy_args args = {
|
227
|
+
.device_manager = d->handle,
|
228
|
+
.address = StringValueCStr(address)
|
229
|
+
};
|
230
|
+
CALL_GVL_FREE_WITH_RET(void *dummy, remove_remote_device_sync, &args);
|
231
|
+
return (Qnil);
|
232
|
+
|
233
|
+
GERROR_BLOCK
|
234
|
+
}
|
235
|
+
|
236
|
+
/*
|
237
|
+
call-seq:
|
238
|
+
#new() -> DeviceManager
|
239
|
+
*/
|
240
|
+
static VALUE DeviceManager_initialize(VALUE self)
|
241
|
+
{
|
242
|
+
GET_GOBJECT_DATA();
|
243
|
+
d->handle = frida_device_manager_new();
|
244
|
+
if (!d->handle)
|
245
|
+
return (raise_rerror("failed to retrieve a device manager.", NULL), Qnil);
|
246
|
+
d->destroy = DeviceManager_destroy;
|
247
|
+
return (self);
|
248
|
+
}
|
249
|
+
|
250
|
+
void define_DeviceManager()
|
251
|
+
{
|
252
|
+
cDeviceManager = rb_define_class_under(mCFrida, "DeviceManager", cGObject);
|
253
|
+
|
254
|
+
rb_define_method(cDeviceManager, "initialize", DeviceManager_initialize, 0);
|
255
|
+
rb_define_method(cDeviceManager, "enumerate_devices", DeviceManager_enumerate_devices, 0);
|
256
|
+
rb_define_method(cDeviceManager, "get_device_matching", DeviceManager_get_device_matching, 0);
|
257
|
+
rb_define_method(cDeviceManager, "add_remote_device", DeviceManager_add_remote_device, -1);
|
258
|
+
rb_define_method(cDeviceManager, "remove_remote_device", DeviceManager_remove_remote_device, 1);
|
259
|
+
rb_define_method(cDeviceManager, "close", DeviceManager_close, 0);
|
260
|
+
}
|
@@ -0,0 +1,189 @@
|
|
1
|
+
#include "EndpointParameters.h"
|
2
|
+
|
3
|
+
VALUE EndpointParameters_from_FridaEndpointParameters(FridaEndpointParameters *handle)
|
4
|
+
{
|
5
|
+
VALUE self;
|
6
|
+
|
7
|
+
if (!handle)
|
8
|
+
return (Qnil);
|
9
|
+
self = rb_class_new_instance(0, NULL, cEndpointParameters);
|
10
|
+
GET_GOBJECT_DATA();
|
11
|
+
d->handle = handle;
|
12
|
+
d->destroy = g_object_unref;
|
13
|
+
return (self);
|
14
|
+
}
|
15
|
+
|
16
|
+
static void frida_rb_authentication_service_iface_init (gpointer g_iface, gpointer iface_data);
|
17
|
+
|
18
|
+
G_DEFINE_TYPE_EXTENDED (FridaRBAuthenticationService, frida_rb_authentication_service, G_TYPE_OBJECT, 0,
|
19
|
+
G_IMPLEMENT_INTERFACE (FRIDA_TYPE_AUTHENTICATION_SERVICE, frida_rb_authentication_service_iface_init))
|
20
|
+
|
21
|
+
static void frida_rb_authentication_service_dispose (GObject * object);
|
22
|
+
static void frida_rb_authentication_service_authenticate (FridaAuthenticationService * service, const gchar * token, GCancellable * cancellable,
|
23
|
+
GAsyncReadyCallback callback, gpointer user_data);
|
24
|
+
static gchar *frida_rb_authentication_service_authenticate_finish (FridaAuthenticationService * service, GAsyncResult * result, GError ** error);
|
25
|
+
|
26
|
+
static FridaRBAuthenticationService *frida_rb_authentication_service_new(VALUE callback)
|
27
|
+
{
|
28
|
+
FridaRBAuthenticationService *service;
|
29
|
+
|
30
|
+
service = g_object_new(FRIDA_TYPE_RB_AUTHENTICATION_SERVICE, NULL);
|
31
|
+
service->callback = callback;
|
32
|
+
|
33
|
+
return (service);
|
34
|
+
}
|
35
|
+
|
36
|
+
static void frida_rb_authentication_service_class_init(FridaRBAuthenticationServiceClass * klass)
|
37
|
+
{
|
38
|
+
GObjectClass * object_class = G_OBJECT_CLASS (klass);
|
39
|
+
|
40
|
+
object_class->dispose = frida_rb_authentication_service_dispose;
|
41
|
+
}
|
42
|
+
|
43
|
+
static void frida_rb_authentication_service_iface_init (gpointer g_iface, gpointer iface_data)
|
44
|
+
{
|
45
|
+
puts("frida_rb_authentication_service_iface_init");
|
46
|
+
FridaAuthenticationServiceIface * iface = g_iface;
|
47
|
+
|
48
|
+
iface->authenticate = frida_rb_authentication_service_authenticate;
|
49
|
+
iface->authenticate_finish = frida_rb_authentication_service_authenticate_finish;
|
50
|
+
}
|
51
|
+
|
52
|
+
static void frida_rb_authentication_service_init (FridaRBAuthenticationService * self)
|
53
|
+
{
|
54
|
+
self->pool = g_thread_pool_new ((GFunc) gvl_bridge_forward_GT, self, 1, FALSE, NULL);
|
55
|
+
}
|
56
|
+
|
57
|
+
static void frida_rb_authentication_service_dispose (GObject * object)
|
58
|
+
{
|
59
|
+
FridaRBAuthenticationService * self = FRIDA_RB_AUTHENTICATION_SERVICE (object);
|
60
|
+
|
61
|
+
if (self->pool != NULL) {
|
62
|
+
g_thread_pool_free (self->pool, FALSE, FALSE);
|
63
|
+
self->pool = NULL;
|
64
|
+
}
|
65
|
+
|
66
|
+
G_OBJECT_CLASS (frida_rb_authentication_service_parent_class)->dispose (object);
|
67
|
+
}
|
68
|
+
|
69
|
+
static void frida_rb_authentication_service_authenticate (FridaAuthenticationService * service, const gchar * token, GCancellable * cancellable,
|
70
|
+
GAsyncReadyCallback callback, gpointer user_data)
|
71
|
+
{
|
72
|
+
FridaRBAuthenticationService * self;
|
73
|
+
GTask * task;
|
74
|
+
|
75
|
+
self = FRIDA_RB_AUTHENTICATION_SERVICE (service);
|
76
|
+
|
77
|
+
task = g_task_new (self, cancellable, callback, user_data);
|
78
|
+
g_task_set_task_data (task, g_strdup (token), g_free);
|
79
|
+
|
80
|
+
g_thread_pool_push (self->pool, task, NULL);
|
81
|
+
}
|
82
|
+
|
83
|
+
static gchar *frida_rb_authentication_service_authenticate_finish (FridaAuthenticationService * service, GAsyncResult * result, GError ** error)
|
84
|
+
{
|
85
|
+
return g_task_propagate_pointer (G_TASK (result), error);
|
86
|
+
}
|
87
|
+
|
88
|
+
/*
|
89
|
+
call-seq:
|
90
|
+
#new(address:, port:, certificate:, origin:, auth_token:, auth_callback:, asset_root:) -> EndpointParameters
|
91
|
+
*/
|
92
|
+
static VALUE EndpointParameters_initialize(int argc, VALUE *argv, VALUE self)
|
93
|
+
{
|
94
|
+
GET_GOBJECT_DATA();
|
95
|
+
GTlsCertificate *certificate = NULL;
|
96
|
+
FridaAuthenticationService *auth_service = NULL;
|
97
|
+
GFile *asset_root = NULL;
|
98
|
+
unsigned short port = 0;
|
99
|
+
char *address = NULL, *origin = NULL, *auth_token = NULL;
|
100
|
+
VALUE kws;
|
101
|
+
|
102
|
+
rb_scan_args(argc, argv, ":", &kws);
|
103
|
+
if (!NIL_P(kws)) {
|
104
|
+
VALUE raddress = rb_hash_aref(kws, ID2SYM(rb_intern("address")));
|
105
|
+
if (!NIL_P(raddress)) {
|
106
|
+
if (!RB_TYPE_P(raddress, T_STRING)) {
|
107
|
+
raise_argerror("address must be a string.");
|
108
|
+
goto invalid_arg;
|
109
|
+
}
|
110
|
+
address = StringValueCStr(raddress);
|
111
|
+
}
|
112
|
+
VALUE rport = rb_hash_aref(kws, ID2SYM(rb_intern("port")));
|
113
|
+
if (!NIL_P(rport)) {
|
114
|
+
if (!RB_TYPE_P(rport, T_FIXNUM)) {
|
115
|
+
raise_argerror("port must be a number.");
|
116
|
+
goto invalid_arg;
|
117
|
+
}
|
118
|
+
port = (unsigned short)NUM2USHORT(rport);
|
119
|
+
}
|
120
|
+
VALUE rcert = rb_hash_aref(kws, ID2SYM(rb_intern("certificate")));
|
121
|
+
if (!NIL_P(rcert)) {
|
122
|
+
if (!RB_TYPE_P(rcert, T_STRING)) {
|
123
|
+
raise_argerror("certificate must be a string.");
|
124
|
+
goto invalid_arg;
|
125
|
+
}
|
126
|
+
char *cert = StringValueCStr(rcert);
|
127
|
+
if (!rbGObject_unmarshal_certificate(cert, &certificate)) {
|
128
|
+
raise_argerror("invalid certificate.");
|
129
|
+
goto invalid_arg;
|
130
|
+
}
|
131
|
+
}
|
132
|
+
VALUE rorigin = rb_hash_aref(kws, ID2SYM(rb_intern("origin")));
|
133
|
+
if (!NIL_P(rorigin)) {
|
134
|
+
if (!RB_TYPE_P(rorigin, T_STRING)) {
|
135
|
+
raise_argerror("origin must be a string.");
|
136
|
+
goto invalid_arg;
|
137
|
+
}
|
138
|
+
origin = StringValueCStr(rorigin);
|
139
|
+
}
|
140
|
+
VALUE rauth_token = rb_hash_aref(kws, ID2SYM(rb_intern("auth_token")));
|
141
|
+
if (!NIL_P(rauth_token)) {
|
142
|
+
if (!RB_TYPE_P(rauth_token, T_STRING)) {
|
143
|
+
raise_argerror("auth_token must be a string.");
|
144
|
+
goto invalid_arg;
|
145
|
+
}
|
146
|
+
auth_token = StringValueCStr(rauth_token);
|
147
|
+
}
|
148
|
+
VALUE rauth_callback = rb_hash_aref(kws, ID2SYM(rb_intern("auth_callback")));
|
149
|
+
if (!NIL_P(rauth_callback)) {
|
150
|
+
// currently support only methods.
|
151
|
+
if (rb_obj_is_kind_of(rauth_callback, rb_const_get(rb_cObject, rb_intern("Method"))) == Qfalse || \
|
152
|
+
NUM2INT(rb_funcall(rauth_callback, rb_intern("arity"), 0, NULL)) != 1) {
|
153
|
+
raise_argerror("auth_callback must be a method with one argument.");
|
154
|
+
goto invalid_arg;
|
155
|
+
}
|
156
|
+
// don't GC
|
157
|
+
rb_ivar_set(self, rb_intern("auth_callback"), rauth_callback);
|
158
|
+
}
|
159
|
+
if (auth_token)
|
160
|
+
auth_service = FRIDA_AUTHENTICATION_SERVICE(frida_static_authentication_service_new(auth_token));
|
161
|
+
else if (rauth_callback != Qnil)
|
162
|
+
auth_service = FRIDA_AUTHENTICATION_SERVICE(frida_rb_authentication_service_new(rauth_callback));
|
163
|
+
VALUE rasset_root = rb_hash_aref(kws, ID2SYM(rb_intern("asset_root")));
|
164
|
+
if (!NIL_P(rasset_root)) {
|
165
|
+
if (!RB_TYPE_P(rasset_root, T_STRING)) {
|
166
|
+
raise_argerror("asset_root must be a string.");
|
167
|
+
goto invalid_arg;
|
168
|
+
}
|
169
|
+
asset_root = g_file_new_for_path(StringValueCStr(rasset_root));
|
170
|
+
}
|
171
|
+
} else
|
172
|
+
return (self);
|
173
|
+
d->handle = frida_endpoint_parameters_new(address, port, certificate, origin, auth_service, asset_root);
|
174
|
+
d->destroy = g_object_unref;
|
175
|
+
return (self);
|
176
|
+
|
177
|
+
invalid_arg:
|
178
|
+
g_clear_object(&asset_root);
|
179
|
+
g_clear_object(&auth_service);
|
180
|
+
g_clear_object(&certificate);
|
181
|
+
return (Qnil);
|
182
|
+
}
|
183
|
+
|
184
|
+
void define_EndpointParameters()
|
185
|
+
{
|
186
|
+
cEndpointParameters = rb_define_class_under(mCFrida, "EndpointParameters", cGObject);
|
187
|
+
|
188
|
+
rb_define_method(cEndpointParameters, "initialize", EndpointParameters_initialize, -1);
|
189
|
+
}
|
@@ -0,0 +1,67 @@
|
|
1
|
+
#include "FileMonitor.h"
|
2
|
+
|
3
|
+
VALUE FileMonitor_from_FridaFileMonitor(FridaFileMonitor *handle)
|
4
|
+
{
|
5
|
+
VALUE self;
|
6
|
+
|
7
|
+
if (!handle)
|
8
|
+
return (Qnil);
|
9
|
+
self = rb_class_new_instance(0, NULL, cFileMonitor);
|
10
|
+
GET_GOBJECT_DATA();
|
11
|
+
d->handle = handle;
|
12
|
+
d->destroy = frida_unref;
|
13
|
+
return (self);
|
14
|
+
}
|
15
|
+
|
16
|
+
GVL_FREE_PROXY_FUNC(enable_sync, void *handle)
|
17
|
+
{
|
18
|
+
GError *gerr = NULL;
|
19
|
+
|
20
|
+
frida_file_monitor_enable_sync(handle, NULL, &gerr);
|
21
|
+
RETURN_GVL_FREE_RESULT(NULL);
|
22
|
+
}
|
23
|
+
|
24
|
+
/*
|
25
|
+
call-seq:
|
26
|
+
#enable() -> nil
|
27
|
+
*/
|
28
|
+
static VALUE FileMonitor_enable(VALUE self)
|
29
|
+
{
|
30
|
+
GET_GOBJECT_DATA();
|
31
|
+
REQUIRE_GOBJECT_HANDLE();
|
32
|
+
|
33
|
+
CALL_GVL_FREE_WITH_RET(void *dummy, enable_sync, d->handle);
|
34
|
+
return (Qnil);
|
35
|
+
|
36
|
+
GERROR_BLOCK
|
37
|
+
}
|
38
|
+
|
39
|
+
GVL_FREE_PROXY_FUNC(disable_sync, void *handle)
|
40
|
+
{
|
41
|
+
GError *gerr = NULL;
|
42
|
+
|
43
|
+
frida_file_monitor_disable_sync(handle, NULL, &gerr);
|
44
|
+
RETURN_GVL_FREE_RESULT(NULL);
|
45
|
+
}
|
46
|
+
|
47
|
+
/*
|
48
|
+
call-seq:
|
49
|
+
#disable() -> nil
|
50
|
+
*/
|
51
|
+
static VALUE FileMonitor_disable(VALUE self)
|
52
|
+
{
|
53
|
+
GET_GOBJECT_DATA();
|
54
|
+
REQUIRE_GOBJECT_HANDLE();
|
55
|
+
|
56
|
+
CALL_GVL_FREE_WITH_RET(void *dummy, disable_sync, d->handle);
|
57
|
+
return (Qnil);
|
58
|
+
|
59
|
+
GERROR_BLOCK
|
60
|
+
}
|
61
|
+
|
62
|
+
void define_FileMonitor()
|
63
|
+
{
|
64
|
+
cFileMonitor = rb_define_class_under(mCFrida, "FileMonitor", cGObject);
|
65
|
+
rb_define_method(cFileMonitor, "enable", FileMonitor_enable, 0);
|
66
|
+
rb_define_method(cFileMonitor, "disable", FileMonitor_disable, 0);
|
67
|
+
}
|
@@ -0,0 +1,138 @@
|
|
1
|
+
#include "GObject.h"
|
2
|
+
|
3
|
+
DEFINE_KLASS_DATA_TYPE(GObject);
|
4
|
+
|
5
|
+
void GObject_free(GObject_d *d)
|
6
|
+
{
|
7
|
+
if (d->handle)
|
8
|
+
d->destroy(d->handle);
|
9
|
+
xfree(d);
|
10
|
+
}
|
11
|
+
|
12
|
+
/*
|
13
|
+
call-seq:
|
14
|
+
#on(signal_name) {} -> nil
|
15
|
+
#on(signal_name, callback) -> nil
|
16
|
+
*/
|
17
|
+
static VALUE GObject_on(int argc, VALUE *argv, VALUE self)
|
18
|
+
{
|
19
|
+
GET_DATA(GObject);
|
20
|
+
REQUIRE_GOBJECT_HANDLE();
|
21
|
+
VALUE signal_name, callback;
|
22
|
+
GType self_type = G_OBJECT_TYPE(d->handle);
|
23
|
+
guint signal_id;
|
24
|
+
bool is_lambda;
|
25
|
+
GSignalQuery squery;
|
26
|
+
|
27
|
+
if (rb_block_given_p()) {
|
28
|
+
// blocks are handy however we cannot compare them because they are unique
|
29
|
+
// so you cannot remove them later!
|
30
|
+
rb_scan_args(argc, argv, "1&", &signal_name, &callback);
|
31
|
+
} else {
|
32
|
+
rb_scan_args(argc, argv, "2", &signal_name, &callback);
|
33
|
+
// either a Method or Proc object.
|
34
|
+
if (!rb_respond_to(callback, rb_intern("call"))) {
|
35
|
+
raise_argerror("callback should be callable.");
|
36
|
+
return (Qnil);
|
37
|
+
}
|
38
|
+
}
|
39
|
+
if (!RB_TYPE_P(signal_name, T_STRING)) {
|
40
|
+
raise_argerror("signal name must be a string.");
|
41
|
+
return (Qnil);
|
42
|
+
}
|
43
|
+
signal_id = g_signal_lookup(StringValueCStr(signal_name), self_type);
|
44
|
+
if (!signal_id) {
|
45
|
+
raise_argerror("invalid signal name.");
|
46
|
+
return (Qnil);
|
47
|
+
}
|
48
|
+
is_lambda = (rb_obj_is_kind_of(callback, rb_const_get(rb_cObject, rb_intern("Method"))) == Qtrue) ? true : (rb_funcall(callback, rb_intern("lambda?"), 0, NULL) == Qtrue);
|
49
|
+
int arity = NUM2INT(rb_funcall(callback, rb_intern("arity"), 0, NULL));
|
50
|
+
g_signal_query(signal_id, &squery);
|
51
|
+
if (is_lambda && arity > (int)(squery.n_params + 1)) {
|
52
|
+
gchar *err = g_strdup_printf("callback expects too many arguments, signal expects %d.", squery.n_params);
|
53
|
+
raise_argerror(err);
|
54
|
+
g_free(err);
|
55
|
+
return (Qnil);
|
56
|
+
}
|
57
|
+
GClosure *closure = g_closure_new_simple(sizeof(RBClosure), (void*)callback);
|
58
|
+
g_closure_set_marshal(closure, (GClosureMarshal)gvl_bridge_forward_GC);
|
59
|
+
TO_RBCLOSURE(closure)->is_lambda = is_lambda;
|
60
|
+
TO_RBCLOSURE(closure)->signal_id = signal_id;
|
61
|
+
TO_RBCLOSURE(closure)->arity = arity;
|
62
|
+
g_signal_connect_closure_by_id(d->handle, signal_id, 0, closure, TRUE);
|
63
|
+
// objects generated on the fly (thus not referenced), e.g blocks `#on("signal", :id) {block}` / `#on("signal", &callable)`
|
64
|
+
// or Methods `#on("signal", method(:defined_fn))` or Procs `#on("signal", ->{})`
|
65
|
+
// will be picked up by the GC, since in Ruby's view there is no more usage/reference to them
|
66
|
+
// so we keep them in this hidden Hash.
|
67
|
+
if (rb_hash_aref(rb_iv_get(self, "callbacks"), signal_name) == Qnil)
|
68
|
+
rb_hash_aset(rb_iv_get(self, "callbacks"), signal_name, rb_ary_new());
|
69
|
+
rb_ary_push(rb_hash_aref(rb_iv_get(self, "callbacks"), signal_name), callback);
|
70
|
+
d->signal_closures = g_slist_prepend(d->signal_closures, closure);
|
71
|
+
return (Qnil);
|
72
|
+
}
|
73
|
+
|
74
|
+
static gint compare_callback(RBClosure *closure, VALUE callback)
|
75
|
+
{
|
76
|
+
return (rb_equal((VALUE)closure->gclosure.data, callback) == Qtrue ? 0 : -1);
|
77
|
+
}
|
78
|
+
|
79
|
+
/*
|
80
|
+
call-seq:
|
81
|
+
#off(signal_name, callback) -> nil
|
82
|
+
*/
|
83
|
+
static VALUE GObject_off(int argc, VALUE *argv, VALUE self)
|
84
|
+
{
|
85
|
+
GET_DATA(GObject);
|
86
|
+
REQUIRE_GOBJECT_HANDLE();
|
87
|
+
VALUE signal_name, callback;
|
88
|
+
GType self_type = G_OBJECT_TYPE(d->handle);
|
89
|
+
guint signal_id;
|
90
|
+
GSList *callback_entry;
|
91
|
+
int is_block = rb_block_given_p();
|
92
|
+
|
93
|
+
// remember you cannot remove Proc objects that you do not hold reference to!
|
94
|
+
rb_scan_args(argc, argv, "2", &signal_name, &callback);
|
95
|
+
if (!RB_TYPE_P(signal_name, T_STRING)) {
|
96
|
+
raise_argerror("signal name must be a string.");
|
97
|
+
return (Qnil);
|
98
|
+
}
|
99
|
+
signal_id = g_signal_lookup(StringValueCStr(signal_name), self_type);
|
100
|
+
if (!signal_id) {
|
101
|
+
raise_argerror("invalid signal name.");
|
102
|
+
return (Qnil);
|
103
|
+
}
|
104
|
+
if (rb_respond_to(callback, rb_intern("call"))) {
|
105
|
+
callback_entry = g_slist_find_custom(d->signal_closures, (gpointer)callback, (GCompareFunc)compare_callback);
|
106
|
+
if (!callback_entry) {
|
107
|
+
raise_argerror("callback not found.");
|
108
|
+
return (Qnil);
|
109
|
+
}
|
110
|
+
} else {
|
111
|
+
raise_argerror("second argument should be callable.");
|
112
|
+
return (Qnil);
|
113
|
+
}
|
114
|
+
GClosure *closure = callback_entry->data;
|
115
|
+
d->signal_closures = g_slist_delete_link(d->signal_closures, callback_entry);
|
116
|
+
g_signal_handlers_disconnect_matched(d->handle, G_SIGNAL_MATCH_CLOSURE, signal_id, 0, closure, NULL, NULL);
|
117
|
+
// this will delete a duplicate callback for a signal, but that is fine ?
|
118
|
+
rb_ary_delete(rb_hash_aref(rb_iv_get(self, "callbacks"), signal_name), callback);
|
119
|
+
return (Qnil);
|
120
|
+
}
|
121
|
+
|
122
|
+
static VALUE GObject_alloc(VALUE klass)
|
123
|
+
{
|
124
|
+
MAKE_DATA(GObject);
|
125
|
+
d->handle = NULL;
|
126
|
+
d->destroy = NULL;
|
127
|
+
d->signal_closures = NULL;
|
128
|
+
rb_ivar_set(obj, rb_intern("callbacks"), rb_hash_new());
|
129
|
+
return (obj);
|
130
|
+
}
|
131
|
+
|
132
|
+
void define_GObject()
|
133
|
+
{
|
134
|
+
cGObject = rb_define_class_under(mCFrida, "GObject", rb_cObject);
|
135
|
+
rb_define_alloc_func(cGObject, GObject_alloc);
|
136
|
+
rb_define_method(cGObject, "on", GObject_on, -1);
|
137
|
+
rb_define_method(cGObject, "off", GObject_off, -1);
|
138
|
+
}
|