[Forensics-changes] [yara] 21/407: Implement dictionaries

Hilko Bengen bengen at moszumanska.debian.org
Sat Jul 1 10:27:59 UTC 2017


This is an automated email from the git hooks/post-receive script.

bengen pushed a commit to annotated tag v3.3.0
in repository yara.

commit 0bff0666fbfd9c6093d09b43c869a226b04274b1
Author: Victor Manuel Alvarez <vmalvarez at virustotal.com>
Date:   Mon Sep 8 16:33:05 2014 +0200

    Implement dictionaries
---
 libyara/compiler.c             |   4 +-
 libyara/exec.c                 |  29 +++++-
 libyara/grammar.c              | 189 ++++++++++++++++++++----------------
 libyara/grammar.y              |  31 +++++-
 libyara/include/yara/error.h   |   2 +-
 libyara/include/yara/exec.h    |   1 +
 libyara/include/yara/modules.h |  30 ++++++
 libyara/include/yara/object.h  |  13 +++
 libyara/include/yara/types.h   |  25 +++++
 libyara/modules/tests.c        |   6 ++
 libyara/object.c               | 215 +++++++++++++++++++++++++++++++++++------
 yara-python/tests.py           |   2 +
 12 files changed, 429 insertions(+), 118 deletions(-)

diff --git a/libyara/compiler.c b/libyara/compiler.c
index 4c518e9..67a7f36 100644
--- a/libyara/compiler.c
+++ b/libyara/compiler.c
@@ -728,11 +728,11 @@ char* yr_compiler_get_error_message(
           "\"%s\" is not a structure",
           compiler->last_error_extra_info);
       break;
-    case ERROR_NOT_AN_ARRAY:
+    case ERROR_NOT_INDEXABLE:
       snprintf(
           buffer,
           buffer_size,
-          "\"%s\" is not a array",
+          "\"%s\" is not an array or dictionary",
           compiler->last_error_extra_info);
       break;
     case ERROR_INVALID_FIELD_NAME:
