第13节 第二种shellcode编写实战(2)

在第二种shellcode编写实战(1)的基础上,新增加一个CAPI类,将所有用到的函数都在这个类中做动态调用的处理,这样使得整个shellcode功能结构更加清晰。

1. 新建类CAPI(即api.h和api.cpp两个文件):

api.h:

#pragma once

#include <windows.h>
#include <Winternl.h>

class CAPI
{
private:
    HMODULE GetKernel32BaseAddress();
    FARPROC _GetPorcAddress();

public:
    void InitFunctions();

public:
    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 int (WINAPI* FN_MessageBoxA)(
        __in_opt HWND hWnd,
        __in_opt LPCSTR lpText,
        __in_opt LPCSTR lpCaption,
        __in UINT uType);
    typedef HMODULE(WINAPI* FN_LoadLibraryA)(
        __in LPCSTR lpLibFileName);

public:
    FN_CreateFileA CreateFileA;
    FN_MessageBoxA MessageBoxA;
    FN_LoadLibraryA LoadLibraryA;
};

api.cpp:

#include "api.h"

// 获取kernel32基址
HMODULE CAPI::GetKernel32BaseAddress()
{
    HMODULE hKernel32 = NULL;

    // 用户保存模块名
    WCHAR wszModuleName[MAX_PATH];

#ifdef _WIN64    // 64位PEB偏移为0x60
    PPEB lpPeb = (PPEB)__readgsqword(0x60);
#else            // 32位PEB偏移为0x30
    PPEB lpPeb = (PPEB)__readfsdword(0x30);
#endif

    PLIST_ENTRY pListHead = &lpPeb->Ldr->InMemoryOrderModuleList;
    PLIST_ENTRY pListData = pListHead->Flink;

    // 遍历所有模块
    while (pListData != pListHead)
    {
        PLDR_DATA_TABLE_ENTRY pLDRData = CONTAINING_RECORD(pListData, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);

        DWORD dwLen = pLDRData->FullDllName.Length / 2;
        if (dwLen > 12)    // 12 是"kernel32.dll"的长度,获取到的完整路径肯定要比模块名长
        {
            // 从获取到的模块完整路径中提取模块名
            for (size_t i = 0; i < 12; i++)
            {
                wszModuleName[11 - i] = pLDRData->FullDllName.Buffer[dwLen - 1 - i];
            }

            // 最终要获取的目标模块名("kernel32.dll"),逐个字节比较,包含大小写。
            if ((wszModuleName[0] == 'k' || wszModuleName[0] == 'K') &&
                (wszModuleName[1] == 'e' || wszModuleName[1] == 'E') &&
                (wszModuleName[2] == 'r' || wszModuleName[2] == 'R') &&
                (wszModuleName[3] == 'n' || wszModuleName[3] == 'N') &&
                (wszModuleName[4] == 'e' || wszModuleName[4] == 'E') &&
                (wszModuleName[5] == 'l' || wszModuleName[5] == 'L') &&
                (wszModuleName[6] == '3') &&
                (wszModuleName[7] == '2') &&
                (wszModuleName[8] == '.') &&
                (wszModuleName[9] == 'd' || wszModuleName[9] == 'D') &&
                (wszModuleName[10] == 'l' || wszModuleName[10] == 'L') &&
                (wszModuleName[11] == 'l' || wszModuleName[11] == 'L'))
            {
                hKernel32 = (HMODULE)pLDRData->DllBase;
                break;
            }
        }
        pListData = pListData->Flink;
    }
    return hKernel32;
}

