windows:shellcode生成框架和加载

  http://www.javashuo.com/article/p-kmjmdwcq-ne.html  分享了shellcode 的基本原理,核心思路是动态获取GetProcAddress和LoadLibrary函数地址,再经过这两个函数获取其余windows dll提供的函数地址;须要注意的是shellcode不能有全局变量和字符串,只能用局部变量和字符数组替代,这样才能在函数执行时在栈动态分配存储空间,不会和目标进程现有的空间冲突。html

       实战中,经过这种方式生成shellcode技术上可行,但比较麻烦,须要改动的地方太多,下面介绍一种shellcode现成的框架,开发人员可直接在特定的地方添加特定的代码便可,简单、灵活、易用;shell

  一、先介绍一下vs的编译顺序windows

        一个大型的工程,每每有多个cpp文件组成,最后都被编译成一个exe文件,那么exe中那么多函数,这些函数都是怎么排序的了?数组

      (1)文件之间:好比有多个文件,默认是按照文件名排序,好比先按照0-9排序,再按照a-z排序;下面默认先编译A.cpp,再编译B.cpp,最后编译main.c;可是也能够认为调整配置文件中的顺序,让B最早编译,A稍后编译,这样一来生成exe中函数顺序就按照这个来排序;框架

         

   (2)文件内部:按照定义/实现的顺序;好比下面的例子:函数实现的顺序分别是main、FuncB、FuncA,那么编译器在生成exe时编译的顺序也是这样的。ide

        

   上面说了这么多编译顺序,能用来干啥了?------>   确认shellcode 的范围和提取代码,好比上面用户把shellcode写进A和B函数,那么FuncA-FuncB者之间的代码都是shellcode,再调用CreateFile函数就能很容易保存到磁盘了;函数

  二、shellcode框架介绍spa

  (1)先来看看shellcode生成框架:四个文件起名颇有讲究,这样一来编译器就会按照这个顺序来编译源文件了,生成的exe中也会按照这个顺序排列函数;设计

    0.entry文件中,并不执行shellcode,只是经过shellcodeEnd-shellcodeStart 确认shellcode 的范围和起始地址,而后写入磁盘的bin文件;3d

       

   (2)a.start: shellcodeStart函数直接jmp到shellcodeEntry;InitFuntions初始化须要用到的几个关键函数;最关键的shellcodeEntry函数:用户能够在这里添加shellcode的自定义逻辑

       

      这里的shellcodeStart函数,是个裸函数,仅有一行代码,就是jmp到shellcodeEntry,这么简单的功能,为啥不直接把shellcodeEntry的代码复制到这里来,从这里跳转的意义是啥?

  •  shellcodeStart在这里,生成shellcode的时候才能把最核心的getKernel32和getProcAddress函数包进来;
  •    后续加载shellcode的时候会用call,那么须要从shellcode返回,这里是裸函数,没有ret,等后续shellcode全部的函数执行完后,最后一个ret恰好能够返回shellcode加载器,这里设计比较巧妙;
__declspec(naked) void ShellcodeStart() 
{
    __asm 
    {
        jmp ShellcodeEntry
    }

}

   (3)b.works:开发人员能够在这里自定义shellcode的执行逻辑(包装在单独的函数里),而后在上面的shellcodeEntry中调用该函数便可;

      

   (4)最后一个z.end:收尾工做,目前是空白的,啥也没作;因为shellcode的范围是shellcodeEnd-shellcodeStart,因此shellcode在End这行代码已经截至,这个函数内部任何代码都不会被收录到shellcode,这里请注意

      

   上面是整个框架的简介,最核心的地方是a.start的shellcodeEntry和b.works,开发人员直接在这里添加自定义的处理逻辑就好,其余地方通常都不用更改了,整个框架的复用性很是好;编译的时候也能看到各个文件编译的顺序:

  

       用IDA查看以下:函数的编译顺序确实是按照上面讲的顺序编译的:

        

   三、shellcode代码加载

  利用上述框架生成的shellcode,保存在磁盘bin文件,怎么加载和运行了?这里先介绍一个简单的方法:本身编写一个loader;

  核心原理很简单:调用VirtualAlloc分配一段内存,而后把shellcode拷贝到这段内存,最后call跳转到shellcode执行;

#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
int main(int argc, char* argv[])
{
    HANDLE hFile = CreateFileA(argv[1], GENERIC_READ, 0, NULL, OPEN_ALWAYS, 0, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
    {
        printf("Open  File Error!%d\n", GetLastError());
        return -1;
    }
    DWORD dwSize;
    dwSize = GetFileSize(hFile, NULL);

    LPVOID lpAddress = VirtualAlloc(NULL, dwSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (lpAddress == NULL)
    {
        printf("VirtualAlloc error:%d\n", GetLastError());
        CloseHandle(hFile);
        return -1;

    }
    DWORD dwRead;
    ReadFile(hFile, lpAddress, dwSize, &dwRead, 0);
    __asm
    {
        call lpAddress;

    }
    _flushall();
    system("pause");
    return 0;
}

  用该加载器成功加载shellcode并运行:

  

 

   四、这里的shellcode是本身loader加载的,运行空间也是loader分配的,容易被查出来;后续会介绍一些其余方法,好比把shellcode注入其余进程执行,增长被查找到的难度;

最后感谢这两个连接的做者(特别是视频介绍,由浅入深,通俗易懂),供初学者参考:

https://www.freebuf.com/articles/system/93983.html (有现成的工程供参考使用)

https://www.bilibili.com/video/BV1y4411k7ch?p=10  (有详细的视频过程演示和说明)

相关文章
相关标签/搜索