惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Recent Commits to openclaw:main
Recent Commits to openclaw:main
博客园 - 叶小钗
Stack Overflow Blog
Stack Overflow Blog
S
SegmentFault 最新的问题
D
DataBreaches.Net
S
Securelist
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Threatpost
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
Jina AI
Jina AI
T
Threat Research - Cisco Blogs
GbyAI
GbyAI
Microsoft Azure Blog
Microsoft Azure Blog
WordPress大学
WordPress大学
Engineering at Meta
Engineering at Meta
T
The Exploit Database - CXSecurity.com
A
Arctic Wolf
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
C
Cisco Blogs
PCI Perspectives
PCI Perspectives
Project Zero
Project Zero
G
Google Developers Blog
宝玉的分享
宝玉的分享
H
Heimdal Security Blog
美团技术团队
Schneier on Security
Schneier on Security
C
CERT Recently Published Vulnerability Notes
Martin Fowler
Martin Fowler
博客园 - 司徒正美
博客园 - 三生石上(FineUI控件)
Help Net Security
Help Net Security
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Google DeepMind News
Google DeepMind News
C
Check Point Blog
Hacker News: Ask HN
Hacker News: Ask HN
L
LINUX DO - 最新话题
O
OpenAI News
Hacker News - Newest:
Hacker News - Newest: "LLM"
N
Netflix TechBlog - Medium
S
Security Affairs
小众软件
小众软件
MongoDB | Blog
MongoDB | Blog
Blog — PlanetScale
Blog — PlanetScale
V
V2EX - 技术
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
F
Fortinet All Blogs
G
GRAHAM CLULEY
云风的 BLOG
云风的 BLOG
S
Secure Thoughts

博客园 - GKLBB

