Android 逆向使用 Python 解析 ELF 文件 ( Capstone 反汇编 ELF 文件中的机器码数据 | 完整代码示例 ) ★★★

Posted 韩曙亮

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 逆向使用 Python 解析 ELF 文件 ( Capstone 反汇编 ELF 文件中的机器码数据 | 完整代码示例 ) ★★★相关的知识,希望对你有一定的参考价值。





一、完整代码示例



使用 Python 解析 ELF 文件完整代码示例 :

# coding=utf-8
# 解析 elf 文件需要导入的依赖库
# 安装 pyelftools 库成功 , 安装 elftools 库会报错
from elftools.elf.elffile import ELFFile
# 导入 Capstone 反汇编框架 , 用于解析 ELF 文件
from capstone import *


def main():
    # 要解析的动态库路径
    elf_path = r'libwtcrypto.so'
    # 打开 elf 文件
    file = open(elf_path, 'rb')
    # 创建 ELFFile 对象 , 该对象是核心对象
    elf_file = ELFFile(file)

    # 打印 elf 文件头
    print(elf_file.header)
    # 打印 程序头入口 个数
    print(elf_file.num_segments())
    # 打印 节区头入口 个数
    print(elf_file.num_sections())

    # 遍历打印 程序头入口
    for segment in elf_file.iter_segments():
        print(segment.header)

    # 遍历打印 节区头入口
    for section in elf_file.iter_sections():
        print('name:', section.name)
        print('header', section.header)

        # 使用 Capstone 反汇编框架
        # 节区入口名称是 .text , 表示该节区数据是代码数据
        if section.name == '.text':
            # 获取节区地址
            file.seek(section.header['sh_addr'])
            # 获取节区大小
            sh_size = section.header['sh_size']
            # 读取 节区 二进制数据
            #   这是需要反汇编的机器码数据
            raw = file.read(sh_size)
            # 创建 Capstone 实例对象
            capstone = Cs(CS_ARCH_X86, CS_MODE_32)
            # 此处设置为 true , 表示需要显示细节 , 打开后 , 会标明每条汇编代码中对寄存器的影响
            #   如 : 本条汇编代码中 , 会读写哪些寄存器
            capstone.detail = True
            # 向汇编解析器中传入 节区数据 对应的 二进制数据 , 这些二进制数据都是机器码数据
            #   即 , 需要反汇编这些二进制数据为 汇编 代码
            # 第一个参数设置二进制数据
            # 第二个参数指的是读取 raw 二进制数据的起始地址 , 一般设置 0 即可
            # 得到的是反汇编后的汇编代码列表 , 如果反汇编失败 , 此处为空
            disasm = capstone.disasm(raw, 0)
            # 遍历反汇编代码列表
            for line in disasm:
                # 打印每行汇编代码的 地址 , 指令 , 操作对象
                text = '%08X: %s %s ' % (line.address, line.mnemonic, line.op_str)
                # 统计汇编代码行的字符串个数 , 保证在第 55 字节处打印寄存器读写信息
                # 00000000: push ebx                                     ; 读寄存器:esp 写寄存器:esp ; 机器码 :53
                length = len(text)
                if length < 55:
                    text += ' ' * (55 - length)
                text += ';'
                # 读取操作影响到的寄存器
                if hasattr(line, 'regs_read') and len(line.regs_read) > 0:
                    text += ' 读寄存器:'
                    for j, r in enumerate(line.regs_read):
                        if j > 0:
                            text += ','
                        text += '%s' % line.reg_name(r)
                # 写出操作影响到的寄存器
                if hasattr(line, 'regs_write') and len(line.regs_write) > 0:
                    text += ' 写寄存器:'
                    for j, r in enumerate(line.regs_write):
                        if j > 0:
                            text += ','
                        text += '%s' % line.reg_name(r)
                text += ' ; 机器码 :'
                # 打印 本条汇编代码对应的 机器码
                for i in range(line.size):
                    text += '%02X ' % line.bytes[i]
                # 打印最终数据
                print(text)
            pass
    # 关闭文件
    file.close()
    pass


if __name__ == '__main__':
    main()





二、执行结果