// 获取GetPorcAddress函数地址
FARPROC CAPI::_GetPorcAddress()
{
    // 保存最终结果
    FARPROC pGetPorcAddress = NULL;

    // kernel32基址
    HMODULE hKernel32 = GetKernel32BaseAddress();
    if (!hKernel32)
    {
        return NULL;
    }

    PIMAGE_DOS_HEADER lpDosHeader = (PIMAGE_DOS_HEADER)hKernel32;
    PIMAGE_NT_HEADERS lpNTHeader = (PIMAGE_NT_HEADERS)((unsigned char*)hKernel32 + 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;
    }

    // 通过导出表中的导出函数名,定位"GetProcAddress"的位置
    PIMAGE_EXPORT_DIRECTORY lpExports = (PIMAGE_EXPORT_DIRECTORY)((unsigned char*)hKernel32 + lpNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
    PDWORD lpdwFunName = (PDWORD)((unsigned char*)hKernel32 + lpExports->AddressOfNames);
    PWORD lpdwOrd = (PWORD)((unsigned char*)hKernel32 + lpExports->AddressOfNameOrdinals);
    PDWORD lpdwFunAddr = (PDWORD)((unsigned char*)hKernel32 + lpExports->AddressOfFunctions);

    for (DWORD dwLoop = 0; dwLoop <= lpExports->NumberOfNames - 1; dwLoop++)
    {
        char* pFunName = (char*)(lpdwFunName[dwLoop] + (unsigned char*)hKernel32);
        // 比较函数名
        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'
            )
        {
            pGetPorcAddress = (FARPROC)(lpdwFunAddr[lpdwOrd[dwLoop]] + (unsigned char*)hKernel32);
            break;
        }
    }
    return pGetPorcAddress;
}

// 初始化所有用到的函数
void CAPI::InitFunctions()
{
    // 获取GetPorcAddress函数地址
    typedef FARPROC(WINAPI* FN_GetProcAddress)(__in HMODULE hModule, __in LPCSTR lpProcName);
    FN_GetProcAddress fn_GetProcAddress = (FN_GetProcAddress)_GetPorcAddress();
    if (fn_GetProcAddress)
    {
        // 获取LoadLibraryA函数地址
        char szLoadLibraryA[] = { 'L','o','a','d','L','i','b','r','a','r','y','A',0 };
        LoadLibraryA = (FN_LoadLibraryA)fn_GetProcAddress(GetKernel32BaseAddress(), szLoadLibraryA);
        if (LoadLibraryA)
        {
            // 获取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 };
            MessageBoxA = (FN_MessageBoxA)fn_GetProcAddress(LoadLibraryA(szUser32), szMessageBoxA);
            
            // 获取CreateFileA函数地址
            char szCreateFileA[] = { 'C','r','e','a','t','e','F','i','l','e','A',0 };
            CreateFileA = (FN_CreateFileA)fn_GetProcAddress(GetKernel32BaseAddress(), szCreateFileA);
        }
    }
}

2. 在CAPI中,使用InitFunctions函数来初始化所有shellcode中用到的函数,在shellcode执行功能处,进行如下调用即可(a.start.cpp):

#include "a.start.h"
#include "shellcode.h"
#include "api.h"

void ShellCodeStart()
{
    CAPI api;
    // 初始化所有用到的函数
    api.InitFunctions();

    CDoShellcode shellcode;

    // 创建文件
    shellcode.DoCreateFile(&api);

    // 弹框提示
    shellcode.DoMessageBox(&api);

    // 其他功能...
}

3. 在类CDoShellcode中,将所有函数功能执行的参数都传递一个CAPI的指针变量,那么所有功能都可以使用CAPI中的函数。比如CDoShellcode中的DoCreateFile方法:

// 功能:创建文件 D:\1.txt
int CDoShellcode::DoCreateFile(CAPI* api)
{
    // 执行动态CreateFileA,创建文件
    char szFilePath[] = { 'D',':','\\','1','.','t','x','t',0 };
    api->CreateFileA(szFilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);

    return 0;
}

如此一来,对类CDoShellcode而言,我们只关注功能的实现,不必再顾及函数动态调用的问题。所有用到的动态函数的实现都可以共享CAPI中的实现。

项目结构:

两个类:

  • CDoShellcode(shellcode.h和shellcode.cpp):shellcode执行的各类功能;
  • CAPI(api.h和api.cpp):所有shellcode使用到的动态函数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/617145.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

绍兴ISO27001认证:信息安全认证的金钥匙