软件神器 --- ctf靶场 之 pwn.college 术语俗话 --- 什么是加密狗 软件神器 --- 自动电脑锁屏软件 软件研发 --- 网络安全 之 putty生成无密码登录密钥 软件神器 --- 视频剪辑 之 Avidemux MP4Joiner Shotcut 软件神器 --- 视频格式转化 之 handbrake 软件研发 --- 应知应会 之 经验之谈 这个是什么图标,经常看到 软件研发 --- 术语俗话 之 多模态 术语俗话 --- 什么是大数据开发 术语俗话 --- 什么是边缘计算 软件研发 --- 应知应会 之 什么是云计算开发 应知应会 --- 如何不装软件查看网速 常见问题解决 --- 360拦截接触 常见问题解决 --- 加入会议摄像头无法打开 网络安全 --- CTF打靶 之 ZIP伪加密 → Robot36慢扫电视 → 二维码补齐 → DeepSound隐写 → GPG解密 → Base64图片 → SilentEye隐写 软件研发 --- 应知应会 之 无错误的闪退如何解决 软件研发 --- 应知应会 之 为什么别人的软件如此复杂我的如此简单 网络安全 --- 应知应会 之 什么是旁站 应知应会 --- 如何查询备案 软件神器 --- 格式转化 之 jpg 2 svg 网络安全 --- CTF打靶 之 flag搜索 软件神器 --- 互联网测速 之 软件神器 --- 局域网测速 之 iperf 常见问题解决 --- 模拟器USG6000打开后,启动设备失败,错误40 软件研发 --- AI网络 之 ensp配置生成 软件研发 --- AI编程 之 极简流程 软件研发 --- AI生图产品比较 常见问题解答 --- 为什么我的服务一直被人DDOS 软件研发 --- 开发万能格式转化工具 网站神器 --- 在线格式转化 之 文档转md 术语俗话 --- 什么是云电脑 常见问题解决 --- 如何在没有安装杀毒软件的情况下知道这个文件是不是牧马 常见问题解决 --- Win10下VMware 17安装VMware Tools选项灰色/失效解决办法 - GKLBB 常见问题解决 --- 云电脑报错 :PAGE FAULT IN NONPAGED AREA - GKLBB 记一次牧马的发现 人生感悟 --- 为什么我们生活中同一件事有多个品牌,他们到底有什么区别 软件运维 --- 云电脑安装打印机 常见问题解决 --- 网络打印默认端口 常见问题解决 --- 京瓷打印云电脑无法设置双面打印 软件研发 --- 网络安全 之 brupsuite如何设置上游袋里 术语俗话 --- 什么是同步和异步 我的目标 软件研发 --- dify配置 之 markword转word带有简单样式的方法 软件研发 --- 接口文档格式 常见问题 --- dify 的 deepseek是旧模型版本 OWASP 非营利性开源社区 计算机标准化组织 术语俗话 --- POSIX 就是 Unix 世界的"普通话",大家说同一种语言就能互相理解。 我的数字生活唯一选择 软件开发 --- 安卓开发 之 命名空间隔离 术语俗话 --- 页面对齐、 跨页 计算机的哪些人 --- 社交之王 马克·扎克伯格 计算机的哪些人 --- 重新定义新能源 之 埃隆·马斯克 软件研发 --- AI生成ppt word excel pdf的开发关键 软件研发 --- AI应用开发 之 AI生成Word 人生感悟 --- 致可悲的人 - GKLBB 软件研发 --- pdf 表格图片 转 excel 常见问题解决 --- 装有系统的固态硬盘错误 人生感悟 --- 什么是行业黑话 术语俗话 --- Kubernetes 术语俗话 --- 什么是DBI,和hook什么区别 答疑解惑 --- 为什么苹果手机电池不允许拆卸 代码可视化技术 术语俗话 --- Wrap 函数 人生感悟 --- 逆向工程为什么十分枯燥且无聊 --- 这里引用一句逆向工程核心原理的话 人生感悟 --- 为什么干活时不见同事,活干完了就来了 软件研发 --- AI应用研发 之 提炼提示词 软件研发 --- AI应用开发 之 AI生成PPT最佳方案 基于屏幕-摄像头的单向数据传输方案设计 俗语俗话 --- 纯虚函数 硬件研发 --- 产品介绍 之 AX6 硬件研发 --- 产品大全 之 SUMAVISION CM50X 应知应会 --- 为什么U盘不识别但是还是可以数据恢复回来 应知应会 --- 为什么我删除了一个文件但是还是可以恢复回来 软件研发 --- AI UI设计 之 PC端效果比对 常见问题修复 --- chrome浏览器白屏 应用安全 --- 逆向工程 之 C++类的本质 软件研发 --- AI提示词开发 之 代码注释提示词 dobby反编译 https://www.cnblogs.com/Un1corn/p/18615567 应知应会 --- 手机作为热点,windows电脑临时作为网关,给其他电脑上网 应知应会 --- 大量小文件如何快速迁移 常见问题解决 --- apk安装过程中闪退 应用安全 --- 安卓逆向 之 dobby框架 在线生成 APK 图标工具推荐 一个开源库 术语俗话 --- 什么是软件即服务 软件神器 --- 常用谷歌插件 应用安全 --- 逆向技巧 之 识别未知函数 人生感悟 --- 为什么两句话可以说明白的事情要500字说明 软件研发 --- Dify 生成 PPT 方案分析 应用安全 --- 逆向技巧 之 IDA未知函数如何识别 https://yuuki.cool/ 应用安全 --- 逆向技巧 之 ELF节(Section) 与 段(Segment) 硬件研发 --- 接口 人生感悟 --- 为什么ld一直爱开会 应用安全 --- 逆向技巧 之 IDA和claude反编译缺陷 应用安全 --- 逆向技巧 之 ida反编译yahfa的so和源码的差异化比对
应用安全 --- IDA签名 之 Sig文件解析
GKLBB · 2026-06-14 · via 博客园 - GKLBB

010editor模板解析

//------------------------------------------------
//--- 010 Editor Binary Template
// File:     FLIRT_SIG_full_010Editor.bt
// Version:  1.1 (adaptive color styles)
// Purpose:  Parse IDA FLIRT IDASGN signature files (v5-v10)
// Notes:    Parses uncompressed Trie bodies. If FEATURE_COMPRESSED is set,
//           the compressed body is mapped as raw zlib payload and must be
//           decompressed externally before the Trie can be expanded.
// Colors:   Uses adaptive Template Styles (010 Editor v14+).
// File Mask: *.sig
// ID Bytes:  49 44 41 53 47 4E
//------------------------------------------------

LittleEndian();

// -----------------------------------------------------------------------------
// Adaptive color legend (010 Editor v14+)
// -----------------------------------------------------------------------------
// sHeading1 : FLIRT file header
// sSection1 : Trie nodes and pattern bytes
// sSection2 : Leaf module groups and CRC data
// sSection3 : Public function records and names
// sSection4 : Referenced function records and names
// sMarker   : Tail-byte constraints
// sData     : Generic variable-length integer payloads
// Accent variants highlight key bytes inside each category.
// Styles automatically adapt to light/dark themes and can be customized under
// Theme/Color Options -> Template Styles.

// -----------------------------------------------------------------------------
// Constants
// -----------------------------------------------------------------------------
#define FEATURE_STARTUP             0x0001
#define FEATURE_CTYPE_CRC           0x0002
#define FEATURE_2BYTE_CTYPE         0x0004
#define FEATURE_ALT_CTYPE_CRC       0x0008
#define FEATURE_COMPRESSED          0x0010

