内核前置——异常处理技术

C++异常处理 throw try catch

异常处理

异常处理分两种:C++的try catch和C的__try __except

程序分两种:32位-x86,64位-x64

区别

(不绝对)

程序\类型 try catch(C++) __try __except(C)
x86(32) 无__unwind块
无try catch块
有流程图
有__unwind
有__try块提示
有流程图
x64(64) 有__unwind
甚至我都没找到catch块中要打印的的字符串”yes”
无流程图
有__unwind
无__try块提示
有流程图

try catch+x86

32位程序

1
2
3
4
5
6
7
8
9
10
#include<iostream>
int main() {
try {
throw 1;
}
catch (int a) {
printf("yes");
}

}
反汇编代码

可以看出,没有__unwind,也没有块提示,只有流程图提示

try catch+x64

1
2
3
4
5
6
7
8
9
10
#include<iostream>
int main() {
try {
throw 1;
}
catch (int a) {
printf("yes");
}

}

有__unwind,无流程图,甚至我都没找到catch块中要打印的的字符串”yes”

__try __except+x86

1
2
3
4
5
6
7
8
9
10
11
#include<Windows.h>
#include<stdio.h>
int main() {
__try {
int a = 0;
a /= 0;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
printf("yes");
}
}

有__unwind,有__try块提示,有流程图

__try __except+x64

1
2
3
4
5
6
7
8
9
10
11
#include<Windows.h>
#include<stdio.h>
int main() {
__try {
int a = 0;
a /= 0;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
printf("yes");
}
}

有__unwind,无__try块提示,有流程图

题目练习

moe–unwind(32)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int __cdecl main_0(int argc, const char **argv, const char **envp)
{
char v4; // [esp-FCh] [ebp-1FCh]

__CheckForDebuggerJustMyCode(&unk_6C063);
puts("Welcome to moectf2023!!! Now you find YunZh1Jun's revenge!!!");
puts("Do you know TEA(an encryption algorithm)? Do you know unwind in SEH? ");
puts("I believe you can understand them! So let me check your flag~");
sub_610CD("Input:", v4);
sub_613CA("%64s", (char)&byte_6A578);
MEMORY[0] = 0;
sub_610FF();
puts("Right flag! Have fun in moectf2023~");
return 0;
}
ida打开源码,看到` MEMORY[0] = 0;`这是异常的表现,往0位置中写0,也就是说在这里的流程图会有对这个异常的解决

可以看到,try块可以进入下面的except解决部分,也可以进入后续程序,但是我们刚刚分析了

1
2
mov     [ebp+ms_exc.registration.TryLevel], 0
mov large dword ptr ds:0, 0
这个是会异常的,也就是一定会进except,所以直接分析这个块,再看后面

try块的内容是调用函数,看看函数

问题在这里,int 3,这个是断点异常,并且观察到,fs:[0],欸?这个不是SEH机制里的异常回调函数结构吗,这里会不会是在安装异常处理结构,所以说

1
2
3
4
5
6
7
.text:0006183B mov     eax, dword ptr ___security_cookie
.text:00061840 xor eax, ebp
.text:00061842 mov [ebp+var_4], eax
.text:00061845 mov [ebp+var_C], offset sub_612FD
.text:0006184C push [ebp+var_C]
.text:0006184F push large dword ptr fs:0
.text:00061856 mov large fs:0, esp

这里的作用便是,安装SEH,安装的回调函数就是sub_612FD,在发生异常的时候,会先遍历当前函数的SEH机制,通过将fs:[0]压入栈,进行处理,这个时候前面安装的回调函数就会被调用

但是需要注意,_except_handler 没有处理异常,然后返回给更高级上层函数处理,但是这个时候栈没清除,且没栈展开,所以系统又一次使用栈中的fs:[0] ,导致这个SEH解决方式进行了两遍

然后如果这个回调函数没有对着个断点异常处理,就会栈展开并且回到该函数的调用者函数,进行二次捕获,这个时候就被_except块捕获到,进行相关操作了

ACTF–dropper(64)

这个是64位的异常,64位异常好像没有看到有人说怎么找异常处理函数,应该是机制的问题,不过可以看看做了什么比如:

这里有一个idiv,那么就有可能发生除零异常,同时这个函数是没有对着个函数异常有处理的(这里可以下不同的断点来测验,是处理成功还是将解决权交给更高层的函数

这里有一种通过import来定位异常的方法,待会吃完饭回来学,然后把这段删掉

先说一下另一种细心的方法

看流程图会发现,多了一个小板块,这个板块在代码页面是没有的,并且断点也是可以断住异常处理的

所以这里是异常处理之后启用的代码

作用如上

自己练习的缝合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include<iostream>
#include<windows.h>
#include<stdio.h>
#include<string.h>
char flag[] = { 0x79,0x67,0x77,0x34,0x6b,0x79,0x79, };
char input[100] = { 0 };
int lenth = strlen(flag);
EXCEPTION_DISPOSITION
__cdecl _except_handler(
struct _EXCEPTION_RECORD* ExceptionRecord,
void* EstablisherFrame,
struct _CONTEXT* ContextRecord,
void* DispatcherContext)
{

for (int i = 0; i < lenth; i++)
{
input[i] += i;
}
return ExceptionContinueSearch;
}
bool exception(char* input) {
int len = strlen(input);
if (len== lenth) {
DWORD handler = (DWORD)_except_handler;
__asm
{
push handler
push FS : [0]
mov FS : [0] , ESP
int 3
mov eax, [ESP]
mov FS : [0] , EAX
add esp, 8
}
}
else {
__asm {
push ebx
xor ebx, ebx
test ebx, ebx
jnz label1
jz label2
label1 :
_emit 0x88
label2 :
pop ebx
}
return false;
}
}
int main() {
std::cout << "请输入密文:" << std::endl;
std::cin >> input;
__try {
if(!exception(input)) {
std::cout << "不对吧好像...再看看呢" << std::endl;
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
if (!strcmp(input, flag)) {
std::cout<<"嘿嘿你做对啦!!" << std::endl;
}
else {
std::cout << "asm--异常出现" << std::endl;
}
}
}

suctf–SU_BBRE