Windows下IDA_Pro与Stelftools工具结合

Windows下IDA_Pro与Stelftools工具结合

前些阶段接了个项目,要求分析给定的僵尸网络样本。但是文件放入IDA后发现一个库函数都识别不出来,该文件被UPX打包过,并且l_info字段被更改过,修复完毕脱壳后是一个32位的ELF文件。最开始使用过FLAIR工具和libc.a做了一个简易的sig文件,但是也没有识别出什么函数来,询问了大佬,大佬推荐了Stelftools工具,于是我就试着用了这个工具。

前提环境

我IDA版本为IDA7.5 SP3

python环境为3.7

一、Stelftools下载

去github下载,https://github.com/shuakabane/stelftools

下载后根据教程,安装相关文件

本人python环境用的是.3.7的

1.1配置python的相关库

这里需要更改相关的sh文件,我电脑python版本比较多(本文使用3.7),这里/setup/init.sh更改如下

#!/bin/bash
#CURRENT_PATH=$(pwd)
CURRENT_PATH=$(pwd | sed -e 's/\//\\\//g')

# fix STELFTOOLS_PATH
sed -i "s/STELFTOOLS_PATH=\"\/path\/to\/stelftools\/\"/STELFTOOLS_PATH=\"$CURRENT_PATH\/\"/g" func_ident.py
sed -i "s/STELFTOOLS_PATH=\"\/path\/to\/stelftools\/\"/STELFTOOLS_PATH=\"$CURRENT_PATH\/\"/g" DubMaker.py
sed -i "s/STELFTOOLS_PATH=\"\/path\/to\/stelftools\/\"/STELFTOOLS_PATH=\"$CURRENT_PATH\/\"/g" libfunc_info_create.py
sed -i "s/STELFTOOLS_PATH=\"\/path\/to\/stelftools\/\"/STELFTOOLS_PATH=\"$CURRENT_PATH\/\"/g" ida_stelftools.py
# install the python3 package
python -m pip install yara-python
python -m pip install capstone
python -m pip install pyelftools
python -m pip install python-magic
python -m pip install arpy
# add directories to be used by scripts
#mkdir ./_tmpdir
mkdir ./_tmpdir/man_datasets
mkdir ./_tmpdir/link_order_list
mkdir ./_tmpdir/dummy_bin  

在gitbash中运行该文件

在这里插入图片描述

这里本人运行时,报出一些连接超时的问题,可以直接在cmd下载相关库与建立文件夹

下载完所有库后,打开根目录下的DubMaker.py、func_ident.py、libfunc_info_create.py文件,将STELFTOOLS_PATH改为自己stelftools目录,因为在gitbash里的路径都为/d/CTFTools/re之类的,其路径遵循的是linux的一套规范

STELFTOOLS_PATH="D:/CTFTools/re/stelftools-main/"

在这里插入图片描述

这一部分结束后,就可以在终端直接使用了,可如官方教程,

在这里插入图片描述

但是这样做不能在IDA里帮你改sub函数,所以接下来我们在IDA里增加插件

二、IDA增加Stelftools插件

首先gitbash里运行./setup/ida_setup.sh文件

在这里插入图片描述

需要注意的是,这里IDA_pro的路径名得注意我这种格式,并且不能有空格。做完会发现自己的ida根目录里plugins会多出一下python文件

注意,这里的ida_shims.py是后期插入的,文章下面会说该问题

在这里插入图片描述

接下来打开IDA,会发现还是不能和官方的md文件里一样的可以在load file里看到相关,这是因为你还有一些函数没下载完毕或者出现问题,我这里做的时候忘记截图了,注意观察IDA中最下方的output window,去看自己的python缺少哪些库,

在这里插入图片描述

大概有以下库shims,cxxfilt库,这里需要你自己去下载,并且出现ImportError: failed to find libmagic. Check your installation

这里参考大佬https://blog.csdn.net/time_money/article/details/119635746重新下载库

pip uninstall python-magic
pip install python-magic-bin==0.4.14

同时这里出现了一个很关键的问题,我着重讲一下,不知道什么原因,在ida_stelftools.py中,导入from shims import ida_shims会报错,这里我更换了python版本发现也不行,于是根据大佬的博客https://www.cnblogs.com/unr4v31/p/16072562.html,我们直接在ida的plugins文件中,自己建立一个ida_shims文件,并更改ida_stelftools.py的引入,如图

在这里插入图片描述

同时,在./plugins建立ida_shims.py文件,其内容为

import idc
import idaapi

try:
    import ida_bytes
except ImportError:
    ida_bytes = None

try:
    import ida_name
except ImportError:
    ida_name = None

try:
    import ida_kernwin
except ImportError:
    ida_kernwin = None

try:
    import ida_nalt
except ImportError:
    ida_nalt = None

try:
    import ida_ua
except ImportError:
    ida_ua = None

try:
    import ida_funcs
except ImportError:
    ida_funcs = None