#define PF_MORE_PUBLIC_NAMES        0x01
#define PF_READ_TAIL_BYTES          0x02
#define PF_READ_REFERENCED_FUNCS    0x04
#define PF_MORE_MODULES_SAME_CRC    0x08
#define PF_MORE_MODULES             0x10

#define FF_LOCAL                    0x02
#define FF_UNRESOLVED_COLLISION     0x08

#define MAX_NODE_LEN                0x40
#define MAX_SCAN_NAME               4096
#define MAX_REASONABLE_COUNT        1000000

// -----------------------------------------------------------------------------
// Global statistics
// -----------------------------------------------------------------------------
local uint32 g_nodes       = 0;
local uint32 g_leaves      = 0;
local uint32 g_modules     = 0;
local uint32 g_publics     = 0;
local uint32 g_tails       = 0;
local uint32 g_refs        = 0;
local uint32 g_max_depth   = 0;
local int    g_verbose     = 1; // 0=summary, 1=node/module summary, 2=verbose

// -----------------------------------------------------------------------------
// Utility functions
// -----------------------------------------------------------------------------
string Indent(int depth) {
    local string s;
    local int i;
    s = "";
    if (depth > 48) depth = 48;
    for (i = 0; i < depth; i++) s += "  ";
    return s;
}

uint64 PopCount64(uint64 v) {
    local uint64 n;
    n = 0;
    while (v != 0) {
        n += (v & 1);
        v >>= 1;
    }
    return n;
}

string BytesToText(int64 pos, uint64 len, int strip_final_nul) {
    local string out;
    local string tmp;
    local uint64 i;
    local ubyte b;
    out = "";
    if (strip_final_nul && len > 0 && ReadUByte(pos + len - 1) == 0)
        len--;
    for (i = 0; i < len; i++) {
        b = ReadUByte(pos + i);
        if (b >= 0x20 && b <= 0x7E) {
            SPrintf(tmp, "%c", b);
        } else {
            SPrintf(tmp, "\\x%02X", b);
        }
        out += tmp;
    }
    return out;
}

int ScanUntilControl(int64 pos) {
    local int n;
    local ubyte b;
    n = 0;
    while ((pos + n) < FileSize() && n < MAX_SCAN_NAME) {
        b = ReadUByte(pos + n);
        if (b < 0x20) break;
        n++;
    }
    if (n == MAX_SCAN_NAME)
        Warning("FLIRT name scan reached MAX_SCAN_NAME; file may be malformed.");
    return n;
}

string PatternText(int node_len, uint64 variant_mask, int64 concrete_pos) {
    local string out;
    local string tmp;
    local int i;
    local int j;
    local uint64 bit;
    out = "";
    j = 0;
    for (i = 0; i < node_len; i++) {
        bit = ((uint64)1 << (node_len - 1 - i));
        if ((variant_mask & bit) != 0) {
            out += "..";
        } else {
            SPrintf(tmp, "%02X", ReadUByte(concrete_pos + j));
            out += tmp;
            j++;
        }
        if (i + 1 < node_len) out += " ";
    }
    return out;
}

// -----------------------------------------------------------------------------
// FLIRT variable-length integer encodings
// -----------------------------------------------------------------------------
// read_multiple_bytes():
//   0xxxxxxx                                  -> 1 byte
//   10xxxxxx xxxxxxxx                         -> 2 bytes
//   110xxxxx xxxxxxxx xxxxxxxx xxxxxxxx       -> 4 bytes
//   111xxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx -> 5 bytes
// The 4-byte form contributes only six bits from b0, matching public parsers.
// -----------------------------------------------------------------------------
typedef struct {
    ubyte b0 <format=hex, style=sDataAccent>;
    if ((b0 & 0x80) == 0) {
        // one-byte encoding
    } else if ((b0 & 0xC0) != 0xC0) {
        ubyte b1_2 <format=hex, style=sData>;
    } else if ((b0 & 0xE0) != 0xE0) {
        ubyte b1_4 <format=hex, style=sData>;
        ubyte b2_4 <format=hex, style=sData>;
        ubyte b3_4 <format=hex, style=sData>;
    } else {
        ubyte b1_5 <format=hex, style=sData>;
        ubyte b2_5 <format=hex, style=sData>;
        ubyte b3_5 <format=hex, style=sData>;
        ubyte b4_5 <format=hex, style=sData>;
    }
} VLI_MULTI <read=FmtVLIMulti, style=sData>;

