首页
社区
课程
招聘
[原创]在ShellCode里面使用异常处理(Win64位平台)
发表于: 2023-6-12 23:46 20774

[原创]在ShellCode里面使用异常处理(Win64位平台)

2023-6-12 23:46
20774

      网上关于ShellCode编写的文章很多,但介绍如何在ShellCode里面使用异常处理的却很少。笔者前段时间写了一个ShellCode,其中有一个功能是内存加载多个别人写的DLL插件,然后调用里面的函数,结果因为某个DLL函数里面发生了异常,导致ShellCode进程直接闪退,所以学习了一下在ShellCode里面如何使用异常处理的方法。


      Windows程序的异常处理,其实是三者结合的:操作系统、编译器和程序代码。因为x86下异常处理的文章太多,所以本文只介绍Win64下的。X86的异常(本文仅谈论SEH异常)一般的流程为:进入 try...语句之前先注册到异常链表,执行完代码后,再摘除,不管有没有异常发生,这个步骤都是必不可少的,所以多多少少会影响程序的性能。而Win64的异常处理,是基于表的。也就是说,编译器在编译代码的时候,会同时对每个函数(还分非叶,不深究)生成一个异常表,最后链接到PE的异常表里。当程序发生异常的时候,操作系统跟根据当前地址,枚举所有异常表,如果地址位于某个表的开始和结束地址之间,则使用这个表处理。相对来说,这个比X86更加安全和高效。


    这个异常表,称为RUNTIME_FUNCTION,MSDN里面定义如下:

    这些表连续存放在PE的异常目录中,每个表对应一个函数,所有成员都是相当于ImageBase的开始相对地址。其中BeginAddress表示这个函数的开始地址,EndAddress则对应结束地址,最重要的,是UnwindInfoAddress,它对应另外一个结构UNWIND_INFO


    成员如下:


    Version:版本号,一般为1,最高目前是2。


    Flags:取值如下

            #define UNW_FLAG_EHANDLER  0x01 ---表示有except块

           #define UNW_FLAG_UHANDLER  0x02 ---表示有finally块

           #define UNW_FLAG_CHAININFO 0x04 ---表示后面是另外一个Runtime_Function


 SizeOfProlog:函数头到try块的位置。


 CountOfCodes:表示后面有多少个UNWIND_CODE 结构。注意:这个数值是偶数对齐的,如果为奇数,说明最后一个为空值的UNWIND_CODE。


 UNWIND_CODE数组:实际上就是回滚表,保存了进入异常代码前的寄存器状态,用于异常处理后回滚到原来的状态。


    ExceptionHandler(可选):如果Flags包含了UNW_FLAG_EHANDLER 或UNW_FLAG_UHANDLER,则ExceptionHandler指向异常处理函数。其中Delphi语言是指向system.pas里面的函数_DelphiExceptionHandler;VS相对来说复杂一些,如果是SEH异常,一般是指向__C_specific_handler函数。


ExceptionData(可选):这个具体语言是不同的,所以windbg解释异常表的时候也是只解释到上一个成员。这个一般(Delphi语言则肯定也只会)指向一个SCOPE_TABLE结构:



    简单一点来说,Runtime_function是给操作系统判断异常发生在哪个函数里面,SCOPE_TABLE则是在异常处理函数里面使用的(触发异常处理函数的时候,会传递过去),主要记录了更精确的异常发生位置区间和需要跳转处理的地址。


    如果想在ShellCode里面使用异常,则请进行如下步骤:



1、提取语言的异常处理函数,让它称为ShellCode的一个函数(Delphi语言是system.pas里面的_DelphiExceptionHandler函数,VS则应该提取C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\crt\src\amd64\chandler.c里面的__C_specific_handler函数)。注意提取后的ShellCode化(修正API调用等)。当然,你也可以完全自己编写处理函数。


2、在需要使用异常处理的函数像往常一样使用try catch...try except...,在保存ShellCode的时候,使用API函数RtlLookupFunctionEntry查找这个函数的Runtime_Function,然后查找成员UNWIND_INFO,修正所有的相对地址后,跟ShellCode放在一起。


3、ShellCode运行后,调用API函数RtlAddFunctionTable将第二步修正的表添加到系统。


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2023-6-14 14:16 被bestbird编辑 ,原因:
上传的附件:
收藏
免费 8
支持
分享
最新回复 (19)
雪    币: 3303
活跃值: (30941)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
mark
2023-6-13 09:52
1
雪    币: 1471
活跃值: (5252)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
3
谢谢!
2023-6-13 15:09
0
雪    币: 248
活跃值: (3789)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
谢谢分享,留个mark
2023-6-13 23:33
0
雪    币: 8391
活跃值: (4966)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
5
mark
2023-6-13 23:47
0
雪    币: 30031
活跃值: (2507)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6

