我发现自己经常质疑自己是否有可能设计一个软件来加载另一个软件并尝试模拟其中的所有可能结果,并找出所分析软件的漏洞和漏洞。
理论上,它可以加载任何软件,具有底层系统的内部表示(CPU寄存器,内存等),如虚拟机软件,并通过分析,它将开始获取指令,模拟它们,它会线性发送,直到找到条件跳转。
为了使其易于理解,当它找到条件跳转时,它将获取系统的当前表示状态的快照并遵循该条件跳转,它将继续评估指令并在某些时候恢复该快照并且不要按照条件跳转,越过它并评估下一条指令,等等。
此类软件足够智能,可模拟用户提供的输入。
为了让事情更清楚,让我们想象一下我们正在分析以下(伪?)C代码:
char* gets(char *s)
{
int i = 0;
while( (s[i] = _getche()) != VK_RETURN ) i++;
s[i] = NULL;
return s;
}
void main() {
char buf[8];
char is_admin = FALSE;
do {
gets( buf );
if( _strcmp(buf, "s3cr3t!") == 0 )
is_admin = TRUE;
else
{
if( is_admin )
super_user.exec( buf );
else
unprivileged_user.exec( buf );
}
} while( _strcmp(buf, "exit") != 0 );
}
它只是继续轮询用户命令并执行它们直到用户输入“退出”。如果用户输入密码“s3cr3t!”它们将以超级用户身份执行以下命令,否则只会冒充非特权用户。
接下来,我们可以要求我们的分析软件检测并找出在被分析的主题代码上以超级用户身份执行命令的方式。
通过遍历每条指令,它将进行条件跳转并测试两种情况,当跳转时和不跳转时。因此,经过几次迭代后,它会知道如果用户输入字符串“s3cr3t!”,它将在以后以超级用户身份执行命令。它不会尝试每个可能的字符串组合,直到它最终到达“s3cr3t!”,看到该字符串的比较是明智的,并看看它在程序流程中的变化。
然后,它还能够看到任何超过8个字母的用户输入字符串将溢出buf char数组的已分配空间,从而破坏内存。在这种特殊情况下,假设堆栈内存布局是因为is_admin变量将位于buf char数组旁边,将is_admin设置为TRUE,然后以超级用户身份执行命令。
它还能够在该gets()函数中发现整数溢出,如果这会以某种方式损坏堆栈内存,最终会从函数调用中更改RETURN地址。确定它是用户输入shellcode并利用RETURN地址进行利用的场景,然后它会跳转到那个也会以超级用户身份执行命令的shellcode。
所以...我知道我不能详细介绍内部工作,但总的来说,我认为我已经说明了我的观点。有没有人看到这种方法有问题或认为它不起作用?
我正在考虑为此开展一个开放式项目。我将不胜感激。
答案 0 :(得分:0)
如果我理解正确,那就有这样的事情。搜索静态分析,控制流程图等。所以一般来说,你的想法很好。
然而,编写一个能找到某些程序中所有错误的程序是不可能的。证据是通过减少Halting问题。显然,用你的方法找到它们是不可能的。
然而,有可能找到一些家庭的所有错误。 例如:当只有一个ASCII字符作为输入时,我可以在一分钟内定义崩溃的“bug系列”。当然你可以检查这个(至少对于确定性程序,对于概率程序 - 一个简单的检查会给出没有错误的概率)。
因此,对于特定的错误,您的方法可能会有效。
最后一点:注意这种方法可能具有很高的时间复杂度。