shellcode编写

文章目录

  • 注意事项
  • 基础知识
  • 开始编写
    • 第一步 初始化
    • 第二步 实现其他函数动态调用
    • 第三部 实现GetProcAddress和LoadLibraryA的动态调用
      • 获取kernel32.dll基址
      • 动态调用GetProcAddress
  • 实战
    • CreateFileA
    • MessageBoxA
    • 导出shellcode
  • 第一种shellcode编写实例1
  • 第一种shellcode编写实例2(优化结构)
  • shellcode加载器

注意事项

  1. 不使用全局变量
  2. 不使用类似于"abc"这样的字符串,通过数组定义字符串,char name[] = {0x6c,0x11,0x65,0x98};。

编译器会把字符串放置在一个特定的Section中(如.rdata或.data)。

  1. 函数、导入表不使用绝对地址

我们无法确定包含所需函数的DLL文件是否已经加载到内存。受ASLR(地址空间布局随机化)机制的影响,系统不会每次都把DLL文件加载到相同地址上。而且,DLL文件可能随着Windows每次新发布的更新而发生变化,所以我们不能依赖DLL文件中某个特定的偏移。
我们需要把DLL文件加载到内存,然后直接通过shellcode查找所需要的函数。幸运的是,Windows API为我们提供了两个函数:LoadLibrary和GetProcAddress。我们可以使用这两个函数来查找函数的地址。

  1. 避免空字节

空字节被认为是字符串的结束符

  1. 确保已加载所使用API的动态链接库

基础知识

#include
#include


int main() {
    // 字符串使用数组
	char kernel32[] = { 0x5f,0x51,0x46,0x5a,0x51,0x58,0x07,0x06,0x34 };
	HMODULE DD = LoadLibraryA(kernel32);
	char addatoma[] = { 0x75,0x50,0x50,0x75,0x40,0x5b,0x59,0x75,0x34 };
    // 函数使用相对地址
	LPVOID FUN1 = GetProcAddress(DD, addatoma);
	// FUN1();
	return 0;
}

以上代码中,LoadLibraryA和GetProcAddress函数还没有实现相对地址——》这时候就要用到peb寄存器
参考:PEB TEB结构体使用
FS段寄存器指向当前的TEB结构,TEB偏移0x30处指针指向PEB,通过fs:[0x30]即可获得PEB信息。
0x030 ProcessEnvironmentBlock : Ptr32 _PEB 当前进程的PEB指针
PEB结构体偏移0c处指针ldr指向进程加载模块链表 PEB_LDR_DATA 。
0x00c Ldr : Ptr32 _PEB_LDR_DATA 进程模块加载链表
PEB获取模块基址硬编码
shellcode编写_第1张图片

注:MOV EAX,[EAX]
以eax里面的值做为地址,取出来给eax 。
比如地址100H = 88aaH
eax = 100H
那么mov eax, [eax]后
eax里面的值是88aaH

PEB_LDR_DATA 模块加载链表,包含有关为进程加载的模块的信息。

typedef struct _PEB_LDR_DATA
{
 ULONG Length; // +0x00
 BOOLEAN Initialized; // +0x04
 PVOID SsHandle; // +0x08
 LIST_ENTRY InLoadOrderModuleList; // +0x0c
 LIST_ENTRY InMemoryOrderModuleList; // +0x14包含进程已加载模块的双向链表的头部。列表中的每一项都是指向LDR_DATA_TABLE_ENTRY结构的指针。
 LIST_ENTRY InInitializationOrderModuleList;// +0x1c
} PEB_LDR_DATA,*PPEB_LDR_DATA; // +0x24
typedef struct _LDR_DATA_TABLE_ENTRY  
{  
    LIST_ENTRY InLoadOrderLinks;  
    LIST_ENTRY InMemoryOrderLinks;  
    LIST_ENTRY InInitializationOrderLinks;  
    PVOID DllBase;  
    PVOID EntryPoint;  
    DWORD SizeOfImage;  
    UNICODE_STRING FullDllName;  
    UNICODE_STRING BaseDllName;  
    DWORD Flags;  
    WORD LoadCount;  
    WORD TlsIndex;  
    LIST_ENTRY HashLinks;  
    PVOID SectionPointer;  
    DWORD CheckSum;  
    DWORD TimeDateStamp;  
    PVOID LoadedImports;  
    PVOID EntryPointActivationContext;  
    PVOID PatchInformation;  
}LDR_DATA_TABLE_ENTRY,*PLDR_DATA_TABLE_ENTRY;  

