Mani Srivastava

66 papers A* 2A 2B 2C 1Misc 8Journal 39Unranked 9
YearRankTypeTitle / Venue / Authors
2026 J jnl
CoRR
Sadik Yagiz Yetim, Gaofeng Dong, Isaac-Neil Zanoria, Ronit Barman, Maggie B. Wigness, Tarek F. Abdelzaher, Mani Srivastava, Suhas N. Diggavi
2025 J jnl
IEEE Internet Comput.
David Irwin, Prashant J. Shenoy, Mohammad Hajiesmaili, Walid A. Hanafy, Jimi Oke, Ramesh K. Sitaraman, Yuvraj Agarwal, Geoffrey J. Gordon, Zico Kolter, Deepak Rajagopal, Mani Srivastava, Vivienne Sze, Priya L. Donti, Andrew A. Chien, John R. Birge, Ali Hortaçsu, Line Roald
2025 J jnl
CoRR
Jason Wu, Kang Yang, Lance M. Kaplan, Mani Srivastava
2025 J jnl
ACM Trans. Sens. Networks
Shakhrul Iman Siam, Hyunho Ahn, Li Liu, Samiul Alam, Hui Shen, Zhichao Cao, Ness B. Shroff, Bhaskar Krishnamachari, Mani Srivastava, Mi Zhang
2025 J jnl
CoRR
Pengrui Quan, Brian Wang, Kang Yang, Liying Han, Mani Srivastava
2025 J jnl
CoRR
Ozan Baris Mulayim, Pengrui Quan, Liying Han, Xiaomin Ouyang, Dezhi Hong, Mario Bergés, Mani Srivastava
2025 J jnl
CoRR
Diptyaroop Maji, Kang Yang, Prashant J. Shenoy, Ramesh K. Sitaraman, Mani Srivastava
2025 Misc conf
SenSys
Iris Nguyen, Liying Han, Burke Dambly, Alireza Kazemi, Marina Kogan, Cory S. Inman, Mani Srivastava, Luis Garcia
2025 J jnl
CoRR
Hetvi Shastri, Pragya Sharma, Walid A. Hanafy, Mani Srivastava, Prashant J. Shenoy
2025 J jnl
CoRR
Ozan Baris, Yizhuo Chen, Gaofeng Dong, Liying Han, Tomoyoshi Kimura, Pengrui Quan, Ruijie Wang, Tianchen Wang, Tarek F. Abdelzaher, Mario Bergés, Paul Pu Liang, Mani Srivastava
2025 A* conf
WWW
Tomoyoshi Kimura, Xinlin Li, Osama A. Hanna, Yatong Chen, Yizhuo Chen, Denizhan Kara, Tianshi Wang, Jinyang Li, Xiaomin Ouyang, Shengzhong Liu, Mani Srivastava, Suhas N. Diggavi, Tarek F. Abdelzaher
2025 J jnl
CoRR
Tomoyoshi Kimura, Xinlin Li, Osama A. Hanna, Yatong Chen, Yizhuo Chen, Denizhan Kara, Tianshi Wang, Jinyang Li, Xiaomin Ouyang, Shengzhong Liu, Mani Srivastava, Suhas N. Diggavi, Tarek F. Abdelzaher
2025 Misc conf
SEC
Hetvi Shastri, Walid A. Hanafy, Li Wu, David Irwin, Mani Srivastava, Prashant J. Shenoy
2025 J jnl
CoRR
Hetvi Shastri, Walid A. Hanafy, Li Wu, David Irwin, Mani Srivastava, Prashant J. Shenoy
2025 Misc conf
SenSys
Xiaomin Ouyang, Jason Wu, Tomoyoshi Kimura, Yihan Lin, Gunjan Verma, Tarek F. Abdelzaher, Mani Srivastava
2025 conf
HumanSys@SenSys
Ziqi Wang, Derek Hua, Wenjun Jiang, Tianwei Xing, Xun Chen, Mani Srivastava
2025 J jnl
CoRR
Ziqi Wang, Derek Hua, Wenjun Jiang, Tianwei Xing, Xun Chen, Mani Srivastava
2025 J jnl
CoRR
Liying Han, Gaofeng Dong, Xiaomin Ouyang, Lance M. Kaplan, Federico Cerutti, Mani Srivastava
2025 Misc conf
SenSys
Hetvi Shastri, Walid A. Hanafy, Li Wu, David Irwin, Mani Srivastava, Prashant J. Shenoy
2025 Misc conf
SenSys
Kang Yang, Wan Du, Mani Srivastava
2025 conf
ACL (Findings)
Xinzhe Zheng, Sijie Ji, Jiawei Sun, Renqi Chen, Wei Gao, Mani Srivastava
2025 J jnl
CoRR
Xinzhe Zheng, Sijie Ji, Jiawei Sun, Renqi Chen, Wei Gao, Mani Srivastava
2025 J jnl
CoRR
Brian Wang, Mani Srivastava
2025 J jnl
CoRR
Kang Yang, Gaofeng Dong, Sijie Ji, Wan Du, Mani Srivastava
2025 Misc conf
HotMobile
Pengrui Quan, Xiaomin Ouyang, Jeya Vikranth Jeyakumar, Ziqi Wang, Yang Xing, Mani Srivastava
2025 J jnl
CoRR
Oliver Wang, Pengrui Quan, Kang Yang, Mani Srivastava
2025 J jnl
CoRR
Liying Han, Gaofeng Dong, Xiaomin Ouyang, Lance M. Kaplan, Federico Cerutti, Mani Srivastava
2025 Misc conf
SenSys
Sijie Ji, Xinzhe Zheng, Wei Gao, Mani Srivastava
2025 B conf
RO-MAN
Marc Roig Vilamala, Jack Furby, Julian de Gortari Briseno, Mani Srivastava, Alun D. Preece, Carolina Fuentes
2025 J jnl
CoRR
Gaofeng Dong, Kang Yang, Mani Srivastava
2024 conf
MILCOM
Brian Wang, Julian de Gortari Briseno, Liying Han, Henry Phillips, Jeffrey Craighead, Ben Purman, Lance M. Kaplan, Mani Srivastava
2024 J jnl
CoRR
Marc Roig Vilamala, Jack Furby, Julian de Gortari Briseno, Mani Srivastava, Alun D. Preece, Carolina Fuentes Toro
2024 conf
BuildSys
Ozan Baris Mulayim, Pengrui Quan, Liying Han, Xiaomin Ouyang, Dezhi Hong, Mario Bergés, Mani Srivastava
2024 J jnl
CoRR
Shakhrul Iman Siam, Hyunho Ahn, Li Liu, Samiul Alam, Hui Shen, Zhichao Cao, Ness B. Shroff, Bhaskar Krishnamachari, Mani Srivastava, Mi Zhang
2024 J jnl
CoRR
Huatao Xu, Panrong Tong, Mo Li, Mani Srivastava
2024 A conf
IROS
Jason Wu, Ziqi Wang, Xiaomin Ouyang, Ho Lyun Jeong, Colin Samplawski, Lance M. Kaplan, Benjamin M. Marlin, Mani Srivastava
2024 J jnl
CoRR
Jason Wu, Ziqi Wang, Xiaomin Ouyang, Ho Lyun Jeong, Colin Samplawski, Lance M. Kaplan, Benjamin M. Marlin, Mani Srivastava
2024 J jnl
CoRR
Ho Lyun Jeong, Ziqi Wang, Colin Samplawski, Jason Wu, Shiwei Fang, Lance M. Kaplan, Deepak Ganesan, Benjamin M. Marlin, Mani Srivastava
2024 J jnl
CoRR
Xiaomin Ouyang, Mani Srivastava
2024 J jnl
CoRR
Xiaomin Ouyang, Jason Wu, Tomoyoshi Kimura, Yihan Lin, Gunjan Verma, Tarek F. Abdelzaher, Mani Srivastava
2024 J jnl
CoRR
Sijie Ji, Xinzhe Zheng, Jiawei Sun, Renqi Chen, Wei Gao, Mani Srivastava
2024 J jnl
CoRR
Tomoyoshi Kimura, Jinyang Li, Tianshi Wang, Denizhan Kara, Yizhuo Chen, Yigong Hu, Ruijie Wang, Maggie B. Wigness, Shengzhong Liu, Mani Srivastava, Suhas N. Diggavi, Tarek F. Abdelzaher
2024 conf
ACL (Findings)
Huatao Xu, Liying Han, Qirui Yang, Mo Li, Mani Srivastava
2024 Misc conf
HotMobile
Huatao Xu, Liying Han, Qirui Yang, Mo Li, Mani Srivastava
2024 conf
SP (Workshops)
Brian Wang, Luis Antonio Garcia, Mani Srivastava
2024 A conf
MobiSys
Gaofeng Dong, Jason Wu, Julian de Gortari Briseno, Akash Deep Singh, Justin Feng, Ankur Sarker, Nader Sehatbakhsh, Mani Srivastava
2024 J jnl
CoRR
Pengrui Quan, Xiaomin Ouyang, Jeya Vikranth Jeyakumar, Ziqi Wang, Yang Xing, Mani Srivastava
2024 C conf
FUSION
Julian de Gortari Briseno, Roko Parac, Leo Ardon, Marc Roig Vilamala, Daniel Furelos-Blanco, Lance M. Kaplan, Vinod K. Mishra, Federico Cerutti, Alun D. Preece, Alessandra Russo, Mani Srivastava
2024 conf
CogMI
Tomoyoshi Kimura, Ashitabh Misra, Yizhuo Chen, Denizhan Kara, Jinyang Li, Tianshi Wang, Ruijie Wang, Joydeep Bhattacharyya, Jae Kim, Prashant J. Shenoy, Mani Srivastava, Maggie B. Wigness, Tarek F. Abdelzaher
2024 J jnl
ACM Trans. Embed. Comput. Syst.
Swapnil Sayan Saha, Sandeep Singh Sandha, Mohit Aggarwal, Brian Wang, Liying Han, Julian de Gortari Briseno, Mani Srivastava
2024 J jnl
CoRR
Akash Deep Singh, Brian Wang, Luis Garcia, Xiang Chen, Mani Srivastava
2023 conf
MetaCom
Tarek F. Abdelzaher, Matthew Caesar, Charith Mendis, Klara Nahrstedt, Mani Srivastava, Minlan Yu
2023 J jnl
Expert Syst. Appl.
Marc Roig Vilamala, Tianwei Xing, Harrison Taylor, Luis Garcia, Mani Srivastava, Lance M. Kaplan, Alun D. Preece, Angelika Kimmig, Federico Cerutti
2023 J jnl
Proc. ACM Interact. Mob. Wearable Ubiquitous Technol.
Xiaoying Yang, Xue Wang, Gaofeng Dong, Zihan Yan, Mani Srivastava, Eiji Hayashi, Yang Zhang
2023 J jnl
Intell. Syst. Appl.
Alice Toniolo, Federico Cerutti, Timothy J. Norman, Nir Oren, John A. Allen, Mani Srivastava, Paul Sullivan
2023 J jnl
CoRR
Huatao Xu, Liying Han, Mo Li, Mani Srivastava
2022 J jnl
Proc. ACM Interact. Mob. Wearable Ubiquitous Technol.
Swapnil Sayan Saha, Sandeep Singh Sandha, Siyou Pei, Vivek Jain, Ziqi Wang, Yuchen Li, Ankur Sarker, Mani Srivastava
2022 J jnl
ACM Trans. Priv. Secur.
Julian de Gortari Briseno, Akash Deep Singh, Mani Srivastava
2022 J jnl
Proc. ACM Interact. Mob. Wearable Ubiquitous Technol.
Swapnil Sayan Saha, Sandeep Singh Sandha, Luis Antonio Garcia, Mani Srivastava
2021 A* conf
KDD
Jian Zhang, Jian Tang, Yiran Chen, Jie Liu, Jieping Ye, Marilyn Wolf, Vijaykrishnan Narayanan, Mani Srivastava, Michael I. Jordan, Victor Bahl
2018 conf
SysTEX@CCS
Renju Liu, Mani Srivastava
2015 ed.
e-Energy
Shivkumar Kalyanaraman, Deva P. Seetharam, Rajeev Shorey, Sarvapali D. Ramchurn, Mani Srivastava
2014 B conf
DCOSS
Mani Srivastava
2014 ed.
BuildSys
Mani Srivastava
2012 ed.
HotPower
Mani Srivastava, Thomas F. Wenisch
1998 J jnl
IEEE Concurr.
Mani Srivastava
redb/ext/spoof_check.py
← Index redb/ext/spoof_check.py python
import copy
import struct
from enum import Enum

