但是,了解 OEP 与 IAT 有何关系?
OEP 与 IAT 无关,但被导入重建工具用于查找封隔器创建的 IAT 类结构的位置。
当应用程序在内存中解包时,我们不能通过遍历 PE 头来获取指向 IAT 的指针吗?
这正是需要导入重构的原因。因为恶意软件以某种方式故意破坏 IAT,只保留一小部分强制性功能,将解析大部分 API 的工作作为解包代码的一部分。因此导入重建需要我们通过其他方式找到IAT(因为PE定义的IAT是不完整的/伪造的)。
为什么我们不在 OEP 上转储应用程序,而是在导致 OEP 的 jmp 上说?还是 OEP 后的一对二指令?
转储时,重要的是已执行与解扰打包代码相关的所有代码。否则,OEP 可能不是有效的可执行代码。除此之外(以及与导入重建相关的问题)转储并仅将 PE 的入口点调整为 OEP 完全没问题。大多数转储工具都允许这样做。
除了回答您的具体问题外,以下是有关 IAT 操作的加壳程序类型以及在转储的 PE 中获得功能性 IAT 所需的条件:
当加壳器不改变原始导入表时,导入重建是不必要的。大多数 PE 转储程序会在原始导入表有效时复制它,或者将其与 PE 一起转储。
一些加壳器携带另一个最初隐藏的 PE,并且只对其整体进行解密/解扰。这些包装工也将完好无损地携带 IAT,大多数自卸车将自动获得 IAT。
一些打包者会创建他们自己的替代 IAT 并实现他们自己版本的 API 加载/解析。对于这些加壳程序,导入重建实用程序将需要定位该替代(或者,我们应该说是真实的吗?)IAT 并从头开始在重建的 PE 中创建一个新的 IAT(基于原始 IAT 实际指向的那些 API)。然后,导入重建将查找“IAT 查找”偏移范围,并确保它们在加载 PE 时位于同一位置。因此,OEP 会扫描使用偏移表的呼叫,这些偏移表可能被怀疑为此类替代 IAT。
有些包装器不会创建单个 IAT,而是创建许多小的 IAT 表,这样您就不再称它们为“表”。在这些情况下,导入重建工具必须遇到足够多的小表并分别重建它们。在这些情况下,更重要的是不要让任何代码段仍然打包,因为仅由这些代码段使用的 API 将不会被重构。
另一种类型的加壳程序通过删除导入表的概念,而是在每次进行 API 调用时解析请求的 API,从而使静态反汇编的 API 解析变得更加困难(尽管不会阻止转储 PE 的执行)。这通常是通过为任何 API 分配一个无法轻易识别的密钥/哈希来完成的,并在每次调用时遍历 DLL 和导出表,为 API 生成相同的密钥/哈希,直到找到正确的密钥。这通常意味着不需要导入重构来执行和调试转储的 PE,但是人类逆向工程师将难以理解正在调用哪些 API。