uint64 GetVLIMulti(VLI_MULTI &v) {
    if ((v.b0 & 0x80) == 0)
        return v.b0;
    if ((v.b0 & 0xC0) != 0xC0)
        return (((uint64)(v.b0 & 0x7F)) << 8) | v.b1_2;
    if ((v.b0 & 0xE0) != 0xE0)
        return (((uint64)(v.b0 & 0x3F)) << 24) |
               (((uint64)v.b1_4) << 16) |
               (((uint64)v.b2_4) << 8)  |
               ((uint64)v.b3_4);
    return (((uint64)v.b1_5) << 24) |
           (((uint64)v.b2_5) << 16) |
           (((uint64)v.b3_5) << 8)  |
           ((uint64)v.b4_5);
}

string FmtVLIMulti(VLI_MULTI &v) {
    local string s;
    SPrintf(s, "%Lu (0x%LX)", GetVLIMulti(v), GetVLIMulti(v));
    return s;
}

// Legacy compact integer used by v5-v8 offsets.
typedef struct {
    ubyte b0 <format=hex, style=sDataAccent>;
    if ((b0 & 0x80) != 0)
        ubyte b1 <format=hex, style=sData>;
} VLI_MAX2 <read=FmtVLIMax2, style=sData>;

uint64 GetVLIMax2(VLI_MAX2 &v) {
    if ((v.b0 & 0x80) == 0)
        return v.b0;
    return (((uint64)(v.b0 & 0x7F)) << 8) | v.b1;
}

string FmtVLIMax2(VLI_MAX2 &v) {
    local string s;
    SPrintf(s, "%Lu (0x%LX)", GetVLIMax2(v), GetVLIMax2(v));
    return s;
}

// v9-v10 use read_multiple_bytes() for offsets and lengths; older versions
// use the compact one/two-byte encoding.
struct ENCODED_VALUE (int version) {
    if (version >= 9)
        VLI_MULTI multi <style=sData>;
    else
        VLI_MAX2 legacy <style=sData>;
};

uint64 GetEncodedValue(ENCODED_VALUE &v, int version) {
    if (version >= 9)
        return GetVLIMulti(v.multi);
    return GetVLIMax2(v.legacy);
}

// -----------------------------------------------------------------------------
// Header
// -----------------------------------------------------------------------------
typedef struct {
    char   magic[6] <style=sHeading1Accent>;
    ubyte  version <style=sHeading1Accent>;
    ubyte  arch <style=sHeading1Accent>;
    uint32 file_types <format=hex, style=sHeading1>;
    uint16 os_types <format=hex, style=sHeading1>;
    uint16 app_types <format=hex, style=sHeading1>;
    uint16 features <format=hex, style=sHeading1Accent>;
    uint16 old_n_functions <style=sHeading1>;
    uint16 header_crc16 <format=hex, style=sHeading1Accent>;
    ubyte  ctype[12] <format=hex, style=sHeading1>;
    ubyte  library_name_len <style=sHeading1Accent>;
    uint16 ctypes_crc16 <format=hex, style=sHeading1Accent>;
    if (version >= 6)
        uint32 n_functions <style=sHeading1>;
    if (version >= 8)
        uint16 pattern_size <style=sHeading1>;
    if (version > 9)
        uint16 unknown_v10 <format=hex, style=sHeading1>;
} FLIRT_HEADER <read=FmtHeader, style=sHeading1>;

string ArchName(ubyte arch) {
    local string s;
    switch (arch) {
        case 0:  return "x86";
        case 12: return "MIPS";
        case 13: return "ARM";
        case 15: return "PowerPC";
        case 19: return ".NET";
        case 23: return "SPARC";
        case 31: return "IA64";
        case 60: return "Dalvik";
        default:
            SPrintf(s, "arch_%u", arch);
            return s;
    }
}

uint32 HeaderFunctionCount(FLIRT_HEADER &h) {
    if (h.version >= 6) return h.n_functions;
    return h.old_n_functions;
}

string FmtHeader(FLIRT_HEADER &h) {
    local string s;
    SPrintf(s, "IDASGN v%u arch=%s funcs=%u features=0x%04X",
            h.version, ArchName(h.arch), HeaderFunctionCount(h), h.features);
    return s;
}

// -----------------------------------------------------------------------------
// Leaf records: public names, tail bytes and referenced functions
// -----------------------------------------------------------------------------
struct PUBLIC_FUNCTION (int version) {
    ENCODED_VALUE offset_delta(version) <style=sSection3Accent>;

    local ubyte probe;
    local int64 name_pos;
    local int name_len;
    local ubyte meta_value;

