node-marshal 0.1.2 → 0.2.0
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.
- checksums.yaml +4 -4
- data/{ext/node-marshal/COPYING → COPYING} +1 -1
- data/README.rdoc +10 -1
- data/bin/noderbc +5 -7
- data/ext/node-marshal/base85r.c +10 -6
- data/ext/node-marshal/nodedump.c +156 -42
- data/ext/node-marshal/nodedump.h +2 -0
- data/ext/node-marshal/nodeinfo.c +23 -8
- data/lib/node-marshal.rb +11 -3
- data/test/test_base.rb +21 -1
- data/test/test_complex.rb +5 -2
- data/test/test_qcall.rb +12 -7
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d564a41c56aa30cec81fe572e069cd4734637995
|
4
|
+
data.tar.gz: 28c7a859af9ba4cfa82c2f8138e0a9b1708f3176
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e7a41dbf52db03ccb69a4ccd9641ff740f45c88ba27488e17dea2897655c0920e1880edfcb29ded1801e25287358bd81d77097453e19c97ca2ff55fa46c90fa0
|
7
|
+
data.tar.gz: f31215d9e96c760d21927279162f48627d4bbace53ad66fe43d7335f8de403788e77022570a933fb6b4e5fee65cbd829f26ae9c3d5cd8c63903087ca10048fdd
|
data/README.rdoc
CHANGED
@@ -17,6 +17,15 @@ The key features of node-marshal gem:
|
|
17
17
|
- 2-clause BSD license suitable for creation of custom source code protection system
|
18
18
|
|
19
19
|
Changelog:
|
20
|
+
- 11.JAN.2016 - 0.2.0
|
21
|
+
- Bugfix: || and && in NODE_OP_ASGN1 (e.g. in x['a'] ||= 'b' or x['b'] &&= false)
|
22
|
+
(this bug caused segfaults in some cases)
|
23
|
+
- Bugfix: NodeMarshal#dump_node_short
|
24
|
+
- Format version changed to NODEMARSHAL11 (support of symbols not representable in
|
25
|
+
the form of String is added)
|
26
|
+
- show_offsets property for controlling verbosity of NodeMarshal#dump_node_short output
|
27
|
+
- Improved information about licenses
|
28
|
+
- Improved rdoc documentation
|
20
29
|
- 24.DEC.2015 - 0.1.2
|
21
30
|
- Ruby 2.3.x preliminary support (including &. safe navigation operator)
|
22
31
|
- Bugfix: NODE_MATCH3 (a =~ /abc/) issue (reported by Gregory Siehień)
|
@@ -24,4 +33,4 @@ Changelog:
|
|
24
33
|
- Bugfix: failure in the case of syntax errors in the input data (now ArgumentError
|
25
34
|
exception will be generated instead of it)
|
26
35
|
- Ability of symbols renaming (for hiding variables and constants name during code obfuscation)
|
27
|
-
- 04.MAY.2015 - 0.1.1 - first public version
|
36
|
+
- 04.MAY.2015 - 0.1.1 - first public version
|
data/bin/noderbc
CHANGED
@@ -2,13 +2,12 @@
|
|
2
2
|
require_relative '../lib/node-marshal.rb'
|
3
3
|
|
4
4
|
help = <<-EOS
|
5
|
-
Ruby source files compiler. It is based
|
6
|
-
|
7
|
-
(syntax tree) serialized into ASCII string.
|
8
|
-
|
9
|
-
be used for code obfuscation.
|
5
|
+
Ruby source files compiler from node-marshal gem. It is based
|
6
|
+
on NodeMarshal class. Source code is irreversibly transformed to the
|
7
|
+
Ruby node (syntax tree) serialized into ASCII string. It can be used
|
8
|
+
for for code obfuscation.
|
10
9
|
|
11
|
-
(C) 2015 Alexey Voskov. License: 2-
|
10
|
+
(C) 2015-2016 Alexey Voskov. License: BSD-2-Clause.
|
12
11
|
|
13
12
|
Usage:
|
14
13
|
noderbc inpfile outfile [options]
|
@@ -61,5 +60,4 @@ else
|
|
61
60
|
outfile = ARGV[1]
|
62
61
|
raise 'inpfile and outfile cannot be equal' if inpfile == outfile
|
63
62
|
NodeMarshal.compile_rb_file(outfile, inpfile, opts)
|
64
|
-
|
65
63
|
end
|
data/ext/node-marshal/base85r.c
CHANGED
@@ -10,8 +10,8 @@
|
|
10
10
|
* 2) big-endian 5-byte numbers (base 85)
|
11
11
|
* 3) empty string: arbitrary two bytes
|
12
12
|
*
|
13
|
-
* (C) 2015 Alexey Voskov
|
14
|
-
* License: 2-
|
13
|
+
* (C) 2015-2016 Alexey Voskov
|
14
|
+
* License: BSD-2-Clause
|
15
15
|
*/
|
16
16
|
#include <stdio.h>
|
17
17
|
#include <stdlib.h>
|
@@ -78,8 +78,10 @@ static int base85_encode_buf_len(int len)
|
|
78
78
|
return buf_len;
|
79
79
|
}
|
80
80
|
|
81
|
-
/*
|
82
|
-
|
81
|
+
/*
|
82
|
+
* Encode string to modified BASE85 ASCII.
|
83
|
+
* Note: call base85_init_tables before using of this function
|
84
|
+
*/
|
83
85
|
VALUE base85r_encode(VALUE input)
|
84
86
|
{
|
85
87
|
VALUE output;
|
@@ -131,8 +133,10 @@ VALUE base85r_encode(VALUE input)
|
|
131
133
|
}
|
132
134
|
|
133
135
|
|
134
|
-
/*
|
135
|
-
|
136
|
+
/*
|
137
|
+
* Decode string in modified BASE85 ASCII format.
|
138
|
+
* Note: call base85_init_tables before using of this function
|
139
|
+
*/
|
136
140
|
VALUE base85r_decode(VALUE input)
|
137
141
|
{
|
138
142
|
int inp_len, out_len, pos, shift;
|
data/ext/node-marshal/nodedump.c
CHANGED
@@ -2,8 +2,8 @@
|
|
2
2
|
* This file contains implementation of classes for Ruby nodes
|
3
3
|
* marshalization (i.e. loading and saving them from disk)
|
4
4
|
*
|
5
|
-
* (C) 2015 Alexey Voskov
|
6
|
-
* License: 2-
|
5
|
+
* (C) 2015-2016 Alexey Voskov
|
6
|
+
* License: BSD-2-Clause
|
7
7
|
*/
|
8
8
|
#define __STDC_FORMAT_MACROS
|
9
9
|
#include <stdio.h>
|
@@ -204,6 +204,23 @@ int LeafTableInfo_addEntry(LeafTableInfo *lti, VALUE key, VALUE value)
|
|
204
204
|
}
|
205
205
|
}
|
206
206
|
|
207
|
+
/*
|
208
|
+
* Adds Ruby ID data type as the entry to the LeafTableInfo struct.
|
209
|
+
* Main features:
|
210
|
+
* 1) ID will be converted to Fixnum
|
211
|
+
* 2) If ID can be converted to string by rb_id2str it will be saved as
|
212
|
+
String object. Otherwise it will be converted to Fixnum.
|
213
|
+
*/
|
214
|
+
int LeafTableInfo_addIDEntry(LeafTableInfo *lti, ID id)
|
215
|
+
{
|
216
|
+
VALUE r_idval = rb_id2str(id);
|
217
|
+
if (TYPE(r_idval) != T_STRING)
|
218
|
+
{
|
219
|
+
r_idval = INT2FIX(id);
|
220
|
+
}
|
221
|
+
return LeafTableInfo_addEntry(lti, INT2FIX(id), r_idval);
|
222
|
+
}
|
223
|
+
|
207
224
|
VALUE LeafTableInfo_getLeavesTable(LeafTableInfo *lti)
|
208
225
|
{
|
209
226
|
VALUE key, keys = rb_funcall(lti->vals, rb_intern("keys"), 0);
|
@@ -389,7 +406,6 @@ static int dump_node_value(NODEInfo *info, char *ptr, NODE *node, int type, VALU
|
|
389
406
|
}
|
390
407
|
else
|
391
408
|
{
|
392
|
-
//memcpy(ptr, &id, sizeof(VALUE));
|
393
409
|
switch(type)
|
394
410
|
{
|
395
411
|
case NT_ENTRY: return DUMP_RAW_VALUE(VL_GVAR, id);
|
@@ -422,7 +438,7 @@ static VALUE dump_nodes(NODEInfo *info)
|
|
422
438
|
nt = nd_type(node);
|
423
439
|
rtypes = (char *) ptr; ptr += sizeof(int);
|
424
440
|
flags_len = value_to_bin(node->flags >> 5, (unsigned char *) ptr); ptr += flags_len;
|
425
|
-
|
441
|
+
|
426
442
|
ut[0] = nodes_ctbl[nt * 3];
|
427
443
|
ut[1] = nodes_ctbl[nt * 3 + 1];
|
428
444
|
ut[2] = nodes_ctbl[nt * 3 + 2];
|
@@ -456,7 +472,6 @@ static VALUE dump_nodes(NODEInfo *info)
|
|
456
472
|
rtypes[3] = flags_len;
|
457
473
|
}
|
458
474
|
rb_str_resize(nodes_bin, (int) (ptr - bin) + 1);
|
459
|
-
//printf("%d", ptr - bin);
|
460
475
|
return nodes_bin;
|
461
476
|
}
|
462
477
|
|
@@ -475,7 +490,7 @@ VALUE NODEInfo_toHash(NODEInfo *info)
|
|
475
490
|
VALUE args;
|
476
491
|
int i, j, id;
|
477
492
|
// Add some signatures
|
478
|
-
rb_hash_aset(ans, ID2SYM(rb_intern("MAGIC")), rb_str_new2(
|
493
|
+
rb_hash_aset(ans, ID2SYM(rb_intern("MAGIC")), rb_str_new2(NODEMARSHAL_MAGIC));
|
479
494
|
rb_hash_aset(ans, ID2SYM(rb_intern("RUBY_PLATFORM")),
|
480
495
|
rb_const_get(rb_cObject, rb_intern("RUBY_PLATFORM")));
|
481
496
|
rb_hash_aset(ans, ID2SYM(rb_intern("RUBY_VERSION")),
|
@@ -573,7 +588,7 @@ static void NODEInfo_addValue(NODEInfo *info, VALUE value)
|
|
573
588
|
* Function counts number of nodes and fills NODEInfo struct
|
574
589
|
* that is neccessary for the node saving to the HDD
|
575
590
|
*/
|
576
|
-
int count_num_of_nodes(NODE *node, NODE *parent, NODEInfo *info)
|
591
|
+
static int count_num_of_nodes(NODE *node, NODE *parent, NODEInfo *info)
|
577
592
|
{
|
578
593
|
int ut[3], num, offset;
|
579
594
|
if (node == 0)
|
@@ -632,7 +647,7 @@ int count_num_of_nodes(NODE *node, NODE *parent, NODEInfo *info)
|
|
632
647
|
}
|
633
648
|
else if (ut[0] == NT_ID)
|
634
649
|
{
|
635
|
-
|
650
|
+
LeafTableInfo_addIDEntry(&info->syms, node->u1.id);
|
636
651
|
}
|
637
652
|
else if (ut[0] == NT_VALUE)
|
638
653
|
{
|
@@ -650,7 +665,7 @@ int count_num_of_nodes(NODE *node, NODE *parent, NODEInfo *info)
|
|
650
665
|
{
|
651
666
|
ID sym = *idtbl++;
|
652
667
|
rb_ary_push(idtbl_ary, INT2FIX(sym));
|
653
|
-
|
668
|
+
LeafTableInfo_addIDEntry(&info->syms, sym);
|
654
669
|
}
|
655
670
|
LeafTableInfo_addEntry(&info->idtabs, tkey, idtbl_ary);
|
656
671
|
}
|
@@ -665,7 +680,7 @@ int count_num_of_nodes(NODE *node, NODE *parent, NODEInfo *info)
|
|
665
680
|
}
|
666
681
|
else if (ut[1] == NT_ID)
|
667
682
|
{
|
668
|
-
|
683
|
+
LeafTableInfo_addIDEntry(&info->syms, node->u2.id);
|
669
684
|
}
|
670
685
|
else if (ut[1] == NT_VALUE)
|
671
686
|
{
|
@@ -685,7 +700,7 @@ int count_num_of_nodes(NODE *node, NODE *parent, NODEInfo *info)
|
|
685
700
|
}
|
686
701
|
else if (ut[2] == NT_ID)
|
687
702
|
{
|
688
|
-
|
703
|
+
LeafTableInfo_addIDEntry(&info->syms, node->u3.id);
|
689
704
|
}
|
690
705
|
else if (ut[2] == NT_ARGS)
|
691
706
|
{
|
@@ -709,29 +724,29 @@ int count_num_of_nodes(NODE *node, NODE *parent, NODEInfo *info)
|
|
709
724
|
|
710
725
|
asym = ainfo->first_post_arg; rb_ary_push(varg, INT2FIX(asym)); // ID
|
711
726
|
if (asym != 0)
|
712
|
-
|
727
|
+
LeafTableInfo_addIDEntry(&info->syms, asym);
|
713
728
|
|
714
729
|
asym = ainfo->rest_arg; rb_ary_push(varg, INT2FIX(asym)); // ID
|
715
730
|
if (asym != 0)
|
716
|
-
|
731
|
+
LeafTableInfo_addIDEntry(&info->syms, asym);
|
717
732
|
|
718
733
|
asym = ainfo->block_arg; rb_ary_push(varg, INT2FIX(asym)); // ID
|
719
734
|
if (asym != 0)
|
720
|
-
|
735
|
+
LeafTableInfo_addIDEntry(&info->syms, asym);
|
721
736
|
rb_ary_push(varg, value_to_str((VALUE) ainfo->kw_args));
|
722
737
|
rb_ary_push(varg, value_to_str((VALUE) ainfo->kw_rest_arg));
|
723
738
|
rb_ary_push(varg, value_to_str((VALUE) ainfo->opt_args));
|
724
739
|
|
725
740
|
LeafTableInfo_addEntry(&info->args, value_to_str((VALUE) ainfo), varg);
|
726
741
|
#else
|
727
|
-
rb_raise(rb_eArgError, "NT_ARGS entry
|
742
|
+
rb_raise(rb_eArgError, "NT_ARGS entry without USE_RB_ARGS_INFO");
|
728
743
|
#endif
|
729
744
|
}
|
730
745
|
else if (ut[2] == NT_ENTRY)
|
731
746
|
{
|
732
747
|
ID gsym = node->u3.entry->id;
|
733
748
|
// Save symbol to the symbol table
|
734
|
-
int newid =
|
749
|
+
int newid = LeafTableInfo_addIDEntry(&info->syms, gsym);
|
735
750
|
LeafTableInfo_addEntry(&info->gentries, value_to_str(node->u3.value), INT2FIX(newid));
|
736
751
|
}
|
737
752
|
else if (ut[2] != NT_LONG && ut[2] != NT_NULL)
|
@@ -799,10 +814,16 @@ void rbstr_printf(VALUE str, const char *fmt, ...)
|
|
799
814
|
}
|
800
815
|
|
801
816
|
#define PRINT_NODE_TAB for (j = 0; j < tab; j++) rbstr_printf(str, " ");
|
802
|
-
|
817
|
+
/*
|
818
|
+
* Recursively transforms node into Ruby string
|
819
|
+
* str -- output Ruby string
|
820
|
+
* node -- input Ruby NODE
|
821
|
+
* tab -- number of tabulations during print
|
822
|
+
* show_offsets -- 0/1 show/hide addresses and symbol IDs
|
823
|
+
*/
|
824
|
+
static void print_node(VALUE str, NODE *node, int tab, int show_offsets)
|
803
825
|
{
|
804
826
|
int i, j, type, ut[3];
|
805
|
-
int show_offsets = 0;
|
806
827
|
VALUE uref[3];
|
807
828
|
|
808
829
|
PRINT_NODE_TAB
|
@@ -815,12 +836,14 @@ void print_node(VALUE str, NODE *node, int tab)
|
|
815
836
|
|
816
837
|
if (show_offsets)
|
817
838
|
{
|
818
|
-
rbstr_printf(str, "@ %s | %16"PRIxPTR " %16"PRIxPTR " %16"PRIxPTR "\n",
|
819
|
-
(
|
839
|
+
rbstr_printf(str, "@ %s | %16"PRIxPTR " %16"PRIxPTR " %16"PRIxPTR " (line %d)\n",
|
840
|
+
ruby_node_name(type),
|
841
|
+
(intptr_t) node->u1.value, (intptr_t) node->u2.value, (intptr_t) node->u3.value,
|
842
|
+
nd_line(node));
|
820
843
|
}
|
821
844
|
else
|
822
845
|
{
|
823
|
-
rbstr_printf(str, "@ %s\n", ruby_node_name(type));
|
846
|
+
rbstr_printf(str, "@ %s (line %d)\n", ruby_node_name(type), nd_line(node));
|
824
847
|
}
|
825
848
|
|
826
849
|
ut[0] = nodes_ctbl[type * 3];
|
@@ -837,7 +860,7 @@ void print_node(VALUE str, NODE *node, int tab)
|
|
837
860
|
if (ut[i] == NT_NODE)
|
838
861
|
{
|
839
862
|
if (nd_type(node) != NODE_OP_ASGN2 || i != 2)
|
840
|
-
print_node(str, RNODE(uref[i]), tab + 1);
|
863
|
+
print_node(str, RNODE(uref[i]), tab + 1, show_offsets);
|
841
864
|
else
|
842
865
|
{
|
843
866
|
if (ut[i] != 0 && TYPE(ut[i]) != T_NODE)
|
@@ -855,7 +878,7 @@ void print_node(VALUE str, NODE *node, int tab)
|
|
855
878
|
PRINT_NODE_TAB; rbstr_printf(str, " ");
|
856
879
|
if (show_offsets)
|
857
880
|
{
|
858
|
-
rbstr_printf(str, ">| ADR: %"PRIxPTR"
|
881
|
+
rbstr_printf(str, ">| ADR: %"PRIxPTR"; CLASS: %s (TYPE %d); VALUE: %s\n",
|
859
882
|
(intptr_t) uref[i],
|
860
883
|
class_name, TYPE(uref[i]),
|
861
884
|
RSTRING_PTR(rb_funcall(uref[i], rb_intern("to_s"), 0)));
|
@@ -869,11 +892,25 @@ void print_node(VALUE str, NODE *node, int tab)
|
|
869
892
|
}
|
870
893
|
else if (ut[i] == NT_ID)
|
871
894
|
{
|
895
|
+
const char *str_null = "<NULL>", *str_intern = "<NONAME>";
|
896
|
+
const char *str_sym;
|
872
897
|
PRINT_NODE_TAB; rbstr_printf(str, " ");
|
898
|
+
|
899
|
+
if (uref[i] == 0)
|
900
|
+
str_sym = str_null;
|
901
|
+
else
|
902
|
+
{
|
903
|
+
VALUE rbstr_sym = rb_id2str(uref[i]);
|
904
|
+
if (TYPE(rbstr_sym) == T_STRING)
|
905
|
+
str_sym = RSTRING_PTR(rb_id2str(uref[i]));
|
906
|
+
else
|
907
|
+
str_sym = str_intern;
|
908
|
+
}
|
909
|
+
|
873
910
|
if (show_offsets)
|
874
|
-
rbstr_printf(str, ">| ID: %d; SYMBOL:
|
911
|
+
rbstr_printf(str, ">| ID: %d; SYMBOL: :%s\n", (ID) uref[i], str_sym);
|
875
912
|
else
|
876
|
-
rbstr_printf(str, ">| SYMBOL: :%s\n",
|
913
|
+
rbstr_printf(str, ">| SYMBOL: :%s\n", str_sym);
|
877
914
|
}
|
878
915
|
else if (ut[i] == NT_LONG)
|
879
916
|
{
|
@@ -927,7 +964,21 @@ void resolve_syms_ords(VALUE data, NODEObjAddresses *relocs)
|
|
927
964
|
relocs->syms_len = RARRAY_LEN(tbl_val);
|
928
965
|
relocs->syms_adr = ALLOC_N(ID, relocs->syms_len);
|
929
966
|
for (i = 0; i < relocs->syms_len; i++)
|
930
|
-
|
967
|
+
{
|
968
|
+
VALUE r_sym = RARRAY_PTR(tbl_val)[i];
|
969
|
+
if (TYPE(r_sym) == T_STRING)
|
970
|
+
{
|
971
|
+
relocs->syms_adr[i] = rb_intern(RSTRING_PTR(r_sym));
|
972
|
+
}
|
973
|
+
else if (TYPE(r_sym) == T_FIXNUM)
|
974
|
+
{
|
975
|
+
relocs->syms_adr[i] = (ID) FIX2INT(r_sym);
|
976
|
+
}
|
977
|
+
else
|
978
|
+
{
|
979
|
+
rb_raise(rb_eArgError, "Symbols table is corrupted");
|
980
|
+
}
|
981
|
+
}
|
931
982
|
}
|
932
983
|
|
933
984
|
void resolve_lits_ords(VALUE data, NODEObjAddresses *relocs)
|
@@ -1053,16 +1104,16 @@ void resolve_args_ords(VALUE data, NODEObjAddresses *relocs)
|
|
1053
1104
|
rb_raise(rb_eArgError, "args entry %d is corrupted", i);
|
1054
1105
|
}
|
1055
1106
|
// Load unresolved values
|
1056
|
-
ainfo->pre_init = (NODE *) FIX2LONG(aiptr[0]); // Node ordinal
|
1057
|
-
ainfo->post_init = (NODE *) FIX2LONG(aiptr[1]); // Node ordinal
|
1107
|
+
ainfo->pre_init = (NODE *) (uintptr_t) FIX2LONG(aiptr[0]); // Node ordinal
|
1108
|
+
ainfo->post_init = (NODE *) (uintptr_t) FIX2LONG(aiptr[1]); // Node ordinal
|
1058
1109
|
ainfo->pre_args_num = FIX2INT(aiptr[2]); // No ordinal resolving
|
1059
1110
|
ainfo->post_args_num = FIX2INT(aiptr[3]); // No ordinal resolving
|
1060
1111
|
ainfo->first_post_arg = FIX2INT(aiptr[4]); // Symbolic ordinal
|
1061
1112
|
ainfo->rest_arg = FIX2INT(aiptr[5]); // Symbolic ordinal
|
1062
1113
|
ainfo->block_arg = FIX2INT(aiptr[6]); // Symbolic ordinal
|
1063
|
-
ainfo->kw_args = (NODE *) FIX2LONG(aiptr[7]); // Node ordinal
|
1064
|
-
ainfo->kw_rest_arg = (NODE *) FIX2LONG(aiptr[8]); // Node ordinal
|
1065
|
-
ainfo->opt_args = (NODE *) FIX2LONG(aiptr[9]); // Node ordinal
|
1114
|
+
ainfo->kw_args = (NODE *) (uintptr_t) FIX2LONG(aiptr[7]); // Node ordinal
|
1115
|
+
ainfo->kw_rest_arg = (NODE *) (uintptr_t) FIX2LONG(aiptr[8]); // Node ordinal
|
1116
|
+
ainfo->opt_args = (NODE *) (uintptr_t) FIX2LONG(aiptr[9]); // Node ordinal
|
1066
1117
|
// Resolve nodes
|
1067
1118
|
ord = (int) (((VALUE) ainfo->pre_init) & 0xFFFFFFFF);
|
1068
1119
|
if (ord < -1 || ord >= relocs->nodes_len)
|
@@ -1107,6 +1158,23 @@ void resolve_args_ords(VALUE data, NODEObjAddresses *relocs)
|
|
1107
1158
|
}
|
1108
1159
|
#endif
|
1109
1160
|
|
1161
|
+
/*
|
1162
|
+
* Transforms binary data with nodes descriptions into Ruby AST (i.e.
|
1163
|
+
* ternary tree of nodes). Each node is represented in the next binary format:
|
1164
|
+
*
|
1165
|
+
* [4 bytes -- pointers info] [node flags] [child ORD1] [child ORD2] [child ORD3]
|
1166
|
+
*
|
1167
|
+
* Pointers info:
|
1168
|
+
* BYTE -- child 1 info (bits 7..4 -- ordinal type, bits 3..0 -- ordinal size, bytes)
|
1169
|
+
* BYTE -- child 2 info
|
1170
|
+
* BYTE -- child 3 info
|
1171
|
+
* BYTE -- node flags length, bytes
|
1172
|
+
* Node flags:
|
1173
|
+
* node->flags field packed by bin_to_value function
|
1174
|
+
* child ORDi Ordinal of ith node child packed by bin_to_value_function
|
1175
|
+
* (it will be transformed to the real address in memory, i.e. pointer
|
1176
|
+
* or symbol ID during data loading)
|
1177
|
+
*/
|
1110
1178
|
void load_nodes_from_str(VALUE data, NODEObjAddresses *relocs)
|
1111
1179
|
{
|
1112
1180
|
int i, j;
|
@@ -1215,7 +1283,7 @@ static VALUE check_hash_magic(VALUE data)
|
|
1215
1283
|
VALUE val, refval;
|
1216
1284
|
// MAGIC signature must be valid
|
1217
1285
|
val = get_hash_strfield(data, "MAGIC");
|
1218
|
-
if (strcmp(
|
1286
|
+
if (strcmp(NODEMARSHAL_MAGIC, RSTRING_PTR(val)))
|
1219
1287
|
rb_raise(rb_eArgError, "Bad value of MAGIC signature");
|
1220
1288
|
// RUBY_PLATFORM signature must match the current platform
|
1221
1289
|
val = get_hash_strfield(data, "RUBY_PLATFORM");
|
@@ -1307,6 +1375,9 @@ static VALUE m_nodedump_from_memory(VALUE self, VALUE dump)
|
|
1307
1375
|
|
1308
1376
|
|
1309
1377
|
/*
|
1378
|
+
* call-seq:
|
1379
|
+
* obj.symbols
|
1380
|
+
*
|
1310
1381
|
* Return array with the list of symbols
|
1311
1382
|
*/
|
1312
1383
|
static VALUE m_nodedump_symbols(VALUE self)
|
@@ -1343,8 +1414,12 @@ static VALUE m_nodedump_symbols(VALUE self)
|
|
1343
1414
|
}
|
1344
1415
|
|
1345
1416
|
/*
|
1346
|
-
*
|
1347
|
-
*
|
1417
|
+
* call-seq:
|
1418
|
+
* obj.change_symbol(old_sym, new_sym)
|
1419
|
+
*
|
1420
|
+
* Replace one symbol by another (to be used for code obfuscation)
|
1421
|
+
* - +old_sym+ -- String that contains symbol name to be replaced
|
1422
|
+
* - +new_sym+ -- String that contains new name of the symbol
|
1348
1423
|
*/
|
1349
1424
|
static VALUE m_nodedump_change_symbol(VALUE self, VALUE old_sym, VALUE new_sym)
|
1350
1425
|
{
|
@@ -1540,6 +1615,7 @@ static VALUE m_nodedump_from_string(VALUE self, VALUE str)
|
|
1540
1615
|
static VALUE m_nodedump_init(VALUE self, VALUE source, VALUE info)
|
1541
1616
|
{
|
1542
1617
|
ID id_usr;
|
1618
|
+
rb_iv_set(self, "@show_offsets", Qfalse);
|
1543
1619
|
Check_Type(source, T_SYMBOL);
|
1544
1620
|
id_usr = SYM2ID(source);
|
1545
1621
|
if (id_usr == rb_intern("srcfile"))
|
@@ -1571,8 +1647,8 @@ static VALUE m_nodedump_init(VALUE self, VALUE source, VALUE info)
|
|
1571
1647
|
* call-seq:
|
1572
1648
|
* obj.dump_tree
|
1573
1649
|
*
|
1574
|
-
* Transforms Ruby syntax tree (NODE) to the
|
1575
|
-
* rb_parser_dump_tree function from node.c (see Ruby source code).
|
1650
|
+
* Transforms Ruby syntax tree (NODE) to the String using
|
1651
|
+
* +rb_parser_dump_tree+ function from +node.c+ (see Ruby source code).
|
1576
1652
|
*/
|
1577
1653
|
static VALUE m_nodedump_parser_dump_tree(VALUE self)
|
1578
1654
|
{
|
@@ -1581,16 +1657,52 @@ static VALUE m_nodedump_parser_dump_tree(VALUE self)
|
|
1581
1657
|
}
|
1582
1658
|
|
1583
1659
|
/*
|
1584
|
-
*
|
1660
|
+
* call-seq:
|
1661
|
+
* obj.dump_tree_short
|
1662
|
+
*
|
1663
|
+
* Transforms Ruby syntax tree (NODE) to the String using custom function
|
1664
|
+
* instead of +rb_parser_dump_tree+ function.
|
1665
|
+
*
|
1666
|
+
* See also #show_offsets, #show_offsets=
|
1585
1667
|
*/
|
1586
1668
|
static VALUE m_nodedump_dump_tree_short(VALUE self)
|
1587
1669
|
{
|
1588
1670
|
VALUE str = rb_str_new2(""); // Output string
|
1589
1671
|
NODE *node = RNODE(rb_iv_get(self, "@node"));
|
1590
|
-
|
1672
|
+
int show_offsets = (rb_iv_get(self, "@show_offsets") == Qtrue) ? 1 : 0;
|
1673
|
+
print_node(str, node, 0, show_offsets);
|
1591
1674
|
return str;
|
1592
1675
|
}
|
1593
1676
|
|
1677
|
+
/*
|
1678
|
+
* call-seq:
|
1679
|
+
* obj.show_offsets
|
1680
|
+
*
|
1681
|
+
* Returns show_offsets property (used by NodeMarshal#dump_tree_short)
|
1682
|
+
* It can be either true or false
|
1683
|
+
*/
|
1684
|
+
static VALUE m_nodedump_show_offsets(VALUE self)
|
1685
|
+
{
|
1686
|
+
return rb_iv_get(self, "@show_offsets");
|
1687
|
+
}
|
1688
|
+
|
1689
|
+
/*
|
1690
|
+
* call-seq:
|
1691
|
+
* obj.show_offsets=
|
1692
|
+
*
|
1693
|
+
* Sets show_offsets property (used by NodeMarshal#dump_tree_short)
|
1694
|
+
* It can be either true or false
|
1695
|
+
*/
|
1696
|
+
static VALUE m_nodedump_set_show_offsets(VALUE self, VALUE value)
|
1697
|
+
{
|
1698
|
+
if (value != Qtrue && value != Qfalse)
|
1699
|
+
{
|
1700
|
+
rb_raise(rb_eArgError, "show_offsets property must be either true or false");
|
1701
|
+
}
|
1702
|
+
return rb_iv_set(self, "@show_offsets", value);
|
1703
|
+
}
|
1704
|
+
|
1705
|
+
|
1594
1706
|
/*
|
1595
1707
|
* call-seq:
|
1596
1708
|
* obj.to_hash
|
@@ -1604,7 +1716,7 @@ static VALUE m_nodedump_dump_tree_short(VALUE self)
|
|
1604
1716
|
*
|
1605
1717
|
* <i>Part 1: Signatures</i>
|
1606
1718
|
*
|
1607
|
-
* - <tt>MAGIC</tt> --
|
1719
|
+
* - <tt>MAGIC</tt> -- NODEMARSHAL11
|
1608
1720
|
* - <tt>RUBY_PLATFORM</tt> -- saved <tt>RUBY_PLATFORM</tt> constant value
|
1609
1721
|
* - <tt>RUBY_VERSION</tt> -- saved <tt>RUBY_VERSION</tt> constant value
|
1610
1722
|
*
|
@@ -1614,7 +1726,8 @@ static VALUE m_nodedump_dump_tree_short(VALUE self)
|
|
1614
1726
|
* its identifier that is used in the node tree.
|
1615
1727
|
*
|
1616
1728
|
* - <tt>literals</tt> -- program literals (strings, ranges etc.)
|
1617
|
-
* - <tt>symbols</tt> -- program symbols
|
1729
|
+
* - <tt>symbols</tt> -- program symbols (values have either String or Fixnum
|
1730
|
+
* data type; numbers are used for symbols that cannot be represented as strings)
|
1618
1731
|
* - <tt>global_entries</tt> -- global variables information
|
1619
1732
|
* - <tt>id_tables</tt> -- array of arrays. Each array contains symbols IDs
|
1620
1733
|
* - <tt>args</tt> -- information about code block argument(s)
|
@@ -1867,7 +1980,7 @@ static VALUE m_base85r_decode(VALUE obj, VALUE input)
|
|
1867
1980
|
}
|
1868
1981
|
|
1869
1982
|
/* call-seq:
|
1870
|
-
* obj.
|
1983
|
+
* obj.to_text
|
1871
1984
|
*
|
1872
1985
|
* Converts NodeMarshal class example to the text string (modified Base85 encoding) that
|
1873
1986
|
* can be saved to the file and used for loading the node from the file.
|
@@ -1888,7 +2001,6 @@ static VALUE m_nodedump_node(VALUE self)
|
|
1888
2001
|
return rb_iv_get(self, "@node");
|
1889
2002
|
}
|
1890
2003
|
|
1891
|
-
|
1892
2004
|
/*
|
1893
2005
|
* This class can load and save Ruby code in the form of the
|
1894
2006
|
* platform-dependent syntax tree (made of NODEs). Such function
|
@@ -1917,6 +2029,8 @@ void Init_nodemarshal()
|
|
1917
2029
|
rb_define_method(cNodeMarshal, "dump_tree", RUBY_METHOD_FUNC(m_nodedump_parser_dump_tree), 0);
|
1918
2030
|
rb_define_method(cNodeMarshal, "dump_tree_short", RUBY_METHOD_FUNC(m_nodedump_dump_tree_short), 0);
|
1919
2031
|
rb_define_method(cNodeMarshal, "compile", RUBY_METHOD_FUNC(m_nodedump_compile), 0);
|
2032
|
+
rb_define_method(cNodeMarshal, "show_offsets", RUBY_METHOD_FUNC(m_nodedump_show_offsets), 0);
|
2033
|
+
rb_define_method(cNodeMarshal, "show_offsets=", RUBY_METHOD_FUNC(m_nodedump_set_show_offsets), 1);
|
1920
2034
|
// Methods for working with the information about the node
|
1921
2035
|
// a) literals, symbols, generic information
|
1922
2036
|
rb_define_method(cNodeMarshal, "symbols", RUBY_METHOD_FUNC(m_nodedump_symbols), 0);
|
data/ext/node-marshal/nodedump.h
CHANGED
data/ext/node-marshal/nodeinfo.c
CHANGED
@@ -8,7 +8,7 @@
|
|
8
8
|
* Fragments from Ruby source code are used here
|
9
9
|
* (mainly from node.c, gc.c)
|
10
10
|
*
|
11
|
-
* License: 2-
|
11
|
+
* License: BSD-2-Clause
|
12
12
|
*
|
13
13
|
*/
|
14
14
|
#include <stdio.h>
|
@@ -165,9 +165,10 @@ static int nodes_child_info[][4] =
|
|
165
165
|
|
166
166
|
|
167
167
|
|
168
|
-
|
169
|
-
*
|
170
|
-
* This function is based on Ruby
|
168
|
+
/*
|
169
|
+
* Check the correctness of nodes table from the viewpoint
|
170
|
+
* This function is based on Ruby source code (node.c)
|
171
|
+
*/
|
171
172
|
void check_nodes_child_info(int pos)
|
172
173
|
{
|
173
174
|
int type = nodes_child_info[pos][0];
|
@@ -565,22 +566,36 @@ void check_nodes_child_info(int pos)
|
|
565
566
|
|
566
567
|
}
|
567
568
|
|
568
|
-
|
569
|
+
/*
|
570
|
+
* Converts nodes_child_info 2D array of int into nodes_ctbl 1D array of int
|
571
|
+
*
|
572
|
+
* nodes_child_info is similar to hash by the structure: each 1D subarray
|
573
|
+
* has the next structure:
|
574
|
+
* {NODE_ID, NT_CHILD1_TYPE, NT_CHILD2_TYPE, NT_CHILD3_TYPE}
|
575
|
+
*/
|
569
576
|
void init_nodes_table(int *nodes_ctbl, int num_of_entries)
|
570
577
|
{
|
571
|
-
int pos,
|
578
|
+
int pos, i;
|
579
|
+
/* Check the input array using information from Ruby source code */
|
572
580
|
for (pos = 0; nodes_child_info[pos][0] != -1; pos++)
|
573
581
|
{
|
574
582
|
check_nodes_child_info(pos);
|
575
583
|
}
|
576
|
-
|
584
|
+
/* Initialize output array by NT_UNKNOWN (if node is not defined
|
585
|
+
in the input table the types of its childs are unknown) */
|
577
586
|
for (i = 0; i < num_of_entries * 3; i++)
|
578
587
|
{
|
579
588
|
nodes_ctbl[i] = NT_UNKNOWN;
|
580
589
|
}
|
590
|
+
/* Fill output array */
|
581
591
|
for (pos = 0; nodes_child_info[pos][0] != -1; pos++)
|
582
592
|
{
|
583
|
-
|
593
|
+
int index = nodes_child_info[pos][0], offset;
|
594
|
+
if (index < 0 || index > num_of_entries)
|
595
|
+
{
|
596
|
+
rb_raise(rb_eArgError, "NODE ID %d is out or nodes_ctbl array boundaries", index);
|
597
|
+
}
|
598
|
+
offset = index * 3;
|
584
599
|
nodes_ctbl[offset++] = nodes_child_info[pos][1];
|
585
600
|
nodes_ctbl[offset++] = nodes_child_info[pos][2];
|
586
601
|
nodes_ctbl[offset++] = nodes_child_info[pos][3];
|
data/lib/node-marshal.rb
CHANGED
@@ -31,7 +31,9 @@ class NodeMarshal
|
|
31
31
|
# - +opts+ -- Hash with options (+:compress+, +:so_path+)
|
32
32
|
# +:compress+ can be +true+ or +false+, +:so_path+ is a test string
|
33
33
|
# with the command for nodemarshal.so inclusion (default is
|
34
|
-
# require_relative '../ext/node-marshal/nodemarshal.so')
|
34
|
+
# <tt>require_relative '../ext/node-marshal/nodemarshal.so'</tt>)
|
35
|
+
#
|
36
|
+
# See also NodeMarshal::compile_rb_file
|
35
37
|
def to_compiled_rb(outfile, *args)
|
36
38
|
compress = true
|
37
39
|
so_path = "require_relative '../ext/node-marshal/nodemarshal.so'"
|
@@ -80,6 +82,12 @@ EOS
|
|
80
82
|
return txt
|
81
83
|
end
|
82
84
|
|
85
|
+
# call-seq:
|
86
|
+
# NodeMarshal::compile_rb_file(outfile, inpfile, opts)
|
87
|
+
#
|
88
|
+
# Reads +.rb+ file (Ruby source) and compiles it to .rb file containing
|
89
|
+
# compressed AST node and its loader. This functions is an envelope for
|
90
|
+
# NodeMarshal#to_compiled_rb
|
83
91
|
def self.compile_rb_file(outfile, inpfile, *args)
|
84
92
|
node = NodeMarshal.new(:srcfile, inpfile)
|
85
93
|
node.to_compiled_rb(outfile, *args)
|
@@ -117,7 +125,7 @@ EOS
|
|
117
125
|
end
|
118
126
|
|
119
127
|
# call-seq:
|
120
|
-
# obj.get_safe_symbols
|
128
|
+
# obj.get_safe_symbols(our_symbols)
|
121
129
|
#
|
122
130
|
# Returns an array that contains strings with the names of symbols that are safe
|
123
131
|
# to change. It excludes symbols that are present in the table of literals (and their derivatives
|
@@ -189,7 +197,7 @@ EOS
|
|
189
197
|
end
|
190
198
|
|
191
199
|
# call-seq:
|
192
|
-
# obj.
|
200
|
+
# obj.rebuild
|
193
201
|
#
|
194
202
|
# Rebuilds the node by converting it to the binary dump and further restoring
|
195
203
|
# of it from this dump. It doesn't change the original node and returns rebuilt
|
data/test/test_base.rb
CHANGED
@@ -37,7 +37,6 @@ end
|
|
37
37
|
ni.map {|x| fact(x) }
|
38
38
|
EOS
|
39
39
|
assert_node_compiler(program)
|
40
|
-
# test_string_eval(program, [1, 2, 6, 24, 120, 720, 5040, 40320, 362880], "Factorial");
|
41
40
|
end
|
42
41
|
|
43
42
|
# Simple ROT13 task that combines several language construction
|
@@ -163,6 +162,27 @@ EOS
|
|
163
162
|
assert_node_compiler(program)
|
164
163
|
end
|
165
164
|
|
165
|
+
# Test expressions like x['a'] &&= true or x['b'] ||= false
|
166
|
+
# (they use NODE_OP_ASGN1 node and symbols that cannot be represented
|
167
|
+
# by String value)
|
168
|
+
def test_node_op_asgn1
|
169
|
+
program = <<EOS
|
170
|
+
x = {a: [1234], b: [5678, 2],
|
171
|
+
and1: true, and2: true, and3: false, and4: false,
|
172
|
+
or1: true, or2: true, or3: false, or4: false}
|
173
|
+
x[:a] &&= 'test'
|
174
|
+
x[:b] ||= 'qqq'
|
175
|
+
|
176
|
+
x[:and1] &&= false; x[:and2] &&= true
|
177
|
+
x[:and3] &&= false; x[:and4] &&= true
|
178
|
+
|
179
|
+
x[:or1] ||= false; x[:or2] ||= true
|
180
|
+
x[:or3] ||= false; x[:or4] ||= true
|
181
|
+
x
|
182
|
+
EOS
|
183
|
+
assert_node_compiler(program)
|
184
|
+
end
|
185
|
+
|
166
186
|
# Check the reaction on the parsing errors during the node creation
|
167
187
|
# In the case of syntax error ArgumentError exception should be generated
|
168
188
|
def test_syntax_error
|
data/test/test_complex.rb
CHANGED
@@ -35,7 +35,7 @@ class TestHashTree
|
|
35
35
|
@depth = depth
|
36
36
|
@value = {:depth => depth, :data => [], :leaves =>[] }
|
37
37
|
data_size.times do
|
38
|
-
case rnd.rand(30000) %
|
38
|
+
case rnd.rand(30000) % 7
|
39
39
|
when 0
|
40
40
|
@value[:data] << 10**(rnd.rand(600000) * 0.001 - 300)
|
41
41
|
when 1
|
@@ -51,6 +51,9 @@ class TestHashTree
|
|
51
51
|
when 5
|
52
52
|
a, b = rnd.rand(100), rnd.rand(10)
|
53
53
|
@value[:data] << (a...(a + b))
|
54
|
+
when 6
|
55
|
+
rndsym = (Random.rand(1_000_000_000).to_s(36)).to_sym
|
56
|
+
@value[:data] << rndsym
|
54
57
|
else
|
55
58
|
nil
|
56
59
|
end
|
@@ -122,7 +125,7 @@ class TestComplex < Test::Unit::TestCase
|
|
122
125
|
puts " Source code size: %d bytes" % tree_str.length
|
123
126
|
puts " Binary data size: %d bytes" % tree_bin.length
|
124
127
|
# Clear the memory
|
125
|
-
node = nil; GC.start
|
128
|
+
node = nil; GC.enable; GC.start
|
126
129
|
# Load the node from the disk and turn it to tree
|
127
130
|
puts 'Loading the node...'
|
128
131
|
node = NodeMarshal.new(:binfile, 'node.bin')
|
data/test/test_qcall.rb
CHANGED
@@ -35,12 +35,17 @@ puts "'#{b&.owner_name}'"
|
|
35
35
|
puts "'#{b&.owner_info&.address}'"
|
36
36
|
[a&.owner_name, a&.owner_info&.address, b&.owner_name, b&.owner_info&.address]
|
37
37
|
}
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
38
|
+
ver = RUBY_VERSION
|
39
|
+
ver = (ver[0] + ver[2] + ver[4]).to_i
|
40
|
+
if ver >= 230
|
41
|
+
node = NodeMarshal.new(:srcmemory, qcall_program)
|
42
|
+
bindump = node.to_bin
|
43
|
+
node = NodeMarshal.new(:binmemory, bindump)
|
44
|
+
res_node = node.compile.eval
|
45
|
+
res_text = eval(qcall_program)
|
46
|
+
assert_equal(res_text, res_node)
|
47
|
+
else
|
48
|
+
assert_true(false, "Ruby 2.3 or higher is required for &. operator test")
|
49
|
+
end
|
45
50
|
end
|
46
51
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: node-marshal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexey Voskov
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir:
|
10
10
|
- bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2016-01-11 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: "This gem is designed for transformation of Ruby source code (eiher in
|
15
15
|
the form of files or strings) to the \nRuby nodes (syntax trees) used by Ruby MRI
|
@@ -25,10 +25,10 @@ extensions:
|
|
25
25
|
extra_rdoc_files:
|
26
26
|
- README.rdoc
|
27
27
|
files:
|
28
|
+
- COPYING
|
28
29
|
- README.rdoc
|
29
30
|
- bin/noderbc
|
30
31
|
- bin/noderbc.bat
|
31
|
-
- ext/node-marshal/COPYING
|
32
32
|
- ext/node-marshal/base85r.c
|
33
33
|
- ext/node-marshal/extconf.rb
|
34
34
|
- ext/node-marshal/libobj/readme.txt
|
@@ -46,9 +46,9 @@ files:
|
|
46
46
|
- test/test_obfuscator.rb
|
47
47
|
- test/test_qcall.rb
|
48
48
|
- test/tinytet.rb
|
49
|
-
homepage:
|
49
|
+
homepage: https://github.com/dig386/node-marshal
|
50
50
|
licenses:
|
51
|
-
- 2-
|
51
|
+
- BSD-2-Clause
|
52
52
|
metadata: {}
|
53
53
|
post_install_message:
|
54
54
|
rdoc_options:
|