获取模块的基址代码

void _getModuleBaseAddr()
{
    void *PEB = NULL,
        *Ldr = NULL,
        *Flink = NULL,
        *p = NULL,
        *BaseAddress = NULL,
        *FullDllName = NULL;

    __asm
    {
        mov eax, fs:[0x30]
        mov PEB, eax
    }
    Ldr = (PVOID)*((PDWORD)((DWORD)PEB + 0x0c));
    Flink = (PVOID)*((PDWORD)((DWORD)Ldr + 0x14));
    p = Flink;
    do
    {
        BaseAddress = (PVOID)*((PDWORD)((DWORD)p + 0x10));
        FullDllName = (PVOID)*((PDWORD)((DWORD)p + 0x20));
        wprintf(L"FullDllName is %s\n", FullDllName);
        printf("BaseAddress is %x\n", BaseAddress);
        p = (PVOID)*((PDWORD)p);
    } while (Flink != p);
}

开始编写

课程:黑客高级技术织shellcode入门到精通

第一步 初始化

  1. 修改程序为release版本,x86

  2. 禁用缓冲器安全检查:配置属性→C/C++ → 代码生成→关闭安全检查shellcode编写_第2张图片

  3. 运行库修改为MT或者MTD:配置属性→C/C++→运行库→改为静态的MTshellcode编写_第3张图片

MT static 静态 (MTD debug模式使用)
MD dynamic 动态 release模式使用

  1. 链接器→子系统→改为窗口

  2. 关闭随机基址,方便调试:链接器→随机基址→改为否

  3. 关闭优化shellcode编写_第4张图片

  4. 修改程序入口点为EntryMain,减少额外添加的代码c++ 自定义程序入口函数 vs2019shellcode编写_第5张图片

  5. 关闭清单文件,不生成段shellcode编写_第6张图片

  6. 关闭调试信息shellcode编写_第7张图片

第二步 实现其他函数动态调用

GetProcAddress+LoadLibraryA可以实现其他函数的动态调用

#include
#include 

int EntryMain() {
	
	MessageBox(NULL, NULL, NULL, NULL);

	return 0;
}

GetProcAddress从指定的动态链接库 (DLL) 中检索导出函数或变量的地址。通过它可以获得函数的真实地址。

LPVOID lp = GetProcAddress(LoadLibraryA("user32.dll"), "MessageBoxA");

此时lp记录的就是MessageBoxA的真实地址,如何调用呢?

#include
#include 
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")

int EntryMain() {
	//MessageBox(NULL, NULL, NULL, NULL);

	LPVOID lp = GetProcAddress(LoadLibraryA("user32.dll"), "MessageBoxA");
	char * pszData = (char *)"Hello World";
	__asm {
		push 0
		push 0
		push pszData
		push 0
		call lp
	}
	return 0;
}

成功调用
shellcode编写_第8张图片

如何编写正规的函数动态调用代码,以CreateFileA和printf作为示例

#include
#include 
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")

int EntryMain() {
	
	CreateFileA("hello.txt", GENERIC_WRITE,0,NULL, CREATE_ALWAYS,0,NULL);

	printf("%s\n", "Hello World!");

	return 0;
}

首先在CreateFileA函数上右键转到定义,将函数声明复制过来

WINBASEAPI
HANDLE
WINAPI
CreateFileA(
    _In_ LPCSTR lpFileName,
    _In_ DWORD dwDesiredAccess,
    _In_ DWORD dwShareMode,
    _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
    _In_ DWORD dwCreationDisposition,
    _In_ DWORD dwFlagsAndAttributes,
    _In_opt_ HANDLE hTemplateFile
    );

修改为如下所示

#include
#include 
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")