    probe = ReadUByte(FTell());
    meta_value = 0;
    if (probe < 0x20) {
        ubyte function_flags <format=hex, style=sSection3Accent,
            comment="Optional metadata: bit1=local/static, bit3=unresolved collision">;
        meta_value = function_flags;
    }

    name_pos = FTell();
    name_len = ScanUntilControl(name_pos);
    if (name_len > 0)
        char name[name_len] <style=sSection3Accent>;

    // The first control byte after the name is not a NUL terminator in the
    // general case. It is the module parsing flag byte.
    ubyte parse_flags <format=hex, style=sSection3Accent,
        comment="bit0=more public names, bit1=tail bytes, bit2=refs, bit3=more same CRC, bit4=more CRC groups">;
};

string PublicName(PUBLIC_FUNCTION &f) {
    return BytesToText(f.name_pos, f.name_len, 0);
}

struct TAIL_BYTE (int version) {
    ENCODED_VALUE relative_offset(version) <style=sMarker>;
    ubyte value <format=hex, style=sMarkerAccent>;
};

struct TAIL_LIST (int version) {
    local uint32 i;
    local uint32 count;
    count = 1;
    if (version >= 8) {
        ubyte count_u8 <style=sMarkerAccent>;
        count = count_u8;
    }
    for (i = 0; i < count; i++) {
        TAIL_BYTE tail(version) <style=sMarker>;
        g_tails++;
    }
};

struct REFERENCED_FUNCTION (int version) {
    ENCODED_VALUE relative_offset(version) <style=sSection4>;
    ubyte short_name_len <style=sSection4Accent>;

    local uint64 full_name_len;
    local int64 name_pos;
    local int negative_offset;

    full_name_len = short_name_len;
    if (short_name_len == 0) {
        VLI_MULTI extended_name_len <style=sSection4Accent>;
        full_name_len = GetVLIMulti(extended_name_len);
    }

    if (full_name_len > MAX_SCAN_NAME)
        Warning("Referenced function name is unusually long; file may be malformed.");

    name_pos = FTell();
    if (full_name_len > 0)
        ubyte raw_name[full_name_len] <style=sSection4Accent>;

    negative_offset = (full_name_len > 0 && ReadUByte(name_pos + full_name_len - 1) == 0);
};

string ReferencedName(REFERENCED_FUNCTION &f) {
    return BytesToText(f.name_pos, f.full_name_len, f.negative_offset);
}

struct REFERENCED_LIST (int version) {
    local uint32 i;
    local uint32 count;
    count = 1;
    if (version >= 8) {
        ubyte count_u8 <style=sSection4Accent>;
        count = count_u8;
    }
    for (i = 0; i < count; i++) {
        REFERENCED_FUNCTION ref(version) <style=sSection4>;
        g_refs++;
        if (g_verbose >= 2) {
            Printf("      [REF] off=0x%LX name=%s%s\n",
                   GetEncodedValue(ref.relative_offset, version),
                   ReferencedName(ref),
                   ref.negative_offset ? " (negative offset)" : "");
        }
    }
};

struct MODULE (int version, ubyte crc_length, uint16 crc16_value, int depth) {
    local string ind;
    local int more_public;
    local uint64 running_offset;
    local ubyte terminal_flags;

    ind = Indent(depth);
    ENCODED_VALUE module_length(version) <style=sSection2Accent>;

    g_modules++;
    if (g_verbose >= 1) {
        Printf("%s[MODULE #%u] crc_len=%u crc16=0x%04X module_len=0x%LX\n",
               ind, g_modules, crc_length, crc16_value,
               GetEncodedValue(module_length, version));
    }

    running_offset = 0;
    terminal_flags = 0;
    more_public = 1;
    while (more_public && !FEof()) {
        PUBLIC_FUNCTION public_fn(version) <style=sSection3>;
        running_offset += GetEncodedValue(public_fn.offset_delta, version);
        terminal_flags = public_fn.parse_flags;
        g_publics++;

        if (g_verbose >= 1) {
            Printf("%s  [PUBLIC #%u] +0x%LX flags=0x%02X meta=0x%02X name=%s\n",
                   ind, g_publics, running_offset,
                   public_fn.parse_flags, public_fn.meta_value,
                   PublicName(public_fn));
        }

        more_public = ((terminal_flags & PF_MORE_PUBLIC_NAMES) != 0);
    }

    if ((terminal_flags & PF_READ_TAIL_BYTES) != 0)
        TAIL_LIST tails(version) <style=sMarker>;
    if ((terminal_flags & PF_READ_REFERENCED_FUNCS) != 0)
        REFERENCED_LIST refs(version) <style=sSection4>;

