yara 源碼學習(一) 綜述

準備工作:


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規則文件:

規則文件的包含關係如上圖:

一個規則文件中可以包含多個命名空間。

一個命名空間可以包含多條規則

一條規則可以包含多條字符串特徵及條件,以及其他的元數據,標籤 等內容。

 

這一部分暫時就這樣了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章