* util: extend string search with user-defined printable characters * util: use RzVector for user_unprintable options * util: address review for configurable unprintable chars * core/cconfig: use goto error_free pattern in cb_str_unprintable * test/cmd_search_z: merge duplicate Armenian utf16le tests
537 lines
25 KiB
C
537 lines
25 KiB
C
// SPDX-FileCopyrightText: 2021 borzacchiello <lucaborza@gmail.com>
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
|
|
#include <rz_util.h>
|
|
#include <rz_search.h>
|
|
#include "minunit.h"
|
|
|
|
static RzUtilStrScanOptions g_opt = {
|
|
.max_str_length = 2048,
|
|
.min_str_length = 4,
|
|
.prefer_big_endian = false,
|
|
.check_ascii_freq = true,
|
|
};
|
|
|
|
bool test_rz_scan_strings_detect_ascii(void) {
|
|
static const unsigned char str[] = "\xff\xff\xffI am an ASCII string\xff\xff";
|
|
RzBuffer *buf = rz_buf_new_with_bytes(str, sizeof(str));
|
|
|
|
RzList *str_list = rz_list_newf((RzListFree)rz_detected_string_free);
|
|
int n = rz_scan_strings(buf, str_list, &g_opt, 0, buf->methods->get_size(buf) - 1, RZ_STRING_ENC_GUESS);
|
|
mu_assert_eq(n, 1, "rz_scan_strings ascii, number of strings");
|
|
|
|
RzDetectedString *s = rz_list_get_n(str_list, 0);
|
|
mu_assert_streq(s->string, "I am an ASCII string", "rz_scan_strings ascii, different string");
|
|
mu_assert_eq(s->addr, 3, "rz_scan_strings ascii, address");
|
|
mu_assert_eq(s->encoding, RZ_STRING_ENC_8BIT, "rz_scan_strings ascii, string type");
|
|
|
|
rz_list_free(str_list);
|
|
rz_buf_free(buf);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
bool test_rz_scan_strings_detect_ibm290(void) {
|
|
static const unsigned char expected[] = "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x58\x5a\x5b\x5c\x5d\x5e\x5f\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9d\x9e\x9f\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xac\xad\xae\xaf\xba\xbb\xbc\xbd\xbe\xbf\xbf\x00";
|
|
RzBuffer *buf = rz_buf_new_with_bytes(expected, sizeof(expected));
|
|
|
|
RzList *str_list = rz_list_newf((RzListFree)rz_detected_string_free);
|
|
int n = rz_scan_strings(buf, str_list, &g_opt, 0, rz_buf_size(buf) - 1, RZ_STRING_ENC_IBM290);
|
|
mu_assert_eq(n, 1, "rz_scan_strings ibm290, number of strings");
|
|
|
|
RzDetectedString *s = rz_list_get_n(str_list, 0);
|
|
mu_assert_streq(s->string, " 。「」、・ヲァィゥ£.<(+|&ェォャュョッー!¥*);¬アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフ¯ヘホマミムメモヤユヨラリルレロワン゛゜゜", "rz_scan_strings ibm290, different string");
|
|
mu_assert_eq(s->encoding, RZ_STRING_ENC_IBM290, "rz_scan_strings ibm290, string type");
|
|
|
|
rz_list_free(str_list);
|
|
rz_buf_free(buf);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
bool test_rz_scan_strings_detect_ibm037(void) {
|
|
static const unsigned char str[] = "\xc9\x40\x81\x94\x40\x81\x95\x40\xc9\xc2\xd4\xf0\xf3\xf7\x40\xa2\xa3\x99\x89\x95\x87\x25";
|
|
RzBuffer *buf = rz_buf_new_with_bytes(str, sizeof(str));
|
|
|
|
RzList *str_list = rz_list_newf((RzListFree)rz_detected_string_free);
|
|
int n = rz_scan_strings(buf, str_list, &g_opt, 0, buf->methods->get_size(buf) - 1, RZ_STRING_ENC_GUESS);
|
|
mu_assert_eq(n, 1, "rz_scan_strings ibm037, number of strings");
|
|
|
|
RzDetectedString *s = rz_list_get_n(str_list, 0);
|
|
mu_assert_streq(s->string, "I am an IBM037 string", "rz_scan_strings ibm037, different string");
|
|
mu_assert_eq(s->encoding, RZ_STRING_ENC_IBM037, "rz_scan_strings ibm037, string type");
|
|
|
|
rz_list_free(str_list);
|
|
rz_buf_free(buf);
|
|
|
|
/**
|
|
* two strings:
|
|
* 1. "Ber. Who's there.?\x00"
|
|
* 2. "Fran. Nay, answer me. Stand and unfold yourself"
|
|
*/
|
|
static const unsigned char str2[] = "\xff\xff\xff\xC2\x85\x99\x4B\x40\xE6\x88\x96\x7D\xA2\x40\xA3\x88\x85\x99\x85\x4B\x6F\x00\xC6\x99\x81\x95\x4B\x40\xD5\x81\xA8\x6B\x40\x81\x95\xA2\xA6\x85\x99\x40\x94\x85\x4B\x40\xE2\xA3\x81\x95\x84\x40\x81\x95\x84\x40\xA4\x95\x86\x96\x93\x84\x40\xA8\x96\xA4\x99\xA2\x85\x93\x86";
|
|
buf = rz_buf_new_with_bytes(str2, sizeof(str2));
|
|
|
|
str_list = rz_list_newf((RzListFree)rz_detected_string_free);
|
|
n = rz_scan_strings(buf, str_list, &g_opt, 0, buf->methods->get_size(buf) - 1, RZ_STRING_ENC_GUESS);
|
|
mu_assert_eq(n, 2, "rz_scan_strings ibm037, number of strings");
|
|
|
|
s = rz_list_get_n(str_list, 0);
|
|
mu_assert_streq(s->string, "Ber. Who's there.?", "rz_scan_strings ibm037, different string");
|
|
mu_assert_eq(s->encoding, RZ_STRING_ENC_IBM037, "rz_scan_strings ibm037, string type");
|
|
|
|
s = rz_list_get_n(str_list, 1);
|
|
mu_assert_streq(s->string, "Fran. Nay, answer me. Stand and unfold yourself", "rz_scan_strings ibm037, different string");
|
|
mu_assert_eq(s->encoding, RZ_STRING_ENC_IBM037, "rz_scan_strings ibm037, string type");
|
|
|
|
rz_list_free(str_list);
|
|
rz_buf_free(buf);
|
|
|
|
// UTF and EBCDIC strings in one memory
|
|
static const unsigned char str3[] =
|
|
"\xff\xff\xff\xc9\x40\x81\x94\x40\x81\x95\x40\xc9\xc2\xd4\xf0\xf3\xf7\x40\xa2\xa3\x99\x89\x95\x87\x25\xff\xff\xff"
|
|
"\xff\xff\xff\xffI am a \xc3\x99TF-8 string\xff\xff\xff\xff";
|
|
buf = rz_buf_new_with_bytes(str3, sizeof(str3));
|
|
|
|
str_list = rz_list_newf((RzListFree)rz_detected_string_free);
|
|
n = rz_scan_strings(buf, str_list, &g_opt, 0, buf->methods->get_size(buf) - 1, RZ_STRING_ENC_GUESS);
|
|
mu_assert_eq(n, 2, "rz_scan_strings mix utf8 and ibm037, number of strings");
|
|
|
|
s = rz_list_get_n(str_list, 0);
|
|
mu_assert_streq(s->string, "I am an IBM037 string", "rz_scan_strings mix utf8 and ibm037, different string");
|
|
mu_assert_eq(s->encoding, RZ_STRING_ENC_IBM037, "rz_scan_strings mix utf8 and ibm037, string type");
|
|
|
|
s = rz_list_get_n(str_list, 1);
|
|
mu_assert_streq(s->string, "I am a \xc3\x99TF-8 string", "rz_scan_strings mix utf8 and ibm037, different string");
|
|
mu_assert_eq(s->encoding, RZ_STRING_ENC_UTF8, "rz_scan_strings mix utf8 and ibm037, string type");
|
|
|
|
rz_list_free(str_list);
|
|
rz_buf_free(buf);
|
|
|
|
// one of the ending chars of UTF-8 is actually one of the starting chars of the EBCDIC string
|
|
static const unsigned char str4[] =
|
|
"\xff\xff\xff\xc9\x40\x81\x94\x40\x81\x95\x40\xc9\xc2\xd4\xf0\xf3\xf7\x40\xa2\xa3\x99\x89\x95\x87\x25"
|
|
"I am a \xc3\x99TF-8 string\xff\xff\xff";
|
|
buf = rz_buf_new_with_bytes(str4, sizeof(str4));
|
|
|
|
str_list = rz_list_newf((RzListFree)rz_detected_string_free);
|
|
n = rz_scan_strings(buf, str_list, &g_opt, 0, buf->methods->get_size(buf) - 1, RZ_STRING_ENC_GUESS);
|
|
mu_assert_eq(n, 2, "rz_scan_strings mix utf8 and ibm037, number of strings");
|
|
|
|
s = rz_list_get_n(str_list, 0);
|
|
mu_assert_streq(s->string, "I am an IBM037 string", "rz_scan_strings mix utf8 and ibm037, different string");
|
|
mu_assert_eq(s->encoding, RZ_STRING_ENC_IBM037, "rz_scan_strings mix utf8 and ibm037, string type");
|
|
|
|
s = rz_list_get_n(str_list, 1);
|
|
mu_assert_streq(s->string, "%I am a \xc3\x99TF-8 string", "rz_scan_strings mix utf8 and ibm037, different string");
|
|
mu_assert_eq(s->encoding, RZ_STRING_ENC_UTF8, "rz_scan_strings mix utf8 and ibm037, string type");
|
|
|
|
rz_list_free(str_list);
|
|
rz_buf_free(buf);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
bool test_rz_scan_strings_detect_utf8(void) {
|
|
static const unsigned char str[] = "\xff\xff\xff\xffI am a \xc3\x99TF-8 string\xff\xff\xff\xff";
|
|
RzBuffer *buf = rz_buf_new_with_bytes(str, sizeof(str));
|
|
|
|
RzList *str_list = rz_list_newf((RzListFree)rz_detected_string_free);
|
|
int n = rz_scan_strings(buf, str_list, &g_opt, 0, buf->methods->get_size(buf) - 1, RZ_STRING_ENC_GUESS);
|
|
mu_assert_eq(n, 1, "rz_scan_strings utf8, number of strings");
|
|
|
|
RzDetectedString *s = rz_list_get_n(str_list, 0);
|
|
mu_assert_streq(s->string, "I am a \xc3\x99TF-8 string", "rz_scan_strings utf8, different string");
|
|
mu_assert_eq(s->addr, 4, "rz_scan_strings utf8, address");
|
|
mu_assert_eq(s->encoding, RZ_STRING_ENC_UTF8, "rz_scan_strings utf8, string type");
|
|
|
|
rz_list_free(str_list);
|
|
rz_buf_free(buf);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
bool test_rz_scan_strings_detect_utf16_le(void) {
|
|
static const unsigned char str[] =
|
|
"\xff\xff\xff\x49\x00\x20\x00\x61\x00\x6d\x00\x20\x00\x61"
|
|
"\x00\x20\x00\x55\x00\x54\x00\x46\x00\x2d\x00\x31\x00\x36"
|
|
"\x00\x6c\x00\x65\x00\x20\x00\x73\x00\x74\x00\x72\x00\x69"
|
|
"\x00\x6e\x00\x67\x00\x00\xff\xff";
|
|
|
|
RzBuffer *buf = rz_buf_new_with_bytes(str, sizeof(str));
|
|
|
|
RzList *str_list = rz_list_newf((RzListFree)rz_detected_string_free);
|
|
|
|
g_opt.prefer_big_endian = false;
|
|
int n = rz_scan_strings(buf, str_list, &g_opt, 0, buf->methods->get_size(buf) - 1, RZ_STRING_ENC_GUESS);
|
|
mu_assert_eq(n, 1, "rz_scan_strings utf16le, number of strings");
|
|
|
|
RzDetectedString *s = rz_list_get_n(str_list, 0);
|
|
mu_assert_streq(s->string, "I am a UTF-16le string", "rz_scan_strings utf16le, different string");
|
|
mu_assert_eq(s->addr, 3, "rz_scan_strings utf16le, address");
|
|
mu_assert_eq(s->encoding, RZ_STRING_ENC_UTF16LE, "rz_scan_strings utf16le, string type");
|
|
|
|
rz_list_free(str_list);
|
|
rz_buf_free(buf);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
bool test_rz_scan_strings_detect_utf16_le_special_chars(void) {
|
|
static const unsigned char str[] =
|
|
"\x09\x00\x77\x00\x69\x00\x64\x00\x65\x00\x5c\x00"
|
|
"\x65\x00\x73\x00\x63\x00\x3a\x00\x20\x00\x1b\x00"
|
|
"\x5b\x00\x30\x00\x6d\x00\xa1\x00\x0d\x00\x0a\x00"
|
|
"\x00\x00\x00\x00";
|
|
|
|
RzBuffer *buf = rz_buf_new_with_bytes(str, sizeof(str));
|
|
|
|
RzList *str_list = rz_list_newf((RzListFree)rz_detected_string_free);
|
|
|
|
g_opt.prefer_big_endian = false;
|
|
int n = rz_scan_strings(buf, str_list, &g_opt, 0, buf->methods->get_size(buf) - 1, RZ_STRING_ENC_GUESS);
|
|
mu_assert_eq(n, 1, "rz_scan_strings utf16le, number of strings");
|
|
|
|
RzDetectedString *s = rz_list_get_n(str_list, 0);
|
|
mu_assert_streq(s->string, "\twide\\esc: \x1b[0m\xc2\xa1\r\n", "rz_scan_strings utf16le, different string");
|
|
mu_assert_eq(s->addr, 0, "rz_scan_strings utf16le, address");
|
|
mu_assert_eq(s->encoding, RZ_STRING_ENC_UTF16LE, "rz_scan_strings utf16le, string type");
|
|
|
|
rz_list_free(str_list);
|
|
rz_buf_free(buf);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
bool test_rz_scan_strings_user_unprintable(void) {
|
|
// ASCII/UTF-8 string: "hello\tworld\ntest\0"
|
|
// With \t (0x09) and \n (0x0a) as user-defined non-printable,
|
|
// the scanner should produce: "hello", "world", "test"
|
|
static const unsigned char str[] = "hello\tworld\ntest";
|
|
static RzCodePoint code_points[] = { 0x09, 0x0a };
|
|
RzBuffer *buf = rz_buf_new_with_bytes(str, sizeof(str));
|
|
RzUtilStrScanOptions opt = g_opt;
|
|
RzVector *user_unprintable = rz_vector_new(sizeof(RzCodePoint), NULL, NULL);
|
|
mu_assert_notnull(user_unprintable, "user_unprintable vector alloc");
|
|
for (size_t i = 0; i < RZ_ARRAY_SIZE(code_points); i++) {
|
|
mu_assert_true(rz_vector_push(user_unprintable, &code_points[i]), "push user_unprintable");
|
|
}
|
|
opt.user_unprintable = user_unprintable;
|
|
opt.min_str_length = 4;
|
|
|
|
RzList *str_list = rz_list_newf((RzListFree)rz_detected_string_free);
|
|
int n = rz_scan_strings(buf, str_list, &opt, 0, buf->methods->get_size(buf) - 1, RZ_STRING_ENC_8BIT);
|
|
mu_assert_eq(n, 3, "rz_scan_strings user_unprintable, number of strings");
|
|
|
|
RzDetectedString *s0 = rz_list_get_n(str_list, 0);
|
|
RzDetectedString *s1 = rz_list_get_n(str_list, 1);
|
|
RzDetectedString *s2 = rz_list_get_n(str_list, 2);
|
|
mu_assert_streq(s0->string, "hello", "rz_scan_strings user_unprintable, first string");
|
|
mu_assert_streq(s1->string, "world", "rz_scan_strings user_unprintable, second string");
|
|
mu_assert_streq(s2->string, "test", "rz_scan_strings user_unprintable, third string");
|
|
|
|
rz_list_free(str_list);
|
|
rz_buf_free(buf);
|
|
rz_vector_free(user_unprintable);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
bool test_rz_scan_strings_user_unprintable_utf8(void) {
|
|
// UTF-8 bytes for U+00E9 (latin small letter e with acute) between "ab" and "cd".
|
|
static const unsigned char str[] = { 'a', 'b', 0xC3, 0xA9, 'c', 'd', 0x00 };
|
|
static RzCodePoint code_points[] = { 0x00e9 }; // U+00E9 (latin small letter e with acute)
|
|
RzBuffer *buf = rz_buf_new_with_bytes(str, sizeof(str));
|
|
RzUtilStrScanOptions opt = g_opt;
|
|
RzVector *user_unprintable = rz_vector_new(sizeof(RzCodePoint), NULL, NULL);
|
|
mu_assert_notnull(user_unprintable, "user_unprintable vector alloc");
|
|
for (size_t i = 0; i < RZ_ARRAY_SIZE(code_points); i++) {
|
|
mu_assert_true(rz_vector_push(user_unprintable, &code_points[i]), "push user_unprintable");
|
|
}
|
|
opt.user_unprintable = user_unprintable;
|
|
opt.min_str_length = 2;
|
|
opt.check_ascii_freq = false;
|
|
|
|
RzList *str_list = rz_list_newf((RzListFree)rz_detected_string_free);
|
|
int n = rz_scan_strings(buf, str_list, &opt, 0, buf->methods->get_size(buf) - 1, RZ_STRING_ENC_UTF8);
|
|
mu_assert_eq(n, 2, "rz_scan_strings user_unprintable utf8, number of strings");
|
|
|
|
RzDetectedString *s0 = rz_list_get_n(str_list, 0);
|
|
RzDetectedString *s1 = rz_list_get_n(str_list, 1);
|
|
mu_assert_streq(s0->string, "ab", "rz_scan_strings user_unprintable utf8, first string");
|
|
mu_assert_streq(s1->string, "cd", "rz_scan_strings user_unprintable utf8, second string");
|
|
|
|
rz_list_free(str_list);
|
|
rz_buf_free(buf);
|
|
rz_vector_free(user_unprintable);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
bool test_rz_scan_strings_detect_utf16_be(void) {
|
|
static const unsigned char str[] =
|
|
"\xff\xff\xff\x00\x49\x00\x20\x00\x61\x00\x6d\x00\x20\x00\x61"
|
|
"\x00\x20\x00\x55\x00\x54\x00\x46\x00\x2d\x00\x31\x00\x36\x00"
|
|
"\x62\x00\x65\x00\x20\x00\x73\x00\x74\x00\x72\x00\x69\x00\x6e"
|
|
"\x00\x67\xff\xff\xff\xff";
|
|
|
|
RzBuffer *buf = rz_buf_new_with_bytes(str, sizeof(str));
|
|
|
|
RzList *str_list = rz_list_newf((RzListFree)rz_detected_string_free);
|
|
|
|
g_opt.prefer_big_endian = true;
|
|
int n = rz_scan_strings(buf, str_list, &g_opt, 0, buf->methods->get_size(buf) - 1, RZ_STRING_ENC_GUESS);
|
|
mu_assert_eq(n, 1, "rz_scan_strings utf16be, number of strings");
|
|
|
|
RzDetectedString *s = rz_list_get_n(str_list, 0);
|
|
mu_assert_streq(s->string, "I am a UTF-16be string", "rz_scan_strings utf16be, different string");
|
|
mu_assert_eq(s->addr, 3, "rz_scan_strings utf16be, address");
|
|
mu_assert_eq(s->encoding, RZ_STRING_ENC_UTF16BE, "rz_scan_strings utf16be, string type");
|
|
|
|
rz_list_free(str_list);
|
|
rz_buf_free(buf);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
bool test_rz_scan_strings_detect_utf32_le(void) {
|
|
static const unsigned char str[] =
|
|
"\xff\xff\x49\x00\x00\x00\x20\x00\x00\x00\x61\x00\x00\x00\x6d"
|
|
"\x00\x00\x00\x20\x00\x00\x00\x61\x00\x00\x00\x20\x00\x00\x00"
|
|
"\x55\x00\x00\x00\x54\x00\x00\x00\x46\x00\x00\x00\x2d\x00\x00"
|
|
"\x00\x33\x00\x00\x00\x32\x00\x00\x00\x6c\x00\x00\x00\x65\x00"
|
|
"\x00\x00\x20\x00\x00\x00\x73\x00\x00\x00\x74\x00\x00\x00\x72"
|
|
"\x00\x00\x00\x69\x00\x00\x00\x6e\x00\x00\x00\x67\x00\x00\x00"
|
|
"\xff\xff\xff\xff\xff\xff\xff\xff";
|
|
|
|
RzBuffer *buf = rz_buf_new_with_bytes(str, sizeof(str));
|
|
|
|
RzList *str_list = rz_list_newf((RzListFree)rz_detected_string_free);
|
|
|
|
g_opt.prefer_big_endian = false;
|
|
int n = rz_scan_strings(buf, str_list, &g_opt, 0, buf->methods->get_size(buf) - 1, RZ_STRING_ENC_GUESS);
|
|
mu_assert_eq(n, 1, "rz_scan_strings utf32le, number of strings");
|
|
|
|
RzDetectedString *s = rz_list_get_n(str_list, 0);
|
|
mu_assert_streq(s->string, "I am a UTF-32le string", "rz_scan_strings utf32le, different string");
|
|
mu_assert_eq(s->addr, 2, "rz_scan_strings utf32le, address");
|
|
mu_assert_eq(s->encoding, RZ_STRING_ENC_UTF32LE, "rz_scan_strings utf32le, string type");
|
|
|
|
rz_list_free(str_list);
|
|
rz_buf_free(buf);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
bool test_rz_scan_strings_detect_utf32_be(void) {
|
|
static const unsigned char str[] =
|
|
"\xff\xff\x00\x00\x00\x49\x00\x00\x00\x20\x00\x00\x00\x61\x00"
|
|
"\x00\x00\x6d\x00\x00\x00\x20\x00\x00\x00\x61\x00\x00\x00\x20"
|
|
"\x00\x00\x00\x55\x00\x00\x00\x54\x00\x00\x00\x46\x00\x00\x00"
|
|
"\x2d\x00\x00\x00\x33\x00\x00\x00\x32\x00\x00\x00\x62\x00\x00"
|
|
"\x00\x65\x00\x00\x00\x20\x00\x00\x00\x73\x00\x00\x00\x74\x00"
|
|
"\x00\x00\x72\x00\x00\x00\x69\x00\x00\x00\x6e\x00\x00\x00\x67"
|
|
"\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff";
|
|
|
|
RzBuffer *buf = rz_buf_new_with_bytes(str, sizeof(str));
|
|
|
|
RzList *str_list = rz_list_newf((RzListFree)rz_detected_string_free);
|
|
|
|
g_opt.prefer_big_endian = true;
|
|
int n = rz_scan_strings(buf, str_list, &g_opt, 0, buf->methods->get_size(buf) - 1, RZ_STRING_ENC_GUESS);
|
|
mu_assert_eq(n, 1, "rz_scan_strings utf32be, number of strings");
|
|
|
|
RzDetectedString *s = rz_list_get_n(str_list, 0);
|
|
mu_assert_streq(s->string, "I am a UTF-32be stringÿ", "rz_scan_strings utf32be, different string");
|
|
mu_assert_eq(s->addr, 2, "rz_scan_strings utf32be, address");
|
|
mu_assert_eq(s->encoding, RZ_STRING_ENC_UTF32BE, "rz_scan_strings utf32be, string type");
|
|
mu_assert_eq(s->size, 92, "rz_scan_strings utf32be, size"); // 92 bytes in size, no NUL byte.
|
|
mu_assert_eq(s->length, 23, "rz_scan_strings utf32be, length"); // 23 characters in length.
|
|
|
|
rz_list_free(str_list);
|
|
rz_buf_free(buf);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
bool test_rz_scan_strings_utf16_be(void) {
|
|
static const unsigned char str[] =
|
|
"\xff\xfftorre, alfiere\xff\x00\x04\x41\x04\x3b\x04\x3e\x04\x3d\x00\x2c\x00\x20\x04\x3b\x04\x30\x04\x34\x04\x4c\x04\x4f";
|
|
|
|
RzBuffer *buf = rz_buf_new_with_bytes(str, sizeof(str));
|
|
|
|
RzList *str_list = rz_list_newf((RzListFree)rz_detected_string_free);
|
|
|
|
g_opt.prefer_big_endian = true;
|
|
int n = rz_scan_strings(buf, str_list, &g_opt, 16, buf->methods->get_size(buf) - 1, RZ_STRING_ENC_UTF16BE);
|
|
mu_assert_eq(n, 1, "rz_scan_strings utf16be, number of strings");
|
|
|
|
RzDetectedString *s = rz_list_get_n(str_list, 0);
|
|
|
|
mu_assert_eq(s->addr, 18, "rz_scan_strings utf16be, address");
|
|
// "слон, ладья" UTF-8 encoded:
|
|
mu_assert_streq(s->string, "\xd1\x81\xd0\xbb\xd0\xbe\xd0\xbd\x2c\x20\xd0\xbb\xd0\xb0\xd0\xb4\xd1\x8c\xd1\x8f", // This is UTF-8 encoded.
|
|
"rz_scan_strings utf16be, different string");
|
|
mu_assert_eq(s->encoding, RZ_STRING_ENC_UTF16BE, "rz_scan_strings utf16be, string type");
|
|
mu_assert_eq(s->size, 22, "rz_scan_strings utf16be, size"); // 22 bytes in size, no NUL byte.
|
|
mu_assert_eq(s->length, 11, "rz_scan_strings utf16be, length"); // 11 characters in length.
|
|
|
|
rz_list_free(str_list);
|
|
rz_buf_free(buf);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
bool test_rz_scan_strings_extended_ascii(void) {
|
|
static const unsigned char str[] =
|
|
"Immensità s'annega il pensier mio: E il naufragar m'è dolce in questo mare.\x00"
|
|
"Ich sah, wie Doris bei Damöten stand, er nahm sie zärtlich bei der Hand.\00"
|
|
"Dans l'éblouissante clarté de leur premier amour.\x00";
|
|
|
|
RzBuffer *buf = rz_buf_new_with_bytes(str, sizeof(str));
|
|
|
|
RzList *str_list = rz_list_newf((RzListFree)rz_detected_string_free);
|
|
|
|
int n = rz_scan_strings(buf, str_list, &g_opt, 0, buf->methods->get_size(buf) - 1, RZ_STRING_ENC_UTF8);
|
|
mu_assert_eq(n, 3, "rz_scan_strings extended_ascii, number of strings");
|
|
|
|
RzDetectedString *s_it = rz_list_get_n(str_list, 0);
|
|
RzDetectedString *s_de = rz_list_get_n(str_list, 1);
|
|
RzDetectedString *s_fr = rz_list_get_n(str_list, 2);
|
|
|
|
mu_assert_streq(s_it->string, "Immensità s'annega il pensier mio: E il naufragar m'è dolce in questo mare.",
|
|
"rz_scan_strings extended_ascii, different strings IT");
|
|
mu_assert_streq(s_de->string, "Ich sah, wie Doris bei Damöten stand, er nahm sie zärtlich bei der Hand.",
|
|
"rz_scan_strings extended_ascii, different strings DE");
|
|
mu_assert_streq(s_fr->string, "Dans l'éblouissante clarté de leur premier amour.",
|
|
"rz_scan_strings extended_ascii, different strings FR");
|
|
|
|
rz_list_free(str_list);
|
|
rz_buf_free(buf);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
/**
|
|
* \brief NUL byte is counted in the RzDetectedString->size member but not in the length member.
|
|
*/
|
|
bool test_rz_scan_strings_detect_length_ascii(void) {
|
|
static const unsigned char no_nul[] = "I am an ASCII string without NUL byte.\xff";
|
|
RzBuffer *buf = rz_buf_new_with_bytes(no_nul, sizeof(no_nul));
|
|
|
|
RzList *str_list = rz_list_newf((RzListFree)rz_detected_string_free);
|
|
int n = rz_scan_strings(buf, str_list, &g_opt, 0, buf->methods->get_size(buf), RZ_STRING_ENC_8BIT);
|
|
mu_assert_eq(n, 1, "rz_scan_strings ascii, number of strings");
|
|
|
|
RzDetectedString *s = rz_list_get_n(str_list, 0);
|
|
mu_assert_streq(s->string, "I am an ASCII string without NUL byte.", "rz_scan_strings ascii, different string");
|
|
mu_assert_eq(s->addr, 0, "rz_scan_strings ascii, address");
|
|
mu_assert_eq(s->size, 38, "rz_scan_strings ascii, size (in bytes, no NUL byte)");
|
|
mu_assert_eq(s->length, 38, "rz_scan_strings ascii, length (in characters without NUL byte)");
|
|
mu_assert_eq(s->encoding, RZ_STRING_ENC_8BIT, "rz_scan_strings ascii, type");
|
|
rz_list_purge(str_list);
|
|
|
|
// Extra space between "a" and "NUL" to get comparable string length.
|
|
static const unsigned char nul[] = "I am an ASCII string with a NUL byte.\0";
|
|
RzBuffer *buf_nul = rz_buf_new_with_bytes(nul, sizeof(nul));
|
|
n = rz_scan_strings(buf_nul, str_list, &g_opt, 0, buf_nul->methods->get_size(buf_nul), RZ_STRING_ENC_8BIT);
|
|
s = rz_list_get_n(str_list, 0);
|
|
mu_assert_eq(n, 1, "rz_scan_strings ascii, number of strings");
|
|
mu_assert_streq(s->string, "I am an ASCII string with a NUL byte.", "rz_scan_strings ascii, different string");
|
|
mu_assert_eq(s->addr, 0, "rz_scan_strings ascii, address");
|
|
// One byte larger in size than above, due to additional NUL byte.
|
|
mu_assert_eq(s->size, 39, "rz_scan_strings ascii, size (in bytes, without NUL byte)");
|
|
mu_assert_eq(s->length, 38, "rz_scan_strings ascii, length (in characters)");
|
|
mu_assert_eq(s->encoding, RZ_STRING_ENC_8BIT, "rz_scan_strings ascii, type");
|
|
|
|
rz_list_free(str_list);
|
|
rz_buf_free(buf);
|
|
rz_buf_free(buf_nul);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
/**
|
|
* \brief NUL byte is counted in the RzDetectedString->size member but not in the length member.
|
|
*/
|
|
bool test_rz_scan_strings_detect_length_utf8(void) {
|
|
static const unsigned char no_nul[] = "⟨I am an UTF-8 string without NUL byte⟩.\xff";
|
|
RzBuffer *buf = rz_buf_new_with_bytes(no_nul, sizeof(no_nul));
|
|
|
|
RzList *str_list = rz_list_newf((RzListFree)rz_detected_string_free);
|
|
int n = rz_scan_strings(buf, str_list, &g_opt, 0, buf->methods->get_size(buf), RZ_STRING_ENC_UTF8);
|
|
mu_assert_eq(n, 1, "rz_scan_strings ascii, number of strings");
|
|
|
|
RzDetectedString *s = rz_list_get_n(str_list, 0);
|
|
mu_assert_streq(s->string, "⟨I am an UTF-8 string without NUL byte⟩.", "rz_scan_strings utf-8, different string");
|
|
mu_assert_eq(s->addr, 0, "rz_scan_strings utf-8, address");
|
|
mu_assert_eq(s->size, 44, "rz_scan_strings utf-8, size (in bytes, no NUL byte)");
|
|
mu_assert_eq(s->length, 40, "rz_scan_strings utf-8, length (in characters without NUL byte)");
|
|
mu_assert_eq(s->encoding, RZ_STRING_ENC_UTF8, "rz_scan_strings utf-8, type");
|
|
rz_list_purge(str_list);
|
|
|
|
// Extra space between "a" and "NUL" to get comparable string length.
|
|
static const unsigned char nul[] = "⟨I am an UTF-8 string with a NUL byte⟩.\0";
|
|
RzBuffer *buf_nul = rz_buf_new_with_bytes(nul, sizeof(nul));
|
|
n = rz_scan_strings(buf_nul, str_list, &g_opt, 0, buf_nul->methods->get_size(buf_nul), RZ_STRING_ENC_UTF8);
|
|
s = rz_list_get_n(str_list, 0);
|
|
mu_assert_eq(n, 1, "rz_scan_strings utf-8, number of strings");
|
|
mu_assert_streq(s->string, "⟨I am an UTF-8 string with a NUL byte⟩.", "rz_scan_strings utf-8, different string");
|
|
mu_assert_eq(s->addr, 0, "rz_scan_strings utf-8, address");
|
|
// One byte larger in size than above, due to additional NUL byte.
|
|
mu_assert_eq(s->size, 45, "rz_scan_strings utf-8, size (in bytes, with NUL byte)");
|
|
mu_assert_eq(s->length, 40, "rz_scan_strings utf-8, length (in characters)");
|
|
mu_assert_eq(s->encoding, RZ_STRING_ENC_UTF8, "rz_scan_strings utf-8, type");
|
|
|
|
rz_list_free(str_list);
|
|
rz_buf_free(buf);
|
|
rz_buf_free(buf_nul);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
/**
|
|
* \brief Test that rz_search_collection_string_add() refuses to add a string if
|
|
* the search requires string scanning, but no scan optoins were given.
|
|
*/
|
|
bool test_rz_scan_strings_scan_options_error(void) {
|
|
RzSearchCollection *collection = rz_search_collection_strings(NULL, 4);
|
|
mu_assert_false(rz_search_collection_string_add(collection, "", 0, 1, RZ_STRING_ENC_IBM037), "Should fail for this config");
|
|
mu_assert_false(rz_search_collection_string_add(collection, "", 0, 1, RZ_STRING_ENC_IBM290), "Should fail for this config");
|
|
mu_assert_false(rz_search_collection_string_add(collection, "", 0, 1, RZ_STRING_ENC_EBCDIC_UK), "Should fail for this config");
|
|
mu_assert_false(rz_search_collection_string_add(collection, "", 0, 1, RZ_STRING_ENC_EBCDIC_US), "Should fail for this config");
|
|
mu_assert_false(rz_search_collection_string_add(collection, "", 0, 1, RZ_STRING_ENC_EBCDIC_ES), "Should fail for this config");
|
|
mu_assert_false(rz_search_collection_string_add(collection, "", 0, 1, RZ_STRING_ENC_GUESS), "Should fail for this config");
|
|
mu_assert_false(rz_search_collection_string_add(collection, "", 0, 1, RZ_STRING_ENC_SETTINGS), "Should fail for this config");
|
|
mu_assert_true(rz_search_collection_string_add(collection, "some_pattern", 0, 1, RZ_STRING_ENC_UTF16BE), "Should succeed for this config");
|
|
mu_assert_true(rz_search_collection_string_add(collection, "some_pattern", 0, 1, RZ_STRING_ENC_UTF16LE), "Should succeed for this config");
|
|
mu_assert_true(rz_search_collection_string_add(collection, "some_pattern", 0, 1, RZ_STRING_ENC_UTF32BE), "Should succeed for this config");
|
|
mu_assert_true(rz_search_collection_string_add(collection, "some_pattern", 0, 1, RZ_STRING_ENC_UTF32LE), "Should succeed for this config");
|
|
mu_assert_true(rz_search_collection_string_add(collection, "some_pattern", 0, 1, RZ_STRING_ENC_8BIT), "Should succeed for this config");
|
|
mu_assert_true(rz_search_collection_string_add(collection, "some_pattern", 0, 1, RZ_STRING_ENC_UTF8), "Should succeed for this config");
|
|
rz_search_collection_free(collection);
|
|
mu_end;
|
|
}
|
|
|
|
bool all_tests() {
|
|
mu_run_test(test_rz_scan_strings_detect_ascii);
|
|
mu_run_test(test_rz_scan_strings_detect_ibm037);
|
|
mu_run_test(test_rz_scan_strings_detect_ibm290);
|
|
mu_run_test(test_rz_scan_strings_detect_utf8);
|
|
mu_run_test(test_rz_scan_strings_detect_utf16_le);
|
|
mu_run_test(test_rz_scan_strings_detect_utf16_le_special_chars);
|
|
mu_run_test(test_rz_scan_strings_user_unprintable);
|
|
mu_run_test(test_rz_scan_strings_user_unprintable_utf8);
|
|
mu_run_test(test_rz_scan_strings_detect_utf16_be);
|
|
mu_run_test(test_rz_scan_strings_detect_utf32_le);
|
|
mu_run_test(test_rz_scan_strings_detect_utf32_be);
|
|
mu_run_test(test_rz_scan_strings_utf16_be);
|
|
mu_run_test(test_rz_scan_strings_extended_ascii);
|
|
mu_run_test(test_rz_scan_strings_detect_length_ascii);
|
|
mu_run_test(test_rz_scan_strings_detect_length_utf8);
|
|
mu_run_test(test_rz_scan_strings_scan_options_error);
|
|
|
|
return tests_passed != tests_run;
|
|
}
|
|
|
|
mu_main(all_tests)
|