Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 86edc1f

Browse files
authored
Add stringtoint() and inttostring(). (#1767)
* Add stringtoint() and inttostring(). Add math.stringtoint() and math.inttostring() which let you convert between an integer and a string representation of it, and back. * Rename functions and use a stack allocation and snprintf() * Use errno.h, not sys/errno.h
1 parent 181783b commit 86edc1f

3 files changed

Lines changed: 234 additions & 1 deletion

File tree

docs/modules/math.rst

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,54 @@ file and create signatures based on those results.
157157
.. c:function:: mode(offset, size)
158158
159159
.. versionadded:: 4.2.0
160-
160+
161161
Returns the most common byte, starting at *offset* and looking at the next
162162
*size* bytes. When scanning a
163163
running process the *offset* argument should be a virtual address within
164164
the process address space. The returned value is a float.
165165
*offset* and *size* are optional; if left empty, the complete file is searched.
166166

167167
*Example: math.mode(0, filesize) == 0xFF*
168+
169+
.. c:function:: to_string(int)
170+
171+
.. versionadded:: 4.3.0
172+
173+
Convert the given integer to a string. Note: integers in YARA are signed.
174+
175+
*Example: math.to_string(10) == "10"*
176+
*Example: math.to_string(-1) == "-1"*
177+
178+
.. c:function:: to_string(int, base)
179+
180+
.. versionadded:: 4.3.0
181+
182+
Convert the given integer to a string in the given base. Supported bases are
183+
10, 8 and 16. Note: integers in YARA are signed.
184+
185+
*Example: math.to_string(32, 16) == "20"*
186+
*Example: math.to_string(-1, 16) == "ffffffffffffffff"*
187+
188+
.. c:function:: to_int(string)
189+
190+
.. versionadded:: 4.3.0
191+
192+
Convert the given string to a signed integer. If the string starts with "0x"
193+
it is treated as base 16. If the string starts with "0" it is treated base
194+
8. Leading '+' or '-' is also supported.
195+
196+
*Example: math.to_int("1234") == 1234*
197+
*Example: math.to_int("-10") == -10*
198+
*Example: math.to_int("-010" == -8*
199+
200+
.. c:function:: to_int(string, base)
201+
202+
.. versionadded:: 4.3.0
203+
204+
Convert the given string, interpreted with the given base, to a signed
205+
integer. Base must be 0 or between 2 and 32 inclusive. If it is zero then
206+
the string will be intrepreted as base 16 if it starts with "0x" or as base
207+
8 if it starts with "0". Leading '+' or '-' is also supported.
208+
209+
*Example: math.to_int("011", 8) == "9"*
210+
*Example: math.to_int("-011", 0) == "-9"*

libyara/modules/math/math.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2727
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2828
*/
2929

30+
#include <stdlib.h>
31+
#include <errno.h>
3032
#include <math.h>
3133
#include <yara/mem.h>
3234
#include <yara/modules.h>
@@ -35,6 +37,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3537
#define MODULE_NAME math
3638

3739
#define PI 3.141592653589793
40+
// This is more than enough space to hold the maximum signed 64bit integer as a
41+
// string in decimal, hex or octal, including the sign and NULL terminator.
42+
#define INT64_MAX_STRING 30
3843

3944
// log2 is not defined by math.h in VC++
4045

@@ -721,6 +726,53 @@ define_function(mode_global)
721726
return_integer(most_common);
722727
}
723728

729+
define_function(to_string)
730+
{
731+
int64_t i = integer_argument(1);
732+
char str[INT64_MAX_STRING];
733+
snprintf(str, INT64_MAX_STRING, "%lld", i);
734+
return_string(&str);
735+
}
736+
737+
define_function(to_string_base)
738+
{
739+
int64_t i = integer_argument(1);
740+
int64_t base = integer_argument(2);
741+
char str[INT64_MAX_STRING];
742+
char *fmt;
743+
switch (base)
744+
{
745+
case 10:
746+
fmt = "%lld";
747+
break;
748+
case 8:
749+
fmt = "%llo";
750+
break;
751+
case 16:
752+
fmt = "%llx";
753+
break;
754+
default:
755+
return_string(YR_UNDEFINED);
756+
}
757+
snprintf(str, INT64_MAX_STRING, fmt, i);
758+
return_string(&str);
759+
}
760+
761+
define_function(to_int)
762+
{
763+
char* s = string_argument(1);
764+
int64_t result = strtoll(s, NULL, 0);
765+
return_integer(result == 0 && errno ? YR_UNDEFINED : result);
766+
}
767+
768+
define_function(to_int_base)
769+
{
770+
char* s = string_argument(1);
771+
int64_t base = integer_argument(2);
772+
int64_t result = strtoll(s, NULL, base);
773+
return_integer(result == 0 && errno ? YR_UNDEFINED : result);
774+
}
775+
724776
begin_declarations
725777
declare_float("MEAN_BYTES");
726778
declare_function("in_range", "fff", "i", in_range);
@@ -744,6 +796,10 @@ begin_declarations
744796
declare_function("percentage", "i", "f", percentage_global);
745797
declare_function("mode", "ii", "i", mode_range);
746798
declare_function("mode", "", "i", mode_global);
799+
declare_function("to_string", "i", "s", to_string);
800+
declare_function("to_string", "ii", "s", to_string_base);
801+
declare_function("to_int", "s", "i", to_int);
802+
declare_function("to_int", "si", "i", to_int_base);
747803
end_declarations
748804

749805
int module_initialize(YR_MODULE* module)

tests/test-math.c

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,140 @@ int main(int argc, char** argv)
223223
}",
224224
"123ABCDEF123456987DE");
225225

