From ff7733400c76c6950cf5def03edbbd4ae0eaf2c3 Mon Sep 17 00:00:00 2001 From: Rukatonoshi Date: Thu, 28 Jul 2022 06:16:54 +0300 Subject: [PATCH 1/8] Changed a little bit readme and few functions for correct working and ported this plugin to rizin --- README.md | 16 +- syms2elf.py | 1684 ++++++++++++++++++++++++++------------------------- 2 files changed, 872 insertions(+), 828 deletions(-) diff --git a/README.md b/README.md index e4dd286..dc7056f 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,15 @@ # syms2elf -The plugin export the symbols (for the moment only functions) recognized by IDA Pro and radare2 to the ELF symbol table. This allows us to use the power of IDA/r2 in recognizing functions (analysis, FLIRT signatures, manual creation, renaming, etc), but not be limited to the exclusive use of this tools. +The plugin export the symbols (for the moment only functions) recognized by IDA Pro and radare2 (also works for rizin and cutter) to the ELF symbol table. This allows us to use the power of IDA/r2 in recognizing functions (analysis, FLIRT signatures, manual creation, renaming, etc), but not be limited to the exclusive use of this tools. Supports 32 and 64-bits file format. ## INSTALLATION * **IDA Pro**: Simply, copy `syms2elf.py` to the IDA's plugins folder. - * **radare2**: You can install via r2pm: `r2pm -i syms2elf` + * **radare2**: In radare2 environment, pass this command: #!pipe python ./syms2elf.py + * **rizin** : In rizin environment, pass this command: #!pipe python ./syms2elf.py + @@ -15,9 +17,8 @@ Supports 32 and 64-bits file format. Based on a full-stripped ELF: -``` -$ file test1_x86_stripped -test1_x86_stripped: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, stripped +```$ file test_x86 +testfile_x86: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=7ee4206d91718e7b0bef16a7c03f8fa49c4a39e7, stripped ``` Rename some functions in IDA or r2, run `syms2elf` and select the output file. @@ -29,8 +30,8 @@ Rename some functions in IDA or r2, run `syms2elf` and select the output file. After that: ``` -$ file test1_x86_unstripped -test1_x86_unstripped: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, not stripped +$ file test_x86_unstripped +test_x86_unstripped: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=7ee4206d91718e7b0bef16a7c03f8fa49c4a39e7, not stripped ``` Now, you can open it with others tools and analyzing in a more comfortable way. @@ -39,7 +40,6 @@ Now, you can open it with others tools and analyzing in a more comfortable way. * Daniel García (@danigargu) * Jesús Olmos (@sha0coder) - ## CONTACT Any comment or request will be highly appreciated :-) diff --git a/syms2elf.py b/syms2elf.py index 0d420cc..d024515 100644 --- a/syms2elf.py +++ b/syms2elf.py @@ -1,820 +1,864 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# sym2elf -# 28/11/2014 -# -# Daniel García -# Jesús Olmos -# -# ELF parser - based on the lib of ROPgadget tool by Jonathan Salwan -# http://shell-storm.org/project/ROPgadget/ -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# - -PLUG_NAME = "syms2elf" - -import os -import sys - -from ctypes import * -from struct import unpack - -USE_R2 = False -USE_IDA = False - -try: - import idaapi - USE_IDA = True -except: - if "radare2" in os.environ.get('PATH',''): - USE_R2 = True - else: - print("ERROR: The plugin must be run in IDA or radare2") - sys.exit(0) - -SHN_UNDEF = 0 -STB_GLOBAL_FUNC = 0x12 - -class SHTypes: - SHT_NULL = 0 - SHT_PROGBITS = 1 - SHT_SYMTAB = 2 - SHT_STRTAB = 3 - SHT_RELA = 4 - SHT_HASH = 5 - SHT_DYNAMIC = 6 - SHT_NOTE = 7 - SHT_NOBITS = 8 - SHT_REL = 9 - SHT_SHLIB = 10 - SHT_DYNSYM = 11 - SHT_NUM = 12 - SHT_LOPROC = 0x70000000 - SHT_HIPROC = 0x7fffffff - SHT_LOUSER = 0x80000000 - SHT_HIUSER = 0xffffffff - -class ELFFlags: - ELFCLASS32 = 0x01 - ELFCLASS64 = 0x02 - EI_CLASS = 0x04 - EI_DATA = 0x05 - ELFDATA2LSB = 0x01 - ELFDATA2MSB = 0x02 - EM_386 = 0x03 - EM_X86_64 = 0x3e - EM_ARM = 0x28 - EM_MIPS = 0x08 - EM_SPARCv8p = 0x12 - EM_PowerPC = 0x14 - EM_ARM64 = 0xb7 - -class SymFlags: - STB_LOCAL = 0 - STB_GLOBAL = 1 - STB_WEAK = 2 - STT_NOTYPE = 0 - STT_OBJECT = 1 - STT_FUNC = 2 - STT_SECTION = 3 - STT_FILE = 4 - STT_COMMON = 5 - STT_TLS = 6 - -class Elf32_Ehdr_LSB(LittleEndianStructure): - _fields_ = [ - ("e_ident", c_ubyte * 16), - ("e_type", c_ushort), - ("e_machine", c_ushort), - ("e_version", c_uint), - ("e_entry", c_uint), - ("e_phoff", c_uint), - ("e_shoff", c_uint), - ("e_flags", c_uint), - ("e_ehsize", c_ushort), - ("e_phentsize", c_ushort), - ("e_phnum", c_ushort), - ("e_shentsize", c_ushort), - ("e_shnum", c_ushort), - ("e_shstrndx", c_ushort) - ] - -class Elf64_Ehdr_LSB(LittleEndianStructure): - _fields_ = [ - ("e_ident", c_ubyte * 16), - ("e_type", c_ushort), - ("e_machine", c_ushort), - ("e_version", c_uint), - ("e_entry", c_ulonglong), - ("e_phoff", c_ulonglong), - ("e_shoff", c_ulonglong), - ("e_flags", c_uint), - ("e_ehsize", c_ushort), - ("e_phentsize", c_ushort), - ("e_phnum", c_ushort), - ("e_shentsize", c_ushort), - ("e_shnum", c_ushort), - ("e_shstrndx", c_ushort) - ] - -class Elf32_Phdr_LSB(LittleEndianStructure): - _fields_ = [ - ("p_type", c_uint), - ("p_offset", c_uint), - ("p_vaddr", c_uint), - ("p_paddr", c_uint), - ("p_filesz", c_uint), - ("p_memsz", c_uint), - ("p_flags", c_uint), - ("p_align", c_uint) - ] - -class Elf64_Phdr_LSB(LittleEndianStructure): - _fields_ = [ - ("p_type", c_uint), - ("p_flags", c_uint), - ("p_offset", c_ulonglong), - ("p_vaddr", c_ulonglong), - ("p_paddr", c_ulonglong), - ("p_filesz", c_ulonglong), - ("p_memsz", c_ulonglong), - ("p_align", c_ulonglong) - ] - -class Elf32_Shdr_LSB(LittleEndianStructure): - _fields_ = [ - ("sh_name", c_uint), - ("sh_type", c_uint), - ("sh_flags", c_uint), - ("sh_addr", c_uint), - ("sh_offset", c_uint), - ("sh_size", c_uint), - ("sh_link", c_uint), - ("sh_info", c_uint), - ("sh_addralign", c_uint), - ("sh_entsize", c_uint) - ] - -class Elf64_Shdr_LSB(LittleEndianStructure): - _fields_ = [ - ("sh_name", c_uint), - ("sh_type", c_uint), - ("sh_flags", c_ulonglong), - ("sh_addr", c_ulonglong), - ("sh_offset", c_ulonglong), - ("sh_size", c_ulonglong), - ("sh_link", c_uint), - ("sh_info", c_uint), - ("sh_addralign", c_ulonglong), - ("sh_entsize", c_ulonglong) - ] - -class Elf32_Ehdr_MSB(BigEndianStructure): - _fields_ = [ - ("e_ident", c_ubyte * 16), - ("e_type", c_ushort), - ("e_machine", c_ushort), - ("e_version", c_uint), - ("e_entry", c_uint), - ("e_phoff", c_uint), - ("e_shoff", c_uint), - ("e_flags", c_uint), - ("e_ehsize", c_ushort), - ("e_phentsize", c_ushort), - ("e_phnum", c_ushort), - ("e_shentsize", c_ushort), - ("e_shnum", c_ushort), - ("e_shstrndx", c_ushort) - ] - -class Elf64_Ehdr_MSB(BigEndianStructure): - _fields_ = [ - ("e_ident", c_ubyte * 16), - ("e_type", c_ushort), - ("e_machine", c_ushort), - ("e_version", c_uint), - ("e_entry", c_ulonglong), - ("e_phoff", c_ulonglong), - ("e_shoff", c_ulonglong), - ("e_flags", c_uint), - ("e_ehsize", c_ushort), - ("e_phentsize", c_ushort), - ("e_phnum", c_ushort), - ("e_shentsize", c_ushort), - ("e_shnum", c_ushort), - ("e_shstrndx", c_ushort) - ] - -class Elf32_Phdr_MSB(BigEndianStructure): - _fields_ = [ - ("p_type", c_uint), - ("p_offset", c_uint), - ("p_vaddr", c_uint), - ("p_paddr", c_uint), - ("p_filesz", c_uint), - ("p_memsz", c_uint), - ("p_flags", c_uint), - ("p_align", c_uint) - ] - -class Elf64_Phdr_MSB(BigEndianStructure): - _fields_ = [ - ("p_type", c_uint), - ("p_flags", c_uint), - ("p_offset", c_ulonglong), - ("p_vaddr", c_ulonglong), - ("p_paddr", c_ulonglong), - ("p_filesz", c_ulonglong), - ("p_memsz", c_ulonglong), - ("p_align", c_ulonglong) - ] - -class Elf32_Shdr_MSB(BigEndianStructure): - _fields_ = [ - ("sh_name", c_uint), - ("sh_type", c_uint), - ("sh_flags", c_uint), - ("sh_addr", c_uint), - ("sh_offset", c_uint), - ("sh_size", c_uint), - ("sh_link", c_uint), - ("sh_info", c_uint), - ("sh_addralign", c_uint), - ("sh_entsize", c_uint) - ] - -class Elf64_Shdr_MSB(BigEndianStructure): - _fields_ = [ - ("sh_name", c_uint), - ("sh_type", c_uint), - ("sh_flags", c_ulonglong), - ("sh_addr", c_ulonglong), - ("sh_offset", c_ulonglong), - ("sh_size", c_ulonglong), - ("sh_link", c_uint), - ("sh_info", c_uint), - ("sh_addralign", c_ulonglong), - ("sh_entsize", c_ulonglong) - ] - -class Elf32_Sym_LSB(LittleEndianStructure): - _fields_ = [ - ("st_name", c_uint), - ("st_value", c_uint), - ("st_size", c_uint), - ("st_info", c_ubyte), - ("st_other", c_ubyte), - ("st_shndx", c_ushort) - ] - -class Elf64_Sym_LSB(LittleEndianStructure): - _fields_ = [ - ("st_name", c_uint), - ("st_info", c_ubyte), - ("st_other", c_ubyte), - ("st_shndx", c_ushort), - ("st_value", c_ulonglong), - ("st_size", c_ulonglong) - ] - -class Elf32_Sym_MSB(BigEndianStructure): - _fields_ = [ - ("st_name", c_uint), - ("st_value", c_uint), - ("st_size", c_uint), - ("st_info", c_ubyte), - ("st_other", c_ubyte), - ("st_shndx", c_ushort) - ] - -class Elf64_Sym_MSB(BigEndianStructure): - _fields_ = [ - ("st_name", c_uint), - ("st_info", c_ubyte), - ("st_other", c_ubyte), - ("st_shndx", c_ushort), - ("st_value", c_ulonglong), - ("st_size", c_ulonglong) - ] - - -""" This class parses the ELF """ -class ELF: - def __init__(self, binary): - self.binary = bytearray(binary) - self.ElfHeader = None - self.shdr_l = [] - self.phdr_l = [] - self.syms_l = [] - self.e_ident = self.binary[:15] - self.ei_data = unpack(" symtab.sh_offset: - self.cut_at_offset(strtab.sh_offset, strtab.sh_size) - self.cut_at_offset(symtab.sh_offset, symtab.sh_size) - else: - self.cut_at_offset(symtab.sh_offset, symtab.sh_size) - self.cut_at_offset(strtab.sh_offset, strtab.sh_size) - - self.binary = self.binary[0:sz_striped] - self.write(0, self.ElfHeader) - return True - - def get_symtab(self): - shstrtab = bytes(self.get_shstrtab_data()) - for sh in self.shdr_l: - sh_name = shstrtab[sh.sh_name:].split(b"\0")[0] - if sh.sh_type == SHTypes.SHT_SYMTAB and \ - (sh.sh_name == SHN_UNDEF or sh_name == ".symtab"): - return sh - return None - - def get_strtab(self): - shstrtab = bytes(self.get_shstrtab_data()) - for sh in self.shdr_l: - sh_name = shstrtab[sh.sh_name:].split(b"\0")[0] - if sh.sh_type == SHTypes.SHT_STRTAB and \ - (sh.sh_name == SHN_UNDEF or sh_name == ".strtab"): - return sh - return None - - def getArchMode(self): - if self.ElfHeader.e_ident[ELFFlags.EI_CLASS] == ELFFlags.ELFCLASS32: - return 32 - elif self.ElfHeader.e_ident[ELFFlags.EI_CLASS] == ELFFlags.ELFCLASS64: - return 64 - else: - log("[Error] ELF.getArchMode() - Bad Arch size") - return None - - """ Parse ELF header """ - def __setHeaderElf(self): - e_ident = self.binary[:15] - - ei_class = unpack(" - """, { - 'formChangeCb' : Form.FormChangeCb(self.OnFormChange), - 'txtFile' : Form.FileInput(save=True, swidth=50) - }) - - self.input_elf = ida_nalt.get_input_file_path() - - def OnFormChange(self, fid): - if fid == self.txtFile.id: - o_file = self.GetControlValue(self.txtFile) - - if os.path.exists(o_file): - s = "Output file already exists\n" \ - "The output file already exists. " \ - "Do you want to overwrite it?" - - if bool(ida_kernwin.ask_form(s, "1")): - os.remove(o_file) - else: - self.SetControlValue(self.txtFile, '') - return 1 - - def Show(self): - if not self.Compiled(): - self.Compile() - - if "ELF" in get_file_type_name(): - ok = self.Execute() - else: - warning("The input file is not a ELF") - ok = 0 - return ok - - class Syms2Elf_t(plugin_t): - flags = PLUGIN_UNL - comment = "" - help = "" - wanted_name = PLUG_NAME - wanted_hotkey = "" - - def init(self): - return PLUGIN_OK - - def run(self, arg=0): - f = Syms2Elf() - - if f.Show(): - symbols = get_ida_symbols() - output_file = f.txtFile.value - write_symbols(f.input_elf, output_file, symbols) - f.Free() - - def term(self): - pass - - def PLUGIN_ENTRY(): - return Syms2Elf_t() - -elif USE_R2: - - import r2pipe - r2p = r2pipe.open() - log = log_r2 - - if len(sys.argv) < 2: - log("Usage: $syms2elf ") - sys.exit(0) - - file_info = r2p.cmdj("ij").get("core") - - if file_info['format'].lower() in ('elf','elf64'): - symbols = get_r2_symbols() - write_symbols(file_info['file'], sys.argv[1], symbols) - else: - log("The input file is not a ELF") - - +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# sym2elf +# 28/11/2014 +# +# Daniel García +# Jesús Olmos +# +# ELF parser - based on the lib of ROPgadget tool by Jonathan Salwan +# http://shell-storm.org/project/ROPgadget/ +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# Ported to rizin by Rukatonoshi + + +PLUG_NAME = "syms2elf" + +import os +import sys +from ctypes import * +from struct import unpack + +USE_R2 = False +USE_IDA = False +USE_RIZIN = False + +try: + import idaapi + USE_IDA = True +except: + if "radare2" in os.environ.get('PATH',''): + USE_R2 = True + elif "rizin" in os.environ.get('PATH',''): + USE_RIZIN = True + else: + print("ERROR: The plugin must be run in IDA, radare2 or rizin") + sys.exit(0) + +SHN_UNDEF = 0 +STB_GLOBAL_FUNC = 0x12 + +class SHTypes: + SHT_NULL = 0 + SHT_PROGBITS = 1 + SHT_SYMTAB = 2 + SHT_STRTAB = 3 + SHT_RELA = 4 + SHT_HASH = 5 + SHT_DYNAMIC = 6 + SHT_NOTE = 7 + SHT_NOBITS = 8 + SHT_REL = 9 + SHT_SHLIB = 10 + SHT_DYNSYM = 11 + SHT_NUM = 12 + SHT_LOPROC = 0x70000000 + SHT_HIPROC = 0x7fffffff + SHT_LOUSER = 0x80000000 + SHT_HIUSER = 0xffffffff + +class ELFFlags: + ELFCLASS32 = 0x01 + ELFCLASS64 = 0x02 + EI_CLASS = 0x04 + EI_DATA = 0x05 + ELFDATA2LSB = 0x01 + ELFDATA2MSB = 0x02 + EM_386 = 0x03 + EM_X86_64 = 0x3e + EM_ARM = 0x28 + EM_MIPS = 0x08 + EM_SPARCv8p = 0x12 + EM_PowerPC = 0x14 + EM_ARM64 = 0xb7 + +class SymFlags: + STB_LOCAL = 0 + STB_GLOBAL = 1 + STB_WEAK = 2 + STT_NOTYPE = 0 + STT_OBJECT = 1 + STT_FUNC = 2 + STT_SECTION = 3 + STT_FILE = 4 + STT_COMMON = 5 + STT_TLS = 6 + +class Elf32_Ehdr_LSB(LittleEndianStructure): + _fields_ = [ + ("e_ident", c_ubyte * 16), + ("e_type", c_ushort), + ("e_machine", c_ushort), + ("e_version", c_uint), + ("e_entry", c_uint), + ("e_phoff", c_uint), + ("e_shoff", c_uint), + ("e_flags", c_uint), + ("e_ehsize", c_ushort), + ("e_phentsize", c_ushort), + ("e_phnum", c_ushort), + ("e_shentsize", c_ushort), + ("e_shnum", c_ushort), + ("e_shstrndx", c_ushort) + ] + +class Elf64_Ehdr_LSB(LittleEndianStructure): + _fields_ = [ + ("e_ident", c_ubyte * 16), + ("e_type", c_ushort), + ("e_machine", c_ushort), + ("e_version", c_uint), + ("e_entry", c_ulonglong), + ("e_phoff", c_ulonglong), + ("e_shoff", c_ulonglong), + ("e_flags", c_uint), + ("e_ehsize", c_ushort), + ("e_phentsize", c_ushort), + ("e_phnum", c_ushort), + ("e_shentsize", c_ushort), + ("e_shnum", c_ushort), + ("e_shstrndx", c_ushort) + ] + +class Elf32_Phdr_LSB(LittleEndianStructure): + _fields_ = [ + ("p_type", c_uint), + ("p_offset", c_uint), + ("p_vaddr", c_uint), + ("p_paddr", c_uint), + ("p_filesz", c_uint), + ("p_memsz", c_uint), + ("p_flags", c_uint), + ("p_align", c_uint) + ] + +class Elf64_Phdr_LSB(LittleEndianStructure): + _fields_ = [ + ("p_type", c_uint), + ("p_flags", c_uint), + ("p_offset", c_ulonglong), + ("p_vaddr", c_ulonglong), + ("p_paddr", c_ulonglong), + ("p_filesz", c_ulonglong), + ("p_memsz", c_ulonglong), + ("p_align", c_ulonglong) + ] + +class Elf32_Shdr_LSB(LittleEndianStructure): + _fields_ = [ + ("sh_name", c_uint), + ("sh_type", c_uint), + ("sh_flags", c_uint), + ("sh_addr", c_uint), + ("sh_offset", c_uint), + ("sh_size", c_uint), + ("sh_link", c_uint), + ("sh_info", c_uint), + ("sh_addralign", c_uint), + ("sh_entsize", c_uint) + ] + +class Elf64_Shdr_LSB(LittleEndianStructure): + _fields_ = [ + ("sh_name", c_uint), + ("sh_type", c_uint), + ("sh_flags", c_ulonglong), + ("sh_addr", c_ulonglong), + ("sh_offset", c_ulonglong), + ("sh_size", c_ulonglong), + ("sh_link", c_uint), + ("sh_info", c_uint), + ("sh_addralign", c_ulonglong), + ("sh_entsize", c_ulonglong) + ] + +class Elf32_Ehdr_MSB(BigEndianStructure): + _fields_ = [ + ("e_ident", c_ubyte * 16), + ("e_type", c_ushort), + ("e_machine", c_ushort), + ("e_version", c_uint), + ("e_entry", c_uint), + ("e_phoff", c_uint), + ("e_shoff", c_uint), + ("e_flags", c_uint), + ("e_ehsize", c_ushort), + ("e_phentsize", c_ushort), + ("e_phnum", c_ushort), + ("e_shentsize", c_ushort), + ("e_shnum", c_ushort), + ("e_shstrndx", c_ushort) + ] + +class Elf64_Ehdr_MSB(BigEndianStructure): + _fields_ = [ + ("e_ident", c_ubyte * 16), + ("e_type", c_ushort), + ("e_machine", c_ushort), + ("e_version", c_uint), + ("e_entry", c_ulonglong), + ("e_phoff", c_ulonglong), + ("e_shoff", c_ulonglong), + ("e_flags", c_uint), + ("e_ehsize", c_ushort), + ("e_phentsize", c_ushort), + ("e_phnum", c_ushort), + ("e_shentsize", c_ushort), + ("e_shnum", c_ushort), + ("e_shstrndx", c_ushort) + ] + +class Elf32_Phdr_MSB(BigEndianStructure): + _fields_ = [ + ("p_type", c_uint), + ("p_offset", c_uint), + ("p_vaddr", c_uint), + ("p_paddr", c_uint), + ("p_filesz", c_uint), + ("p_memsz", c_uint), + ("p_flags", c_uint), + ("p_align", c_uint) + ] + +class Elf64_Phdr_MSB(BigEndianStructure): + _fields_ = [ + ("p_type", c_uint), + ("p_flags", c_uint), + ("p_offset", c_ulonglong), + ("p_vaddr", c_ulonglong), + ("p_paddr", c_ulonglong), + ("p_filesz", c_ulonglong), + ("p_memsz", c_ulonglong), + ("p_align", c_ulonglong) + ] + +class Elf32_Shdr_MSB(BigEndianStructure): + _fields_ = [ + ("sh_name", c_uint), + ("sh_type", c_uint), + ("sh_flags", c_uint), + ("sh_addr", c_uint), + ("sh_offset", c_uint), + ("sh_size", c_uint), + ("sh_link", c_uint), + ("sh_info", c_uint), + ("sh_addralign", c_uint), + ("sh_entsize", c_uint) + ] + +class Elf64_Shdr_MSB(BigEndianStructure): + _fields_ = [ + ("sh_name", c_uint), + ("sh_type", c_uint), + ("sh_flags", c_ulonglong), + ("sh_addr", c_ulonglong), + ("sh_offset", c_ulonglong), + ("sh_size", c_ulonglong), + ("sh_link", c_uint), + ("sh_info", c_uint), + ("sh_addralign", c_ulonglong), + ("sh_entsize", c_ulonglong) + ] + +class Elf32_Sym_LSB(LittleEndianStructure): + _fields_ = [ + ("st_name", c_uint), + ("st_value", c_uint), + ("st_size", c_uint), + ("st_info", c_ubyte), + ("st_other", c_ubyte), + ("st_shndx", c_ushort) + ] + +class Elf64_Sym_LSB(LittleEndianStructure): + _fields_ = [ + ("st_name", c_uint), + ("st_info", c_ubyte), + ("st_other", c_ubyte), + ("st_shndx", c_ushort), + ("st_value", c_ulonglong), + ("st_size", c_ulonglong) + ] + +class Elf32_Sym_MSB(BigEndianStructure): + _fields_ = [ + ("st_name", c_uint), + ("st_value", c_uint), + ("st_size", c_uint), + ("st_info", c_ubyte), + ("st_other", c_ubyte), + ("st_shndx", c_ushort) + ] + +class Elf64_Sym_MSB(BigEndianStructure): + _fields_ = [ + ("st_name", c_uint), + ("st_info", c_ubyte), + ("st_other", c_ubyte), + ("st_shndx", c_ushort), + ("st_value", c_ulonglong), + ("st_size", c_ulonglong) + ] + + +""" This class parses the ELF """ +class ELF: + def __init__(self, binary): + self.binary = bytearray(binary) + self.ElfHeader = None + self.shdr_l = [] + self.phdr_l = [] + self.syms_l = [] + self.e_ident = self.binary[:15] + self.ei_data = unpack(" symtab.sh_offset: + self.cut_at_offset(strtab.sh_offset, strtab.sh_size) + self.cut_at_offset(symtab.sh_offset, symtab.sh_size) + else: + self.cut_at_offset(symtab.sh_offset, symtab.sh_size) + self.cut_at_offset(strtab.sh_offset, strtab.sh_size) + + self.binary = self.binary[0:sz_striped] + self.write(0, self.ElfHeader) + return True + + def get_symtab(self): + shstrtab = bytes(self.get_shstrtab_data()) + for sh in self.shdr_l: + sh_name = shstrtab[sh.sh_name:].split(b"\0")[0] + if sh.sh_type == SHTypes.SHT_SYMTAB and \ + (sh.sh_name == SHN_UNDEF or sh_name == ".symtab"): + return sh + return None + + def get_strtab(self): + shstrtab = bytes(self.get_shstrtab_data()) + for sh in self.shdr_l: + sh_name = shstrtab[sh.sh_name:].split(b"\0")[0] + if sh.sh_type == SHTypes.SHT_STRTAB and \ + (sh.sh_name == SHN_UNDEF or sh_name == ".strtab"): + return sh + return None + + def getArchMode(self): + if self.ElfHeader.e_ident[ELFFlags.EI_CLASS] == ELFFlags.ELFCLASS32: + return 32 + elif self.ElfHeader.e_ident[ELFFlags.EI_CLASS] == ELFFlags.ELFCLASS64: + return 64 + else: + log("[Error] ELF.getArchMode() - Bad Arch size") + return None + + """ Parse ELF header """ + def __setHeaderElf(self): + e_ident = self.binary[:15] + + ei_class = unpack(" + """, { + 'formChangeCb' : Form.FormChangeCb(self.OnFormChange), + 'txtFile' : Form.FileInput(save=True, swidth=50) + }) + + self.input_elf = ida_nalt.get_input_file_path() + + def OnFormChange(self, fid): + if fid == self.txtFile.id: + o_file = self.GetControlValue(self.txtFile) + + if os.path.exists(o_file): + s = "Output file already exists\n" \ + "The output file already exists. " \ + "Do you want to overwrite it?" + + if bool(ida_kernwin.ask_form(s, "1")): + os.remove(o_file) + else: + self.SetControlValue(self.txtFile, '') + return 1 + + def Show(self): + if not self.Compiled(): + self.Compile() + + if "ELF" in get_file_type_name(): + ok = self.Execute() + else: + warning("The input file is not a ELF") + ok = 0 + return ok + + class Syms2Elf_t(plugin_t): + flags = PLUGIN_UNL + comment = "" + help = "" + wanted_name = PLUG_NAME + wanted_hotkey = "" + + def init(self): + return PLUGIN_OK + + def run(self, arg=0): + f = Syms2Elf() + + if f.Show(): + symbols = get_ida_symbols() + output_file = f.txtFile.value + write_symbols(f.input_elf, output_file, symbols) + f.Free() + + def term(self): + pass + + def PLUGIN_ENTRY(): + return Syms2Elf_t() + +elif USE_R2: + import r2pipe + r2p = r2pipe.open() + log = log_r2 + + if len(sys.argv) < 2: + log("Usage: #!pipe python ./syms2elf.py ") + sys.exit(0) + + file_info = r2p.cmdj("ij").get("core") + #print(file_info) + + if file_info['format'].lower() in ('elf','elf64'): + symbols = get_r2_symbols() + write_symbols(file_info['file'], sys.argv[1], symbols) + else: + log("The input file is not a ELF") + +elif USE_RIZIN: + import rzpipe + + rzp = rzpipe.open() + log = log_r2 + + if len(sys.argv) < 2: + log("Usage: #!pipe python ./syms2elf.py ") + sys.exit(0) + + file_info = rzp.cmdj("ij").get("core") + #print(file_info) + + if file_info['format'].lower() in ('elf','elf64'): + symbols = get_rizin_symbols() + write_symbols(file_info['file'], sys.argv[1], symbols) + else: + log("The input file is not a ELF") + sys.exit(0) From 016f048772bc94894f733c2bded22d8918f832b0 Mon Sep 17 00:00:00 2001 From: Rukatonoshi <40752497+Rukatonoshi@users.noreply.github.com> Date: Thu, 28 Jul 2022 16:20:25 +0300 Subject: [PATCH 2/8] Update README.md Fixed commands and added picture of working with rizin\radare2 --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dc7056f..be608f3 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,8 @@ Supports 32 and 64-bits file format. * **IDA Pro**: Simply, copy `syms2elf.py` to the IDA's plugins folder. * **radare2**: In radare2 environment, pass this command: #!pipe python ./syms2elf.py * **rizin** : In rizin environment, pass this command: #!pipe python ./syms2elf.py - + * Also, if you are using radare2, make sure that you have install r2pipe. You can use this command: pip3 install r2pipe + * For rizin: pip3 install rzpipe @@ -25,7 +26,7 @@ Rename some functions in IDA or r2, run `syms2elf` and select the output file. ![IDA output log](https://cloud.githubusercontent.com/assets/1675387/13477862/a02aa742-e0ce-11e5-835e-3a0992a3f171.png) -![r2_syms2elf](https://cloud.githubusercontent.com/assets/1675387/13831270/adddfae2-ebd2-11e5-8dcd-877c9c67faed.png) +![r2_syms2elf](https://user-images.githubusercontent.com/40752497/181514837-0fe5de8a-29db-4a67-a614-f10a773b5e1c.png) After that: From a76b69094de517215ae3713475a03de14a9fbb1b Mon Sep 17 00:00:00 2001 From: Rukatonoshi Date: Thu, 28 Jul 2022 17:16:29 +0300 Subject: [PATCH 3/8] Ported syms2elf plugin to cutter --- syms2elf.py | 141 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 130 insertions(+), 11 deletions(-) diff --git a/syms2elf.py b/syms2elf.py index d024515..d97a317 100644 --- a/syms2elf.py +++ b/syms2elf.py @@ -15,7 +15,8 @@ # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # Ported to rizin by Rukatonoshi - +from PySide2.QtCore import Qt +from PySide2.QtWidgets import QHBoxLayout, QLabel, QWidget, QSizePolicy, QPushButton, QLineEdit PLUG_NAME = "syms2elf" @@ -27,18 +28,23 @@ USE_R2 = False USE_IDA = False USE_RIZIN = False +USE_CUTTER = False try: - import idaapi - USE_IDA = True + import cutter + USE_CUTTER = True except: - if "radare2" in os.environ.get('PATH',''): - USE_R2 = True - elif "rizin" in os.environ.get('PATH',''): - USE_RIZIN = True - else: - print("ERROR: The plugin must be run in IDA, radare2 or rizin") - sys.exit(0) + try: + import idaapi + USE_IDA = True + except: + if "radare2" in os.environ.get('PATH',''): + USE_R2 = True + elif "rizin" in os.environ.get('PATH',''): + USE_RIZIN = True + else: + print("ERROR: The plugin must be run in IDA, radare2, rizin or cutter") + sys.exit(0) SHN_UNDEF = 0 STB_GLOBAL_FUNC = 0x12 @@ -575,7 +581,10 @@ def __str__(self): self.info, self.shname) def log(msg=''): - print("[%s] %s" % (PLUG_NAME, msg)) + try: + print("[%s] %s" % (PLUG_NAME, msg)) + except: + cutter.message("[%s] %s" % (PLUG_NAME, msg)) def log_r2(msg=''): print("%s" % msg) @@ -715,6 +724,12 @@ def get_section_rz(addr): return (idx, s['name']) return None +def get_section_cutter(addr): + for idx, s in enumerate(cutter.cmdj("iSj")): + if s['vaddr'] <= addr < (s['vaddr'] + s['size']): + return (idx, s['name']) + return None + def r2_fcn_filter(fcn): if fcn['name'].startswith(("sym.imp", "loc.imp", "section")): return False @@ -754,6 +769,38 @@ def get_rizin_symbols(): return symbols +def get_section_cutter(addr): + for idx, s in enumerate(cutter.cmdj("iSj")): + if s['vaddr'] <= addr < (s['vaddr'] + s['size']): + return (idx, s['name']) + return None + +def get_cutter_symbols(): + symbols = [] + + for fnc in filter(r2_fcn_filter, cutter.cmdj("aflj")): + sh_idx, sh_name = get_section_cutter(fnc['offset']) + fnc_name = fnc['name'] + + if fnc_name.startswith(("sym","fcn")): + fnc_name = fnc_name[4:] + if fnc_name.startswith("go."): + fnc_name = fnc_name[3:] + + symbols.append(Symbol(fnc_name, STB_GLOBAL_FUNC, + fnc['offset'], int(fnc['size']), sh_name)) + + return symbols + +def get_path(file_path): + i = 0 + path_to_dir = "" + for pos, char in enumerate(file_path): + if char == '/': + i = pos + path_to_dir = file_path[:i+1] + return path_to_dir + if USE_IDA: import ida_kernwin @@ -862,3 +909,75 @@ def PLUGIN_ENTRY(): else: log("The input file is not a ELF") sys.exit(0) + +elif USE_CUTTER: + class Syms2ElfWidget(cutter.CutterDockWidget): + def __init__(self, parent): + super(Syms2ElfWidget, self).__init__(parent) + self.setObjectName("WidgetForSyms2Elf") + self.setWindowTitle("syms2elf") + + content = QWidget() + self.setWidget(content) + + # Create layout and label + layout = QHBoxLayout(content) + + self.output_path = QLineEdit(content) + self.output_path.setPlaceholderText("Enter the filename") + self.output_path.setMinimumWidth(400) + layout.addWidget(self.output_path) + layout.setAlignment(self.output_path, Qt.AlignHCenter | Qt.AlignTrailing) + + button = QPushButton(content) + button.setText("Export") + button.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) + button.setMaximumHeight(50) + button.setMaximumWidth(200) + layout.addWidget(button) + layout.setAlignment(button, Qt.AlignHCenter | Qt.AlignLeading) + + button.clicked.connect(self.export_syms) + + self.show() + + def export_syms(self): + file_info = cutter.cmdj("ij").get("core") + #cutter.message("%s\n" % file_info) + file_name = self.output_path.text() + + if file_info['format'].lower() in ('elf','elf64'): + symbols = get_cutter_symbols() + #cutter.message("%s\n" % symbols) + path = get_path(file_info['file']) + file_name = path + file_name + #cutter.message("%s\n" % file_name) + write_symbols(file_info['file'], file_name, symbols) + else: + cutter.message("The input file is not an ELF!") + + + class CutterSyms2ElfPlugin(cutter.CutterPlugin): + name = "Syms2Elf Plugin" + description = "Export the symbols to the ELF symbol table." + version = "1.1" + author = "Rukatonoshi" + + # Override CutterPlugin methods + + def __init__(self): + super(CutterSyms2ElfPlugin, self).__init__() + + def setupPlugin(self): + pass + + def setupInterface(self, main): + # Dock widget + widget = Syms2ElfWidget(main) + main.addPluginDockWidget(widget) + + def terminate(self): # optional + cutter.message("CutterSyms2ElfPlugin shutting down") + + def create_cutter_plugin(): + return CutterSyms2ElfPlugin() From 2267a8eac5b70309ef656bb729ca27d007e9283b Mon Sep 17 00:00:00 2001 From: Rukatonoshi <40752497+Rukatonoshi@users.noreply.github.com> Date: Thu, 28 Jul 2022 17:20:13 +0300 Subject: [PATCH 4/8] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index be608f3..6828764 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,9 @@ Rename some functions in IDA or r2, run `syms2elf` and select the output file. ![r2_syms2elf](https://user-images.githubusercontent.com/40752497/181514837-0fe5de8a-29db-4a67-a614-f10a773b5e1c.png) +![cutter](https://user-images.githubusercontent.com/40752497/181536360-f725857c-1893-48c4-ac4a-96288a034b31.png) + + After that: ``` From 28e9908789ecf707171a883682dd793eff91ca74 Mon Sep 17 00:00:00 2001 From: Rukatonoshi <40752497+Rukatonoshi@users.noreply.github.com> Date: Tue, 16 Aug 2022 16:11:09 +0300 Subject: [PATCH 5/8] Update README.md --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6828764..544dda3 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,10 @@ Supports 32 and 64-bits file format. ## INSTALLATION * **IDA Pro**: Simply, copy `syms2elf.py` to the IDA's plugins folder. - * **radare2**: In radare2 environment, pass this command: #!pipe python ./syms2elf.py - * **rizin** : In rizin environment, pass this command: #!pipe python ./syms2elf.py - * Also, if you are using radare2, make sure that you have install r2pipe. You can use this command: pip3 install r2pipe - * For rizin: pip3 install rzpipe + * **radare2**: In radare2 environment, pass this command: `#!pipe python ./syms2elf.py ` + * **rizin** : In rizin environment, pass this command: `#!pipe python ./syms2elf.py ` + * Also, if you are using radare2, make sure that you have install r2pipe. You can use this command: `pip3 install r2pipe` + * For rizin: `pip3 install rzpipe` @@ -44,6 +44,9 @@ Now, you can open it with others tools and analyzing in a more comfortable way. * Daniel García (@danigargu) * Jesús Olmos (@sha0coder) + * Stupnitskiy Ivan (@YanagiRu) -- plugin porting ## CONTACT Any comment or request will be highly appreciated :-) + +This modification (plugin porting to rizin & cutter) was started as a part of [Digital Security](https://github.com/DSecurity)'s Research Centre internship ["Summ3r of h4ck 2022"](https://dsec.ru/about/vacancies/#internship). From 6893b057db0a5fedde802ba14693332c15e30ea7 Mon Sep 17 00:00:00 2001 From: Rukatonoshi <40752497+Rukatonoshi@users.noreply.github.com> Date: Tue, 16 Aug 2022 16:11:49 +0300 Subject: [PATCH 6/8] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 544dda3..7d0f357 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Now, you can open it with others tools and analyzing in a more comfortable way. * Daniel García (@danigargu) * Jesús Olmos (@sha0coder) - * Stupnitskiy Ivan (@YanagiRu) -- plugin porting + * Ivan Stupnitskiy (@YanagiRu) -- plugin porting ## CONTACT Any comment or request will be highly appreciated :-) From a1b2053df6bc389f4e95b6aa113da917738eca63 Mon Sep 17 00:00:00 2001 From: Rukatonoshi <40752497+Rukatonoshi@users.noreply.github.com> Date: Tue, 16 Aug 2022 16:12:26 +0300 Subject: [PATCH 7/8] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7d0f357..f76aa6c 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Supports 32 and 64-bits file format. * **IDA Pro**: Simply, copy `syms2elf.py` to the IDA's plugins folder. * **radare2**: In radare2 environment, pass this command: `#!pipe python ./syms2elf.py ` * **rizin** : In rizin environment, pass this command: `#!pipe python ./syms2elf.py ` - * Also, if you are using radare2, make sure that you have install r2pipe. You can use this command: `pip3 install r2pipe` + * If you are using radare2, make sure that you have install r2pipe. You can use this command: `pip3 install r2pipe` * For rizin: `pip3 install rzpipe` From e491a9342f7e808843da9f864599b214f04c0696 Mon Sep 17 00:00:00 2001 From: Rukatonoshi <40752497+Rukatonoshi@users.noreply.github.com> Date: Wed, 17 Aug 2022 16:22:51 +0300 Subject: [PATCH 8/8] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f76aa6c..0638a04 100644 --- a/README.md +++ b/README.md @@ -49,4 +49,5 @@ Now, you can open it with others tools and analyzing in a more comfortable way. Any comment or request will be highly appreciated :-) +## AND ALSO This modification (plugin porting to rizin & cutter) was started as a part of [Digital Security](https://github.com/DSecurity)'s Research Centre internship ["Summ3r of h4ck 2022"](https://dsec.ru/about/vacancies/#internship).