更新了一下附件,主要是针对多线程的异常做了演示,同时为"PE64异常表枚举工具"关闭了文件重定向,添加了一个注入到记事本的加载程序和代码。

最后于 2023-6-15 23:35 被bestbird编辑 ,原因:
上传的附件:
2023-6-15 23:01
0
雪    币: 262
活跃值: (763)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
7
32位的程序里面会出现shellcode 与 loader的编译器版本不一样,而导致shellcode里面的异常无法正常运行。大佬直到这个咋解决吗
2023-6-16 22:40
0
雪    币: 283
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
8
感谢分享!
2023-6-17 08:35
0
雪    币: 30031
活跃值: (2507)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
9
_emmm_ 32位的程序里面会出现shellcode 与 loader的编译器版本不一样,而导致shellcode里面的异常无法正常运行。大佬直到这个咋解决吗
32位的我还没有弄过,所以没办法回答,不好意思。
2023-6-17 14:13
0
雪    币: 30031
活跃值: (2507)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
10
_emmm_ 32位的程序里面会出现shellcode 与 loader的编译器版本不一样,而导致shellcode里面的异常无法正常运行。大佬直到这个咋解决吗
花时间看了一下win32的(delphi语言),感觉跟x64的处理是大同小异的,所以我有点怀疑你的情况是生成shellcode后,没有对异常处理函数的地址作修正---有可能你没有把异常处理函数(Delphi下是system.pas里面的_HandleAnyException)扣出来跟shellcode放在一起,所以我大胆猜测:你是直接保存了shellcode,里面的异常处理函数地址指向原来的(以Delphi为例,_HandleAnyException位于低地址),你的Loader加载Shellcode后,当ShellCode里面有异常发生,就跳转到地址比如说0x5678,而这个地址恰好是Loader里面的异常处理函数的地址,所以一切看起来都没有问题,但是如果你更换了不同的编译器,导致这个地址改变了,所以肯定无效而且估计会闪崩。ShellCode的异常处理是不应该依赖Loader的,比如说,你将shellcode注入到其它进程执行,也不应该有问题才是。
2023-6-17 16:41
0
雪    币: 10659
活跃值: (2354)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
期待完善方案,并配套基本代码跟着学学
2023-6-20 14:44
0
雪    币: 1854
活跃值: (4090)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
mark
2023-6-20 21:47
0
雪    币: 262
活跃值: (763)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
13
bestbird 花时间看了一下win32的(delphi语言),感觉跟x64的处理是大同小异的,所以我有点怀疑你的情况是生成shellcode后,没有对异常处理函数的地址作修正---有可能你没有把异常处理函数(Del ...
好像不太是,不同版本的编译器生成的异常有点区别,比如说VC6.0生成的程序,和VS 2013生成的。我如果去用
vs2013生成的loader去加载vs2013生成的 程序,就能正常运行。但是去加载 vc6.0生成的程序就无法正常运行。
2023-6-24 18:16
0
雪    币: 287
活跃值: (757)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
mark
2023-6-27 11:26
0
雪    币: 1
活跃值: (714)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
大佬,可否给个C++的版本以供学习,谢谢
2023-6-27 20:41
0
雪    币: 30031
活跃值: (2507)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
16
_emmm_ 好像不太是,不同版本的编译器生成的异常有点区别,比如说VC6.0生成的程序,和VS 2013生成的。我如果去用 vs2013生成的loader去加载vs2013生成的 程序,就能正常运行。但是去加载 ...
没有用C,所以不清楚了。
2023-7-10 14:21
0
雪    币: 30031
活跃值: (2507)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
17
wx_pretty^ 大佬,可否给个C++的版本以供学习,谢谢

C++的没有玩过,大同小异的。

最后于 2023-7-10 22:02 被bestbird编辑 ,原因:
2023-7-10 14:22
0
雪    币: 30031
活跃值: (2507)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
18

.

最后于 2023-7-12 17:18 被bestbird编辑 ,原因:
2023-7-11 15:52
0
雪    币: 5276
活跃值: (2905)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
好滴,支持
2023-7-14 15:07
0
雪    币: 30031
活跃值: (2507)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
20
_emmm_ 好像不太是,不同版本的编译器生成的异常有点区别,比如说VC6.0生成的程序,和VS 2013生成的。我如果去用 vs2013生成的loader去加载vs2013生成的 程序,就能正常运行。但是去加载 ...
我还是很疑惑。因为不管是32位还是64位的,如果你想在ShellCode里面使用异常处理,理论上一个是对需要处理的代码段注册,异常触发后操作系统就会去执行注册的异常回调函数。如果你的异常回调函数本身是在ShellCode里面的,理论上是跟你的loader毫无关系的。
顺便说一句,32位的我也写了一篇:https://bbs.kanxue.com/thread-278009.htm,感兴趣的话可以去看看。
2023-7-14 16:49
0
游客
登录 | 注册 方可回帖
返回
//