IDAPython 字符串使用 str() 不断返回 NoneType

逆向工程 艾达 蟒蛇 idapro插件
2021-06-26 05:12:06

我正在尝试使用 IDA Pro 6.5 和 IDA Python 自动反汇编固件映像。我想要实现的过程之一是定位字符串并在它们周围创建一个数据段。

使用 GUI,我这样做几乎没有问题。但是,在使用idautils.Strings()API 调用时,我可以检索StringItem对象列表,但无法使用str()访问实际的字符串数据unicode()下面是失败的函数,它取自IDA Python Google 代码存档

def find_strings():
    s = idautils.Strings(False)
    s.setup(strtypes=Strings.STR_UNICODE | Strings.STR_C)
    for i, v in enumerate(s):
        if v is None:
            print("Failed to retrieve string index %d" % i)
        else:
            print("%x: len=%d type=%d index=%d-> '%s'" % (v.ea, v.length, v.type, i, str(v)))

遇到IDA,报如下错误:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "<string>", line 8, in find_strings
TypeError: 'StringItem' object is not callable

当更换str(v)与常变量aaaprint函数,我得到的名单StringItem没有任何问题的对象:

Python>find_strings()
208e: len=8 type=3 index=0-> 'aaa'
21b0: len=55 type=0 index=1-> 'aaa'
229d: len=6 type=0 index=2-> 'aaa'
22c5: len=5 type=0 index=3-> 'aaa'
22d3: len=33 type=0 index=4-> 'aaa'
...

如果我尝试使用该unicode()函数,则会出现以下错误:

Python>find_strings()
208e: len=8 type=3 index=0-> '
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "<string>", line 8, in find_strings
TypeError: coercing to Unicode: need string or buffer, NoneType found

根据我的理解,似乎由于StringItem未知原因(或插件的问题,可能是 Python 的特定版本?)不包含任何字符串,但是它们显示在 GUI 中。

我正在寻求关于我做错了什么的建议,或者使用 IDApython 插件提取字符串的替代方法。谢谢

更新

添加注释中提到的缺少的括号后,上面的代码似乎有效。然而,这只是帖子中的一个错字,而不是问题的根源。find_strings其他典型的二进制文件的罚款。进一步的证明是,通过使用idc.GetString(self.ea, self.length, self.type)还返回的NoneType.

Diff 提到get_ascii_contents2正在失败并因此返回null,这很可能是原因。不清楚的是为什么该函数失败,而 GUI 成功定位了大部分字符串。

0x208E 处的第一个字符串是垃圾 Unicode 字符串。0x21B0 处的字符串是由 37 个字符组成的实际 ASCII 字符串。由于披露/法律问题,我无法发布完整的字符串。请注意,当在十六进制编辑器中显示时,ASCII 视图的字节顺序因未知原因而反转。整体固件的位数为 16 位。

434F 5059 5249 4748 5420 A920 ... 4544 2000 0000 : OCYPIRHG T ¬ ... DE.

最后,请注意该功能MakeStr可以正常工作。我有以下代码,当在 0x21B0 处使用时,将成功在数据段内创建一个字符串:

def create_string(self, _startea, _endea, _segname=".const", _unicode=False):
        
        if (SegStart(_startea) == idc.BADADDR):
            self.create_data_segment(_startea, _endea, ".const")
        else:
            segtype = GetSegmentAttr(_startea, SEGATTR_TYPE)
            if (segtype != IDAEngine.SEG_TYPE_DATA):
                DelSeg(_startea, 0)
                self.create_data_segment(_startea, _endea, _segname)
        
        result = MakeStr(_startea, _endea)
        if (result == IDAEngine.FAIL):
            print "[-] Failed to create a string at 0x{:x} to 0x{:x}.".format(_startea, _endea)

在这一点上,我认为应该归咎于固件的结构(位组合、缺少符号和过时但受支持的微处理器),但是我无法确定确切的问题。现在,因为我可以find_strings()用来检索偏移量,然后MakeStr在具有一定长度的字符串上使用并手动审查“真实”字符串。

结语

对于后代,我从来没有真正解决过这个问题,但是我可以确认底层的二进制文件负责在get_ascii_contents2. 我重新加载了同一个文件,但是作为一个大段中的原始二进制文件,该功能运行完美。

1个回答

这需要进行一些挖掘,但是您似乎遇到了脚本的原始作者没有考虑的有趣的边缘情况。

str(StringItem)idautils.py 中调用以下代码

    def __str__(self):
        return self._toseq(False)

这导致_toseqidautils.py ;

    def _toseq(self, as_unicode):
        if self.is_2_bytes_encoding():
            conv = idaapi.ACFOPT_UTF16
            pyenc = "utf-16"
        elif self.is_4_bytes_encoding():
            conv = idaapi.ACFOPT_UTF8
            pyenc = "utf-8"
        else:
            conv = idaapi.ACFOPT_ASCII
            pyenc = 'ascii'
        strbytes = idaapi.get_ascii_contents2(self.ea, self.length, self.type, conv)
        return unicode(strbytes, pyenc, 'replace') if as_unicode else strbytes

如果我们深入研究get_ascii_contents2内部py_bytes.hpp方法,我们会发现该方法实际上可以返回NoneTypeifget_ascii_contents2失败;

if ( !get_ascii_contents2(ea, len, type, buf, len+1, &used_size, flags) )
{
  qfree(buf);
  Py_RETURN_NONE;
}

本质上,代码很好,但是如果 astr(StringItem)返回 with a则您应该添加检查或异常处理TypeNone因为可能返回这种类型的值。

你可以帮助调试进一步通过提供十六进制数据是什么ea0x208e与长度8为表示对您的输出;

208e: len=8 type=3 index=0->