"""
Checks that the metadata within a file's Rich header does not contradict the
other metadata contained within it.

References:
    https://gist.github.com/skochinsky/07c8e95e33d9429d81a75622b5d24c8b
    https://www.sec.in.tum.de/i20/publications/finding-the-needle-a-study-of-
    the-pe32-rich-header-and-respective-malware-triage
"""

KNOWN_PRODUCT_IDS = {
    0: "Unknown",
    1: "Import0",
    2: "Linker510",
    3: "Cvtomf510",
    4: "Linker600",
    5: "Cvtomf600",
    6: "Cvtres500",
    7: "Utc11_Basic",
    8: "Utc11_C",
    9: "Utc12_Basic",
    10: "Utc12_C",
    11: "Utc12_CPP",
    12: "AliasObj60",
    13: "VisualBasic60",
    14: "Masm613",
    15: "Masm710",
    16: "Linker511",
    17: "Cvtomf511",
    18: "Masm614",
    19: "Linker512",
    20: "Cvtomf512",
    21: "Utc12_C_Std",
    22: "Utc12_CPP_Std",
    23: "Utc12_C_Book",
    24: "Utc12_CPP_Book",
    25: "Implib700",
    26: "Cvtomf700",
    27: "Utc13_Basic",
    28: "Utc13_C",
    29: "Utc13_CPP",
    30: "Linker610",
    31: "Cvtomf610",
    32: "Linker601",
    33: "Cvtomf601",
    34: "Utc12_1_Basic",
    35: "Utc12_1_C",
    36: "Utc12_1_CPP",
    37: "Linker620",
    38: "Cvtomf620",
    39: "AliasObj70",
    40: "Linker621",
    41: "Cvtomf621",
    42: "Masm615",
    43: "Utc13_LTCG_C",
    44: "Utc13_LTCG_CPP",
    45: "Masm620",
    46: "ILAsm100",
    47: "Utc12_2_Basic",
    48: "Utc12_2_C",
    49: "Utc12_2_CPP",
    50: "Utc12_2_C_Std",
    51: "Utc12_2_CPP_Std",
    52: "Utc12_2_C_Book",
    53: "Utc12_2_CPP_Book",
    54: "Implib622",
    55: "Cvtomf622",
    56: "Cvtres501",
    57: "Utc13_C_Std",
    58: "Utc13_CPP_Std",
    59: "Cvtpgd1300",
    60: "Linker622",
    61: "Linker700",
    62: "Export622",
    63: "Export700",
    64: "Masm700",
    65: "Utc13_POGO_I_C",
    66: "Utc13_POGO_I_CPP",
    67: "Utc13_POGO_O_C",
    68: "Utc13_POGO_O_CPP",
    69: "Cvtres700",
    70: "Cvtres710p",
    71: "Linker710p",
    72: "Cvtomf710p",
    73: "Export710p",
    74: "Implib710p",
    75: "Masm710p",
    76: "Utc1310p_C",
    77: "Utc1310p_CPP",
    78: "Utc1310p_C_Std",
    79: "Utc1310p_CPP_Std",
    80: "Utc1310p_LTCG_C",
    81: "Utc1310p_LTCG_CPP",
    82: "Utc1310p_POGO_I_C",
    83: "Utc1310p_POGO_I_CPP",
    84: "Utc1310p_POGO_O_C",
    85: "Utc1310p_POGO_O_CPP",
    86: "Linker624",
    87: "Cvtomf624",
    88: "Export624",
    89: "Implib624",
    90: "Linker710",
    91: "Cvtomf710",
    92: "Export710",
    93: "Implib710",
    94: "Cvtres710",
    95: "Utc1310_C",
    96: "Utc1310_CPP",
    97: "Utc1310_C_Std",
    98: "Utc1310_CPP_Std",
    99: "Utc1310_LTCG_C",
    100: "Utc1310_LTCG_CPP",
    101: "Utc1310_POGO_I_C",
    102: "Utc1310_POGO_I_CPP",
    103: "Utc1310_POGO_O_C",
    104: "Utc1310_POGO_O_CPP",
    105: "AliasObj710",
    106: "AliasObj710p",
    107: "Cvtpgd1310",
    108: "Cvtpgd1310p",
    109: "Utc1400_C",
    110: "Utc1400_CPP",
    111: "Utc1400_C_Std",
    112: "Utc1400_CPP_Std",
    113: "Utc1400_LTCG_C",
    114: "Utc1400_LTCG_CPP",
    115: "Utc1400_POGO_I_C",
    116: "Utc1400_POGO_I_CPP",
    117: "Utc1400_POGO_O_C",
    118: "Utc1400_POGO_O_CPP",
    119: "Cvtpgd1400",
    120: "Linker800",
    121: "Cvtomf800",
    122: "Export800",
    123: "Implib800",
    124: "Cvtres800",
    125: "Masm800",
    126: "AliasObj800",
    127: "PhoenixPrerelease",
    128: "Utc1400_CVTCIL_C",
    129: "Utc1400_CVTCIL_CPP",
    130: "Utc1400_LTCG_MSIL",
    131: "Utc1500_C",
    132: "Utc1500_CPP",
    133: "Utc1500_C_Std",
    134: "Utc1500_CPP_Std",
    135: "Utc1500_CVTCIL_C",
    136: "Utc1500_CVTCIL_CPP",
    137: "Utc1500_LTCG_C",
    138: "Utc1500_LTCG_CPP",
    139: "Utc1500_LTCG_MSIL",
    140: "Utc1500_POGO_I_C",
    141: "Utc1500_POGO_I_CPP",
    142: "Utc1500_POGO_O_C",
    143: "Utc1500_POGO_O_CPP",
    144: "Cvtpgd1500",
    145: "Linker900",
    146: "Export900",
    147: "Implib900",
    148: "Cvtres900",
    149: "Masm900",
    150: "AliasObj900",
    151: "Resource900",
    152: "AliasObj1000",
    154: "Cvtres1000",
    155: "Export1000",
    156: "Implib1000",
    157: "Linker1000",
    158: "Masm1000",
    170: "Utc1600_C",
    171: "Utc1600_CPP",
    172: "Utc1600_CVTCIL_C",
    173: "Utc1600_CVTCIL_CPP",
    174: "Utc1600_LTCG_C ",
    175: "Utc1600_LTCG_CPP",
    176: "Utc1600_LTCG_MSIL",
    177: "Utc1600_POGO_I_C",
    178: "Utc1600_POGO_I_CPP",
    179: "Utc1600_POGO_O_C",
    180: "Utc1600_POGO_O_CPP",
    183: "Linker1010",
    184: "Export1010",
    185: "Implib1010",
    186: "Cvtres1010",
    187: "Masm1010",
    188: "AliasObj1010",
    199: "AliasObj1100",
    201: "Cvtres1100",
    202: "Export1100",
    203: "Implib1100",
    204: "Linker1100",
    205: "Masm1100",
    206: "Utc1700_C",
    207: "Utc1700_CPP",
    208: "Utc1700_CVTCIL_C",
    209: "Utc1700_CVTCIL_CPP",
    210: "Utc1700_LTCG_C ",
    211: "Utc1700_LTCG_CPP",
    212: "Utc1700_LTCG_MSIL",
    213: "Utc1700_POGO_I_C",
    214: "Utc1700_POGO_I_CPP",
    215: "Utc1700_POGO_O_C",
    216: "Utc1700_POGO_O_CPP",
    219: "Cvtres1200",
    220: "Export1200",
    221: "Implib1200",
    222: "Linker1200",
    223: "Masm1200",
    # Speculation
    224: "AliasObj1200",
    237: "Cvtres1210",
    238: "Export1210",
    239: "Implib1210",
    240: "Linker1210",
    241: "Masm1210",
    # Speculation
    242: "Utc1810_C",
    243: "Utc1810_CPP",
    244: "Utc1810_CVTCIL_C",
    245: "Utc1810_CVTCIL_CPP",
    246: "Utc1810_LTCG_C ",
    247: "Utc1810_LTCG_CPP",
    248: "Utc1810_LTCG_MSIL",
    249: "Utc1810_POGO_I_C",
    250: "Utc1810_POGO_I_CPP",
    251: "Utc1810_POGO_O_C",
    252: "Utc1810_POGO_O_CPP",
    255: "Cvtres1400",
    256: "Export1400",
    257: "Implib1400",
    258: "Linker1400",
    259: "Masm1400",
    260: "Utc1900_C",
    261: "Utc1900_CPP",
    # Speculation
    262: "Utc1900_CVTCIL_C",
    263: "Utc1900_CVTCIL_CPP",
    264: "Utc1900_LTCG_C ",
    265: "Utc1900_LTCG_CPP",
    266: "Utc1900_LTCG_MSIL",
    267: "Utc1900_POGO_I_C",
    268: "Utc1900_POGO_I_CPP",
    269: "Utc1900_POGO_O_C",
    270: "Utc1900_POGO_O_CPP",
}


