欺骗单步步过F8导致程序跑飞

前言:欺骗单步步过F8导致程序跑飞的笔记

单步步过跑飞的原理

我们这里说的跑飞就是在调试器中调试的时候为什么有时候在CALL F8的时候就会导致程序跑飞的现象

首先需要知道的一点就是F8单步步过CALL的简单实现,实际上是调试器会在CALL+5个字节,也就是调试器会帮你在CALL XXXX的地址的下一行地址上打一个断点,那么此时如果CALL中执行的代码最后返回的不是下一行地址,那么程序就会断在下一行地址了,而最后CALL跳转的地址都没有打过断点,这就会导致CPU一直在执行机器码,这就是跑飞现象的原因

简单的代码实现

我这里通过代码简单的模拟一个F8单步步过跑飞的现象

#include<stdio.h>

int iEax;
int iRet;
void _declspec(naked) test01()
{
	printf("cheat f8 test...\n");
	__asm
	{
		mov iEax, eax; // save eax
		mov eax, [esp];
		add eax, 7;
		mov iRet, eax;
		pop eax;
		mov eax, iEax;
		push iRet;
		ret;
	}
}

void test02()
{
	printf("test02...\n");
}

int main()
{
	int a = 0;
	test01();
	a = 1;
	printf("test...");
	return 0;
}

载入到调试器中进行调试,调用处如下位置

此时如果F8的话,可以看到程序直接终止了,如下图所示

如果F7步入的话,那么还能继续执行,首先F7进到CALL中

这里继续单步,然后就要执行返回了RET了

可以看到继续执行了

所以这里对于F8跑飞的解决方式就是对CALL进行单步步入即可

但是一般在程序中为了F8跑飞的实现,程序可能会多个嵌套的跑飞,所以你也需要多个F7单步步入来进行调试

如何识别是否是跑飞CALL

可以先看下CALL的跳转,如果就在附近的话,那么就F7单步步入慢慢跟就好了

壳中的应用

在壳用跑飞其实很常见的,自己这里拿一个来Yoda's Crypter(1.2)来演示跑飞效果

将壳程序载入到调试器中,可以看到pushad,那么这里就直接用ESP定律即可,接着F9你就会来到如下的地方

此时这个CALL就会导致跑飞,因为该CALL中就直接让你跳到别的地方,如果F8步过CALL的话,那么就直接跑飞了,可以看到F8步过CALL之后就直接来到了其他的地方

如果是F7跟入的话,此时会执行这两条

0040541B    58              pop eax                                  ; UnPackMe.004053FE
0040541C    C3              retn

而pop eax之后,此时的栈顶就是OEP的地址,那么单步走的话就直接来到OEP了,CALL下面的语句就不会执行

posted @ 2020-02-13 20:31  zpchcbd  阅读(308)  评论(0编辑  收藏  举报