在跳转目的地基于动态环境值的情况下,如何构建控制流图?

Posted

技术标签:

【中文标题】在跳转目的地基于动态环境值的情况下,如何构建控制流图?【英文标题】:How are control flow graphs built in cases where the jump destination is based on a dynamic environment value? 【发布时间】:2021-12-26 06:57:05 【问题描述】:

在研究逆向工程时,我经常想到,由于我可以传递任何位置(我有权访问)作为参数,因此带有一些非硬编码或“非确定性”目标的跳转指令(如程序之前没有明确定义)可以瞄准任何地方。因此,如果我使用基于操作系统版本字符串的值加载EAX 并执行jmp eax,那么似乎任何试图生成控制流图的工具都不知道目标在哪里(它可以以您当前的环境为基础,但这可能会导致程序中断)。

我错过了什么吗?因为如果我正确理解了这一点,我在 IDA 中打开的每个恶意软件似乎都会这样做(基于他们了解其目标环境的某些条件),但我没有看到像这样损坏的控制流图。再说一次,我对逆向工程还是很陌生。

【问题讨论】:

吹毛求疵,没有Jcc EAX。所有条件跳转指令都立即进行位移。 @NateEldredge 啊,我想知道我是不是搞砸了。我对汇编的学习还不是很实际。泰。 【参考方案1】:

确实,正如您已经猜到的那样,JMP EAX 形式的指令可能会跳转到任何地方,因此会破坏您尝试逆向工程的程序的 CFG(也就是说,您不会有已知片段的退出弧当前基本块中的代码)。

但是,编译器很少发出绝对间接跳转。当它们这样做时,它们通常用于为switch 语句生成的跳转表。如果我们谈论的是间接调用(或 jmp 尾调用),那么我们还有函数指针,你会看到 CALL EAX 形式的指令(在 C++ 中很常见,即 vtables)。例如,对于switch 语句,为了正确处理其输入变量或表达式的所有可能值(例如int),通常有一些代码在使用之前确保该值在给定范围内它索引一个代码指针数组,然后通过寄存器进行绝对间接跳转(或者更常见的是jmp [table + eax*4],可能在对 EAX 进行一些数学运算之后)。

这种情况下使用的习语类型和编译器实现(即生成什么机器代码)通常是众所周知的,因此反汇编器和反编译器可以检测它们并找出输入约束以及跳转表的位置,因此是正确的目的地(这就是 IDA/HexRays 所做的)。然而,有时这对于您的反汇编器/反编译器来说是不可能的或太难弄清楚(例如,编译器使用了不同的未知语义,或者程序员故意尝试使逆向工程更难)。

【讨论】:

“但是,编译器很少发出绝对间接跳转。”好吧,函数指针和虚方法。我想是调用而不是跳转,但原理相同。 @NateEldredge 是的,好点,添加【参考方案2】:

您的观察是正确的。有两种主要方法可以为间接跳转绘制控制流图。

首先,可以使用静态分析。例如,如果发现跳转目标是从长度有限的跳转表中选择的,则反编译器可以将跳转表的条目列为可能的目标。另一种常见的情况是跳转目标取自程序中其他地方的变量集,但总是相同的值。反编译器也可以分析变量的可能值,推导出可能的跳转目标。

另一种选择是构建控制流图,而不是根据程序的潜在行为,而是根据从模拟或实际运行的代码中观察到的实际行为。虽然这可能会遗漏一些可能的控制流,但它通常可以让您很好地了解跳转(包括间接跳转)通常的去向,并可以解释程序的行为。

【讨论】:

Aha, so I handled it the right way :)(参见图表底部的最后一个条目)我真的是 in over my head 在这个话题上,甚至不确定这样的细节。我阅读了 x86-64 的大部分英特尔开发手册,但在 hello world 之外的组装经验很少。甚至使用 C 语言...我是一名 javascript 开发人员,我是怎么到这里的... "或实际运行的代码。"这也是我好奇的一点。显然,仿真器与逃避作斗争。因此,在预期环境中实际运行程序是一种有趣的方法。当我们在裸机上运行时,除非我们修改程序,否则寄存器值对外部分析是不透明的,对吧?如果我理解正确的话,即使调试 API,也可以利用 x86 架构上的一个特性,允许将指令标记为断点或其他东西,所以本质上我们正在修补程序以便能够利用它,是吗? (1/1) @J.Todd 一些调试器可以绕过常见的反调试策略,例如模拟使调试器可检测的指令(例如pushf)。但是是的,面对这样的对策,很难得到正确的执行痕迹。 (2/2) 那么当对恶意程序进行这种分析时,该程序可以查看自己的内存并查看这些修改,并表现出不同的行为,是吗?我希望有一种方法可以查看指令跟踪,而程序根本无法知道它正在被监视。我认为也许 JTAG 可以做类似的事情,但它的频率不够高,无法在每条指令执行时查询所有寄存器,甚至没有关闭。 @J.Todd 据我所知,一个用户模式程序可以做到这一点,但是当你进行这种尝试时,你的调试器可能会伪造错误的值。

以上是关于在跳转目的地基于动态环境值的情况下,如何构建控制流图?的主要内容,如果未能解决你的问题,请参考以下文章

asp.net(vs2008 c# 中) 如何在跳转的页面传递参数?

vue如何在跳转页面时不打开新窗口

判断微信微信小程序及其他环境

实验3 Open vSwitch实验

A页面调用了setInterval(),如何在跳转到B页面之前清除掉setInterval??

pyc文件修复出题经历