class Result(Enum):
    VALID = 0
    INVALID = 1
    UNABLE_TO_PARSE = 2


def _rol(val, num):
    """Rotates val to the left by num bits."""
    return ((val << (num % 32)) & 0xFFFFFFFF) | (val >> (32 - (num % 32)))


def checksum_test(pe, rich_header):
    """Tests that the Rich header checksum is valid.

    Computes what the Rich header checksum should be. If the Rich header
    contains a different checksum value, this function returns INVALID
    This indicates that either the Rich header or MS-DOS stub has been modified

    The Rich header checksum is computed from the following:
        Length of the MS-DOS stub
        Contents of the MS-DOS stub, with e_lfanew zeroed out
        Rich header @Comp.IDs and lowest 5 bits of each count
    """
    if rich_header is None:
        rich_header = {}
    # Checksum stored in Rich header
    rich_checksum = rich_header.get("checksum", None)

    # Get DOS header data
    if pe.DOS_HEADER.e_lfanew > len(pe.__data__):
        return Result.UNABLE_TO_PARSE
    data = pe.__data__[: pe.DOS_HEADER.e_lfanew]

    # Get start marker
    mask = 0x536E6144  # DanS (little-endian)
    start_marker = struct.pack(
        "<LLLL", rich_checksum ^ mask, rich_checksum, rich_checksum, rich_checksum
    )
    if not len(start_marker):
        return Result.UNABLE_TO_PARSE

    # Get index of start marker
    start_index = data.find(start_marker)
    if start_index == -1:
        return Result.UNABLE_TO_PARSE

    # Get list of @Comp.IDs and counts from Rich header
    # Elements in rich_fields at even indices are @Comp.IDs
    # Elements in rich_fields at odd indices are counts
    rich_fields = copy.deepcopy(rich_header.get("values", None))
    if len(rich_fields) % 2 != 0:
        return Result.UNABLE_TO_PARSE

    # Compute cd as MS-DOS stub portion of checksum
    # Zero out e_lfanew from 0x3c to 0x3f
    cd = 0
    for i in range(start_index):
        if i >= 0x3C and i <= 0x3F:
            cd += _rol(0, i)
        else:
            cd += _rol(data[i], i)

    # Compute cd as Rich header portion of checksum
    cr = 0
    while len(rich_fields):
        compid = rich_fields.pop(0)
        count = rich_fields.pop(0)
        cr += _rol(compid, count & 0x1F)

    # Compute checksum from MS-DOS stub start index, cd, cr
    # Only keep lowest 32 bits
    checksum = (start_index + cd + cr) & 0xFFFFFFFF

    # Compare computed checksum with the checksum in the Rich header
    if checksum != rich_checksum:
        return Result.INVALID
    else:
        return Result.VALID