int EntryMain() {
	
//	CreateFileA("hello.txt", GENERIC_WRITE,0,NULL, CREATE_ALWAYS,0,NULL);
    typedef HANDLE(WINAPI* FN_CreateFileA)(
            _In_ LPCSTR lpFileName,
            _In_ DWORD dwDesiredAccess,
            _In_ DWORD dwShareMode,
            _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
            _In_ DWORD dwCreationDisposition,
            _In_ DWORD dwFlagsAndAttributes,
            _In_opt_ HANDLE hTemplateFile
        );
    //定义一个函数指针变量
    FN_CreateFileA fn_CreateFileA;
    //强制类型转换
    fn_CreateFileA = (FN_CreateFileA)GetProcAddress(LoadLibraryA("kernel32.dll"), "CreateFileA");
    //然后就可以正常使用CreateFileA了
    fn_CreateFileA("hello.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);

	return 0;
}

成功运行

shellcode编写_第9张图片
printf也是一样
shellcode编写_第10张图片

#include
#include 
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")

int EntryMain() {
	
//	printf("%s\n", "Hello World!");
    typedef int(__CRTDECL* FN_printf)(_In_z_ _Printf_format_string_ char const* const _Format, ...);
    FN_printf fn_printf;
    fn_printf = (FN_printf)GetProcAddress(LoadLibraryA("msvcrt.dll"), "printf");
    fn_printf("%s\n", "Hello World!");
    
	return 0;
}

在这里插入图片描述

第三部 实现GetProcAddress和LoadLibraryA的动态调用

在前一节中可以通过GetProcAddress和LoadLibraryA实现其他所有函数的动态调用,但是这两个函数也需要获得真实地址。
LoadLibraryA可以通过GetProcAddress获取,kernel32基址获取与getprocaddress地址获取

不管是winxp还是其他windows版本,kernel32.dll都是第三个被调用的模块
shellcode编写_第11张图片

获取kernel32.dll基址

#include
#include

__declspec(naked) DWORD getKernel32()
{
	__asm
	{
		mov eax,fs:[0x30]   //fs:[30] 纯存的是PEB,也就是进程环境块,操作系统在加载进程的过程中会自动初始化一个PEB结构体用来初始化该进程的各种信息的结构体
		mov eax,[eax+0x0c]    //也就是PEB 0ch处的偏移,该结构体的三个成员链表都可以获取kernel32的基址
		mov eax,[eax+0x14]    //获取初始化顺序链表的地址,首地址是第一个模块
		mov eax,[eax]        //第二个模块
		mov eax,[eax]        //第三个模块
		mov eax,[eax+0x10]    // 10h偏移处就是kernel32的基地址
		ret
	}
}

int main() {

    HMODULE hLoadLibraryA = (HMODULE)getKernel32();
    printf("0x%08X\n", hLoadLibraryA);
    printf("0x%08X\n", LoadLibraryA("kernel32.dll"));

    LPVOID lpLoadLibraryA = GetProcAddress(hLoadLibraryA, "LoadLibraryA");
}

在这里插入图片描述

动态调用GetProcAddress

#include
#include

__declspec(naked) DWORD getKernel32()
{
	__asm
	{
		mov eax,fs:[0x30]   //fs:[30] 纯存的是PEB,也就是进程环境块,操作系统在加载进程的过程中会自动初始化一个PEB结构体用来初始化该进程的各种信息的结构体
		mov eax,[eax+0x0c]    //也就是PEB 0ch处的偏移,该结构体的三个成员链表都可以获取kernel32的基址
		mov eax,[eax+0x14]    //获取初始化顺序链表的地址,首地址是第一个模块
		mov eax,[eax]        //第二个模块
		mov eax,[eax]        //第三个模块
		mov eax,[eax+0x10]    // 10h偏移处就是kernel32的基地址
		ret
	}
}
FARPROC _GetProcAddress(HMODULE hModuleBase)
{
    PIMAGE_DOS_HEADER lpDosHeader = (PIMAGE_DOS_HEADER)hModuleBase;
    PIMAGE_NT_HEADERS32 lpNtHeader = (PIMAGE_NT_HEADERS)((DWORD)hModuleBase + lpDosHeader->e_lfanew);
    if (!lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size) {
        return NULL;
    }
    if (!lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) {
        return NULL;
    }
    PIMAGE_EXPORT_DIRECTORY lpExports = (PIMAGE_EXPORT_DIRECTORY)((DWORD)hModuleBase + (DWORD)lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
    PDWORD lpdwFunName = (PDWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfNames);
    PWORD lpword = (PWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfNameOrdinals);
    PDWORD lpdwFunAddr = (PDWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfFunctions);

    DWORD dwLoop = 0;
    FARPROC pRet = NULL;
    for (; dwLoop <= lpExports->NumberOfNames - 1; dwLoop++) {
        char* pFunName = (char*)(lpdwFunName[dwLoop] + (DWORD)hModuleBase);

        if (pFunName[0] == 'G' &&
            pFunName[1] == 'e' &&
            pFunName[2] == 't' &&
            pFunName[3] == 'P' &&
            pFunName[4] == 'r' &&
            pFunName[5] == 'o' &&
            pFunName[6] == 'c' &&
            pFunName[7] == 'A' &&
            pFunName[8] == 'd' &&
            pFunName[9] == 'd' &&
            pFunName[10] == 'r' &&
            pFunName[11] == 'e' &&
            pFunName[12] == 's' &&
            pFunName[13] == 's')
        {
            pRet = (FARPROC)(lpdwFunAddr[lpword[dwLoop]] + (DWORD)hModuleBase);
            break;
        }
    }
    return pRet;
}



int main() {

    HMODULE hLoadLibraryA = (HMODULE)getKernel32();

    typedef FARPROC (WINAPI *FN_GetProcAddress)(
        _In_ HMODULE hModule,
        _In_ LPCSTR lpProcName
        );
    FN_GetProcAddress fn_GetProcAddress;
    fn_GetProcAddress = (FN_GetProcAddress)_GetProcAddress(hLoadLibraryA);

    printf("0x%08X\n", fn_GetProcAddress);
    printf("0x%08X\n", GetProcAddress);

    //LPVOID lpLoadLibraryA = GetProcAddress(hLoadLibraryA, "LoadLibraryA");
}

成功!
shellcode编写_第12张图片

实战

CreateFileA

将以下代码转换为shellcode

#include
#include

int EntryMain() {
    CreateFileA("hello.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
	return 0;
}
#include
#include

//声明
DWORD getKernel32();
FARPROC _GetProcAddress(HMODULE hModuleBase);

int EntryMain() {
    typedef FARPROC(WINAPI* FN_GetProcAddress)(
        _In_ HMODULE hModule,
        _In_ LPCSTR lpProcName
        );
    //获取GetProcAddress实际地址
    FN_GetProcAddress fn_GetProcAddress = (FN_GetProcAddress)_GetProcAddress((HMODULE)getKernel32());
    typedef HANDLE (WINAPI *FN_CreateFileA)(
            _In_ LPCSTR lpFileName,
            _In_ DWORD dwDesiredAccess,
            _In_ DWORD dwShareMode,
            _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
            _In_ DWORD dwCreationDisposition,
            _In_ DWORD dwFlagsAndAttributes,
            _In_opt_ HANDLE hTemplateFile
        );
    //获取CreateFileA真实地址
    char szCreateFileA[] = {'C','r','e','a','t','e','F','i','l','e','A', 0};
    FN_CreateFileA fn_CreateFileA = (FN_CreateFileA)fn_GetProcAddress((HMODULE)getKernel32(), szCreateFileA);

    //调用CreateFileA函数
    char szhello[] = { 'h', 'e', 'l', 'l', 'o', '.', 't', 'x', 't', 0 };
    fn_CreateFileA(szhello, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
    //  CreateFileA("hello.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);

	return 0;
}

__declspec(naked) DWORD getKernel32()
{
    __asm
    {
        mov eax, fs: [30h]
        mov eax, [eax + 0ch]
        mov eax, [eax + 14h]
        mov eax, [eax]
        mov eax, [eax]
        mov eax, [eax + 10h]
        ret
    }
}

FARPROC _GetProcAddress(HMODULE hModuleBase)
{
    PIMAGE_DOS_HEADER lpDosHeader = (PIMAGE_DOS_HEADER)hModuleBase;
    PIMAGE_NT_HEADERS32 lpNtHeader = (PIMAGE_NT_HEADERS)((DWORD)hModuleBase + lpDosHeader->e_lfanew);
    if (!lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size) {
        return NULL;
    }
    if (!lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) {
        return NULL;
    }
    PIMAGE_EXPORT_DIRECTORY lpExports = (PIMAGE_EXPORT_DIRECTORY)((DWORD)hModuleBase + (DWORD)lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
    PDWORD lpdwFunName = (PDWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfNames);
    PWORD lpword = (PWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfNameOrdinals);
    PDWORD lpdwFunAddr = (PDWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfFunctions);

    DWORD dwLoop = 0;
    FARPROC pRet = NULL;
    for (; dwLoop <= lpExports->NumberOfNames - 1; dwLoop++) {
        char* pFunName = (char*)(lpdwFunName[dwLoop] + (DWORD)hModuleBase);

        if (pFunName[0] == 'G' &&
            pFunName[1] == 'e' &&
            pFunName[2] == 't' &&
            pFunName[3] == 'P' &&
            pFunName[4] == 'r' &&
            pFunName[5] == 'o' &&
            pFunName[6] == 'c' &&
            pFunName[7] == 'A' &&
            pFunName[8] == 'd' &&
            pFunName[9] == 'd' &&
            pFunName[10] == 'r' &&
            pFunName[11] == 'e' &&
            pFunName[12] == 's' &&
            pFunName[13] == 's')
        {
            pRet = (FARPROC)(lpdwFunAddr[lpword[dwLoop]] + (DWORD)hModuleBase);
            break;
        }
    }
    return pRet;
}

MessageBoxA

#include
#include

int EntryMain() {
    MessageBoxA(NULL, "Hello World!", "tip", MB_OK);
	return 0;
}
#include
#include

//声明
DWORD getKernel32();
FARPROC _GetProcAddress(HMODULE hModuleBase);

int EntryMain() {
    typedef FARPROC(WINAPI *FN_GetProcAddress)(
            _In_ HMODULE hModule,
            _In_ LPCSTR lpProcName
        );
    //获取GetProcAddress实际地址
    FN_GetProcAddress fn_GetProcAddress = (FN_GetProcAddress)_GetProcAddress((HMODULE)getKernel32());
    typedef HMODULE (WINAPI *FN_LoadLibraryA)(
            _In_ LPCSTR lpLibFileName
        );
    //获取LoadLibraryA实际地址
    char szLoadLibraryA[] = { 'L', 'o', 'a', 'd', 'L', 'i','b','r','a','r','y','A', 0};
    FN_LoadLibraryA fn_LoadLibraryA = (FN_LoadLibraryA)fn_GetProcAddress((HMODULE)getKernel32(), szLoadLibraryA);
    typedef int (WINAPI *FN_MessageBoxA)(
            _In_opt_ HWND hWnd,
            _In_opt_ LPCSTR lpText,
            _In_opt_ LPCSTR lpCaption,
            _In_ UINT uType);
    //获取MessageBoxA实际地址
    char szUser32[] = { 'U', 's', 'e', 'r', '3', '2', '.', 'd', 'l', 'l', 0 };
    char szMessageBoxA[] = {'M','e', 's', 's', 'a', 'g', 'e', 'B', 'o', 'x', 'A', 0};
    FN_MessageBoxA fn_MessageBoxA = (FN_MessageBoxA)GetProcAddress(fn_LoadLibraryA(szUser32), szMessageBoxA);

    //调用fn_MessageBoxA函数
    char szHelloWorld[] = { 'H','e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!', 0 };
    char szTip[] = { 't', 'i', 'p', 0 };
    fn_MessageBoxA(NULL, szHelloWorld, szTip, MB_OK);
 //   MessageBoxA(NULL, "Hello World!", "tip", MB_OK);
	return 0;
}

__declspec(naked) DWORD getKernel32()
{
    __asm
    {
        mov eax, fs: [30h]
        mov eax, [eax + 0ch]
        mov eax, [eax + 14h]
        mov eax, [eax]
        mov eax, [eax]
        mov eax, [eax + 10h]
        ret
    }
}

FARPROC _GetProcAddress(HMODULE hModuleBase)
{
    PIMAGE_DOS_HEADER lpDosHeader = (PIMAGE_DOS_HEADER)hModuleBase;
    PIMAGE_NT_HEADERS32 lpNtHeader = (PIMAGE_NT_HEADERS)((DWORD)hModuleBase + lpDosHeader->e_lfanew);
    if (!lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size) {
        return NULL;
    }
    if (!lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) {
        return NULL;
    }
    PIMAGE_EXPORT_DIRECTORY lpExports = (PIMAGE_EXPORT_DIRECTORY)((DWORD)hModuleBase + (DWORD)lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
    PDWORD lpdwFunName = (PDWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfNames);
    PWORD lpword = (PWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfNameOrdinals);
    PDWORD lpdwFunAddr = (PDWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfFunctions);

    DWORD dwLoop = 0;
    FARPROC pRet = NULL;
    for (; dwLoop <= lpExports->NumberOfNames - 1; dwLoop++) {
        char* pFunName = (char*)(lpdwFunName[dwLoop] + (DWORD)hModuleBase);

        if (pFunName[0] == 'G' &&
            pFunName[1] == 'e' &&
            pFunName[2] == 't' &&
            pFunName[3] == 'P' &&
            pFunName[4] == 'r' &&
            pFunName[5] == 'o' &&
            pFunName[6] == 'c' &&
            pFunName[7] == 'A' &&
            pFunName[8] == 'd' &&
            pFunName[9] == 'd' &&
            pFunName[10] == 'r' &&
            pFunName[11] == 'e' &&
            pFunName[12] == 's' &&
            pFunName[13] == 's')
        {
            pRet = (FARPROC)(lpdwFunAddr[lpword[dwLoop]] + (DWORD)hModuleBase);
            break;
        }
    }
    return pRet;
}

导出shellcode

使用上面的代码生成.exe文件后,用peid查看文件偏移
shellcode编写_第13张图片
从该偏移量开始即为shellcode
shellcode编写_第14张图片
shellcode编写_第15张图片
不过这里用视频里的方法,用这段shellcode直接替换目标exe偏移开始部分同等长度的16进制代码执行失败,因为自己对pe文件导出表、导入表部分基础还不太熟悉所以也不知道原因。

第一种shellcode编写实例1

目标:直接把shellcode输出在bin文件中。
原理:看视频

shellcode编写_第16张图片

头文件 header.h

#pragma once

#include

void ShellcodeStsrt();
void ShellcodeEntry();
void ShellcodeEnd();
void CreateShellcode();

0.entry.cpp

#include "header.h"

#pragma comment(linker,"/entry:EntryMain")

int EntryMain() {
	CreateShellcode();
	return 0;
}

void CreateShellcode() {
	HMODULE hMsvcrt = LoadLibraryA("msvcrt.dll");
	typedef int (__CRTDECL* fn_printf)(
		_In_z_ _Printf_format_string_ char const* const _Format,
		...);
	fn_printf xprintf = (fn_printf)GetProcAddress(hMsvcrt, "printf");

	xprintf("1");
	HANDLE hBin = CreateFileA("sh.bin", GENERIC_ALL, 0, NULL, CREATE_ALWAYS, 0, NULL);
	if (hBin == INVALID_HANDLE_VALUE)
	{
		xprintf("create file errot:%d\n",GetLastError());
		return;
	}
	DWORD dwSize = (DWORD)ShellcodeEnd - (DWORD)ShellcodeStsrt;
	DWORD dwWriten;
	WriteFile(hBin, ShellcodeStsrt, dwSize, &dwWriten, NULL);
	CloseHandle(hBin);
}

a.start.cpp

#include "header.h"

__declspec(naked) void ShellcodeStsrt() {
	__asm {
		jmp ShellcodeEntry
	}
}
__declspec(naked) DWORD getKernel32()
{
    __asm
    {
        mov eax, fs: [30h] ;
        test eax, eax;
        js  finished;
        mov eax, [eax + 0ch];
        mov eax, [eax + 14h];
        mov eax, [eax];
        mov eax, [eax]
        mov eax, [eax + 10h]
    finished:
        ret
    }
}

FARPROC _GetProcAddress(HMODULE hModuleBase)
{
    PIMAGE_DOS_HEADER lpDosHeader = (PIMAGE_DOS_HEADER)hModuleBase;
    PIMAGE_NT_HEADERS32 lpNtHeader = (PIMAGE_NT_HEADERS)((DWORD)hModuleBase + lpDosHeader->e_lfanew);
    if (!lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size) {
        return NULL;
    }
    if (!lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) {
        return NULL;
    }
    PIMAGE_EXPORT_DIRECTORY lpExports = (PIMAGE_EXPORT_DIRECTORY)((DWORD)hModuleBase + (DWORD)lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
    PDWORD lpdwFunName = (PDWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfNames);
    PWORD lpword = (PWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfNameOrdinals);
    PDWORD lpdwFunAddr = (PDWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfFunctions);

    DWORD dwLoop = 0;
    FARPROC pRet = NULL;
    for (; dwLoop <= lpExports->NumberOfNames - 1; dwLoop++) {
        char* pFunName = (char*)(lpdwFunName[dwLoop] + (DWORD)hModuleBase);

        if (pFunName[0] == 'G' &&
            pFunName[1] == 'e' &&
            pFunName[2] == 't' &&
            pFunName[3] == 'P' &&
            pFunName[4] == 'r' &&
            pFunName[5] == 'o' &&
            pFunName[6] == 'c' &&
            pFunName[7] == 'A' &&
            pFunName[8] == 'd' &&
            pFunName[9] == 'd' &&
            pFunName[10] == 'r' &&
            pFunName[11] == 'e' &&
            pFunName[12] == 's' &&
            pFunName[13] == 's')
        {
            pRet = (FARPROC)(lpdwFunAddr[lpword[dwLoop]] + (DWORD)hModuleBase);
            break;
        }
    }
    return pRet;
}
void ShellcodeEntry() {
    typedef FARPROC(WINAPI* FN_GetProcAddress)(
        _In_ HMODULE hModule,
        _In_ LPCSTR lpProcName
        );
    //获取GetProcAddress实际地址
    FN_GetProcAddress fn_GetProcAddress = (FN_GetProcAddress)_GetProcAddress((HMODULE)getKernel32());
    typedef HMODULE(WINAPI* FN_LoadLibraryA)(
        _In_ LPCSTR lpLibFileName
        );
    //获取LoadLibraryA实际地址
    char szLoadLibraryA[] = { 'L', 'o', 'a', 'd', 'L', 'i','b','r','a','r','y','A', 0 };
    FN_LoadLibraryA fn_LoadLibraryA = (FN_LoadLibraryA)fn_GetProcAddress((HMODULE)getKernel32(), szLoadLibraryA);
    typedef int (WINAPI* FN_MessageBoxA)(
        _In_opt_ HWND hWnd,
        _In_opt_ LPCSTR lpText,
        _In_opt_ LPCSTR lpCaption,
        _In_ UINT uType);
    //获取MessageBoxA实际地址
    char szUser32[] = { 'U', 's', 'e', 'r', '3', '2', '.', 'd', 'l', 'l', 0 };
    char szMessageBoxA[] = { 'M','e', 's', 's', 'a', 'g', 'e', 'B', 'o', 'x', 'A', 0 };
    FN_MessageBoxA fn_MessageBoxA = (FN_MessageBoxA)GetProcAddress(fn_LoadLibraryA(szUser32), szMessageBoxA);

    //调用fn_MessageBoxA函数
    char szHelloWorld[] = { 'H','e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!', 0 };
    char szTip[] = { 't', 'i', 'p', 0 };
    fn_MessageBoxA(NULL, szHelloWorld, szTip, MB_OK);
    //   MessageBoxA(NULL, "Hello World!", "tip", MB_OK);
}

z.end.cpp

#include "header.h"

void ShellcodeEnd() {

}

这里运行一下就自动生成了含有MessageBoxA的shellcode的bin文件,我们用最后面的shellcode加载器就可以运行这段shellcode。
shellcode编写_第17张图片

第一种shellcode编写实例2(优化结构)

优化了一下,将功能部分和逻辑部分分开,直接把要实现的功能写在b.work.cpp中即可,逻辑部分写在其他三个文件中。
shellcode编写_第18张图片

头文件
api.h

#pragma once

#include 

typedef FARPROC(WINAPI* FN_GetProcAddress)(
    _In_ HMODULE hModule,
    _In_ LPCSTR lpProcName
    );

typedef HMODULE(WINAPI* FN_LoadLibraryA)(
    _In_ LPCSTR lpLibFileName
    );

typedef int (WINAPI* FN_MessageBoxA)(
    _In_opt_ HWND hWnd,
    _In_opt_ LPCSTR lpText,
    _In_opt_ LPCSTR lpCaption,
    _In_ UINT uType);

typedef struct FUNCTIONS
{
    FN_GetProcAddress fn_GetProcAddress;
    FN_LoadLibraryA fn_LoadLibraryA;
    FN_MessageBoxA fn_MessageBoxA;
}FUNCTIONS, *PFUNCTIONS;

header.h

#pragma once

#include "api.h"

#include
#include

void ShellcodeStsrt();
void ShellcodeEntry();
void ShellcodeEnd();

void CreateShellcode();
void InitFunctions(PFUNCTIONS pFn);

void CreateConfigFile(PFUNCTIONS pFn);

0.entry.cpp

#include "header.h"

#pragma comment(linker,"/entry:EntryMain")

int EntryMain() {
	CreateShellcode();
	return 0;
}

void CreateShellcode() {
	HMODULE hMsvcrt = LoadLibraryA("msvcrt.dll");
	typedef int (__CRTDECL* fn_printf)(
		_In_z_ _Printf_format_string_ char const* const _Format,
		...);
	fn_printf xprintf = (fn_printf)GetProcAddress(hMsvcrt, "printf");

	xprintf("1");
	HANDLE hBin = CreateFileA("sh.bin", GENERIC_ALL, 0, NULL, CREATE_ALWAYS, 0, NULL);
	if (hBin == INVALID_HANDLE_VALUE)
	{
		xprintf("create file error:%d\n",GetLastError());
		return;
	}
	DWORD dwSize = (DWORD)ShellcodeEnd - (DWORD)ShellcodeStsrt;
	DWORD dwWriten;
	WriteFile(hBin, ShellcodeStsrt, dwSize, &dwWriten, NULL);
	CloseHandle(hBin);
}

a.start.cpp

#include "header.h"
#include "api.h"

__declspec(naked) void ShellcodeStsrt() {
	__asm {
		jmp ShellcodeEntry
	}
}
__declspec(naked) DWORD getKernel32()
{
    __asm
    {
        mov eax, fs: [30h] ;
        test eax, eax;
        js  finished;
        mov eax, [eax + 0ch];
        mov eax, [eax + 14h];
        mov eax, [eax];
        mov eax, [eax]
        mov eax, [eax + 10h]
    finished:
        ret
    }
}

FARPROC _GetProcAddress(HMODULE hModuleBase)
{
    PIMAGE_DOS_HEADER lpDosHeader = (PIMAGE_DOS_HEADER)hModuleBase;
    PIMAGE_NT_HEADERS32 lpNtHeader = (PIMAGE_NT_HEADERS)((DWORD)hModuleBase + lpDosHeader->e_lfanew);
    if (!lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size) {
        return NULL;
    }
    if (!lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) {
        return NULL;
    }
    PIMAGE_EXPORT_DIRECTORY lpExports = (PIMAGE_EXPORT_DIRECTORY)((DWORD)hModuleBase + (DWORD)lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
    PDWORD lpdwFunName = (PDWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfNames);
    PWORD lpword = (PWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfNameOrdinals);
    PDWORD lpdwFunAddr = (PDWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfFunctions);

    DWORD dwLoop = 0;
    FARPROC pRet = NULL;
    for (; dwLoop <= lpExports->NumberOfNames - 1; dwLoop++) {
        char* pFunName = (char*)(lpdwFunName[dwLoop] + (DWORD)hModuleBase);

        if (pFunName[0] == 'G' &&
            pFunName[1] == 'e' &&
            pFunName[2] == 't' &&
            pFunName[3] == 'P' &&
            pFunName[4] == 'r' &&
            pFunName[5] == 'o' &&
            pFunName[6] == 'c' &&
            pFunName[7] == 'A' &&
            pFunName[8] == 'd' &&
            pFunName[9] == 'd' &&
            pFunName[10] == 'r' &&
            pFunName[11] == 'e' &&
            pFunName[12] == 's' &&
            pFunName[13] == 's')
        {
            pRet = (FARPROC)(lpdwFunAddr[lpword[dwLoop]] + (DWORD)hModuleBase);
            break;
        }
    }
    return pRet;
}

void InitFunctions(PFUNCTIONS pFn)
{
    //获取GetProcAddress实际地址
    pFn->fn_GetProcAddress = (FN_GetProcAddress)_GetProcAddress((HMODULE)getKernel32());
    char szLoadLibraryA[] = { 'L', 'o', 'a', 'd', 'L', 'i','b','r','a','r','y','A', 0 };
    //获取LoadLibraryA实际地址
    pFn->fn_LoadLibraryA = (FN_LoadLibraryA)pFn->fn_GetProcAddress((HMODULE)getKernel32(), szLoadLibraryA);
    char szUser32[] = { 'U', 's', 'e', 'r', '3', '2', '.', 'd', 'l', 'l', 0 };
    char szMessageBoxA[] = { 'M','e', 's', 's', 'a', 'g', 'e', 'B', 'o', 'x', 'A', 0 };
    //获取MessageBoxA实际地址
    pFn->fn_MessageBoxA = (FN_MessageBoxA)pFn->fn_GetProcAddress(pFn->fn_LoadLibraryA(szUser32), szMessageBoxA);
}

void ShellcodeEntry() 
{

    FUNCTIONS fn;
    InitFunctions(&fn);
    CreateConfigFile(&fn);
}

b.work.h

#include "api.h"
#include "header.h"

void CreateConfigFile(PFUNCTIONS pFn)
{
    //调用fn_MessageBoxA函数
    char szHelloWorld[] = { 'H','e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!', 0 };
    char szTip[] = { 't', 'i', 'p', 0 };
    pFn->fn_MessageBoxA(NULL, szHelloWorld, szTip, MB_OK);
    //   MessageBoxA(NULL, "Hello World!", "tip", MB_OK);
}

z.end.cpp

#include "header.h"

void ShellcodeEnd() {

}

shellcode加载器

// runbin.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include 
#include 

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编写_第19张图片

你可能感兴趣的:(二进制逆向,c++,开发语言,shellcode,汇编)