    local ubyte final_parse_flags;
    final_parse_flags = terminal_flags;
};

struct MODULE_GROUP (int version, int depth) {
    local string ind;
    local uint16 crc16_value;
    local int more_same_crc;
    local ubyte last_flags;

    ind = Indent(depth);
    ubyte crc_length <style=sSection2Accent>;
    ubyte crc16_hi <format=hex, style=sSection2>;
    ubyte crc16_lo <format=hex, style=sSection2>;
    crc16_value = (((uint16)crc16_hi) << 8) | crc16_lo;

    more_same_crc = 1;
    last_flags = 0;
    while (more_same_crc && !FEof()) {
        MODULE module(version, crc_length, crc16_value, depth) <style=sSection2>;
        last_flags = module.final_parse_flags;
        more_same_crc = ((last_flags & PF_MORE_MODULES_SAME_CRC) != 0);
    }

    local int more_crc_groups;
    more_crc_groups = ((last_flags & PF_MORE_MODULES) != 0);
};

struct MODULE_LIST (int version, int depth) {
    local int more_groups;
    more_groups = 1;
    while (more_groups && !FEof()) {
        MODULE_GROUP group(version, depth) <style=sSection2>;
        more_groups = group.more_crc_groups;
    }
};

// -----------------------------------------------------------------------------
// Trie nodes
// -----------------------------------------------------------------------------
struct FLIRT_NODE;

struct FLIRT_NODE (int version, int is_root, int depth, uint32 prefix_len) {
    local string ind;
    local uint64 variant_mask;
    local uint64 fixed_count;
    local int64 concrete_pos;
    local uint64 child_count_value;
    local uint32 i;

    ind = Indent(depth);
    if ((uint32)depth > g_max_depth) g_max_depth = depth;
    g_nodes++;

    variant_mask = 0;
    fixed_count = 0;
    concrete_pos = FTell();

    if (!is_root) {
        ubyte node_length <style=sSection1Accent>;
        if (node_length > MAX_NODE_LEN)
            Warning("FLIRT node length is greater than 64; parser will continue conservatively.");

        if (node_length < 0x10) {
            VLI_MAX2 variant_mask_short <style=sSection1>;
            variant_mask = GetVLIMax2(variant_mask_short);
        } else if (node_length <= 0x20) {
            VLI_MULTI variant_mask_low <style=sSection1>;
            variant_mask = GetVLIMulti(variant_mask_low);
        } else if (node_length <= 0x40) {
            VLI_MULTI variant_mask_high <style=sSection1>;
            VLI_MULTI variant_mask_low <style=sSection1>;
            variant_mask = (GetVLIMulti(variant_mask_high) << 32) |
                           GetVLIMulti(variant_mask_low);
        }

        fixed_count = node_length - PopCount64(variant_mask);
        concrete_pos = FTell();
        if (fixed_count > 0)
            ubyte concrete_bytes[fixed_count] <format=hex, style=sSection1Accent>;

        if (g_verbose >= 1) {
            Printf("%s[NODE #%u] depth=%u segment=%u prefix=%u mask=0x%LX fixed=%Lu pattern=%s\n",
                   ind, g_nodes, depth, node_length, prefix_len + node_length,
                   variant_mask, fixed_count,
                   PatternText(node_length, variant_mask, concrete_pos));
        }

        prefix_len += node_length;
    } else if (g_verbose >= 1) {
        Printf("[ROOT NODE]\n");
    }

    VLI_MULTI child_count <style=sSection1Accent>;
    child_count_value = GetVLIMulti(child_count);

    if (child_count_value > MAX_REASONABLE_COUNT)
        Warning("Unreasonable FLIRT child count; file may be malformed.");

    if (child_count_value == 0) {
        g_leaves++;
        if (g_verbose >= 1)
            Printf("%s[LEAF #%u] prefix=%u\n", ind, g_leaves, prefix_len);
        MODULE_LIST modules(version, depth + 1) <style=sSection2>;
    } else {
        for (i = 0; i < child_count_value; i++)
            FLIRT_NODE child(version, 0, depth + 1, prefix_len) <style=sSection1>;
    }
};

// -----------------------------------------------------------------------------
// Main
// -----------------------------------------------------------------------------
Printf("============================================================\n");
Printf("IDA FLIRT IDASGN parser for 010 Editor\n");
Printf("============================================================\n");

FLIRT_HEADER hdr <style=sHeading1>;