&#x1f308;&#x1f308;绍兴ISO27001认证&#xff1a;✌️信息安全认证的金钥匙&#x1f511; &#x1f498;随着信息技术的飞速发展&#xff0c;&#x1f481;信息安全问题日益凸显。&#x1f510;为了提升信息安全管理水平&#xff0c;&#x1f46e;保障企业数据资产安全…

PROTEUS仿真软件的使用及存储器的设计

proteus proteus&#xff0c;即EDA工具软件。Proteus软件是英国Lab Center Electronics公司出版的EDA工具软件。它不仅具有其它EDA工具软件的仿真功能&#xff0c;还能仿真单片机及外围器件。它是比较好的仿真单片机及外围器件的工具。虽然国内推广刚起步&#xff0c;但已受到…

SpringBoot基于微信小程序的星座配对(源码)

博主介绍&#xff1a;✌程序员徐师兄、10年大厂程序员经历。全网粉丝12W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447…

数列排序C++

题目&#xff1a; 思路&#xff1a; 创建一个数组a&#xff0c;循环遍历输入&#xff0c;然后使用函数sort进行上升排序&#xff0c;最后循环遍历输出a[i]. #include <bits/stdc.h> using namespace std; int main(){int a[201];int n;cin>>n;//输入for(int i0;i&l…

数据链路层——计算机网络学习笔记三

使用点对点信道的数据链路层 前言&#xff1a; 1.数据链路层的重要性&#xff1a;网络中的主机、路由器都必须实现数据连输层&#xff1b; 2.数据链路层中使用的信道&#xff1a; 点对点信道&#xff1a;这种信道是一对一的通信方式&#xff1b; 广播信道&#xff1a;使用一对多…

VMware虚拟机故障:“显示指定的文件不是虚拟磁盘“,处理办法

一、故障现象 由于虚拟机宕机&#xff0c;强制重新启动虚拟机后显示错误&#xff0c;没有办法启动虚拟机。 虚拟机有快照&#xff0c;执行快照还原&#xff0c;结果也不行&#xff0c;反复操作&#xff0c;在虚拟机文件目录出现很多莫名文件 二、故障原因 根据故障提示&#…

StarRocks 【新一代MPP数据库】