def _get_fn_by_version(lib, curr_fn, archive_fn, archive_lib=None):
    if idaapi.IDA_SDK_VERSION >= 700:
        try:
            return getattr(lib, curr_fn)
        except AttributeError:
            raise Exception('%s is not a valid function in %s' % (curr_fn,
                                                                  lib))
    use_lib = lib if archive_lib is None else archive_lib
    try:
        return getattr(use_lib, archive_fn)
    except AttributeError:
        raise Exception('%s is not a valid function in %s' % (archive_fn,
                                                              use_lib))
def print_insn_mnem(ea):
    fn = _get_fn_by_version(idc, 'print_insn_mnem', 'GetMnem')
    return fn(ea)

def print_operand(ea, n):
    fn = _get_fn_by_version(idc, 'print_operand', 'GetOpnd')
    return fn(ea, n)

def define_local_var(start, end, location, name):
    fn = _get_fn_by_version(idc, 'define_local_var', 'MakeLocal')
    return fn(start, end, location, name)

def find_func_end(ea):
    fn = _get_fn_by_version(idc, 'find_func_end', 'FindFuncEnd')
    return fn(ea)


def is_code(flag):
    fn = _get_fn_by_version(ida_bytes, 'is_code', 'isCode', idaapi)
    return fn(flag)


def get_full_flags(ea):
    fn = _get_fn_by_version(ida_bytes, 'get_full_flags', 'getFlags', idaapi)
    return fn(ea)


def get_name(ea):
    fn = _get_fn_by_version(idc, 'get_name', 'Name')

    if idaapi.IDA_SDK_VERSION > 700:
        return fn(ea, ida_name.GN_VISIBLE)
    return fn(ea)


def get_func_off_str(ea):
    fn = _get_fn_by_version(idc, 'get_func_off_str', 'GetFuncOffset')
    return fn(ea)


def jumpto(ea, opnum=-1, uijmp_flags=0x0001):
    fn = _get_fn_by_version(ida_kernwin, 'jumpto', 'Jump', idc)
    if idaapi.IDA_SDK_VERSION >= 700:
        return fn(ea, opnum, uijmp_flags)
    return fn(ea)


def ask_yn(default, format_str):
    fn = _get_fn_by_version(ida_kernwin, 'ask_yn', 'AskYN', idc)
    return fn(default, format_str)


def ask_file(for_saving, default, dialog):
    fn = _get_fn_by_version(ida_kernwin, 'ask_file', 'AskFile', idc)
    return fn(for_saving, default, dialog)


def get_func_attr(ea, attr):
    fn = _get_fn_by_version(idc, 'get_func_attr', 'GetFunctionAttr')
    return fn(ea, attr)


def get_name_ea_simple(name):
    fn = _get_fn_by_version(idc, 'get_name_ea_simple', 'LocByName')
    return fn(name)


def next_head(ea, maxea=4294967295):
    fn = _get_fn_by_version(idc, 'next_head', 'NextHead')
    return fn(ea, maxea)


def get_screen_ea():
    fn = _get_fn_by_version(idc, 'get_screen_ea', 'ScreenEA')
    return fn()


def choose_func(title):
    fn = _get_fn_by_version(idc, 'choose_func', 'ChooseFunction')
    return fn(title)


def ask_ident(default, prompt):
    fn = _get_fn_by_version(ida_kernwin, 'ask_str', 'AskIdent', idc)
    if idaapi.IDA_SDK_VERSION >= 700:
        return fn(default, ida_kernwin.HIST_IDENT, prompt)
    return fn(default, prompt)


def set_name(ea, name):
    fn = _get_fn_by_version(idc, 'set_name', 'MakeName')
    if idaapi.IDA_SDK_VERSION >= 700:
        return fn(ea, name, ida_name.SN_CHECK)
    return fn(ea, name)


def get_wide_dword(ea):
    fn = _get_fn_by_version(idc, 'get_wide_dword', 'Dword')
    return fn(ea)


def get_strlit_contents(ea):
    fn = _get_fn_by_version(idc, 'get_strlit_contents', 'GetString')
    return fn(ea)


def get_func_name(ea):
    fn = _get_fn_by_version(idc, 'get_func_name', 'GetFunctionName')
    return fn(ea)


def get_first_seg():
    fn = _get_fn_by_version(idc, 'get_first_seg', 'FirstSeg')
    return fn()


def get_segm_attr(segea, attr):
    fn = _get_fn_by_version(idc, 'get_segm_attr', 'GetSegmentAttr')
    return fn(segea, attr)


def get_next_seg(ea):
    fn = _get_fn_by_version(idc, 'get_next_seg', 'NextSeg')
    return fn(ea)


def is_strlit(flags):
    fn = _get_fn_by_version(ida_bytes, 'is_strlit', 'isASCII', idc)
    return fn(flags)


def create_strlit(start, lenth):
    fn = _get_fn_by_version(ida_bytes, 'create_strlit', 'MakeStr', idc)
    if idaapi.IDA_SDK_VERSION >= 700:
        return fn(start, lenth, ida_nalt.STRTYPE_C)
    return fn(start, idc.BADADDR)


