shellcode编写(未完)

一:基本
对于shellcode来说,它是独立的,可以附加在各种各样的进程中,所以他的每句代码都是独立,只与shellcode中的代码有联系,与外部代码都是隔绝的。
在生成exe的时候,编译器将函数转为真正实现这个函数功能的入口地址(绝对地址),由于shellcode是附加在其他进程上的,每个进程是不一样的,这个地址可能是其他功能,所以运用绝对地址不符合。所以需要动态调用,先获得函数的地址,在进行执行。
类似于这种:
GetProcAddress(LoadLibraryA(“kernel32.dll”), “CreateFileA”);
但是,LoadLibraryA与GetProcAddress的地址也需获取,在windows操作系统下,每一个进程都会对ntdll、kernel32、kernelbase做一个系统内部的加载,所以只需寻找内部加载的地址,就可以得到LoadLibraryA(“kernel32.dll”)的地址。
1,得到LoadLibraryA(“kernel32.dll”)
FS寄存器指向当前活动线程的TEB结构(线程结构)
偏移 说明
000 指向SEH链指针
004 线程堆栈顶部
008 线程堆栈底部
00C SubSystemTib
010 FiberData
014 ArbitraryUserPointer
018 FS段寄存器在内存中的镜像地址
020 进程PID
024 线程ID
02C 指向线程局部存储指针
030 PEB结构地址(进程结构)
034 上个错误号
偷了张图片:
在这里插入图片描述
模块在内存顺序:
在这里插入图片描述


__declspec(naked) DWORD getKernel32()
{
    __asm
    {
        mov eax,fs:[30h] //得到PEB
        mov eax,[eax+0ch]  //PEB_LDR_DATA
        mov eax,[eax+14h]   //得到inmemoryodermodulelist,第一个模块
        mov eax,[eax]
        mov eax,[eax]     //第三个模块kernel32.dll
        mov eax,[eax+10h]  //得到Baseaddress,kernel的基址
        ret
    }
}

2,得到GetProcAddress地址
GetProcAddress这个函数也在kernel32中,


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;
}

3,字符串打散
字符串常量是一个固定地址,之前提到,为了避免使用绝对地址,改为使用字符数组,并且最后记得加上截断字符,避免越界。
4,函数生成位置
在单文件中,函数地址顺序与在代码编辑时的函数定义顺序有关。
在多文件中,在这个vcxproj下面。
在这里插入图片描述
二,编写shellcode
基本框架:

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

FARPROC  getProcAddress(HMODULE hModuleBase);
DWORD getKernel32();

int EntryMain()
{
	//声明定义GetProcAddress
	typedef FARPROC(WINAPI *FN_GetProcAddress)(
		_In_ HMODULE hModule,
		_In_ LPCSTR lpProcName
		);

	//获取GetProcAddress真实地址
	FN_GetProcAddress fn_GetProcAddress = (FN_GetProcAddress)getProcAddress((HMODULE)getKernel32());


	//声明定义CreateFileA
	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)GetProcAddress(LoadLibrary("kernel32.dll"), "CreateFileA");
	//带引号的字符串打散处理
	char xyCreateFile[] = { 'C','r','e','a','t','e','F','i','l','e','A',0 };
	//动态获取CreateFile的地址
	FN_CreateFileA fn_CreateFileA = (FN_CreateFileA)fn_GetProcAddress((HMODULE)getKernel32(), xyCreateFile);
	char xyNewFile[] = { '1','.','t','x','t','\0' };
	fn_CreateFileA(xyNewFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值