diff --git a/libyara/exec.c b/libyara/exec.c
index a8aae87..7728580 100644
--- a/libyara/exec.c
+++ b/libyara/exec.c
@@ -429,10 +429,10 @@ int yr_execute_code(
         break;
 
       case OP_INDEX_ARRAY:
-        pop(r1);
-        pop(r2);
+        pop(r1);  // index
+        pop(r2);  // array
 
-        if (r1 == UNDEFINED)
+        if (IS_UNDEFINED(r1))
         {
           push(UNDEFINED);
           break;
@@ -449,6 +449,29 @@ int yr_execute_code(
 
         break;
 
+      case OP_LOOKUP_DICT:
+        pop(r1);  // key
+        pop(r2);  // dictionary
+
+        if (IS_UNDEFINED(r1))
+        {
+          push(UNDEFINED);
+          break;
+        }
+
+        object = UINT64_TO_PTR(YR_OBJECT*, r2);
+        assert(object->type == OBJECT_TYPE_DICTIONARY);
+
+        object = yr_object_dict_get_item(
+            object, 0, UINT64_TO_PTR(const char*, r1));
+
+        if (object != NULL)
+          push(PTR_TO_UINT64(object));
+        else
+          push(UNDEFINED);
+
+        break;
+
       case OP_CALL:
 
         // r1 = number of arguments
diff --git a/libyara/grammar.c b/libyara/grammar.c
index 98f1105..bde75d0 100644
--- a/libyara/grammar.c
+++ b/libyara/grammar.c
@@ -637,14 +637,14 @@ static const yytype_uint16 yyrline[] =
      244,   272,   276,   304,   309,   310,   315,   316,   322,   325,
      343,   356,   393,   394,   399,   415,   428,   441,   458,   459,
      464,   478,   477,   494,   511,   512,   517,   518,   519,   520,
-     525,   613,   662,   685,   725,   728,   750,   783,   828,   845,
-     854,   863,   878,   892,   906,   922,   937,   972,   936,  1083,
-    1082,  1159,  1165,  1171,  1177,  1185,  1194,  1203,  1212,  1221,
-    1248,  1275,  1302,  1306,  1314,  1315,  1320,  1342,  1354,  1370,
-    1369,  1375,  1384,  1385,  1390,  1395,  1404,  1405,  1409,  1417,
-    1421,  1431,  1444,  1456,  1468,  1480,  1492,  1504,  1516,  1526,
-    1549,  1564,  1579,  1601,  1638,  1648,  1658,  1668,  1678,  1688,
-    1698,  1708,  1718,  1728,  1738,  1748
+     525,   613,   662,   712,   752,   755,   777,   810,   855,   872,
+     881,   890,   905,   919,   933,   949,   964,   999,   963,  1110,
+    1109,  1186,  1192,  1198,  1204,  1212,  1221,  1230,  1239,  1248,
+    1275,  1302,  1329,  1333,  1341,  1342,  1347,  1369,  1381,  1397,
+    1396,  1402,  1411,  1412,  1417,  1422,  1431,  1432,  1436,  1444,
+    1448,  1458,  1471,  1483,  1495,  1507,  1519,  1531,  1543,  1553,
+    1576,  1591,  1606,  1628,  1665,  1675,  1685,  1695,  1705,  1715,
+    1725,  1735,  1745,  1755,  1765,  1775
 };
 #endif
 
@@ -2306,12 +2306,39 @@ yyreduce:
     {
         if ((yyvsp[(1) - (4)].object) != NULL && (yyvsp[(1) - (4)].object)->type == OBJECT_TYPE_ARRAY)
         {
+          if ((yyvsp[(3) - (4)].expression).type != EXPRESSION_TYPE_INTEGER)
+          {
+            yr_compiler_set_error_extra_info(
+                compiler, "array indexes must be of integer type");
+            compiler->last_result = ERROR_WRONG_TYPE;
+          }
+
+          ERROR_IF(compiler->last_result != ERROR_SUCCESS);
+
           compiler->last_result = yr_parser_emit(
               yyscanner,
               OP_INDEX_ARRAY,
               NULL);
 
-          (yyval.object) = ((YR_OBJECT_ARRAY*) (yyvsp[(1) - (4)].object))->items->objects[0];
+          (yyval.object) = ((YR_OBJECT_ARRAY*) (yyvsp[(1) - (4)].object))->prototype_item;
+        }
+        else if ((yyvsp[(1) - (4)].object) != NULL && (yyvsp[(1) - (4)].object)->type == OBJECT_TYPE_DICTIONARY)
+        {
+          if ((yyvsp[(3) - (4)].expression).type != EXPRESSION_TYPE_STRING)
+          {
+            yr_compiler_set_error_extra_info(
+                compiler, "dictionary keys must be of string type");
+            compiler->last_result = ERROR_WRONG_TYPE;
+          }
+
+          ERROR_IF(compiler->last_result != ERROR_SUCCESS);
+
+          compiler->last_result = yr_parser_emit(
+              yyscanner,
+              OP_LOOKUP_DICT,
+              NULL);
+
+          (yyval.object) = ((YR_OBJECT_DICTIONARY*) (yyvsp[(1) - (4)].object))->prototype_item;
         }
         else
         {
@@ -2319,7 +2346,7 @@ yyreduce:
               compiler,
               (yyvsp[(1) - (4)].object)->identifier);
 
-          compiler->last_result = ERROR_NOT_AN_ARRAY;
+          compiler->last_result = ERROR_NOT_INDEXABLE;
         }
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
@@ -2327,7 +2354,7 @@ yyreduce:
     break;
 
   case 43:
-#line 686 "grammar.y"
+#line 713 "grammar.y"
     {
         int args_count;
 
@@ -2365,14 +2392,14 @@ yyreduce:
     break;
 
   case 44:
-#line 725 "grammar.y"
+#line 752 "grammar.y"
     {
         (yyval.c_string) = yr_strdup("");
       }
     break;
 
   case 45:
-#line 729 "grammar.y"
+#line 756 "grammar.y"
     {
         (yyval.c_string) = yr_malloc(MAX_FUNCTION_ARGS + 1);
 
@@ -2397,7 +2424,7 @@ yyreduce:
     break;
 
   case 46:
-#line 751 "grammar.y"
+#line 778 "grammar.y"
     {
         if (strlen((yyvsp[(1) - (3)].c_string)) == MAX_FUNCTION_ARGS)
         {
@@ -2429,7 +2456,7 @@ yyreduce:
     break;
 
   case 47:
-#line 784 "grammar.y"
+#line 811 "grammar.y"
     {
         SIZED_STRING* sized_string = (yyvsp[(1) - (1)].sized_string);
         RE* re;
@@ -2473,7 +2500,7 @@ yyreduce:
     break;
 
   case 48:
-#line 829 "grammar.y"
+#line 856 "grammar.y"
     {
         if ((yyvsp[(1) - (1)].expression).type == EXPRESSION_TYPE_STRING)
         {
@@ -2490,7 +2517,7 @@ yyreduce:
     break;
 
   case 49:
-#line 846 "grammar.y"
+#line 873 "grammar.y"
     {
         compiler->last_result = yr_parser_emit_with_arg(
             yyscanner, OP_PUSH, 1, NULL);
@@ -2502,7 +2529,7 @@ yyreduce:
     break;
 
   case 50:
-#line 855 "grammar.y"
+#line 882 "grammar.y"
     {
         compiler->last_result = yr_parser_emit_with_arg(
             yyscanner, OP_PUSH, 0, NULL);
@@ -2514,7 +2541,7 @@ yyreduce:
     break;
 
   case 51:
-#line 864 "grammar.y"
+#line 891 "grammar.y"
     {
         CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_STRING, "matches");
         CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_REGEXP, "matches");
@@ -2532,7 +2559,7 @@ yyreduce:
     break;
 
   case 52:
-#line 879 "grammar.y"
+#line 906 "grammar.y"
     {
         CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_STRING, "contains");
         CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_STRING, "contains");
@@ -2549,7 +2576,7 @@ yyreduce:
     break;
 
   case 53:
-#line 893 "grammar.y"
+#line 920 "grammar.y"
     {
         int result = yr_parser_reduce_string_identifier(
             yyscanner,
@@ -2566,7 +2593,7 @@ yyreduce:
     break;
 
   case 54:
-#line 907 "grammar.y"
+#line 934 "grammar.y"
     {
         CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, "at");
 
@@ -2585,7 +2612,7 @@ yyreduce:
     break;
 
   case 55:
-#line 923 "grammar.y"
+#line 950 "grammar.y"
     {
         compiler->last_result = yr_parser_reduce_string_identifier(
             yyscanner,
@@ -2602,7 +2629,7 @@ yyreduce:
     break;
 
   case 56:
-#line 937 "grammar.y"
+#line 964 "grammar.y"
     {
         int var_index;
 
@@ -2640,7 +2667,7 @@ yyreduce:
     break;
 
   case 57:
-#line 972 "grammar.y"
+#line 999 "grammar.y"
     {
         int mem_offset = LOOP_LOCAL_VARS * compiler->loop_depth;
         int8_t* addr;
@@ -2678,7 +2705,7 @@ yyreduce:
     break;
 
   case 58:
-#line 1007 "grammar.y"
+#line 1034 "grammar.y"
     {
         int mem_offset;
 
@@ -2757,7 +2784,7 @@ yyreduce:
     break;
 
   case 59:
-#line 1083 "grammar.y"
+#line 1110 "grammar.y"
     {
         int mem_offset = LOOP_LOCAL_VARS * compiler->loop_depth;
         int8_t* addr;
@@ -2790,7 +2817,7 @@ yyreduce:
     break;
 
   case 60:
-#line 1113 "grammar.y"
+#line 1140 "grammar.y"
     {
         int mem_offset;
 
@@ -2840,7 +2867,7 @@ yyreduce:
     break;
 
   case 61:
-#line 1160 "grammar.y"
+#line 1187 "grammar.y"
     {
         yr_parser_emit(yyscanner, OP_OF, NULL);
 
@@ -2849,7 +2876,7 @@ yyreduce:
     break;
 
   case 62:
-#line 1166 "grammar.y"
+#line 1193 "grammar.y"
     {
         yr_parser_emit(yyscanner, OP_NOT, NULL);
 
@@ -2858,7 +2885,7 @@ yyreduce:
     break;
 
   case 63:
-#line 1172 "grammar.y"
+#line 1199 "grammar.y"
     {
         yr_parser_emit(yyscanner, OP_AND, NULL);
 
@@ -2867,7 +2894,7 @@ yyreduce:
     break;
 
   case 64:
-#line 1178 "grammar.y"
+#line 1205 "grammar.y"
     {
         CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_BOOLEAN, "or");
 
@@ -2878,7 +2905,7 @@ yyreduce:
     break;
 
   case 65:
-#line 1186 "grammar.y"
+#line 1213 "grammar.y"
     {
         CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_INTEGER, "<");
         CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, "<");
@@ -2890,7 +2917,7 @@ yyreduce:
     break;
 
   case 66:
-#line 1195 "grammar.y"
+#line 1222 "grammar.y"
     {
         CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_INTEGER, ">");
         CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, ">");
@@ -2902,7 +2929,7 @@ yyreduce:
     break;
 
   case 67:
-#line 1204 "grammar.y"
+#line 1231 "grammar.y"
     {
         CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_INTEGER, "<=");
         CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, "<=");
@@ -2914,7 +2941,7 @@ yyreduce:
     break;
 
   case 68:
-#line 1213 "grammar.y"
+#line 1240 "grammar.y"
     {
         CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_INTEGER, ">=");
         CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, ">=");
@@ -2926,7 +2953,7 @@ yyreduce:
     break;
 
   case 69:
-#line 1222 "grammar.y"
+#line 1249 "grammar.y"
     {
         if ((yyvsp[(1) - (3)].expression).type != (yyvsp[(3) - (3)].expression).type)
         {
@@ -2956,7 +2983,7 @@ yyreduce:
     break;
 
   case 70:
-#line 1249 "grammar.y"
+#line 1276 "grammar.y"
     {
         if ((yyvsp[(1) - (3)].expression).type != (yyvsp[(3) - (3)].expression).type)
         {
@@ -2986,7 +3013,7 @@ yyreduce:
     break;
 
   case 71:
-#line 1276 "grammar.y"
+#line 1303 "grammar.y"
     {
         if ((yyvsp[(1) - (3)].expression).type != (yyvsp[(3) - (3)].expression).type)
         {
@@ -3016,31 +3043,31 @@ yyreduce:
     break;
 
   case 72:
-#line 1303 "grammar.y"
+#line 1330 "grammar.y"
     {
         (yyval.expression) = (yyvsp[(1) - (1)].expression);
       }
     break;
 
   case 73:
-#line 1307 "grammar.y"
+#line 1334 "grammar.y"
     {
         (yyval.expression) = (yyvsp[(2) - (3)].expression);
       }
     break;
 
   case 74:
-#line 1314 "grammar.y"
+#line 1341 "grammar.y"
     { (yyval.integer) = INTEGER_SET_ENUMERATION; }
     break;
 
   case 75:
-#line 1315 "grammar.y"
+#line 1342 "grammar.y"
     { (yyval.integer) = INTEGER_SET_RANGE; }
     break;
 
   case 76:
-#line 1321 "grammar.y"
+#line 1348 "grammar.y"
     {
         if ((yyvsp[(2) - (6)].expression).type != EXPRESSION_TYPE_INTEGER)
         {
@@ -3061,7 +3088,7 @@ yyreduce:
     break;
 
   case 77:
-#line 1343 "grammar.y"
+#line 1370 "grammar.y"
     {
         if ((yyvsp[(1) - (1)].expression).type != EXPRESSION_TYPE_INTEGER)
         {
@@ -3076,7 +3103,7 @@ yyreduce:
     break;
 
   case 78:
-#line 1355 "grammar.y"
+#line 1382 "grammar.y"
     {
         if ((yyvsp[(3) - (3)].expression).type != EXPRESSION_TYPE_INTEGER)
         {
@@ -3090,7 +3117,7 @@ yyreduce:
     break;
 
   case 79:
-#line 1370 "grammar.y"
+#line 1397 "grammar.y"
     {
         // Push end-of-list marker
         yr_parser_emit_with_arg(yyscanner, OP_PUSH, UNDEFINED, NULL);
@@ -3098,7 +3125,7 @@ yyreduce:
     break;
 
   case 81:
-#line 1376 "grammar.y"
+#line 1403 "grammar.y"
     {
         yr_parser_emit_with_arg(yyscanner, OP_PUSH, UNDEFINED, NULL);
         yr_parser_emit_pushes_for_strings(yyscanner, "$*");
@@ -3106,7 +3133,7 @@ yyreduce:
     break;
 
   case 84:
-#line 1391 "grammar.y"
+#line 1418 "grammar.y"
     {
         yr_parser_emit_pushes_for_strings(yyscanner, (yyvsp[(1) - (1)].c_string));
         yr_free((yyvsp[(1) - (1)].c_string));
@@ -3114,7 +3141,7 @@ yyreduce:
     break;
 
   case 85:
-#line 1396 "grammar.y"
+#line 1423 "grammar.y"
     {
         yr_parser_emit_pushes_for_strings(yyscanner, (yyvsp[(1) - (1)].c_string));
         yr_free((yyvsp[(1) - (1)].c_string));
@@ -3122,28 +3149,28 @@ yyreduce:
     break;
 
   case 87:
-#line 1406 "grammar.y"
+#line 1433 "grammar.y"
     {
         yr_parser_emit_with_arg(yyscanner, OP_PUSH, UNDEFINED, NULL);
       }
     break;
 
   case 88:
-#line 1410 "grammar.y"
+#line 1437 "grammar.y"
     {
         yr_parser_emit_with_arg(yyscanner, OP_PUSH, 1, NULL);
       }
     break;
 
   case 89:
-#line 1418 "grammar.y"
+#line 1445 "grammar.y"
     {
         (yyval.expression) = (yyvsp[(2) - (3)].expression);
       }
     break;
 
   case 90:
-#line 1422 "grammar.y"
+#line 1449 "grammar.y"
     {
         compiler->last_result = yr_parser_emit(
             yyscanner, OP_FILESIZE, NULL);
@@ -3156,7 +3183,7 @@ yyreduce:
     break;
 
   case 91:
-#line 1432 "grammar.y"
+#line 1459 "grammar.y"
     {
         yywarning(yyscanner,
             "Using deprecated \"entrypoint\" keyword. Use the \"entry_point\" " "function from PE module instead.");
@@ -3172,7 +3199,7 @@ yyreduce:
     break;
 
   case 92:
-#line 1445 "grammar.y"
+#line 1472 "grammar.y"
     {
         CHECK_TYPE((yyvsp[(3) - (4)].expression), EXPRESSION_TYPE_INTEGER, "int8");
 
@@ -3187,7 +3214,7 @@ yyreduce:
     break;
 
   case 93:
-#line 1457 "grammar.y"
+#line 1484 "grammar.y"
     {
         CHECK_TYPE((yyvsp[(3) - (4)].expression), EXPRESSION_TYPE_INTEGER, "int16");
 
@@ -3202,7 +3229,7 @@ yyreduce:
     break;
 
   case 94:
-#line 1469 "grammar.y"
+#line 1496 "grammar.y"
     {
         CHECK_TYPE((yyvsp[(3) - (4)].expression), EXPRESSION_TYPE_INTEGER, "int32");
 
@@ -3217,7 +3244,7 @@ yyreduce:
     break;
 
   case 95:
-#line 1481 "grammar.y"
+#line 1508 "grammar.y"
     {
         CHECK_TYPE((yyvsp[(3) - (4)].expression), EXPRESSION_TYPE_INTEGER, "uint8");
 
@@ -3232,7 +3259,7 @@ yyreduce:
     break;
 
   case 96:
-#line 1493 "grammar.y"
+#line 1520 "grammar.y"
     {
         CHECK_TYPE((yyvsp[(3) - (4)].expression), EXPRESSION_TYPE_INTEGER, "uint16");
 
@@ -3247,7 +3274,7 @@ yyreduce:
     break;
 
   case 97:
-#line 1505 "grammar.y"
+#line 1532 "grammar.y"
     {
         CHECK_TYPE((yyvsp[(3) - (4)].expression), EXPRESSION_TYPE_INTEGER, "uint32");
 
@@ -3262,7 +3289,7 @@ yyreduce:
     break;
 
   case 98:
-#line 1517 "grammar.y"
+#line 1544 "grammar.y"
     {
         compiler->last_result = yr_parser_emit_with_arg(
             yyscanner, OP_PUSH, (yyvsp[(1) - (1)].integer), NULL);
@@ -3275,7 +3302,7 @@ yyreduce:
     break;
 
   case 99:
-#line 1527 "grammar.y"
+#line 1554 "grammar.y"
     {
         SIZED_STRING* sized_string = (yyvsp[(1) - (1)].sized_string);
         char* string;
@@ -3301,7 +3328,7 @@ yyreduce:
     break;
 
   case 100:
-#line 1550 "grammar.y"
+#line 1577 "grammar.y"
     {
         compiler->last_result = yr_parser_reduce_string_identifier(
             yyscanner,
@@ -3319,7 +3346,7 @@ yyreduce:
     break;
 
   case 101:
-#line 1565 "grammar.y"
+#line 1592 "grammar.y"
     {
         compiler->last_result = yr_parser_reduce_string_identifier(
             yyscanner,
@@ -3337,7 +3364,7 @@ yyreduce:
     break;
 
   case 102:
-#line 1580 "grammar.y"
+#line 1607 "grammar.y"
     {
         compiler->last_result = yr_parser_emit_with_arg(
             yyscanner,
@@ -3362,7 +3389,7 @@ yyreduce:
     break;
 
   case 103:
-#line 1602 "grammar.y"
+#line 1629 "grammar.y"
     {
         if ((yyvsp[(1) - (1)].object) == (YR_OBJECT*) -1)  // loop identifier
         {
@@ -3402,7 +3429,7 @@ yyreduce:
     break;
 
   case 104:
-#line 1639 "grammar.y"
+#line 1666 "grammar.y"
     {
         CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_INTEGER, "+");
         CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, "+");
@@ -3415,7 +3442,7 @@ yyreduce:
     break;
 
   case 105:
-#line 1649 "grammar.y"
+#line 1676 "grammar.y"
     {
         CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_INTEGER, "-");
         CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, "-");
@@ -3428,7 +3455,7 @@ yyreduce:
     break;
 
   case 106:
-#line 1659 "grammar.y"
+#line 1686 "grammar.y"
     {
         CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_INTEGER, "*");
         CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, "*");
@@ -3441,7 +3468,7 @@ yyreduce:
     break;
 
   case 107:
-#line 1669 "grammar.y"
+#line 1696 "grammar.y"
     {
         CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_INTEGER, "\\");
         CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, "\\");
@@ -3454,7 +3481,7 @@ yyreduce:
     break;
 
   case 108:
-#line 1679 "grammar.y"
+#line 1706 "grammar.y"
     {
         CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_INTEGER, "%");
         CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, "%");
@@ -3467,7 +3494,7 @@ yyreduce:
     break;
 
   case 109:
-#line 1689 "grammar.y"
+#line 1716 "grammar.y"
     {
         CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_INTEGER, "^");
         CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, "^");
@@ -3480,7 +3507,7 @@ yyreduce:
     break;
 
   case 110:
-#line 1699 "grammar.y"
+#line 1726 "grammar.y"
     {
         CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_INTEGER, "^");
         CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, "^");
@@ -3493,7 +3520,7 @@ yyreduce:
     break;
 
   case 111:
-#line 1709 "grammar.y"
+#line 1736 "grammar.y"
     {
         CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_INTEGER, "|");
         CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, "|");
@@ -3506,7 +3533,7 @@ yyreduce:
     break;
 
   case 112:
-#line 1719 "grammar.y"
+#line 1746 "grammar.y"
     {
         CHECK_TYPE((yyvsp[(2) - (2)].expression), EXPRESSION_TYPE_INTEGER, "~");
 
@@ -3519,7 +3546,7 @@ yyreduce:
     break;
 
   case 113:
-#line 1729 "grammar.y"
+#line 1756 "grammar.y"
     {
         CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_INTEGER, "<<");
         CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, "<<");
@@ -3532,7 +3559,7 @@ yyreduce:
     break;
 
   case 114:
-#line 1739 "grammar.y"
+#line 1766 "grammar.y"
     {
         CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_INTEGER, ">>");
         CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, ">>");
@@ -3545,7 +3572,7 @@ yyreduce:
     break;
 
   case 115:
-#line 1749 "grammar.y"
+#line 1776 "grammar.y"
     {
         (yyval.expression) = (yyvsp[(1) - (1)].expression);
       }
@@ -3553,7 +3580,7 @@ yyreduce:
 
 
 /* Line 1267 of yacc.c.  */
-#line 3557 "grammar.c"
+#line 3584 "grammar.c"
       default: break;
     }
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
@@ -3767,6 +3794,6 @@ yyreturn:
 }
 
 
-#line 1754 "grammar.y"
+#line 1781 "grammar.y"
 
 
diff --git a/libyara/grammar.y b/libyara/grammar.y
index b54e279..aabeb41 100644
--- a/libyara/grammar.y
+++ b/libyara/grammar.y
@@ -663,12 +663,39 @@ identifier
       {
         if ($1 != NULL && $1->type == OBJECT_TYPE_ARRAY)
         {
+          if ($3.type != EXPRESSION_TYPE_INTEGER)
+          {
+            yr_compiler_set_error_extra_info(
+                compiler, "array indexes must be of integer type");
+            compiler->last_result = ERROR_WRONG_TYPE;
+          }
+
+          ERROR_IF(compiler->last_result != ERROR_SUCCESS);
+
           compiler->last_result = yr_parser_emit(
               yyscanner,
               OP_INDEX_ARRAY,
               NULL);
 
-          $$ = ((YR_OBJECT_ARRAY*) $1)->items->objects[0];
+          $$ = ((YR_OBJECT_ARRAY*) $1)->prototype_item;
+        }
+        else if ($1 != NULL && $1->type == OBJECT_TYPE_DICTIONARY)
+        {
+          if ($3.type != EXPRESSION_TYPE_STRING)
+          {
+            yr_compiler_set_error_extra_info(
+                compiler, "dictionary keys must be of string type");
+            compiler->last_result = ERROR_WRONG_TYPE;
+          }
+
+          ERROR_IF(compiler->last_result != ERROR_SUCCESS);
+
+          compiler->last_result = yr_parser_emit(
+              yyscanner,
+              OP_LOOKUP_DICT,
+              NULL);
+
+          $$ = ((YR_OBJECT_DICTIONARY*) $1)->prototype_item;
         }
         else
         {
@@ -676,7 +703,7 @@ identifier
               compiler,
               $1->identifier);
 
-          compiler->last_result = ERROR_NOT_AN_ARRAY;
+          compiler->last_result = ERROR_NOT_INDEXABLE;
         }
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
diff --git a/libyara/include/yara/error.h b/libyara/include/yara/error.h
index c3f08a9..c1615e8 100644
--- a/libyara/include/yara/error.h
+++ b/libyara/include/yara/error.h
@@ -57,7 +57,7 @@ limitations under the License.
 #define ERROR_INVALID_FIELD_NAME                33
 #define ERROR_UNKNOWN_MODULE                    34
 #define ERROR_NOT_A_STRUCTURE                   35
-#define ERROR_NOT_AN_ARRAY                      36
+#define ERROR_NOT_INDEXABLE                     36
 #define ERROR_NOT_A_FUNCTION                    37
 #define ERROR_INVALID_FORMAT                    38
 #define ERROR_TOO_MANY_ARGUMENTS                39
diff --git a/libyara/include/yara/exec.h b/libyara/include/yara/exec.h
index 97b3012..5254425 100644
--- a/libyara/include/yara/exec.h
+++ b/libyara/include/yara/exec.h
@@ -83,6 +83,7 @@ limitations under the License.
 #define OP_CONTAINS       53
 #define OP_MATCHES        54
 #define OP_IMPORT         55
+#define OP_LOOKUP_DICT    56
 
 
 #define OPERATION(operator, op1, op2) \
diff --git a/libyara/include/yara/modules.h b/libyara/include/yara/modules.h
index 6b92364..fde28e0 100644
--- a/libyara/include/yara/modules.h
+++ b/libyara/include/yara/modules.h
@@ -122,6 +122,21 @@ limitations under the License.
   }
 
 
+#define declare_integer_dictionary(name) { \
+    YR_OBJECT* dict; \
+    FAIL_ON_ERROR(yr_object_create( \
+        OBJECT_TYPE_DICTIONARY, \
+        name, \
+        stack[stack_top], \
+        &dict)); \
+    FAIL_ON_ERROR(yr_object_create( \
+        OBJECT_TYPE_INTEGER, \
+        name, \
+        dict, \
+        NULL)); \
+  }
+
+
 #define declare_string(name) { \
     FAIL_ON_ERROR(yr_object_create( \
         OBJECT_TYPE_STRING, \
@@ -146,6 +161,21 @@ limitations under the License.
   }
 
 
+#define declare_string_dictionary(name) { \
+    YR_OBJECT* dict; \
+    FAIL_ON_ERROR(yr_object_create( \
+        OBJECT_TYPE_DICTIONARY, \
+        name, \
+        stack[stack_top], \
+        &dict)); \
+    FAIL_ON_ERROR(yr_object_create( \
+        OBJECT_TYPE_STRING, \
+        name, \
+        dict, \
+        NULL)); \
+  }
+
+
 #define declare_function(name, args_fmt, ret_fmt, func) { \
     YR_OBJECT* function; \
     FAIL_ON_ERROR(yr_object_function_create( \
diff --git a/libyara/include/yara/object.h b/libyara/include/yara/object.h
index bd09dd4..508babf 100644
--- a/libyara/include/yara/object.h
+++ b/libyara/include/yara/object.h
@@ -28,6 +28,7 @@ limitations under the License.
 #define OBJECT_TYPE_ARRAY       4
 #define OBJECT_TYPE_FUNCTION    5
 #define OBJECT_TYPE_REGEXP      6
+#define OBJECT_TYPE_DICTIONARY  7
 
 
 int yr_object_create(
@@ -105,6 +106,18 @@ int yr_object_array_set_item(
     int index);
 
 
+YR_OBJECT* yr_object_dict_get_item(
+    YR_OBJECT* object,
+    int flags,
+    const char* key);
+
+
+int yr_object_dict_set_item(
+    YR_OBJECT* object,
+    YR_OBJECT* item,
+    const char* key);
+
+
 int yr_object_structure_set_member(
     YR_OBJECT* object,
     YR_OBJECT* member);
diff --git a/libyara/include/yara/types.h b/libyara/include/yara/types.h
index 32c8186..ff25080 100644
--- a/libyara/include/yara/types.h
+++ b/libyara/include/yara/types.h
@@ -434,11 +434,21 @@ typedef struct _YR_OBJECT_STRUCTURE
 typedef struct _YR_OBJECT_ARRAY
 {
   OBJECT_COMMON_FIELDS
+  YR_OBJECT* prototype_item;
   struct _YR_ARRAY_ITEMS* items;
 
 } YR_OBJECT_ARRAY;
 
 
+typedef struct _YR_OBJECT_DICTIONARY
+{
+  OBJECT_COMMON_FIELDS
+  YR_OBJECT* prototype_item;
+  struct _YR_DICTIONARY_ITEMS* items;
+
+} YR_OBJECT_DICTIONARY;
+
+
 struct _YR_OBJECT_FUNCTION;
 
 
@@ -476,4 +486,19 @@ typedef struct _YR_ARRAY_ITEMS
 } YR_ARRAY_ITEMS;
 
 
+typedef struct _YR_DICTIONARY_ITEMS
+{
+  int used;
+  int free;
+
+  struct {
+
+    char* key;
+    YR_OBJECT* obj;
+
+  } objects[1];
+
+} YR_DICTIONARY_ITEMS;
+
+
 #endif
diff --git a/libyara/modules/tests.c b/libyara/modules/tests.c
index 4f4c9a9..d839a5f 100644
--- a/libyara/modules/tests.c
+++ b/libyara/modules/tests.c
@@ -41,6 +41,9 @@ begin_declarations;
   declare_integer_array("integer_array");
   declare_string_array("string_array");
 
+  declare_integer_dictionary("integer_dict");
+  declare_string_dictionary("string_dict");
+
   begin_struct_array("struct_array");
     declare_integer("i");
     declare_string("s");
@@ -84,6 +87,9 @@ int module_load(
   set_string("bar", module_object, "string_array[%i]", 1);
   set_string("baz", module_object, "string_array[%i]", 2);
 
+  set_string("foo", module_object, "string_dict[%s]", "foo");
+  set_string("bar", module_object, "string_dict[\"bar\"]");
+
   return ERROR_SUCCESS;
 }
 
diff --git a/libyara/object.c b/libyara/object.c
index 5347c91..877330d 100644
--- a/libyara/object.c
+++ b/libyara/object.c
@@ -46,6 +46,9 @@ int yr_object_create(
     case OBJECT_TYPE_ARRAY:
       object_size = sizeof(YR_OBJECT_ARRAY);
       break;
+    case OBJECT_TYPE_DICTIONARY:
+      object_size = sizeof(YR_OBJECT_DICTIONARY);
+      break;
     case OBJECT_TYPE_INTEGER:
       object_size = sizeof(YR_OBJECT_INTEGER);
       break;
@@ -85,6 +88,11 @@ int yr_object_create(
       break;
     case OBJECT_TYPE_ARRAY:
       ((YR_OBJECT_ARRAY*) obj)->items = NULL;
+      ((YR_OBJECT_ARRAY*) obj)->prototype_item = NULL;
+      break;
+    case OBJECT_TYPE_DICTIONARY:
+      ((YR_OBJECT_DICTIONARY*) obj)->items = NULL;
+      ((YR_OBJECT_ARRAY*) obj)->prototype_item = NULL;
       break;
     case OBJECT_TYPE_INTEGER:
       ((YR_OBJECT_INTEGER*) obj)->value = UNDEFINED;
@@ -103,9 +111,10 @@ int yr_object_create(
 
   if (parent != NULL)
   {
-    assert( parent->type == OBJECT_TYPE_STRUCTURE ||
-            parent->type == OBJECT_TYPE_ARRAY ||
-            parent->type == OBJECT_TYPE_FUNCTION);
+    assert(parent->type == OBJECT_TYPE_STRUCTURE ||
+           parent->type == OBJECT_TYPE_ARRAY ||
+           parent->type == OBJECT_TYPE_DICTIONARY ||
+           parent->type == OBJECT_TYPE_FUNCTION);
 
     switch(parent->type)
     {
@@ -116,9 +125,11 @@ int yr_object_create(
         break;
 
       case OBJECT_TYPE_ARRAY:
-        FAIL_ON_ERROR_WITH_CLEANUP(
-            yr_object_array_set_item(parent, obj, 0),
-            yr_free(obj));
+        ((YR_OBJECT_ARRAY*) parent)->prototype_item = obj;
+        break;
+
+      case OBJECT_TYPE_DICTIONARY:
+        ((YR_OBJECT_DICTIONARY*) parent)->prototype_item = obj;
         break;
     }
   }
@@ -234,6 +245,7 @@ void yr_object_destroy(
   YR_STRUCTURE_MEMBER* member;
   YR_STRUCTURE_MEMBER* next_member;
   YR_ARRAY_ITEMS* array_items;
+  YR_DICTIONARY_ITEMS* dict_items;
 
   RE* re;
   int i;
@@ -266,15 +278,42 @@ void yr_object_destroy(
       break;
 
     case OBJECT_TYPE_ARRAY:
+      if (((YR_OBJECT_ARRAY*) object)->prototype_item != NULL)
+        yr_free(((YR_OBJECT_ARRAY*) object)->prototype_item);
+
       array_items = ((YR_OBJECT_ARRAY*) object)->items;
 
-      for (i = 0; i < array_items->count; i++)
-        if (array_items->objects[i] != NULL)
-          yr_object_destroy(array_items->objects[i]);
+      if (array_items != NULL)
+      {
+        for (i = 0; i < array_items->count; i++)
+          if (array_items->objects[i] != NULL)
+            yr_object_destroy(array_items->objects[i]);
+      }
 
       yr_free(array_items);
       break;
 
+    case OBJECT_TYPE_DICTIONARY:
+      if (((YR_OBJECT_DICTIONARY*) object)->prototype_item != NULL)
+        yr_free(((YR_OBJECT_DICTIONARY*) object)->prototype_item);
+
+      dict_items = ((YR_OBJECT_DICTIONARY*) object)->items;
+
+      if (dict_items != NULL)
+      {
+        for (i = 0; i < dict_items->used; i++)
+        {
+          if (dict_items->objects[i].key != NULL)
+            yr_free(dict_items->objects[i].key);
+
+          if (dict_items->objects[i].obj != NULL)
+            yr_object_destroy(dict_items->objects[i].obj);
+        }
+      }
+
+      yr_free(dict_items);
+      break;
+
     case OBJECT_TYPE_FUNCTION:
       yr_object_destroy(((YR_OBJECT_FUNCTION*) object)->return_obj);
       break;
@@ -317,7 +356,9 @@ YR_OBJECT* _yr_object_lookup(
   YR_OBJECT* obj = object;
 
   const char* p = pattern;
-  char field_name[256];
+  const char* key;
+
+  char str[256];
 
   int i;
   int index;
@@ -326,17 +367,17 @@ YR_OBJECT* _yr_object_lookup(
   {
     i = 0;
 
-    while(*p != '\0' && *p != '.' && *p != '[')
+    while(*p != '\0' && *p != '.' && *p != '[' && i < sizeof(str))
     {
-      field_name[i++] = *p++;
+      str[i++] = *p++;
     }
 
-    field_name[i] = '\0';
+    str[i] = '\0';
 
     if (obj->type != OBJECT_TYPE_STRUCTURE)
       return NULL;
 
-    obj = yr_object_lookup_field(obj, field_name);
+    obj = yr_object_lookup_field(obj, str);
 
     if (obj == NULL)
       return NULL;
@@ -347,20 +388,37 @@ YR_OBJECT* _yr_object_lookup(
 
       if (*p == '%')
       {
-        if (*++p == 'i')
-        {
-          index = va_arg(args, int);
-          p++;
-        }
-        else
+        p++;
+
+        switch(*p++)
         {
-          return NULL;
+          case 'i':
+            index = va_arg(args, int);
+            break;
+          case 's':
+            key = va_arg(args, const char*);
+            break;
+
+          default:
+            return NULL;
         }
       }
       else if (*p >= '0' && *p <= '9')
       {
         index = strtol(p, (char**) &p, 10);
       }
+      else if (*p == '"')
+      {
+        i = 0;
+        p++;              // skip the opening quotation mark
+
+        while (*p != '"' && *p != '\0' && i < sizeof(str))
+          str[i++] = *p++;
+
+        str[i] = '\0';
+        p++;              // skip the closing quotation mark
+        key = str;
+      }
       else
       {
         return NULL;
@@ -369,7 +427,16 @@ YR_OBJECT* _yr_object_lookup(
       assert(*p++ == ']');
       assert(*p == '.' || *p == '\0');
 
-      obj = yr_object_array_get_item(obj, flags, index);
+      switch(obj->type)
+      {
+        case OBJECT_TYPE_ARRAY:
+          obj = yr_object_array_get_item(obj, flags, index);
+          break;
+
+        case OBJECT_TYPE_DICTIONARY:
+          obj = yr_object_dict_get_item(obj, flags, key);
+          break;
+      }
     }
 
     if (*p == '\0')
@@ -518,20 +585,18 @@ YR_OBJECT* yr_object_array_get_item(
     int index)
 {
   YR_OBJECT* result = NULL;
-  YR_ARRAY_ITEMS* array_items;
+  YR_OBJECT_ARRAY* array;
 
   assert(object->type == OBJECT_TYPE_ARRAY);
 
-  array_items = ((YR_OBJECT_ARRAY*) object)->items;
+  array = (YR_OBJECT_ARRAY*) object;
 
-  assert(array_items != NULL);
-
-  if (array_items->count > index)
-    result = array_items->objects[index];
+  if (array->items != NULL && array->items->count > index)
+      result = array->items->objects[index];
 
   if (result == NULL && flags & OBJECT_CREATE)
   {
-    yr_object_copy(array_items->objects[0], &result);
+    yr_object_copy(array->prototype_item, &result);
 
     if (result != NULL)
       yr_object_array_set_item(object, result, index);
@@ -592,6 +657,98 @@ int yr_object_array_set_item(
 }
 
 
+YR_OBJECT* yr_object_dict_get_item(
+    YR_OBJECT* object,
+    int flags,
+    const char* key)
+{
+  YR_OBJECT* result = NULL;
+  YR_OBJECT_DICTIONARY* dict;
+
+  assert(object->type == OBJECT_TYPE_DICTIONARY);
+
+  dict = (YR_OBJECT_DICTIONARY*) object;
+
+  if (dict->items != NULL)
+  {
+    for (int i = 0; i < dict->items->used; i++)
+    {
+      if (strcmp(dict->items->objects[i].key, key) == 0)
+        result = dict->items->objects[i].obj;
+    }
+  }
+
+  if (result == NULL && flags & OBJECT_CREATE)
+  {
+    yr_object_copy(dict->prototype_item, &result);
+
+    if (result != NULL)
+      yr_object_dict_set_item(object, result, key);
+  }
+
+  return result;
+}
+
+
+int yr_object_dict_set_item(
+    YR_OBJECT* object,
+    YR_OBJECT* item,
+    const char* key)
+{
+  YR_OBJECT_DICTIONARY* dict;
+
+  int i;
+  int count;
+
+  assert(object->type == OBJECT_TYPE_DICTIONARY);
+
+  dict = ((YR_OBJECT_DICTIONARY*) object);
+
+  if (dict->items == NULL)
+  {
+    count = 64;
+
+    dict->items = yr_malloc(
+        sizeof(YR_DICTIONARY_ITEMS) + count * sizeof(dict->items->objects[0]));
+
+    if (dict->items == NULL)
+      return ERROR_INSUFICIENT_MEMORY;
+
+    memset(dict->items->objects, 0, count * sizeof(dict->items->objects[0]));
+
+    dict->items->free = count;
+    dict->items->used = 0;
+  }
+  else if (dict->items->free == 0)
+  {
+    count = dict->items->used * 2;
+    dict->items = yr_realloc(
+        dict->items,
+        sizeof(YR_DICTIONARY_ITEMS) + count * sizeof(dict->items->objects[0]));
+
+    if (dict->items == NULL)
+      return ERROR_INSUFICIENT_MEMORY;
+
+    for (i = dict->items->used; i < count; i++)
+    {
+      dict->items->objects[i].key = NULL;
+      dict->items->objects[i].obj = NULL;
+    }
+
+    dict->items->free = dict->items->used;
+  }
+
+  item->parent = object;
+
+  dict->items->objects[dict->items->used].key = yr_strdup(key);
+  dict->items->objects[dict->items->used].obj = item;
+
+  dict->items->used++;
+
+  return ERROR_SUCCESS;
+}
+
+
 int64_t yr_object_get_integer(
     YR_OBJECT* object,
     char* field,
diff --git a/yara-python/tests.py b/yara-python/tests.py
index 648a7d3..33de8f1 100644
--- a/yara-python/tests.py
+++ b/yara-python/tests.py
@@ -707,6 +707,8 @@ class TestYara(unittest.TestCase):
             'import "tests" rule test { condition: tests.integer_array[1] == 1}',
             'import "tests" rule test { condition: tests.string_array[0] == "foo"}',
             'import "tests" rule test { condition: tests.string_array[2] == "baz"}',
+            'import "tests" rule test { condition: tests.string_dict["foo"] == "foo"}',
+            'import "tests" rule test { condition: tests.string_dict["bar"] == "bar"}',
             'import "tests" rule test { condition: tests.sum(1,1) == 2}',
           ])
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/forensics/yara.git



More information about the forensics-changes mailing list