if (Strncmp(hdr.magic, "IDASGN", 6) != 0) {
    Warning("Not an IDASGN FLIRT signature file.");
} else if (hdr.version < 5 || hdr.version > 10) {
    Warning("Unsupported FLIRT signature version. Expected v5-v10.");
} else {
    char library_name[hdr.library_name_len] <style=sHeading1Accent>;

    Printf("[HEADER] version       : %u\n", hdr.version);
    Printf("[HEADER] architecture  : %s (%u)\n", ArchName(hdr.arch), hdr.arch);
    Printf("[HEADER] file types    : 0x%08X\n", hdr.file_types);
    Printf("[HEADER] os types      : 0x%04X\n", hdr.os_types);
    Printf("[HEADER] app types     : 0x%04X\n", hdr.app_types);
    Printf("[HEADER] features      : 0x%04X\n", hdr.features);
    Printf("[HEADER] functions     : %u\n", HeaderFunctionCount(hdr));
    if (hdr.version >= 8)
        Printf("[HEADER] pattern size  : %u\n", hdr.pattern_size);
    Printf("[HEADER] library name  : %s\n", BytesToText(startof(library_name), hdr.library_name_len, 0));
    Printf("[BODY]   starts at     : 0x%LX\n", FTell());

    if ((hdr.features & FEATURE_COMPRESSED) != 0) {
        ubyte compressed_zlib_payload[FileSize() - FTell()] <format=hex, style=sMarkerAccent,
            comment="Compressed zlib Trie body. Decompress externally before expanding Trie records.">;
        Warning("FEATURE_COMPRESSED is set. Header is parsed, but the Trie body remains zlib-compressed.");
    } else {
        FLIRT_NODE root(hdr.version, 1, 0, 0) <style=sSection1>;

        Printf("============================================================\n");
        Printf("[SUMMARY] nodes        : %u\n", g_nodes);
        Printf("[SUMMARY] leaves       : %u\n", g_leaves);
        Printf("[SUMMARY] modules      : %u\n", g_modules);
        Printf("[SUMMARY] public names : %u\n", g_publics);
        Printf("[SUMMARY] tail bytes   : %u\n", g_tails);
        Printf("[SUMMARY] references   : %u\n", g_refs);
        Printf("[SUMMARY] max depth    : %u\n", g_max_depth);
        Printf("[SUMMARY] final offset : 0x%LX / 0x%LX\n", FTell(), FileSize());
        if (FTell() != FileSize())
            Warning("The template did not consume the full file. Check version, compression flag or malformed data.");
    }
}

已完成。你上传的原模板对这个单函数样本能够“读出部分内容”,但有四处基础假设不正确:文件头字段错位、VLI 规则不完整、Trie 被当成固定 32 字节原始模式、叶子记录被简化为固定结构。遇到多分支 Trie、通配掩码、多个模块、尾部字节、引用函数或压缩 .sig 时,会发生连续错位。

可直接使用的文件

下载优化后的 010 Editor 模板:FLIRT_SIG_full_010Editor.bt

下载压缩体展开辅助脚本:flirt_sig_expand.py

下载由粘贴字节还原的示例文件:Unnamed_sample_library.sig

新版模板按照公开实现中的 FLIRT 结构重新整理,覆盖未压缩 v5–v10 .sig:完整文件头、不同长度的变长整数、递归 Trie、通配掩码、CRC 分组、模块长度、公开函数名、局部函数标记、冲突标记、尾部字节和引用函数列表。公开解析实现同样将树节点、模块与函数信息分层解析,而不是将 Trie 直接当作“32 字节模式 + 固定叶子”。(GitHub)

你的样本实际解析结果

偏移元素解析值
0x00 魔数 IDASGN
0x06 格式版本 0x0A,即 v10
0x07 处理器架构 0x00
0x08 文件类型掩码 0xFFFFFFFF
0x0C 操作系统掩码 0xFFFF
0x0E 应用类型掩码 0xFFFF
0x10 特征标志 0x0000,未压缩
0x12 旧版函数计数 0
0x14 头部 CRC16 0x0000
0x16 C 类型区 12 字节全零
0x22 库名长度 0x16,即 22 字节
0x23 C 类型 CRC16 0x0000
0x25 函数总数 1
0x29 最大模式长度 0x0020,即 32 字节
0x2B v10 扩展字段 0x0000
0x2D 库名 Unnamed sample library
0x43 根节点子节点数量 1
0x44 子节点模式长度 0x20,即 32 字节
0x45 通配掩码编码 C0 78 0F 000x00780F00
0x49 实际存储的确定字节 24 字节
0x61 当前节点子节点数量 0,说明进入叶子模块
0x62 CRC 覆盖长度 0
0x63 CRC16 0x0000
0x65 函数长度 0x24,即 36 字节
0x66 函数偏移增量 0
0x67 函数名称 Rust 符号名
0xC4 解析标志 0x00,记录结束
0xC5 最终位置 与文件总长度完全一致,无残余字节