def duplicate_test(pe, rich_header):
    """Checks for duplicate @Comp.IDs in the Rich header.

    If the Rich header contains duplicate entries, returns INVALID
    This indicates that the Rich header has been modified
    """
    if rich_header is None:
        rich_header = {}

    # Get list of @Comp.IDs and counts from Rich header
    # Elements in rich_fields at even indices are @Comp.IDs
    # Elements in rich_fields at odd indices are counts
    rich_fields = copy.deepcopy(rich_header.get("values", None))
    if len(rich_fields) % 2 != 0:
        return Result.UNABLE_TO_PARSE

    # Get a list of @Comp.IDs in rich_fields
    compids = []
    for i in range(len(rich_fields)):
        if i % 2 == 0:
            compids.append(rich_fields[i])

    # Check if any @Comp.IDs are duplicates
    if len(compids) != len(set(compids)):
        return Result.INVALID

    return Result.VALID


def linker_test(pe, rich_header):
    """Checks that the Rich and PE header linker versions do not conflict.

    Certain Rich Header ProdIDs correspond to linker versions
    Although they are undocumented, we have used prior research as well as our
    own to determine many of them
    There are likely more linker version ProdIDs that we have not identified

    If the linker versions conflict, this function returns INVALID
    This indicates that the Rich header or PE header has been modified
    """
    if rich_header is None:
        rich_header = {}

    # Get list of @Comp.IDs and counts from Rich header
    # Elements in rich_fields at even indices are @Comp.IDs
    # Elements in rich_fields at odd indices are counts
    rich_fields = copy.deepcopy(rich_header.get("values", None))
    if len(rich_fields) % 2 != 0:
        return Result.UNABLE_TO_PARSE

    # Get list of ProdIDs from rich_fields
    prodids = []
    for i in range(len(rich_fields)):
        if i % 2 == 0:
            prodids.append(rich_fields[i] >> 16)

    # Parse major and minor linker versions from PE header
    pe_major = pe.OPTIONAL_HEADER.MajorLinkerVersion
    pe_minor = pe.OPTIONAL_HEADER.MinorLinkerVersion

    # Iterate over Rich header ProdIDs
    found_linker = False
    for prodid in prodids:

        # Only interested in ProdIDs that correspond to linker versions
        if KNOWN_PRODUCT_IDS.get(prodid) is None:
            continue
        prodid_name = KNOWN_PRODUCT_IDS[prodid]
        if not prodid_name.startswith("Linker"):
            continue

        found_linker = True

        # Parse major and minor linker version from ProdID
        prodid_name = prodid_name[6:]
        if prodid_name.endswith("p"):
            prodid_name = prodid_name[:-1]
        rich_major = int(prodid_name[:-2])
        rich_minor = int(prodid_name[-2:])

        # Check whether the Rich and PE linker versions match
        if pe_major == rich_major and pe_minor == rich_minor:
            return Result.VALID

    if not found_linker:
        return Result.UNABLE_TO_PARSE

    return Result.INVALID


