DigtheWay

  1. Dig the way
    1. 栈溢出

Dig the way

栈溢出

这是一道栈溢出的题目,拖进ida查看主函数

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
69
70
71
72
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // ebx
int v5; // ebx
char Str[20]; // [esp+1Ch] [ebp-48h] BYREF
int v7[3]; // [esp+30h] [ebp-34h] BYREF
size_t v8; // [esp+3Ch] [ebp-28h]
int v9; // [esp+40h] [ebp-24h]
int v10; // [esp+44h] [ebp-20h]
int v11[3]; // [esp+48h] [ebp-1Ch]
int v12; // [esp+54h] [ebp-10h]
size_t v13; // [esp+58h] [ebp-Ch]
FILE *Stream; // [esp+5Ch] [ebp-8h]

__main();
v11[0] = (int)func0;
v11[1] = (int)func1;
v11[2] = (int)func2;
v7[0] = 0;
v7[1] = 1;
v7[2] = 2;
v8 = 3;
v9 = 3;
v10 = 4;
Stream = fopen("data", "rb");
if ( !Stream )
return -1;
fseek(Stream, 0, 2);
v13 = ftell(Stream);
fseek(Stream, 0, 0);
v12 = ftell(Stream);
if ( v12 )
{
puts("something wrong");
return 0;
}
else
{
for ( i = 0; i < (int)v13; ++i )
{
v4 = i;
Str[v4] = fgetc(Stream);
}
if ( strlen(Str) <= v13 )
{
v13 = v8; // v8==3
i = 0; // //v9==3
v12 = v10; // v10==4
while ( i <= 2 ) // v7==[0,1,2]
{
v5 = i + 1;
v7[v5] = ((int (__cdecl *)(int *, int, int))v11[i])(v7, v9, v10);// 栈溢出
v9 = ++i;
v10 = i + 1;
}
if ( v8 )
{
return -1;
}
else
{
get_key(v13, v12);
system("PAUSE");
return 0;
}
}
else
{
return -1;
}
}
}

得到flag的条件是v8==0,但并没有对v8的操作,仔细看可以发现在while循环中当i=3时存在栈溢出,实际上是对v8进行赋值,这是再去看func0,func1,func2

1
2
3
4
5
6
7
8
9
int __cdecl func0(int a1, int a2, int a3)
{
int v4; // [esp+Ch] [ebp-4h]

v4 = *(_DWORD *)(4 * a2 + a1);
*(_DWORD *)(a1 + 4 * a2) = *(_DWORD *)(4 * a3 + a1);
*(_DWORD *)(a1 + 4 * a3) = v4;
return 1;
}
1
2
3
4
5
6
7
unsigned int __cdecl func1(int a1, int a2, int a3)
{
return abs32(*(_DWORD *)(4 * a2 + a1) + *(_DWORD *)(4 * a3 + a1))
- abs32(*(_DWORD *)(4 * a3 + a1))
- abs32(*(_DWORD *)(4 * a2 + a1))
+ 2;
}
1
2
3
4
5
6
7
unsigned int __cdecl func2(int a1, int a2, int a3)
{
return abs32(*(_DWORD *)(4 * a3 + a1))
- abs32(*(_DWORD *)(4 * a3 + a1) + *(_DWORD *)(4 * a2 + a1))
+ abs32(*(_DWORD *)(4 * a2 + a1))
+ 2;
}

func0是一个互换函数,func1的返回值可以为0但func2的返回值恒大于0,所以可以利用读入data文件时的数据溢出来修改函数的参数,利用func0将func1和func2的顺序交换,这样才能使v8的值为0,读入的data会赋给str数组,而str数组的长度是20,然后就是v7的地址,偏移量分别就是20+0=20,20+4 =24,20+4 * 2=28,然后是v8,20+4 * 3=32,v9=>20+4 * 4=36,v10=>20+5 * 4=40,然后是三个函数,v11[0]=>20+4 * 6,v11[1]=>20+4 * 7,v11[2]=20+4 * 8

分析后可以知道,func的参数是v9和v10,但是需要将他修改为v11[1]和v11[2],也就是把36字节和40字节处的数据改为7和8

调用func1的时候v[2]=2,所以需要将v8改为-1,即地址为32处改为FF FF FF FF

![屏幕截图 2023-11-15 182751](D:\Blog\source_posts\DigtheWay\屏幕截图 2023-11-15 182751.png)


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 3049155267@qq.com

💰

×

Help us with donation