D:\\001_Develop\\022_Python\\Python39\\python.exe C:/Users/octop/PycharmProjects/ELF_Parser/main.py
Container({'e_ident': Container({'EI_MAG': [127, 69, 76, 70], 'EI_CLASS': 'ELFCLASS32', 'EI_DATA': 'ELFDATA2LSB', 'EI_VERSION': 'EV_CURRENT', 'EI_OSABI': 'ELFOSABI_SYSV', 'EI_ABIVERSION': 0}), 'e_type': 'ET_DYN', 'e_machine': 'EM_386', 'e_version': 'EV_CURRENT', 'e_entry': 0, 'e_phoff': 52, 'e_shoff': 16652, 'e_flags': 0, 'e_ehsize': 52, 'e_phentsize': 32, 'e_phnum': 7, 'e_shentsize': 40, 'e_shnum': 21, 'e_shstrndx': 20})
7
21
Container({'p_type': 'PT_PHDR', 'p_offset': 52, 'p_vaddr': 52, 'p_paddr': 52, 'p_filesz': 224, 'p_memsz': 224, 'p_flags': 4, 'p_align': 4})
Container({'p_type': 'PT_LOAD', 'p_offset': 0, 'p_vaddr': 0, 'p_paddr': 0, 'p_filesz': 11872, 'p_memsz': 11872, 'p_flags': 5, 'p_align': 4096})
Container({'p_type': 'PT_LOAD', 'p_offset': 15944, 'p_vaddr': 20040, 'p_paddr': 20040, 'p_filesz': 444, 'p_memsz': 4568, 'p_flags': 6, 'p_align': 4096})
Container({'p_type': 'PT_DYNAMIC', 'p_offset': 15956, 'p_vaddr': 20052, 'p_paddr': 20052, 'p_filesz': 272, 'p_memsz': 272, 'p_flags': 6, 'p_align': 4})
Container({'p_type': 'PT_GNU_EH_FRAME', 'p_offset': 11716, 'p_vaddr': 11716, 'p_paddr': 11716, 'p_filesz': 156, 'p_memsz': 156, 'p_flags': 4, 'p_align': 4})
Container({'p_type': 'PT_GNU_STACK', 'p_offset': 0, 'p_vaddr': 0, 'p_paddr': 0, 'p_filesz': 0, 'p_memsz': 0, 'p_flags': 6, 'p_align': 0})
Container({'p_type': 'PT_GNU_RELRO', 'p_offset': 15944, 'p_vaddr': 20040, 'p_paddr': 20040, 'p_filesz': 440, 'p_memsz': 440, 'p_flags': 6, 'p_align': 4})
name: 
header Container({'sh_name': 0, 'sh_type': 'SHT_NULL', 'sh_flags': 0, 'sh_addr': 0, 'sh_offset': 0, 'sh_size': 0, 'sh_link': 0, 'sh_info': 0, 'sh_addralign': 0, 'sh_entsize': 0})
name: .dynsym
header Container({'sh_name': 11, 'sh_type': 'SHT_DYNSYM', 'sh_flags': 2, 'sh_addr': 276, 'sh_offset': 276, 'sh_size': 832, 'sh_link': 2, 'sh_info': 1, 'sh_addralign': 4, 'sh_entsize': 16})
name: .dynstr
header Container({'sh_name': 19, 'sh_type': 'SHT_STRTAB', 'sh_flags': 2, 'sh_addr': 1108, 'sh_offset': 1108, 'sh_size': 892, 'sh_link': 0, 'sh_info': 0, 'sh_addralign': 1, 'sh_entsize': 0})
name: .hash
header Container({'sh_name': 27, 'sh_type': 'SHT_HASH', 'sh_flags': 2, 'sh_addr': 2000, 'sh_offset': 2000, 'sh_size': 364, 'sh_link': 1, 'sh_info': 0, 'sh_addralign': 4, 'sh_entsize': 4})
name: .rel.dyn
header Container({'sh_name': 33, 'sh_type': 'SHT_REL', 'sh_flags': 2, 'sh_addr': 2364, 'sh_offset': 2364, 'sh_size': 24, 'sh_link': 1, 'sh_info': 0, 'sh_addralign': 4, 'sh_entsize': 8})
name: .rel.plt
header Container({'sh_name': 42, 'sh_type': 'SHT_REL', 'sh_flags': 2, 'sh_addr': 2388, 'sh_offset': 2388, 'sh_size': 280, 'sh_link': 1, 'sh_info': 6, 'sh_addralign': 4, 'sh_entsize': 8})
name: .plt
header Container({'sh_name': 46, 'sh_type': 'SHT_PROGBITS', 'sh_flags': 6, 'sh_addr': 2672, 'sh_offset': 2672, 'sh_size': 576, 'sh_link': 0, 'sh_info': 0, 'sh_addralign': 16, 'sh_entsize': 4})
name: .text
header Container({'sh_name': 51, 'sh_type': 'SHT_PROGBITS', 'sh_flags': 6, 'sh_addr': 3248, 'sh_offset': 3248, 'sh_size': 6327, 'sh_link': 0, 'sh_info': 0, 'sh_addralign': 16, 'sh_entsize': 0})
00000000: push ebx                                     ; 读寄存器:esp. 写寄存器:esp ; 机器码 :53 
00000001: call 0xab                                    ; 读寄存器:esp,eip. 写寄存器:esp ; 机器码 :E8 A5 00 00 00 
00000006: add ebx, 0x42b2                              ;. 写寄存器:eflags ; 机器码 :81 C3 B2 42 00 00 
0000000C: lea esp, [esp - 0x18]                        ; ; 机器码 :8D 64 24 E8 
00000010: lea eax, [ebx + 0x98]                        ; ; 机器码 :8D 83 98 00 00 00 
00000016: mov dword ptr [esp], eax                     ; ; 机器码 :89 04 24 
00000019: call 0xfffffdf0                              ; 读寄存器:esp,eip. 写寄存器:esp ; 机器码 :E8 D2 FD FF FF 
0000001E: lea esp, [esp + 0x18]                        ; ; 机器码 :8D 64 24 18 
00000022: pop ebx                                      ; 读寄存器:esp. 写寄存器:esp ; 机器码 :5B 
00000023: ret                                          ; 读寄存器:esp. 写寄存器:esp ; 机器码 :C3 
00000024: add byte ptr [eax], al                       ;. 写寄存器:eflags ; 机器码 :00 00 
00000026: add byte ptr [eax], al                       ;. 写寄存器:eflags ; 机器码 :00 00 
00000028: add byte ptr [eax], al                       ;. 写寄存器:eflags ; 机器码 :00 00 
0000002A: add byte ptr [eax], al                       ;. 写寄存器:eflags ; 机器码 :00 00 
0000002C: add byte ptr [eax], al                       ;. 写寄存器:eflags ; 机器码 :00 00 
0000002E: add byte ptr [eax], al                       ;. 写寄存器:eflags ; 机器码 :00 00 
00000030: lea esp, [esp - 0xc]                         ; ; 机器码 :8D 64 24 F4 
00000034: mov eax, dword ptr [esp + 0x10]              ; ; 机器码 :8B 44 24 10 
00000038: test eax, eax                                ;. 写寄存器:eflags ; 机器码 :85 C0 
0000003A: je 0x3e                                      ; 读寄存器:eflags ; 机器码 :74 02 
0000003C: call eax                                     ; 读寄存器:esp. 写寄存器:esp ; 机器码 :FF D0 