def import_count_test(pe, rich_header):
    """Checks that import0 does not conflict with the IAT import count.

    The Rich header contains a ProdID called import0
    It is related to the number of imports in the IAT, but we are unsure how
    It is never less than the number of imports in the IAT

    If import0 is less than IAT import count, this function returns INVALID
    This indicates that the Rich header or IAT has been modified
    """
    if rich_header is None:
        rich_header = {}

    # Check whether the file has an IAT
    if not hasattr(pe, "DIRECTORY_ENTRY_IMPORT"):
        return Result.UNABLE_TO_PARSE

    # Get the number of imports in the IAT
    iat_count = 0
    for entry in pe.DIRECTORY_ENTRY_IMPORT:
        for imported_function in entry.imports:
            iat_count += 1

    # Get list of @Comp.IDs and counts from Rich header
    # Elements in rich_fields at even indices are @Comp.IDs
    # Elements in rich_fields at odd indices are counts
    rich_fields = copy.deepcopy(rich_header.get("values", None))
    if len(rich_fields) % 2 != 0:
        return Result.INVALID

    # Get @Comp.ID 65536 (ProdID Import0)
    import0_count = None
    while len(rich_fields):
        compid = rich_fields.pop(0)
        count = rich_fields.pop(0)
        if compid == 65536:
            import0_count = count

    # Legitimate files never have import0_count < iat_count
    if import0_count is None:
        return Result.VALID

    if import0_count < iat_count:
        return Result.INVALID

    return Result.VALID