準備工作:
yara源碼 V1.7.1 https://github.com/VirusTotal/yara/releases/tag/v1.7.1
csdn:https://download.csdn.net/download/lacoucou/12501273
vs2010
vscode
參考資料:
yara文檔:
https://yara.readthedocs.io/en/stable/index.html
Yacc 與 Lex 快速入門
https://www.ibm.com/developerworks/cn/linux/sdk/lex/
使用lex與yacc構建簡單計算器
https://blog.csdn.net/crond123/article/details/3932014
一個Lex/Yacc完整的示例
https://blog.csdn.net/huyansoft/article/details/8860224
編譯源碼:
打開 .\yara 1.7.1\windows\yara\yara.sln 直接編譯就可以了,非常順利。
1.程序入口
yara.c 的main函數
int main(int argc, char const* argv[])
{
int i, pid, errors;
YARA_CONTEXT* context;
FILE* rule_file;
TAG* tag;
TAG* next_tag;
//初始化結構
yr_init();
context = yr_create_context();
if (context == NULL)
return 0;
//處理命令行參數
if (!process_cmd_line(context, argc, argv))
{
yr_destroy_context(context);
return 0;
}
if (argc == 1 || optind == argc)
{
yr_destroy_context(context);
show_help();
return 0;
}
context->error_report_function = report_error;
for (i = optind; i < argc - 1; i++)
{
rule_file = fopen(argv[i], "r");
if (rule_file != NULL)
{
yr_push_file_name(context, argv[i]);
//編譯規則文件
errors = yr_compile_file(rule_file, context);
fclose(rule_file);
if (errors) /* errors during compilation */
{
yr_destroy_context(context);
return 0;
}
}
else
{
fprintf(stderr, "could not open file: %s\n", argv[i]);
}
}
if (optind == argc - 1) /* no rule files, read rules from stdin */
{
yr_push_file_name(context, "stdin");
errors = yr_compile_file(stdin, context);
if (errors > 0) /* errors during compilation */
{
yr_destroy_context(context);
return 0;
}
}
//掃描部分
if (is_numeric(argv[argc - 1]))
{
pid = atoi(argv[argc - 1]);
switch (i = yr_scan_proc(pid, context, callback, (void*) argv[argc - 1]))
{
case ERROR_SUCCESS:
break;
case ERROR_COULD_NOT_ATTACH_TO_PROCESS:
fprintf(stderr, "can not attach to process (try running as root)\n");
break;
case ERROR_INSUFICIENT_MEMORY:
fprintf(stderr, "not enough memory\n");
break;
default:
fprintf(stderr, "internal error: %d\n", i);
break;
}
}
else if (is_directory(argv[argc - 1]))
{
scan_dir(argv[argc - 1], recursive_search, context, callback);
}
else
{
yr_scan_file(argv[argc - 1], context, callback, (void*) argv[argc - 1]);
}
yr_destroy_context(context);
/* free tag list allocated by process_cmd_line */
tag = specified_tags_list;
while(tag != NULL)
{
next_tag = tag->next;
free(tag);
tag = next_tag;
}
return 1;
}
流程分三步:
1.初始化,解析命令行。
2.編譯規則,生成YARA_CONTEXT* context結構。
這一部分詳細解析見 此係列的第二篇 yara 源碼學習(二) 規則編譯部分
3.掃描文件,根據參數輸出掃描結果。
這一部分詳細解析見 此係列的第三篇 yara 源碼學習(三) 掃描部分
此文主要說一下 初始化過程,以及相關數據結構。
1.yr_init函數相當簡單,具體代碼就是申請了一塊堆空間。
void yr_init()
{
yr_heap_alloc();
}
void yr_heap_alloc()
{
hHeap = HeapCreate(0, 0x8000, 0);
}
2.yr_create_context 函數
YARA_CONTEXT* yr_create_context()
{
YARA_CONTEXT* context = (YARA_CONTEXT*) yr_malloc(sizeof(YARA_CONTEXT));
context->rule_list.head = NULL;
context->rule_list.tail = NULL;
context->hash_table.non_hashed_strings = NULL;
context->hash_table.populated = FALSE;
context->errors = 0;
context->error_report_function = NULL;
context->last_error = ERROR_SUCCESS;
context->last_error_line = 0;
context->last_result = ERROR_SUCCESS;
context->file_stack_ptr = 0;
context->file_name_stack_ptr = 0;
context->current_rule_strings = NULL;
context->current_rule_flags = 0;
context->inside_for = 0;
context->namespaces = NULL;
context->variables = NULL;
context->allow_includes = TRUE;
context->current_namespace = yr_create_namespace(context, "default");
context->fast_match = FALSE;
context->scanning_process_memory = FALSE;
memset(context->rule_list.hash_table, 0, sizeof(context->rule_list.hash_table));
memset(context->hash_table.hashed_strings_2b, 0, sizeof(context->hash_table.hashed_strings_2b));
memset(context->hash_table.hashed_strings_1b, 0, sizeof(context->hash_table.hashed_strings_1b));
return context;
}
重點就是YARA_CONTEXT 結構。
typedef struct _MATCH
{
size_t offset; //文件中偏移
unsigned char* data; //匹配的數據
unsigned int length; //數據長度
struct _MATCH* next; //下一個匹配記錄
} MATCH;
typedef struct _REGEXP
{
void *regexp;
void *extra;
} REGEXP;
typedef struct _STRING
{
int flags; //類型
char* identifier; //ID
unsigned int length; //長度
unsigned char* string; //字符串
union {
unsigned char* mask; //掩碼 hex_string 用
REGEXP re; //正則表達式
};
MATCH* matches_head; //匹配的記錄頭
MATCH* matches_tail; ///匹配的記錄頭
struct _STRING* next; //下一條 特徵字符串
} STRING;
typedef struct _VARIABLE
{
int type;
char* identifier;
union {
char* string;
size_t integer;
int boolean;
};
struct _VARIABLE* next;
} VARIABLE;
typedef struct _TAG //標籤
{
char* identifier;
struct _TAG* next;
} TAG;
typedef struct _TERM //條件
{
int type;
} TERM;
typedef struct _NAMESPACE
{
char* name;
int global_rules_satisfied;
struct _NAMESPACE* next;
} NAMESPACE;
typedef struct _META
{
int type;
char* identifier;
union {
char* string;
size_t integer;
int boolean;
};
struct _META* next;
} META;
#define RULE_FLAGS_MATCH 0x01
#define RULE_FLAGS_PRIVATE 0x02
#define RULE_FLAGS_GLOBAL 0x04
#define RULE_FLAGS_REQUIRE_EXECUTABLE 0x08
#define RULE_FLAGS_REQUIRE_FILE 0x10
typedef struct _RULE
{
char* identifier; //規則名
int flags; //標誌字段 上邊RULE_ 這些
NAMESPACE* ns; //命名空間
STRING* string_list_head; //特徵字符串鏈表
TAG* tag_list_head; //標籤鏈表
META* meta_list_head; //元數據鏈表
TERM* condition; //條件鏈表
struct _RULE* next;
} RULE;
typedef struct _STRING_LIST_ENTRY
{
STRING* string;
struct _STRING_LIST_ENTRY* next;
} STRING_LIST_ENTRY;
typedef struct _RULE_LIST_ENTRY
{
RULE* rule;
struct _RULE_LIST_ENTRY* next;
} RULE_LIST_ENTRY;
#define RULE_LIST_HASH_TABLE_SIZE 10007
typedef struct _RULE_LIST
{
RULE* head;
RULE* tail;
RULE_LIST_ENTRY hash_table[RULE_LIST_HASH_TABLE_SIZE];
} RULE_LIST;
typedef struct _HASH_TABLE
{
STRING_LIST_ENTRY* hashed_strings_2b[256][256];
STRING_LIST_ENTRY* hashed_strings_1b[256];
STRING_LIST_ENTRY* non_hashed_strings;
int populated;
} HASH_TABLE;
typedef int (*YARACALLBACK)(RULE* rule, void* data);
typedef void (*YARAREPORT)(const char* file_name, int line_number, const char* error_message);
typedef struct _YARA_CONTEXT
{
int last_result; //記錄函數運行結果
YARAREPORT error_report_function; //函數指針,錯誤報告函數的函數指針
int errors; //錯誤個數 yyerror 函數中用到
int last_error;
int last_error_line; //錯誤產生的行號
RULE_LIST rule_list; //規則鏈表
HASH_TABLE hash_table; //哈希表
NAMESPACE* namespaces; //命名空間
NAMESPACE* current_namespace; //當前命名空間
VARIABLE* variables; //用戶自定義變量
STRING* current_rule_strings; //當前特徵字符串列表
int current_rule_flags; //當前特徵字符串的符號
int inside_for;
char* file_name_stack[MAX_INCLUDE_DEPTH];
int file_name_stack_ptr;
FILE* file_stack[MAX_INCLUDE_DEPTH];
int file_stack_ptr;
char last_error_extra_info[256];
char lex_buf[LEX_BUF_SIZE];
char* lex_buf_ptr;
unsigned short lex_buf_len;
int fast_match;
int allow_includes;
int scanning_process_memory;
char include_base_dir[MAX_PATH];
} YARA_CONTEXT;
主要的數據結構都定義在yara.h中。
yara規則文件的層次
yara規則文件:
規則文件的包含關係如上圖:
一個規則文件中可以包含多個命名空間。
一個命名空間可以包含多條規則
一條規則可以包含多條字符串特徵及條件,以及其他的元數據,標籤 等內容。
這一部分暫時就這樣了。