这几天在重看SEH机制,收获颇丰。

随手写了一个用SEH进行跳转的代码贴于此处以作纪念。

当发生异常,并捕捉了异常。在OS的异常处理机制下。会进入异常过滤函数。

过滤函数能够返回EXCEPTION_EXECUTE_HANDLER/EXCEPTION_CONTINUE_SEARCH/EXCEPTION_CONTINUE_EXECUTION三者之中的一个,以此决定OS的兴许操作。

假设返回EXCEPTION_CONTINUE_EXECUTION。OS觉得异常已解决,能够从发生异常的指令处继续执行。一般这是用于解决訪问内存出错的情况。比方:

int* ptr=NULL;

int ex(EXCEPTION_POINTERS* ExceptionInfo)
{
ExceptionInfo->ContextRecord->Eax=(DWORD)malloc(sizeof(int));
return EXCEPTION_CONTINUE_EXECUTION;
} int main()
{
__try
{
*ptr = 0x00;
//004010AC   mov         eax,[ptr (00422780)]
//004010B1   mov         dword ptr [eax],0
 MessageBox(NULL,"","",MB_OK);
}
__except(ex(GetExceptionInformation()))
{ }
}

当运行*ptr=0x00时,因为ptr指向空。因此mov dword ptr [eax],0这句会引起异常。为了让代码继续往下运行弹出对话框。仅仅要让eax指向有效内存就可以。那怎样让eax指向有效地址?仅仅要给eax创建堆内存就可以,因此能够在异常过滤函数中开辟空间。按windows的设计。异常发生时OS会把压入在堆栈中寄存器值保存到线程环境中(通过KiTrapFrameToContext);当从异常返回时,用保存的线程环境恢复寄存器继续运行(通过KiContextToTrapFrame)。

那么所谓的线程环境在哪?代码中ExceptionInfo->ContextRecord即为所求。

因此,我在过滤函数中改动Context->Eax。使之指向有效内存,实现了修复异常继续指令流的目的。

事实上,这整个流程类似于SetThreadContext/GetThreadContext。

另外。值得一提的是,当异常发生时,假设异常类型是訪存失败,错误码是0xC0000005的情况下。

ExceptionInfo->ExceptionRecord->NumberParameters;

ExceptionInfo->ExceptionRecord->ExceptionAddress;

    ExceptionInfo->ExceptionRecord->ExceptionInformation[1];

这几个域包括了重要信息。

来看个常见而又蛋痛的对话框:

当你happy的玩着游戏时。跳出这个。是不是都毁了?假设细致看出错信息上面给出了例如以下信息:出错的指令的地址-0x6F001080,出错的原因-0xC0000005(訪问无效内存),无效内存的地址0xE2AF524C。

这些信息,进入内核态以后能够轻松获得,可是用户态有没有办法获得?比方想做一个用户态的调试器?当然有。上面提到的3个域依次相应:异常时ExceptionInformation数组的元素数量、出错的指令的地址、訪问无效内存的地址。

有了这些辅助信息后,開始讨论正题。事实上,这里已经呼之欲出了:代码混淆一般就是通过各种手段混乱代码运行流程,放在这篇文章中。仅仅要改动EXCEPTION_CONTINUE_EXECUTION返回时的地址就可以(注意我的用词,是EXCEPTION_CONTINUE_EXECUTION的返回地址,不是异常的返回地址,假设没记错对于vc++6.0异常的返回地址应该是_except_handle3)。进一步说,就是触发异常并保存线程环境时Eip的值。

罗列一下代码:代码运行流程为1)-5)

#include <windows.h>
#include <stdio.h> int* ptr;
//4)Msg被调用
void Msg(int a,int b)
{
int c = a+b;
printf("%d\n",c);
MessageBox(NULL,"","",MB_OK);
__asm
{
mov eax,c
}
} int ex(EXCEPTION_POINTERS* ExceptionInfo)
{
//3)准备跳转到Msg中
//Msg是带參数函数,參数保存在异常发生前的堆栈上。即Esp指向
//此时ExceptionInfo->ContextRecord->Eip[0]指向Lab1代表的地址
//ExceptionInfo->ContextRecord->Eip[4]=0x01 ExceptionInfo->ContextRecord->Eip[8]=0x02
ExceptionInfo->ContextRecord->Eip = (DWORD)Msg;
return EXCEPTION_CONTINUE_EXECUTION;
} int main()
{
int i=0;
ptr = (int*)&main;
__try
{
/*
原本向jmp Lab2,结果提示"illegal jump into __try scope",就这么取代一下
*/
if(1)
goto Lab2;
Lab1:
//5)从Msg返回后 指令流进入Lab1
i++;
printf("%d\n",i);
ExitProcess(0);
Lab2:
__asm
{
//1)制造Msg函数的參数及返回地址.模拟c调用函数的过程.异常触发后要跳入Msg运行
//对于Msg函数。他根本不知道是谁调用他的,他仅仅关心參数是否正确
push 0x02;
push 0x01;
lea eax,Lab1;
push eax;
}
//2)触发异常。给与Lab1中真正须要运行的代码于机会
(*ptr) = 0x01; }
__except(ex(GetExceptionInformation()))
{}
return 0;
}

最新文章

  1. rsync快速删除海量文件
  2. 根据网址把图片下载到服务器C#代码
  3. #VSTS日志# 2015/12/10 – 终于可以删除工作项了
  4. 页面设计--Grid列表
  5. 《Java编程那点事儿》读书笔记(四)——String和StringBuffer
  6. jira 无法停止启动解决方案
  7. LeetCode OJ 297. Serialize and Deserialize Binary Tree
  8. 升级版本后报这个异常 : org.springframework.beans.factory.NoUniqueBeanDefinitionException
  9. swift中标签的使用
  10. mongodb菜鸟整理
  11. 深入理解JVM(六)&mdash;&mdash;类加载器原理
  12. Linux新手的最佳包管理器
  13. [转][Angularjs]$http.post与$.post
  14. Linux下查看某个进程打开的文件数-losf工具常用参数介绍
  15. &gt;HTML编辑笔记2
  16. syslog-ng日志收集分析服务搭建及配置
  17. SSM后台管理系统(Spring SpringMVC Mybatis Mysql EasyUI)
  18. Jmeter --- 分布式测试
  19. Windows连接Linux服务器中MySQL数据库-权限配置
  20. Objective-C中的meta-class

热门文章

  1. 网页显示403. That’s an error的解决方法。
  2. js编码处理(转)
  3. 全国绿色计算大赛 模拟赛第二阶段 (Python)
  4. BZOJ 2039 人员雇佣 二元关系 最小割
  5. 零基础入门学习Python(7)--了不起的分支和循环1
  6. ubuntu Android Studio以及SDK安装
  7. 88-On Balance Volume 能量潮指标.(2015.7.4)
  8. allegro学习--区域约束
  9. 【03】AJAX 向服务器发送请求
  10. PS一些技巧