• Window环境下编写Shellcode(入门篇)


    Window环境下编写Shellcode

    一、 什么是shellcode
    a) 定义
    是一段可注入的指令(opcode),可以在被攻击的程序内运行。

    b) 特点
    独立存在,无需任何文件格式的包装,因为shellcode直接操作寄存器和函数,所以opcode必须是16进制形式。因此也不能用高级语言编写shellcode。
    在内存中运行,无需运行在固定的宿主进程上。

    c) 作用
    我们想让目标程序以不同于设计者预期的方式运行,或者是按照和我们的意图形式。
    d) Shellcode的利用原理
    将shellcode注入缓冲区,然后欺骗目标程序执行它。而将shellcode注入缓冲区最常用的方法是利用目标系统上的缓冲区溢出漏洞。
    二、 环境的基本搭建
    Windows下Visio studio2012 visual c++ 控制台应用程序的设置:
    1、 设置入口点,去除自动生成的多余的exe代码
    操作:项目属性链接器高级入口点(可自定义,或加上#pragma comment(linker,"/entry:EntryMain"))
    实验:可在更改配置的前后,将用IDA打开生成的exe文件,
    结果: 前=》很多杂七杂八的没在代码里调用的函数 后=》只有自己在源代码中编写的函数
    2、 去除安全检查
    项目->属性->C/C++->代码生成->安全检查
    3、 兼容xp平台
    设置字符集:未设置
    4、 设置运行库
    MT选项:链接LIB版的C和C++运行库。在链接时就会在将C和C++运行时库集成到程序中成为程序中的代码,程序体积会变大。
    MTd选项:LIB的调试版。
    MD选项:使用DLL版的C和C++运行库,这样在程序运行时会动态的加载对应的DLL,程序体积会减小,缺点是在系统没有对应DLL时程序无法运行。
    MDd选项:表示使用DLL的调试版。
    动态版(DLL)和静态版(LIB)C和C++运行库的优缺点
    动态版(DLL):优点=exe程序小,缺点=没有对应的dll就无法运行。
    静态版(LIB):缺点=因为静态版必须把C和C++运行库复制到目标程序中,所以产生的可执行问会比较大。并且对于大型的项目,在程序运行时会产生对个运行库,在链接时可能会出现重复定义的问题。
    5、 关闭生成清单
    操作:链接器-》清单文件--》关闭
    实验:PEID打开配置前后的exe文件,查看其各个段
    结果:前=》只有代码段 后=》只有数据段
    6、 关闭调试信息
    链接器-》调试器-》FALSE
    三、 相关工具
    a) Visual studio2012-代码编写
    b) PEID-PE结构扫描
    查看可执行文件的入口点
    c) Winhex-16进制查看工具
    查找对应位置的字符串,并保存为bin文件
    d) IDA-汇编调试工具
    e) MSDN Library-库函数查询工具
    安装离线库文档
    可查函数的具体描述,包括调用的系统api
    四、 Shellcode编写原则
    a) 避免使用任何全局变量,因为全局变量运行时属于独立地内存空间,违背了shellcode使用绝对地址的原则
    b) 不能使用static来定义变量,与全局变量的意义类似
    c) 确保已加载所需使用的API动态链接库,确保所调用的链接库在内存中,保证正常的跳转。
    五、 第一种shellcode的编写实例

    #include <windows.h>
    
    #pragma comment(linker,"/entry:EntryMain")
    
    /**
    例子:message这个弹框文件的存在
    */
    
    int EntryMain()
    {
    	// MessageBox(NULL,NULL, NULL,NULL);
    	//例子2:如何获取MessageBox的地址,并通过这个返回的地址调用这个函数
    	// 方法:通过函数的地址,嵌入汇编->压栈
    
    	//几个常用的动态链接库:kernel32.dll user32.dll  gdi32.dll  msvcrt.dll
    	LPVOID lp =  GetProcAddress(LoadLibraryA("user32.dll"),"MessageBoxA");
    	char * pdata = "hello word";
    	_asm
    	{
    		push 0
    		push 0
    		push pdata
    		push 0   // 压入4个参数:相当于例子1中的4个为NULL的参数
    		call lp  //调用改地址
    	} //能够实现直接调用MessageBox的例子
    	return 0;
    }
    

    六、 函数生成的位置规律
    a) 单文件函数生成的位置规律
    1、规律:单文件函数的生成规律,与函数实现的先后顺序有关,而与函数的定义顺序无关
    2、例子:

    #include <stdio.h>
    #include <windows.h>
    
    int FuncA(int a ,int b);
    int FuncB(int a ,int b);
    int main()
    {
    	DWORD dwSize = (DWORD)FuncB - (DWORD)FuncA;
    	return 0;
    }
    int FuncB(int a ,int b)
    {
    	puts("FuncB...");
    	return a+b;
    }
    int FuncA(int a ,int b)
    {
    	puts("FuncA...");
    	return a+b;
    }
    

    3、结果

    b) 多文件函数生成的位置规律
    1、 规律:与包含文件的位置无关,与实际调用的顺序有关
    2、 例子:
    文件目录:
    |-头文件:头文件夹
    |-A.h
    |-B.h
    |-源文件:源文件夹
    |-main,cpp

    /********A.h*****************/
    #include <stdio.h>
    void A()
    {
    	puts("AAA");
    }
    
    /********B.h*****************/
    #include <stdio.h>
    
    void B()
    {
    	puts("BBB");
    }
    
    /*********main.cpp*********/
    #include "B.h"
    #include "A.h"
    #include <stdio.h>
    
    int main()
    {	
    	A();
    	B();
    	return 0;
    }
    

    3、 结果

    七、 第二种shellcode的编写实例
    a) Shellcode编写的基本框架
    编写shellcode的基本逻辑框架:先用调用标准库中的各种函数实现shellcode的工程,再深入所调用的函数,对其进行通过基地址函数的调用改写。
    以下代码由【第一种shellcode的实现】改写而来,仔细对比,发现其中的规律。

    #include <stdio.h>
    #include <windows.h>
    #pragma comment(linker, "/entry:EntryMain")
    
    //获取kernel32动态链接库的基地址
    
    __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 hMoudleBase)
    {
    	PIMAGE_DOS_HEADER lpDosHeader = (PIMAGE_DOS_HEADER)hMoudleBase;
    	PIMAGE_NT_HEADERS32 lpNtHeader = (PIMAGE_NT_HEADERS)((DWORD)hMoudleBase+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)hMoudleBase+(DWORD)lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
    	PDWORD lpdwFunName = (PDWORD)((DWORD)hMoudleBase +(DWORD)lpExports->AddressOfNames);
    	PWORD lpwOrd = (PWORD)((DWORD)hMoudleBase +(DWORD)lpExports->AddressOfFunctions);
    	PDWORD lpdwFunAddr = (PDWORD)((DWORD)hMoudleBase +(DWORD)lpExports->AddressOfFunctions);
    
    	DWORD dwLoop = 0;
    	FARPROC pRet = NULL;
    	for(;dwLoop<=lpExports->NumberOfNames-1; dwLoop++)
    	{
    		char* pFunName = (char*)(lpdwFunName[dwLoop]+(DWORD)hMoudleBase);
    		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)hMoudleBase);
    			break;
    		}
    	}
    	return pRet;
    }
    
    int EntryMain()
    {
    	//CreateFileA("1.txt",GENERIC_WRITE,0,NULL,CREATE_ALWAYS,0,NULL);
    
    	typedef FARPROC(WINAPI* FN_GetProcAddress)
    	(
    		_In_ HMODULE hModule,
    		_In_ LPCSTR lpProcName
        );
    	FN_GetProcAddress fn_GetProcAddress = (FN_GetProcAddress)getProcAddress((HMODULE)getKernel32());//得到GetProAddress的真实地址
    
    	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
        );
    
    	char sFile[] = {'C','r','e','a','t','e','F','i','l','e','A',0};
    	FN_CreateFileA fn_CreateFileA = (FN_CreateFileA)fn_GetProcAddress((HMODULE)getKernel32(),sFile);
    	char sNewFile[] = {'1','.','t','x','t',''};
    	fn_CreateFileA(sNewFile,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,0,NULL);
    	//MessageBoxA(NULL,"HelloWord!","tip",MB_OK);
    	return 0;
    }
    

    b) Shellcode编写框架的优化
    1、 文件目录及说明
    |-头文件:头文件夹
    |--------api.h :文件中所调用的api,在此定义,放入一个结构体中
    |--------header.h : 文件中所有的定义都放在这里,便于统一的管理
    |-源文件:源文件目录

    -------- 0.entry.cpp :入口文件,提取shellcode,提取a.start.cpp和z.end.cpp中间的代码。

    ----- a.start.cpp : shellcode的开始位置,跳转到shellcode的入口位置,并调用执行shellcode的功能
    |--------b.word.cpp :这是中间文件,不会影响shellcode提取
    |-------- z.end.cpp : shellcode的结束位置
    2、 例子

    #pragma once
    
    #include <windows.h>
    
    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 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
        );
    
    typedef struct _FUNCTIONS
    {
    	FN_GetProcAddress fn_GetProcAddress;
    	FN_LoadLibraryA fn_LoadLibraryA;
    	Fn_MessageBoxA fn_MessageBoxA;
    	FN_CreateFileA fn_CreateFileA;
    
    }FUNCTIONS,*PFUNCTIONS;
    
    #pragma once
    
    #include "api.h"
    #include <stdio.h>
    #include <windows.h>
    
    void ShellcodeStart();
    void ShellcodeEntry();
    void ShellcodeEnd();
    
    void CreateShellcode();
    
    void InitFunctions(PFUNCTIONS pFn);
    
    void CreateConfigFile(PFUNCTIONS pFn);
    void ShowMessage(PFUNCTIONS pFn);
    
    
    #include "header.h"
    
    #pragma comment(linker,"/entry:EntryMain")
    
    
    int EntryMain()
    {
    	CreateShellcode();
    	return 0;
    }
    void CreateShellcode()
    {
    	HMODULE hMsvcrt=LoadLibraryA("msvcrt.dll");
    	typedef int( __cdecl *fn_printf)(_In_z_ _Printf_format_string_ const char * _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
    ",GetLastError());
    		return ;
    	}
    
    	DWORD dwSize=(DWORD)ShellcodeEnd-(DWORD)ShellcodeStart;//计算程序ShellcodeEnd到ShellcodeStart之间的字节长度
    
    	DWORD dwWriten;
    
    	WriteFile(hBin,ShellcodeStart,dwSize,&dwWriten,NULL);//将这段程序写入sh.bin文件中。
    
    	CloseHandle(hBin);
    	//ShellcodeEntry();
    	 
    }
    
    #include "api.h"
    #include "header.h"
    
    
    
    _declspec(naked) void ShellcodeStart()
    {
    	_asm
    	{
    		jmp ShellcodeEntry
    	}
    }
    //获取 kernel32库地址
    _declspec(naked) DWORD getKernel32()//获取Kernel32地址指针
    {
    	_asm
    	{
    		mov eax,fs:[30h]
    		mov eax,[eax+0ch]
    		mov eax,[eax+14h]
    		mov eax,[eax]
    		mov eax,[eax]
    		mov eax,[eax+10h]
    		ret
    	}
    
    }
    
    
    //获取GetProcAddress 方法地址
    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)
    {
    	pFn->fn_GetProcAddress=(FN_GetProcAddress)getProcAddress((HMODULE)getKernel32());
    	char szLoadLibraryA[]={'L','o','a','d','L','i','b','r','a','r','y','A',0}; 
    	pFn->fn_LoadLibraryA=(FN_LoadLibraryA)pFn->fn_GetProcAddress((HMODULE)getKernel32(),szLoadLibraryA);//通过GetProcAddress获取 LoadLibraryA地址
    
    	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};
    	pFn->fn_MessageBoxA=(Fn_MessageBoxA)pFn->fn_GetProcAddress(pFn->fn_LoadLibraryA(szUser32),szMessageBoxA);//通过LoadLibraryA加载User32.dll后获取MessageBoxA方法地址
    
    	char szCreateFileA[]={'C','r','e','a','t','e','F','i','l','e','A',0};
    	pFn->fn_CreateFileA=(FN_CreateFileA)pFn->fn_GetProcAddress((HMODULE)getKernel32(),szCreateFileA);//获取CreateFileA方法地址
    }
    
    void ShellcodeEntry()
    { 
    	FUNCTIONS fn;
    	InitFunctions(&fn); 
    	ShowMessage(&fn);
    	CreateConfigFile(&fn);
    }
    
    
    #include "api.h"
    #include "header.h"
    
    void CreateConfigFile(PFUNCTIONS pFn)
    {
    	 char fileName[]={'1','.','t','x','t',0};
    	 pFn->fn_CreateFileA(fileName,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,0,NULL);
    }
    
    void ShowMessage(PFUNCTIONS pFn)
    {
    	char szHello[]={'H','e','l','l','o',' ','w','o','r','l','l','d',0};
    	char szTip[]={'t','i','p',0};
    	pFn->fn_MessageBoxA(NULL,szHello,szTip,MB_OK); 
    }
    
    
    #include "header.h"
    
    void ShellcodeEnd()
    {
    
    }
    

    八、 编写shellcode加载器
    作用:实现两种方式的shellcode的执行
    Bin-》exe
    Exe-》shellcode
    基本操作:
    1、 打开文件
    2、 读取文件大小
    3、 申请与文件大小相等的内存空间
    4、 将文件读入3申请的空间
    5、 调用shellcode

    例子:

    #include <stdio.h>
    #include <Windows.h>
    
    //ShellCode加载器
    
    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 
    ",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 
    ",GetLastError());
    		CloseHandle(hFile);
    		return -1;
    	}
    	DWORD dwRead;
    
    	ReadFile(hFile,lpAddress,dwSize,&dwRead,0);//将打开文件读入申请的虚拟内存中
    
    	_asm //
    	{
    		call lpAddress;//调用程序
    	}
    	_flushall();
    	system("pasue");
    
    	return 0;
    }
    
  • 相关阅读:
    界面控件DevExpress ASP.NET Controls v21.2 甘特图性能增强
    New!DevExpress ASP.NET v21.2最新版本系统环境配置要求
    界面控件DevExpress WinForm MVVM命令讲解(一)
    界面控件DevExpress WPF入门级教程 触摸滚动条
    DevExtreme初级入门教程(React篇) 应用程序模板(Part 1)
    WinForm应用界面美化攻略 MVVM 高级绑定功能
    Telerik UI组件官宣支持.NET 6 和 VS 2022,让现代UI变得更简单
    界面控件Telerik UI for WinForm初级教程 版本升级
    界面控件DevExpress WPF入门指南 表达式 & 表达式编辑器
    DevExtreme初级入门教程(React篇) 应用程序模板(Part 2)
  • 原文地址:https://www.cnblogs.com/Erma/p/12378401.html
Copyright © 2020-2023  润新知