def is_unknown(flags):
    fn = _get_fn_by_version(ida_bytes, 'is_unknown', 'isUnknown', idc)
    return fn(flags)


def is_byte(flags):
    fn = _get_fn_by_version(ida_bytes, 'is_byte', 'isByte', idc)
    return fn(flags)


def create_dword(ea):
    fn = _get_fn_by_version(ida_bytes, 'create_data', 'MakeDword', idc)
    if idaapi.IDA_SDK_VERSION >= 700:
        return fn(ea, ida_bytes.FF_DWORD, 4, idaapi.BADADDR)
    return fn(ea)


def op_plain_offset(ea, n, base):
    fn = _get_fn_by_version(idc, 'op_plain_offset', 'OpOff')
    return fn(ea, n, base)


def next_addr(ea):
    fn = _get_fn_by_version(ida_bytes, 'next_addr', 'NextAddr', idc)
    return fn(ea)


def can_decode(ea):
    fn = _get_fn_by_version(ida_ua, 'can_decode', 'decode_insn', idaapi)
    return fn(ea)


def get_operands(insn):
    if idaapi.IDA_SDK_VERSION >= 700:
        return insn.ops
    return idaapi.cmd.Operands


def get_canon_feature(insn):
    if idaapi.IDA_SDK_VERSION >= 700:
        return insn.get_canon_feature()
    return idaapi.cmd.get_canon_feature()


def get_segm_name(ea):
    fn = _get_fn_by_version(idc, 'get_segm_name', 'SegName')
    return fn(ea)


def add_func(ea):
    fn = _get_fn_by_version(ida_funcs, 'add_func', 'MakeFunction', idc)
    return fn(ea)


def create_insn(ea):
    fn = _get_fn_by_version(idc, 'create_insn', 'MakeCode')
    return fn(ea)


def get_segm_end(ea):
    fn = _get_fn_by_version(idc, 'get_segm_end', 'SegEnd')
    return fn(ea)


def get_segm_start(ea):
    fn = _get_fn_by_version(idc, 'get_segm_start', 'SegStart')
    return fn(ea)


def decode_insn(ea):
    fn = _get_fn_by_version(ida_ua, 'decode_insn', 'decode_insn', idaapi)
    if idaapi.IDA_SDK_VERSION >= 700:
        insn = ida_ua.insn_t()
        fn(insn, ea)
        return insn
    fn(ea)
    return idaapi.cmd


def get_bookmark(index):
    fn = _get_fn_by_version(idc, 'get_bookmark', 'GetMarkedPos')
    return fn(index)


def get_bookmark_desc(index):
    fn = _get_fn_by_version(idc, 'get_bookmark_desc', 'GetMarkComment')
    return fn(index)


def set_color(ea, what, color):
    fn = _get_fn_by_version(idc, 'set_color', 'SetColor')
    return fn(ea, what, color)


def msg(message):
    fn = _get_fn_by_version(ida_kernwin, 'msg', 'Message', idc)
    return fn(message)


def get_highlighted_identifier():
    fn = _get_fn_by_version(ida_kernwin, 'get_highlight',
                            'get_highlighted_identifier', idaapi)

    if idaapi.IDA_SDK_VERSION >= 700:
        viewer = ida_kernwin.get_current_viewer()
        highlight = fn(viewer)
        if highlight and highlight[1]:
            return highlight[0]
    return fn()


def start_ea(obj):
    if not obj:
        return None

    try:
        return obj.startEA
    except AttributeError:
        return obj.start_ea


def end_ea(obj):
    if not obj:
        return None

    try:
        return obj.endEA
    except AttributeError:
        return obj.end_ea


def set_func_flags(ea, flags):
    fn = _get_fn_by_version(idc, 'set_func_attr', 'SetFunctionFlags')
    if idaapi.IDA_SDK_VERSION >= 700:
        return fn(ea, idc.FUNCATTR_FLAGS, flags)
    return fn(ea, flags)


def get_func_flags(ea):
    fn = _get_fn_by_version(idc, 'get_func_attr', 'GetFunctionFlags')
    if idaapi.IDA_SDK_VERSION >= 700:
        return fn(ea, idc.FUNCATTR_FLAGS)
    return fn(ea)

更改完毕后,全部保存,重新打开自己的IDA,即可看到如下插件

在这里插入图片描述

接下来我们就可以选择相关的规则文件,进行函数鉴别了。

三、鉴别过程

1.鉴别前
在这里插入图片描述

2.使用工具,调用鉴别规则,我这边是32位elf文件,所以选择i686架构的,具体选择可以看官方文档,根据自己的文件进行选择

在这里插入图片描述

3.确认完毕后即可看到左上角,functions windows里的函数识别出来一部分了

在这里插入图片描述

四、总结

该工具比FLAIR对于函数的识别正确率要更高,且对该样本的确有效,一路上真的踩了好多坑!!!终于可以看该病毒的样本啦啦啦啦啦!

本小菜鸡第一篇博客!希望自己在新的一年里变得更强哈哈哈哈!!

  • 15
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值