利用函数调用栈平衡原理实现溢出调用(有点类似于栈溢出,只不过这里是直接修改,也可以命使用溢出方式实现)
============================================================================================
#include <stdio.h>
#include <string.h>
unsigned int oldEbpAddress = 0;
unsigned int oldRetAddress = 0;
typedef void (*pf)();
//这里只能修复到继续返回main执行,但是在main函数结束时栈被破坏,报异常
void fun2()
{
//记录老EBP地址
__asm mov [oldEbpAddress],ebp
//通过老EBP找出函数返回地址,并给它设置原函数返回地址
*((unsigned int*)(oldEbpAddress + 4)) = oldRetAddress;
printf("fun2\n");
}
//这里采用naked模式编写fun2完美实现栈修复,可以与上面的进行比较看效果
char *str = "fun2\n";
void __declspec(naked) fun2()
{
__asm
{
//压入函数返回地址
push oldRetAddress
//调用printf函数
push offset str
call dword ptr printf //注意这里的dword ptr
add esp, 4 //自己维护栈平衡
ret //函数返回
}
}
void fun()
{
//记录老EBP地址
__asm mov [oldEbpAddress],ebp
//通过老EBP记录下函数返回地址,在fun2中再使用
oldRetAddress = *((unsigned int*)(oldEbpAddress + 4));
//通过老EBP修改函数返回地址为fun2函数首地址
*((unsigned int*)(oldEbpAddress + 4)) = (unsigned int)(pf)fun2;printf("fun\n");
}
//说明:这里我们没能调用函数fun2,但是由于我们在fun函数中对返回地址做了一系列修改让fun2也得到了执行机会,
//同时在fun2中对栈也做了一个简单处理能返回main函数继续执行
int main()
{
printf("main\n");
fun();
printf("main next\n");
getchar();
}
=====================================================利用函数调用栈平衡原理实现栈回溯=====================================================
#include <stdio.h>
#include <Windows.h>
int fun3()
{
unsigned int ebpAddress;
unsigned int ebpPreviousAddress;
printf("----------------fun3------------------\n");
__asm mov [ebpAddress],ebp //得到当前函数EBP
ebpPreviousAddress = *((unsigned int*)ebpAddress); //EBP地址中保存的值为来自调用函数的EBP值
printf("0x%08X\n", ebpPreviousAddress);
//循环执行上面的步骤
while(1){
__try{
ebpAddress = ebpPreviousAddress;
ebpPreviousAddress = *((unsigned int*)ebpAddress);
printf("0x%08X\n", ebpPreviousAddress);
}
__except(EXCEPTION_EXECUTE_HANDLER){
//这里一直回溯到无法回溯时产生异常退出回溯
break;
}
}
return 0;
}
int fun2()
{
printf("----------------fun2------------------\n");
fun3();
return 0;
}
int fun1()
{
printf("----------------fun1------------------\n");
fun2();
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
fun1();
getchar();
return 0;
}