三、博客资源



GitHub : https://github.com/han1202012/ELF_Parser

以上是关于Android 逆向使用 Python 解析 ELF 文件 ( Capstone 反汇编 ELF 文件中的机器码数据 | 完整代码示例 ) ★★★的主要内容,如果未能解决你的问题,请参考以下文章

Android 逆向使用 Python 代码解析 ELF 文件 ( PyCharm 中创建 Python 程序 | 导入 ELFFile 库 | 解析 ELF 文件 )

Android 逆向使用 Python 解析 ELF 文件 ( Capstone 反汇编框架 | PyCharm 中导入 Capstone 反汇编框架 )

Android 逆向使用 Python 解析 ELF 文件 ( Capstone 反汇编 ELF 文件中的机器码数据 | 完整代码示例 ) ★★★

Android 逆向使用 Python 解析 ELF 文件 ( Capstone 反汇编 ELF 文件中的机器码数据 | 创建反汇编解析器实例对象 | 设置汇编解析器显示细节 )(代码片段

Android 逆向使用 Python 解析 ELF 文件 ( Capstone 反汇编 ELF 文件中的机器码数据 | 反汇编二进制机器码 | 打印反汇编数据 )

Android 逆向Android 逆向方法 ( 静态逆向解析 | 函数调用分析 | 动态运行跟踪 | 运行日志分析 | 文件格式解析 | 敏感信息分析 | 网络信息监控 | 环境伪装模拟 )