COFF
COFF全称是Common Object File Format,可以通过编译工具生成。
在CobaltStrike中被用于扩展更多的功能
生成
| 1 | 
 | 
i686-w64-mingw32-gcc -c hello.c -o hello_mingw32.o
010editor
为了学习COFF结构,实现了一个010editor的解析插件如下
COFF.bt
//------------------------------------------------
//--- 010 Editor v4.0.3 Binary Template
//
//      File: COFF.bt
//   Authors: guage
//    E-mail: zhaopeiyuan6@gmail.com
//   Website: https://guage.cool https://github.com/howmp/
//   Version: 0.1
//   Purpose: Parse Common Object File Format files.
//            Supports 32 and 64 bit.
//  Category: Executable
// File Mask: *.o,*.obj
//   History:
//   0.1     2022-08-12 guage: Initial commit
//
// Recommended reading:
// 1. https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#other-contents-of-the-file
// 2. https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/BinaryFormat/COFF.h
typedef struct
{
    WORD IMAGE_FILE_RELOCS_STRIPPED:1           <comment=”0x0001  Relocation info stripped from file”>;
    WORD IMAGE_FILE_EXECUTABLE_IMAGE:1          <comment=”0x0002  File is executable”>;
    WORD IMAGE_FILE_LINE_NUMS_STRIPPED:1        <comment=”0x0004  Line nunbers stripped from file”>;
    WORD IMAGE_FILE_LOCAL_SYMS_STRIPPED:1       <comment=”0x0008  Local symbols stripped from file”>;
    WORD IMAGE_FILE_AGGRESIVE_WS_TRIM:1         <comment=”0x0010  Agressively trim working set”>;
    WORD IMAGE_FILE_LARGE_ADDRESS_AWARE:1       <comment=”0x0020  App can handle >2gb addresses”>;
    WORD                               :1       <comment=”0x0040  Reserved”,hidden=true>;
    WORD IMAGE_FILE_BYTES_REVERSED_LO:1         <comment=”0x0080  Bytes of machine word are reversed”>;
    WORD IMAGE_FILE_32BIT_MACHINE:1             <comment=”0x0100  32 bit word machine”>;
    WORD IMAGE_FILE_DEBUG_STRIPPED:1            <comment=”0x0200  Debugging info stripped from file in .DBG file”>;
    WORD IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP:1   <comment=”0x0400  If Image is on removable media, copy and run from the swap file”>;
    WORD IMAGE_FILE_NET_RUN_FROM_SWAP:1         <comment=”0x0800  If Image is on Net, copy and run from the swap file”>;
    WORD IMAGE_FILE_SYSTEM:1                    <comment=”0x1000  System File”>;
    WORD IMAGE_FILE_DLL:1                       <comment=”0x2000  File is a DLL”>;
    WORD IMAGE_FILE_UP_SYSTEM_ONLY:1            <comment=”0x4000  File should only be run on a UP machine”>;
    WORD IMAGE_FILE_BYTES_REVERSED_HI:1         <comment=”0x8000  Bytes of machine word are reversed”>;
} FILE_CHARACTERISTICS <comment=”WORD”>;
typedef enum
{
    IMAGE_MACHINE_UNKNOWN  = 0,
    I386      = 0x014c,  // Intel 386 or later processors and compatible processors
    R3000     = 0x0162,  // MIPS little-endian, 0x160 big-endian
    R4000     = 0x0166,  // MIPS little-endian
    R10000    = 0x0168,  // MIPS little-endian
    WCEMIPSV2 = 0x0169,  // MIPS little-endian WCE v2
    ALPHA     = 0x0184,  // Alpha_AXP
    SH3       = 0x01a2,  // Hitachi SH3
    SH3DSP    = 0x01a3,  // Hitachi SH3 DSP
    SH3E      = 0x01a4,  // Hitachi SH3E little-endian
    SH4       = 0x01a6,  // Hitachi SH4
    SH5       = 0x01a8,  // Hitachi SH5
    ARM       = 0x01c0,  // ARM little-endian
    THUMB     = 0x01c2,  // Thumb
    ARMNT     = 0x01c4,  // Arm Thumb-2 little-endian
    AM33      = 0x01d3,  // Matsushita AM33
    POWERPC   = 0x01f0,  // Power PC little endian
    POWERPCFP = 0x01f1,  // Power PC with floating point support
    IA64      = 0x0200,  // Intel Itanium processor family
    MIPS16    = 0x0266,  // MIPS16
    ALPHA64   = 0x0284,  // ALPHA64
    MIPSFPU   = 0x0366,  // MIPS with FPU
    MIPSFPU16 = 0x0466,  // MIPS16 with FPU
    TRICORE   = 0x0520,  // Infineon
    CEF       = 0x0CEF,
    EBC       = 0x0EBC,  // EFI Byte Code
    RISCV32   = 0x5032,  // RISC-V 32-bit address space
    RISCV64   = 0x5064,  // RISC-V 64-bit address space
    RISCV128  = 0x5128,  // RISC-V 128-bit address space
    AMD64     = 0x8664,  // x64
    M32R      = 0x9041,  // Mitsubishi M32R little-endian
    ARM64     = 0xAA64,  // ARM64 little-endian
    CEE       = 0xC0EE
} IMAGE_MACHINE <comment=”WORD”>;
typedef enum  {
  I386_ABSOLUTE = 0x0000,
  I386_DIR16 = 0x0001,
  I386_REL16 = 0x0002,
  I386_DIR32 = 0x0006,
  I386_DIR32NB = 0x0007,
  I386_SEG12 = 0x0009,
  I386_SECTION = 0x000A,
  I386_SECREL = 0x000B,
  I386_TOKEN = 0x000C,
  I386_SECREL7 = 0x000D,
  I386_REL32 = 0x0014
} RelocationTypeI386; 
typedef enum  {
  AMD64_ABSOLUTE = 0x0000,
  AMD64_ADDR64 = 0x0001,
  AMD64_ADDR32 = 0x0002,
  AMD64_ADDR32NB = 0x0003,
  AMD64_REL32 = 0x0004,
  AMD64_REL32_1 = 0x0005,
  AMD64_REL32_2 = 0x0006,
  AMD64_REL32_3 = 0x0007,
  AMD64_REL32_4 = 0x0008,
  AMD64_REL32_5 = 0x0009,
  AMD64_SECTION = 0x000A,
  AMD64_SECREL = 0x000B,
  AMD64_SECREL7 = 0x000C,
  AMD64_TOKEN = 0x000D,
  AMD64_SREL32 = 0x000E,
  AMD64_PAIR = 0x000F,
  AMD64_SSPAN32 = 0x0010
} RelocationTypeAMD64; 
typedef enum  {
  ARM_ABSOLUTE = 0x0000,
  ARM_ADDR32 = 0x0001,
  ARM_ADDR32NB = 0x0002,
  ARM_BRANCH24 = 0x0003,
  ARM_BRANCH11 = 0x0004,
  ARM_TOKEN = 0x0005,
  ARM_BLX24 = 0x0008,
  ARM_BLX11 = 0x0009,
  ARM_REL32 = 0x000A,
  ARM_SECTION = 0x000E,
  ARM_SECREL = 0x000F,
  ARM_MOV32A = 0x0010,
  ARM_MOV32T = 0x0011,
  ARM_BRANCH20T = 0x0012,
  ARM_BRANCH24T = 0x0014,
  ARM_BLX23T = 0x0015,
  ARM_PAIR = 0x0016,
} RelocationTypesARM; 
typedef enum  {
  ARM64_ABSOLUTE = 0x0000,
  ARM64_ADDR32 = 0x0001,
  ARM64_ADDR32NB = 0x0002,
  ARM64_BRANCH26 = 0x0003,
  ARM64_PAGEBASE_REL21 = 0x0004,
  ARM64_REL21 = 0x0005,
  ARM64_PAGEOFFSET_12A = 0x0006,
  ARM64_PAGEOFFSET_12L = 0x0007,
  ARM64_SECREL = 0x0008,
  ARM64_SECREL_LOW12A = 0x0009,
  ARM64_SECREL_HIGH12A = 0x000A,
  ARM64_SECREL_LOW12L = 0x000B,
  ARM64_TOKEN = 0x000C,
  ARM64_SECTION = 0x000D,
  ARM64_ADDR64 = 0x000E,
  ARM64_BRANCH19 = 0x000F,
  ARM64_BRANCH14 = 0x0010,
  ARM64_REL32 = 0x0011,
} RelocationTypesARM64; 
typedef struct
{
    ULONG IMAGE_SCN_TYPE_DSECT:1                 <comment=”0x00000001 Reserved”,hidden=true>;
    ULONG IMAGE_SCN_TYPE_NOLOAD:1                <comment=”0x00000002 Reserved”,hidden=true>;
    ULONG IMAGE_SCN_TYPE_GROUP:1                 <comment=”0x00000004 Reserved”,hidden=true>;
    ULONG IMAGE_SCN_TYPE_NO_PAD:1                <comment=”0x00000008 Reserved”>;
    ULONG IMAGE_SCN_TYPE_COPY:1                  <comment=”0x00000010 Reserved”,hidden=true>;
ULONG IMAGE_SCN_CNT_CODE:1                   <comment="0x00000020 Section contains code">;
ULONG IMAGE_SCN_CNT_INITIALIZED_DATA:1       <comment="0x00000040 Section contains initialized data">;
ULONG IMAGE_SCN_CNT_UNINITIALIZED_DATA:1     <comment="0x00000080 Section contains uninitialized data">;
ULONG IMAGE_SCN_LNK_OTHER:1                  <comment="0x00000100 Reserved">;
ULONG IMAGE_SCN_LNK_INFO:1                   <comment="0x00000200 Section contains comments or some other type of information">;
ULONG IMAGE_SCN_TYPE_OVER:1                  <comment="0x00000400 Reserved",hidden=true>;
ULONG IMAGE_SCN_LNK_REMOVE:1                 <comment="0x00000800 Section contents will not become part of image">;
ULONG IMAGE_SCN_LNK_COMDAT:1                 <comment="0x00001000 Section contents comdat">;
ULONG                      :1                <comment="0x00002000 Reserved">;
ULONG IMAGE_SCN_NO_DEFER_SPEC_EXC:1          <comment="0x00004000 Reset speculative exceptions handling bits in the TLB entries for this section.",hidden=true>;
ULONG IMAGE_SCN_GPREL:1                      <comment="0x00008000 Section content can be accessed relative to GP">;
ULONG IMAGE_SCN_MEM_SYSHEAP:1                <comment="0x00010000 Obsolete",hidden=true>;
ULONG IMAGE_SCN_MEM_16BIT:1                  <comment="0x00020000">;
ULONG IMAGE_SCN_MEM_LOCKED:1                 <comment="0x00040000 ">;
ULONG IMAGE_SCN_MEM_PRELOAD:1                <comment="0x00080000">;
ULONG IMAGE_SCN_ALIGN_1BYTES:1               <comment="0x00100000">;
ULONG IMAGE_SCN_ALIGN_2BYTES:1               <comment="0x00200000">;
ULONG IMAGE_SCN_ALIGN_8BYTES:1               <comment="0x00400000">;
ULONG IMAGE_SCN_ALIGN_128BYTES:1             <comment="0x00800000">;
ULONG IMAGE_SCN_LNK_NRELOC_OVFL:1            <comment="0x01000000 Section contains extended relocations">;
ULONG IMAGE_SCN_MEM_DISCARDABLE:1            <comment="0x02000000 Section can be discarded.">;
ULONG IMAGE_SCN_MEM_NOT_CACHED:1             <comment="0x04000000 Section is not cachable">;
ULONG IMAGE_SCN_MEM_NOT_PAGED:1              <comment="0x08000000 Section is not pageable.">;
ULONG IMAGE_SCN_MEM_SHARED:1                 <comment="0x10000000 Section is shareable">;
ULONG IMAGE_SCN_MEM_EXECUTE:1                <comment="0x20000000 Section is executable">;
ULONG IMAGE_SCN_MEM_READ:1                   <comment="0x40000000 Section is readable">;
ULONG IMAGE_SCN_MEM_WRITE:1                  <comment="0x80000000 Section is writeable">;
} SECTION_CHARACTERISTICS;
typedef enum  {
  IMAGE_SYM_TYPE_NULL = 0,
  IMAGE_SYM_TYPE_VOID = 1,
  IMAGE_SYM_TYPE_CHAR = 2,
  IMAGE_SYM_TYPE_SHORT = 3,
  IMAGE_SYM_TYPE_INT = 4,
  IMAGE_SYM_TYPE_LONG = 5,
  IMAGE_SYM_TYPE_FLOAT = 6,
  IMAGE_SYM_TYPE_DOUBLE = 7,
  IMAGE_SYM_TYPE_STRUCT = 8,
  IMAGE_SYM_TYPE_UNION = 9,
  IMAGE_SYM_TYPE_ENUM = 10,
  IMAGE_SYM_TYPE_MOE = 11,
  IMAGE_SYM_TYPE_BYTE = 12,
  IMAGE_SYM_TYPE_WORD = 13,
  IMAGE_SYM_TYPE_UINT = 14,
  IMAGE_SYM_TYPE_DWORD = 15
} SymbolBaseType; 
typedef enum  {
  IMAGE_SYM_DTYPE_NULL = 0,
  IMAGE_SYM_DTYPE_POINTER = 1,
  IMAGE_SYM_DTYPE_FUNCTION = 2,
  IMAGE_SYM_DTYPE_ARRAY = 3,
} SymbolComplexType; 
/// Storage class tells where and what the symbol represents
typedef enum  { 
  IMAGE_SYM_CLASS_END_OF_FUNCTION = -1,
  IMAGE_SYM_CLASS_NULL = 0,
  IMAGE_SYM_CLASS_AUTOMATIC = 1,
  IMAGE_SYM_CLASS_EXTERNAL = 2,
  IMAGE_SYM_CLASS_STATIC = 3,
  IMAGE_SYM_CLASS_REGISTER = 4,
  IMAGE_SYM_CLASS_EXTERNAL_DEF = 5,
  IMAGE_SYM_CLASS_LABEL = 6,
  IMAGE_SYM_CLASS_UNDEFINED_LABEL = 7,
  IMAGE_SYM_CLASS_MEMBER_OF_STRUCT = 8,
  IMAGE_SYM_CLASS_ARGUMENT = 9,
  IMAGE_SYM_CLASS_STRUCT_TAG = 10,
  IMAGE_SYM_CLASS_MEMBER_OF_UNION = 11,
  IMAGE_SYM_CLASS_UNION_TAG = 12,
  IMAGE_SYM_CLASS_TYPE_DEFINITION = 13,
  IMAGE_SYM_CLASS_UNDEFINED_STATIC = 14,
  IMAGE_SYM_CLASS_ENUM_TAG = 15,
  IMAGE_SYM_CLASS_MEMBER_OF_ENUM = 16,
  IMAGE_SYM_CLASS_REGISTER_PARAM = 17,
  IMAGE_SYM_CLASS_BIT_FIELD = 18,
  IMAGE_SYM_CLASS_BLOCK = 100,
  IMAGE_SYM_CLASS_FUNCTION = 101,
  IMAGE_SYM_CLASS_END_OF_STRUCT = 102,
  IMAGE_SYM_CLASS_FILE = 103,
  IMAGE_SYM_CLASS_SECTION = 104,
  IMAGE_SYM_CLASS_WEAK_EXTERNAL = 105,
  IMAGE_SYM_CLASS_CLR_TOKEN = 107
} SymbolStorageClass;
typedef struct
{
    IMAGE_MACHINE    Machine                    <fgcolor=cPurple,format=hex,comment=”WORD”>;
    WORD    NumberOfSections                    <fgcolor=cBlue,comment=”Section num”>;
    time_t  TimeDateStamp                       <format=hex,comment=”DWORD,from 01/01/1970 12:00 AM”>;
    DWORD   PointerToSymbolTable                <format=hex>;
    DWORD   NumberOfSymbols;
    WORD    SizeOfOptionalHeader;
    FILE_CHARACTERISTICS   Characteristics      <comment=”WORD”>;
} IMAGE_FILE_HEADER;
typedef struct
{
    BYTE    Name[8] <comment=”can end without zero”>;
    DWORD VirtualSize;
    DWORD   VirtualAddress          <format=hex>;
    DWORD   SizeOfRawData           <format=hex>;
    DWORD   PointerToRawData        <format=hex>;
    DWORD   PointerToRelocations    <format=hex>;
    DWORD   PointerToLinenumbers;
    WORD    NumberOfRelocations;
    WORD    NumberOfLinenumbers;
    SECTION_CHARACTERISTICS Characteristics <format=hex>;
} IMAGE_SECTION_HEADER <read=ReadImageSectionHeader>;
typedef struct (IMAGE_SECTION_HEADER& SecHeader)
{
    local string sSecName = SecHeader.Name;
    if( sSecName == “.text” )
    {
        // Disassemble .text section
        if( FileHeader.Machine == AMD64 )
            DisasmSetMode( DISASM_X86_64 );
        else if ( FileHeader.Machine == I386 )
            DisasmSetMode( DISASM_X86_32 );
        else if ( FileHeader.Machine == ARM )
            DisasmSetMode( DISASM_ARM_32 );
        else if ( FileHeader.Machine == ARM64 )
            DisasmSetMode( DISASM_ARM_64 );
        Opcode Data[SecHeader.SizeOfRawData];
    }
    else
        UCHAR Data[SecHeader.SizeOfRawData];
} IMAGE_SECTION_DATA <read=ReadSectionData>;
typedef struct (IMAGE_SECTION_HEADER& SecHeader)
{
    local string sSecName = SecHeader.Name;
    DWORD   VirtualAddress <format=hex>;
    DWORD   SymbolTableIndex;
    if( FileHeader.Machine == AMD64 )
        RelocationTypeAMD64 Type;
    else if ( FileHeader.Machine == I386 )
        RelocationTypeI386 Type;
    else if ( FileHeader.Machine == ARM )
        RelocationTypesARM Type;
    else if ( FileHeader.Machine == ARM64 )
        RelocationTypesARM64 Type;
} IMAGE_RELOC_DATA <read=ReadRelocData>;
typedef struct {
  union {
    BYTE  Name[8];
    struct {
        DWORD Zeroes <comment=”A field that is set to all zeros if the name is longer than 8 bytes.”>;
        DWORD Offset <comment=”An offset into the string table.”>;
    }LongName;
  } Name;
  DWORD Value <format=hex>;
  WORD SectionNumber;
  SymbolBaseType  BaseType:4;
  SymbolComplexType  ComplexType:4;
  BYTE  Reserved <comment=”Reserved”,hidden=true>;
  SymbolStorageClass StorageClass;
  BYTE NumberOfAuxSymbols;
} IMAGE_SYMBOL_DATA <read=ReadImageSymbolData>;
typedef struct {
    BYTE Name[];
}String <read=ReadStringData>;;
string ReadImageSectionHeader(IMAGE_SECTION_HEADER& h)
{
    return h.Name;
}
string ReadRelocData(IMAGE_RELOC_DATA& r){
    return ReadImageSymbolData(Symbol[r.SymbolTableIndex]);
}
string ReadImageSymbolData(IMAGE_SYMBOL_DATA& s)
{
    if(s.StorageClass == IMAGE_SYM_CLASS_NULL)
        return “”;
    if(s.Name.LongName.Zeroes !=0)
        return s.Name.Name;
    return ReadString(dwStringTableOffset + s.Name.LongName.Offset);
}
string ReadSectionData(IMAGE_SECTION_DATA& SecData)
{
    if (SecData.sSecName[0] == ‘/‘){
        return ReadString(dwStringTableOffset + Atoi(SubStr(SecData.sSecName,1)));
    }
    return SecData.sSecName;
}
string ReadStringData(String& s)
{
    return s.Name;
}
/**** PARSING CODE ****/
LittleEndian();
// COFF Header
IMAGE_FILE_HEADER FileHeader <bgcolor=cLtPurple>;
// COFF Sections
IMAGE_SECTION_HEADER SectionHeaders[FileHeader.NumberOfSections] <bgcolor=cYellow>;
// COFF Sections Data
local ULONG sIndex=0;
local ULONG rIndex=0;
for (sIndex=0; sIndex < FileHeader.NumberOfSections; sIndex++)
{
    if ( 0 == SectionHeaders[sIndex].PointerToRawData )
    {
        continue;
    }
    if ( 0 == SectionHeaders[sIndex].SizeOfRawData )
    {
        continue;
    }
    FSeek(SectionHeaders[sIndex].PointerToRawData);
    IMAGE_SECTION_DATA Section(SectionHeaders[sIndex]) <bgcolor=cBlue>;
}
// COFF Relocations Data
for (sIndex=0; sIndex < FileHeader.NumberOfSections; sIndex++)
{
    if ( 0 == SectionHeaders[sIndex].NumberOfRelocations )
    {
        continue;
    }
    FSeek(SectionHeaders[sIndex].PointerToRelocations);
    for (rIndex=0; rIndex < SectionHeaders[sIndex].NumberOfRelocations; rIndex++)
    {
        IMAGE_RELOC_DATA Reloc(SectionHeaders[sIndex]) <bgcolor=cAqua>;
    }
}
// COFF Symbols Data
FSeek(FileHeader.PointerToSymbolTable);
for (sIndex=0; sIndex < FileHeader.NumberOfSymbols; sIndex++)
{
    IMAGE_SYMBOL_DATA Symbol <bgcolor=cSilver>;
}
// COFF String Data
local DWORD dwStringTableOffset = FTell();
DWORD StringTableLen;
while(!FEof()){
    String StringTable <bgcolor=cLtYellow>;
}
效果如下