完整恢复后的 32 字节模式为:

49 89 D0 0F B6 01 48 8D 0D .. .. .. .. 48 8B 14
C1 4C 8D 0D .. .. .. .. 49 63 0C 81 4C 01 C9 E9

其中 .. 是通配字节。你的原模板把 C0 78 0F 00 和后面的内容误认为模式本体的一部分,根本原因是没有解析节点通配掩码。FLIRT 的设计目标是从函数开头构建可匹配的签名,并允许将容易变化的字节排除出稳定模式;Hex-Rays 的官方说明也强调了函数签名匹配和变体字节处理的重要性。(docs.hex-rays.com)

原模板中需要修正的关键点

1. 库名长度不是 uint32

你的模板中使用了:

uint32 library_name_len;

对于这个 v10 样本,正确字段是单字节:

uchar library_name_len;

因此固定头部在库名之前共 45 字节,库名从 0x2D 开始。原结构会将后续字段吞入长度值,使 Trie 起始位置整体错位。

2. VLI 不是简单的 1、2、3、5 字节规则

正确的多字节 VLI 读取逻辑需要按照首字节高位分支处理。公开实现中,第三种编码占用 4 字节,而不是原模板中的 3 字节。通配掩码 C0 78 0F 00 正是这类编码的直接例子。(GitHub)

3. Trie 节点不是直接存储完整模式

当前样本中:

01             根节点有 1 个子节点
20             节点模式长度为 32
C0 78 0F 00    通配掩码
...            仅保存非通配位置的 24 个确定字节
00             节点没有下一层子节点,进入模块记录

新版模板会递归解析节点,并将缺失位置恢复为 ..。010 Editor 的模板语言支持递归结构和带参数结构,因此可以将 Trie 作为真正的树形结构显示。(Sweetscape)

4. 叶子并非固定六字节头部

叶子区域实际由 CRC 分组、模块记录、公开函数记录和可选扩展信息组成。名称后面的控制字节决定是否还存在:

含义
0x01 同一模块还有公开函数名
0x02 存在尾部字节信息
0x04 存在引用函数信息
0x08 同一 CRC 分组还有模块
0x10 还有后续 CRC 分组

新版模板会根据这些标志继续推进,不再依赖函数名后的固定布局。(GitHub)

使用方式

在 010 Editor 中打开 .sig 文件,然后运行下载的模板:

Templates → Run Template

选择:

FLIRT_SIG_full_010Editor.bt

模板会在结果树中展示 Header、Library Name、Trie Root、递归 Node、CRC Group、Module、Public Function、Tail Bytes 和 Referenced Functions。

遇到压缩 .sig

FLIRT 的特征标志 0x0010 表示 Trie 数据经过压缩。新版模板会识别并提示,不会将压缩流误解析为节点。公开解析实现同样先检查压缩特征位,再对后续数据解压。(GitHub)

010 Editor 模板环境不适合直接将解压后的字节数组重新作为完整二进制流递归映射,因此附带了一个展开脚本。010 Editor 社区讨论中也提到,模板内部直接处理解压字节流存在限制,通常需要借助外部处理步骤。(010 Editor Forum)

运行:

python flirt_sig_expand.py input.sig input.expanded.sig

再使用模板打开:

input.expanded.sig

辅助脚本会保留原文件头和库名,展开压缩 Trie,并清除压缩标志。该脚本已经用当前样本构造的压缩版本完成往返校验。

校验说明

我使用与模板相同的解析逻辑,对你粘贴的 197 字节样本进行了逐字段验证:解析从 0x00 开始,在 0xC5 精确结束,没有残余字节,也没有越界读取。当前运行环境没有安装 010 Editor,因此无法在软件界面内执行最终编译测试;若 010 Editor 对某一行提示语法错误,将 Output 中的具体行号和报错文本贴出即可继续收敛。

免责声明 本文档所有内容仅供安全研究、学术交流与技术学习使用,严禁用于任何未经授权的逆向破解、网络攻击、隐私窃取、恶意软件开发及其他违反《中华人民共和国网络安全法》《数据安全法》等法律法规的行为,使用者应确保已获得目标软件权利人的合法授权并自行承担因使用本文档内容所产生的一切法律责任与后果,作者不对任何直接或间接损害承担任何责任,继续阅读即视为您已知悉并同意上述全部条款。