1、StarRocks 1.1、StarRocks 简介 StarRocks 是新一代极速全场景 MPP (Massively Parallel Processing&#xff0c;MPP数据库是一种基于大规模并行处理技术的数据库系统&#xff0c;旨在高效处理大量数据。) 数据库。StarRocks 的愿景是能够让用户的数据分析变得更加简单和敏…

【Cesium】Cesium核心类、坐标系与着色器简介

核心类&#xff1a; Viewer: Viewer 是 Cesium 中最基本的视图容器&#xff0c;用于显示地球、地图、三维场景等。它提供了创建和管理场景的功能&#xff0c;可以配置视图的各种属性和行为。 Scene: Scene 是 Cesium 中的核心类之一&#xff0c;代表了一个三维场景&#xff0c…

py黑帽子学习笔记_环境准备

1 下载os装os 下载一个kali虚机镜像然后用虚机管理软件创虚机&#xff0c;装完如下图&#xff0c;我用的版本是2024.1的版本kali-linux-2024.1-installer-amd64&#xff0c;可以从镜像站下载&#xff0c;官网下的慢还断网Index of /kali-images/kali-2024.1/ | 清华大学开源软…

序列到序列模型在语言识别Speech Applications中的应用 Transformer应用于TTS Transformer应用于ASR 端到端RNN

序列到序列模型在语言识别Speech Applications中的应用 A Comparative Study on Transformer vs RNN in Speech Applications 序列到序列(Seq2Seq)模型在语音识别(Speech Applications)中有重要的应用。虽然Seq2Seq模型最初是为了解决自然语言处理中的序列生成问题而设计的…

力扣例题(用栈实现队列)

目录 链接. - 力扣&#xff08;LeetCode&#xff09; 描述 思路 push pop peek empty 代码 链接. - 力扣&#xff08;LeetCode&#xff09; 描述 思路 push 例如我们将10个元素放入栈中&#xff0c;假设最左边为栈顶&#xff0c;最右侧为栈底 则为10,9,8,7,6,5,4,3,…

windows使用Docker-Desktop部署lobe-chat

文章目录 window安装docker-desktop下载和启动lobe-chatAI大语言模型的选择lobe-chat设置大模型连接 window安装docker-desktop docker-desktop下载地址 正常安装应用&#xff0c;然后启动应用&#xff0c;注意启动docker引擎 打开右上角的设置&#xff0c;进入Docker Engine设…

ZFS 文件系统结构及 ZFS 文件系统数据恢复

ZFS是一种革命性的文件系统&#xff0c;它遵循完全不同的文件系统管理方法&#xff0c;同时提供目前其他文件系统无法提供的新功能和优势。ZFS 可靠、可扩展且易于管理。 它放弃了卷的概念&#xff0c;从而摆脱了传统的文件系统原则。另外&#xff0c;ZFS 提供更复杂的存储池&…

torch_geometric安装(CPU版本)

①打开官方安装网址&#xff1a;https://pytorch-geometric.readthedocs.io/en/2.3.0/install/installation.html ②对根据Pytorch选择相应版本。此前一直用CUDA不成功&#xff0c;这次使用CPU版本&#xff08;因为不用对应cuda&#xff0c;pytorchcudageometric三者对应起来很…

线下线上陪玩APP小程序H5搭建设计-源码交付,支持二开!

一、电竞陪玩系统APP的概念 电竞陪玩系统APP是一种专门为电子竞技玩家提供服务的平台。通过这个平台&#xff0c;玩家可以找到专业的电竞陪玩者&#xff0c;他们可以帮助玩家提升游戏技能&#xff0c;提供游戏策略建议&#xff0c;甚至陪伴玩家一起进行游戏。这种服务不仅可以提…

医疗图像处理2023年CVPR:Label-Free Liver Tumor Segmentation-无标签肝肿瘤分割

目录 一、摘要 二、介绍 三、相关工作 四、网络框架 1.位置选择 2.纹理处理 3.形状生成 4.后处理 5.参数设计 五、实验 1.数据集&#xff1a; 2.评价指标&#xff1a; 3.实现&#xff1a; 4.结果&#xff1a; 六、结论 一、摘要 通过在CT扫描中使用合成肿瘤&am…

分布式存储故障导致数据库无法启动故障处理---惜分飞

国内xx医院使用了国外医疗行业龙头的pacs系统,由于是一个历史库,存放在分布式存储中,由于存储同时多个节点故障,导致数据库多个文件异常,数据库无法启动,三方维护人员尝试通通过rman归档进行应用日志,结果发现日志有损坏报ORA-00354 ORA-00353,无法记录恢复,希望我们给予支持 M…

队列的相关操作:用队列实现栈

1.思路解析 由于C语言封装度不是很高&#xff0c;不像C可以直接用现成的&#xff0c;所以我们要自己做一个“轮子”&#xff0c;即自己实现一个队列&#xff0c;这里直接放出代码&#xff0c;详解可以移步到我的另一篇关于队列的博客&#xff0c;点我移步&#xff0c;原题来源于…

Mp3tag for Mac:音乐标签,轻松管理

还在为杂乱无章的音乐文件而烦恼吗&#xff1f;Mp3tag for Mac&#xff0c;让您的音乐库焕然一新&#xff01;它支持多种音频格式&#xff0c;批量编辑标签&#xff0c;让音乐管理变得简单高效。同时&#xff0c;自动获取在线数据库的音乐元数据&#xff0c;确保您的音乐库始终…

并发-判断线程对象是否处于活动状态 - isAlive

t.isAlive() 测试线程t是否处于活动状态&#xff0c;只要线程启动并且没有终止&#xff0c;方法返回值就是truestart()之前&#xff0c;线程不处于活动状态&#xff0c;之后就处于活动状态示例&#xff1a;运行结果&#xff1a;但是事情并没有这么简单&#xff0c;先来看一下以…