226+
assert_true_rule(
227+
"import \"math\" \
228+
rule test { \
229+
condition: \
230+
math.to_string(1234) == \"1234\" \
231+
}",
232+
NULL);
233+
234+
// We use signed integers by default if no base is specified.
235+
assert_true_rule(
236+
"import \"math\" \
237+
rule test { \
238+
condition: \
239+
math.to_string(-1) == \"-1\" \
240+
}",
241+
NULL);
242+
243+
assert_true_rule(
244+
"import \"math\" \
245+
rule test { \
246+
condition: \
247+
math.to_string(32, 16) == \"20\" \
248+
}",
249+
NULL);
250+
251+
assert_true_rule(
252+
"import \"math\" \
253+
rule test { \
254+
condition: \
255+
math.to_string(32, 8) == \"40\" \
256+
}",
257+
NULL);
258+
259+
assert_true_rule(
260+
"import \"math\" \
261+
rule test { \
262+
condition: \
263+
math.to_string(32, 10) == \"32\" \
264+
}",
265+
NULL);
266+
267+
// Base 10 is always a signed integer, all other bases are unsigned.
268+
assert_true_rule(
269+
"import \"math\" \
270+
rule test { \
271+
condition: \
272+
math.to_string(-1, 10) == \"-1\" and \
273+
math.to_string(-1, 16) == \"ffffffffffffffff\" and \
274+
math.to_string(-1, 8) == \"1777777777777777777777\" \
275+
}",
276+
NULL);
277+
278+
// Passing a base that is not 10, 8 or 16 will result in UNDEFINED.
279+
assert_true_rule(
280+
"import \"math\" \
281+
rule test { \
282+
condition: \
283+
not defined(math.to_string(32, 9)) \
284+
}",
285+
NULL);
286+
287+
assert_true_rule(
288+
"import \"math\" \
289+
rule test { \
290+
condition: \
291+
math.to_int(\"1234\") == 1234 \
292+
}",
293+
NULL);
294+
295+
assert_true_rule(
296+
"import \"math\" \
297+
rule test { \
298+
condition: \
299+
math.to_int(\"-1\") == -1 \
300+
}",
301+
NULL);
302+
303+
// Leading spaces and + are allowed.
304+
assert_true_rule(
305+
"import \"math\" \
306+
rule test { \
307+
condition: \
308+
math.to_int(\" +1\") == 1 \
309+
}",
310+
NULL);
311+
312+
// Strings can be prefixed with 0x and will be interpreted as hexadecimal.
313+
assert_true_rule(
314+
"import \"math\" \
315+
rule test { \
316+
condition: \
317+
math.to_int(\"0x10\") == 16 \
318+
}",
319+
NULL);
320+
321+
// Strings prefixed with 0 will be interpreted as octal.
322+
assert_true_rule(
323+
"import \"math\" \
324+
rule test { \
325+
condition: \
326+
math.to_int(\"010\") == 8 \
327+
}",
328+
NULL);
329+
330+
// Strings that are only partially converted are still fine.
331+
assert_true_rule(
332+
"import \"math\" \
333+
rule test { \
334+
condition: \
335+
math.to_int(\"10A20\") == 10 \
336+
}",
337+
NULL);
338+
339+
assert_true_rule(
340+
"import \"math\" \
341+
rule test { \
342+
condition: \
343+
math.to_int(\"10\", 8) == 8 \
344+
}",
345+
NULL);
346+
347+
// Base 0 is a special case that tries to interpret the string by prefix, or
348+
// default to decimal. We aren't doing anything special to get this, it is
349+
// part of strtoll by default.
350+
assert_true_rule(
351+
"import \"math\" \
352+
rule test { \
353+
condition: \
354+
math.to_int(\"010\", 0) == 8 and \
355+
math.to_int(\"0x10\", 0) == 16 and \
356+
math.to_int(\"10\", 0) == 10 \
357+
}",
358+
NULL);
359+
226360
yr_finalize();
227361

228362
YR_DEBUG_FPRINTF(

0 commit comments

Comments
 (0)