第16节 实战:文件转shellcode

我最近做了一个关于shellcode入门和开发的专题课👩🏻‍💻,主要面向对网络安全技术感兴趣的小伙伴。这是视频版内容对应的文字版材料,内容里面的每一个环境我都亲自测试实操过的记录,有需要的小伙伴可以参考。

我的个人主页:https://imbyter.com

对于一些功能简单的shellcode编写,我们可以用前面介绍的shellcode框架直接编写生成,但对于功能比较复杂的需求,我们也可以选择先以常规C/C++开发方式,编写好dll和exe文件后,再将其转换为shellcode文件,或者对于已有的dll或exe文件,不需要重写代码,直接将其转换为shellcode文件。

这节主要介绍如何实现对指定的PE文件(dll和exe文件)转shellcode的方法。dll和exe两种类型的文件,两者在shellcode转换方面的主要区别是:

dll文件exe文件
重定位表的处理一定存在重定位表,需要对其地址进行重定位处理。不一定存在重定位表,存在处理重定位和不处理两种情况。
入口函数调用可能有DllMain函数或自定义导出函数。main函数或自定义入口函数。

不管是dll还是exe,将其转为shellcode的关键点有以下几个:

  1. PE文件在shellcode中的存放;
  2. shellcode运行时PE文件的定位;
  3. PE文件在shellcode中的内存加载执行;

现在我们来逐一解决以上问题:

一、生成shellcode时PE的封装​

在我们前面所说的shellcode编写方式中,shellcode总大小就是我们实际编写shellcode的所有代码,但对于PE转成的shellcode而言,最后生成的shellcode文件总大小为我们编写的shellcode与PE文件的总和。

我们可以根据自己的需求来设计PE文件在整个shellcode中的位置,可以放在前面、中间,或者后面。将PE文件放在整个shellcode的最后面实现起来相对容易,如图所示:

在代码上的实现如下:

0.createshellcode.cpp:

#include "a.start.h"
#include "z.end.h"

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

// 该函数用于生成shellcode文件。函数本身与生成的shellcode功能没有任何关系,
// 并没包含在生成的shellcode里面,所以该函数编写不受shellcode编写规范限制。
int EntryMain()
{
    DWORD   dwWriten = 0;
    DWORD   dwRead = 0;
    HANDLE  hShellcodeFile = NULL;
    HANDLE  hPEFile = NULL;

    // 创建文件,用于保存最后的shellcode
    hShellcodeFile = CreateFileA("shellcode.bin", GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
    if (hShellcodeFile == INVALID_HANDLE_VALUE)
    {
        return -1;
    }

    // 计算shellcode头大小
    SIZE_T dwShellcodeHeaderSize = (SIZE_T)ShellCodeEnd - (SIZE_T)ShellCodeStart;

    // 将shellcode写入到文件
    WriteFile(hShellcodeFile, ShellCodeStart, (DWORD)dwShellcodeHeaderSize, &dwWriten, NULL);

    // 打开目标PE文件(EXE或者DLL)
    hPEFile = CreateFileA("TestDll.dll", GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    if (hPEFile == INVALID_HANDLE_VALUE)
    {
        CloseHandle(hShellcodeFile);
        return -1;
    }

    // 获取目标PE大小
    DWORD dwPESize = GetFileSize(hPEFile, NULL);
    LPVOID lpPEData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwPESize);

    // 读取目标文件内容
    ReadFile(hPEFile, lpPEData, dwPESize, &dwRead, NULL);

    // 将PE文件内容写入shellcode文件
    WriteFile(hShellcodeFile, lpPEData, dwPESize, &dwWriten, NULL);

    HeapFree(GetProcessHeap(), 0, lpPEData);

    CloseHandle(hShellcodeFile);
    CloseHandle(hPEFile);

    return 0;
}

以上代码:

  1. 创建shellcode.bin文件;
  2. 将shellcode头写入到文件中;
  3. 读取目标PE文件,此处为动态链接库TestDll.dll文件(dll或exe文件,可根据实际需求修改);
  4. 将PE文件内容继续写入shellcode.bin中。

二、运行shellcode时PE的定位​

将整个Shellcode拷贝到内存中运行时,我们首先需要知道PE文件在shellcode中的位置,才能将其内存加载运行。在内存中,PE文件是紧跟在shellcode头后面的,所以要想确定PE文件的位置,可以用shellcode所在内存的基址+shellcode头的长度得到。

  • shellcode内存的基址的获取:我们可以在加载器中,将申请的shellcode执行地址作为参数,传递给shellcode的ShellCodeStart函数,这样就能轻松得到这个基址;
  • shellcode头长度:即 ShellCodeEnd 与 ShellCodeStart 的差值;

a.start.cpp:

#include "a.start.h"
#include "api.h"
#include "loadpe.h"
#include "z.end.h"

// lpAddress:shellcode所在内存基址
void ShellCodeStart(LPVOID lpAddress)
{
    CAPI api;
    // 初始化所有用到的函数
    api.InitFunctions();

    // 定位到PE文件内容
    // 完整的shellcode内容 = shellcode头 + PE文件内容
    SIZE_T dwShellcodeHeaderLen = (SIZE_T)ShellCodeEnd - (SIZE_T)ShellCodeStart;
    unsigned char* lpPEDataStart = (unsigned char*)lpAddress + dwShellcodeHeaderLen;

    // 加载PE文件
    CLoadPE PE(&api, lpPEDataStart);
    PE.MemoryLoad();
}

三、运行shellcode时PE的执行​

正常执行PE文件(dll或exe)时,PE文件是由系统加载运行的,在shellcode中,我们需要自己手动实现PE文件在内存中的“展开”和执行。 我们创建一个CLoadPE类,专门用于PE文件的内存加载。

  1. 构造函数CLoadPE(CAPI* api, PVOID lpFileData)接受两个参数,一个CAPI类型用于使用动态调用的函数,一个PVOID表示PE数据的地址:
  2. 函数IsValidPE()通过检查PE文件的"MZ"头和"PE"头,来确定PE文件是否有效;
  3. 函数AllocImageBaseAddress()用于给PE文件分配执行内存;
  4. 函数CopySections()用于将PE文件的个节“展开”到执行内存中;
  5. 函数RepairIAT()用于修复导入表;
  6. 函数RepairReloc()用于修复重定位表;
  7. 函数CallEntryPoint()用于执行入口函数功能;
  8. 为方便执行,整个流程封装在函数MemoryLoad()中执行;

类CLoadPE(loadpe.h和loadpe.cpp):

loadpe.h:

#pragma once

#include "api.h"

class CLoadPE
{
public:
    CLoadPE(CAPI* api, PVOID lpFileData);

public:
    BOOL MemoryLoad();              // 内存加载PE

private:
    BOOL IsValidPE();               // 判断PE格式是否正确
    BOOL IsDllFile();               // 判断PE是DLL还是EXE
    BOOL AllocImageBaseAddress();   // 申请内存空间(基址)
    VOID CopySections();            // 复制节到申请的内存中
    BOOL RepairIAT();               // 修复导入表
    BOOL RepairReloc();             // 修复重定位表

    PVOID MemGetProcAddress(PCSTR FunctionName);  // 获取内存中dll指定函数名的导出函数地址
    VOID CallEntryPoint(CLoadPE* Object);         // 执行入口函数

    PVOID m_ImageBase;              // 内存中PE文件基址

    ULONG_PTR m_EntryPointer;       // 内存中PE文件入口点地址

    // 文件中的PE结构变量
    PIMAGE_DOS_HEADER m_DosHeader;
    PIMAGE_NT_HEADERS m_PeHeader;
    PIMAGE_SECTION_HEADER m_SectionHeader;

    // 加载到内存后的PE结构变量
    PIMAGE_DOS_HEADER m_MemDosHeader;
    PIMAGE_NT_HEADERS m_MemPeHeader;

private:
    CAPI* m_api;

public:
    PVOID m_FileData;               // PE文件内容
};

loadpe.cpp:

#include "loadpe.h"

CLoadPE::CLoadPE(CAPI* api, PVOID lpFileData)
{
    m_api           = api;
    m_FileData      = lpFileData;

    m_ImageBase     = NULL;
    m_EntryPointer  = NULL;

    m_DosHeader     = NULL;
    m_PeHeader      = NULL;
    m_SectionHeader = NULL;
    m_MemDosHeader  = NULL;
    m_MemPeHeader   = NULL;
}

BOOL CLoadPE::MemoryLoad()
{
    if (m_FileData == NULL)
    {
        return FALSE;
    }
    
    m_DosHeader = (PIMAGE_DOS_HEADER)m_FileData;
    m_PeHeader = (PIMAGE_NT_HEADERS)(m_DosHeader->e_lfanew + (ULONG_PTR)m_DosHeader);

    // 检查PE格式是否有效
    if (!IsValidPE())
    {
        return FALSE;
    }

    // 申请内存空间
    if (!AllocImageBaseAddress())
    {
        return FALSE;
    }
    // 分配数据节块 
    CopySections();

    // 修复导入表
    if (!RepairIAT())
    {
        return FALSE;
    }

    // 修复重定位表
    if (!RepairReloc())
    {
        return FALSE;
    }

    // 执行入口函数功能
    CallEntryPoint(this);

    return TRUE;
}

BOOL CLoadPE::IsValidPE()
{
    if (m_DosHeader->e_magic != IMAGE_DOS_SIGNATURE || m_PeHeader->Signature != IMAGE_NT_SIGNATURE)
    {
        // 不是有效的PE文件
        return FALSE;
    }

#ifdef _WIN64
    if (m_PeHeader->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64)
    {
        return FALSE;
    }
#else
    if (m_PeHeader->FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
    {
        return FALSE;
    }
#endif

    return TRUE;
}

BOOL CLoadPE::IsDllFile()
{
    return m_PeHeader->FileHeader.Characteristics & IMAGE_FILE_DLL;
}

BOOL CLoadPE::AllocImageBaseAddress()
{
    if (m_PeHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size == 0)
    {
        // 尝试在基址处申请空间
        m_ImageBase = m_api->VirtualAlloc((LPVOID)m_PeHeader->OptionalHeader.ImageBase, m_PeHeader->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
        if (m_ImageBase == NULL)
        {
            return FALSE;
        }
    }
    else
    {
        // 尝试申请新内存空间
        m_ImageBase = m_api->VirtualAlloc(NULL, m_PeHeader->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
        if (m_ImageBase == NULL)
        {
            return FALSE;
        }
    }

    m_api->memcpy(m_ImageBase, m_DosHeader, m_PeHeader->OptionalHeader.SizeOfHeaders);

    return TRUE;
}

VOID CLoadPE::CopySections()
{
    m_SectionHeader = IMAGE_FIRST_SECTION(m_PeHeader);
    for (size_t i = 0; i < m_PeHeader->FileHeader.NumberOfSections; i++)
    {
        if (m_SectionHeader->SizeOfRawData != 0 && m_SectionHeader->VirtualAddress != 0)
        {
            m_api->memcpy((PVOID)((ULONG_PTR)m_ImageBase + m_SectionHeader->VirtualAddress), (PVOID)((ULONG_PTR)m_DosHeader + m_SectionHeader->PointerToRawData), m_SectionHeader->SizeOfRawData);
        }
        m_SectionHeader++;
    }
    m_MemDosHeader = (PIMAGE_DOS_HEADER)m_ImageBase;
    m_MemPeHeader  = (PIMAGE_NT_HEADERS)(m_MemDosHeader->e_lfanew + (ULONG_PTR)m_MemDosHeader);

    m_EntryPointer = (ULONG_PTR)m_ImageBase + m_MemPeHeader->OptionalHeader.AddressOfEntryPoint;
}

BOOL CLoadPE::RepairIAT()
{
#ifdef _WIN64
    union
    {
        struct
        {
            ULONGLONG low : 63;
            ULONGLONG high : 1;
        }BitField;
        ULONGLONG Value;
    }Temp = { 0 };
#else
    union
    {
        struct
        {
            ULONG low : 31;
            ULONG high : 1;
        }BitField;
        ULONG Value;
    }Temp = { 0 };
#endif 

    if (m_MemPeHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size > 0)
    {
        PIMAGE_IMPORT_DESCRIPTOR pIID = (PIMAGE_IMPORT_DESCRIPTOR)((ULONG_PTR)m_ImageBase + m_MemPeHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
        while (pIID->Name != NULL)
        {
            PIMAGE_THUNK_DATA pITD = (PIMAGE_THUNK_DATA)((ULONG_PTR)m_ImageBase + pIID->OriginalFirstThunk);
            HMODULE hModule = m_api->LoadLibraryA((char*)((ULONG_PTR)m_ImageBase + pIID->Name));
            if (hModule == NULL)
            {
                // DLL加载失败
                return FALSE;
            }

            PULONG_PTR pFuncAddr = (PULONG_PTR)((ULONG_PTR)m_ImageBase + pIID->FirstThunk);
            while (*pFuncAddr != 0)
            {
                Temp.Value = pITD->u1.AddressOfData;
                if (Temp.BitField.high == 1)
                {
                    // 通过序号取函数地址
                    *pFuncAddr = (ULONG_PTR)m_api->GetProcAddress(hModule, (LPCSTR)Temp.BitField.low);
                }
                else
                {
                    // 通过名称取函数地址
                    PIMAGE_IMPORT_BY_NAME pFuncName = (PIMAGE_IMPORT_BY_NAME)((ULONG_PTR)m_ImageBase + pITD->u1.AddressOfData);
                    *pFuncAddr = (ULONG_PTR)m_api->GetProcAddress(hModule, pFuncName->Name);
                }
                pITD++;
                pFuncAddr++;
            }
            pIID++;
        }
    } 
    return TRUE;
}

BOOL CLoadPE::RepairReloc()
{
    if (m_MemPeHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size > 0)
    {
        typedef struct BASE_RELOCATION_ENTRY {
            USHORT Offset : 12;
            USHORT Type : 4;
        } BASE_RELOCATION_ENTRY, * PBASE_RELOCATION_ENTRY;

        INT_PTR Offset = (INT_PTR)((ULONG_PTR)m_ImageBase - m_PeHeader->OptionalHeader.ImageBase);
        IMAGE_BASE_RELOCATION* pIBR = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)m_ImageBase + m_MemPeHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);

        while (pIBR->VirtualAddress != 0)
        {
            int NumberOfBlocks = (pIBR->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(BASE_RELOCATION_ENTRY);
            BASE_RELOCATION_ENTRY* Block = (BASE_RELOCATION_ENTRY*)((ULONG_PTR)pIBR + sizeof(IMAGE_BASE_RELOCATION));

            for (int i = 0; i < NumberOfBlocks; i++)
            {
                if (Block->Type != IMAGE_REL_BASED_ABSOLUTE)
                {
                    PINT_PTR RepairAddr = (PINT_PTR)((ULONG_PTR)m_ImageBase + pIBR->VirtualAddress + Block->Offset);
                    if (*RepairAddr <= 0) 
                    {
                        return FALSE; 
                    }
                    *RepairAddr += Offset;
                }
                Block++;
            }
            pIBR = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)pIBR + pIBR->SizeOfBlock);
        }
        m_MemPeHeader->OptionalHeader.ImageBase = (ULONG_PTR)m_ImageBase;
    }
    return TRUE;
}

PVOID CLoadPE::MemGetProcAddress(PCSTR FunctionName)
{
    // 从到处目录获取指定函数
    if (m_MemPeHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size > 0)
    {
        PIMAGE_EXPORT_DIRECTORY pIED = (PIMAGE_EXPORT_DIRECTORY)((ULONG_PTR)m_ImageBase + m_MemPeHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

        PDWORD FuncNameTable = (PDWORD)((ULONG_PTR)m_ImageBase + pIED->AddressOfNames);
        PDWORD FuncAddrTable = (PDWORD)((ULONG_PTR)m_ImageBase + pIED->AddressOfFunctions);

        for (DWORD i = 0; i < pIED->NumberOfNames; i++)
        {
            if (m_api->strcmp(FunctionName, (PCSTR)((ULONG_PTR)m_ImageBase + *FuncNameTable)) == 0)
            {
                return (PVOID)((ULONG_PTR)m_ImageBase + *FuncAddrTable);
            }
            FuncNameTable++;
            FuncAddrTable++;
        }
    }
    return NULL;
}

VOID CLoadPE::CallEntryPoint(CLoadPE* Object)
{
    if (IsDllFile())
    {
        // DllMain入口函数
        typedef BOOL(WINAPI* DllEntryProc)(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpReserved);
        ((DllEntryProc)Object->m_EntryPointer)((HINSTANCE)Object->m_ImageBase, DLL_PROCESS_ATTACH, NULL);

        // 导出函数(根据实际函数定义修改)
        typedef void(*ExportFun)();
        char szExpFun[] = {'t','e','s','t','f','u','n',0};
        ExportFun lpproc = (ExportFun)MemGetProcAddress(szExpFun);
        if (lpproc != NULL)
        {
            lpproc();
        }
    }
    else
    {
        // main函数
        ((void(*)())(Object->m_EntryPointer))();
    }
}

四、项目属性设置​

  1. 禁用“优化”选项:

  2. Release的“运行库”设为“多线程(/MT)”,禁用“安全检查”:

自己动手,更进一步:

  1. 在生成的shellcode中,将PE文件进行压缩和加密;
  2. 在运行shellcode时,先解密解压然后再内存加载。

如果有任何问题,可以在我们的知识社群中提问和沟通交流:

图片​​

一个人走得再快,不如一群人走得更远!🤜🤛


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

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

相关文章

《告别重复:Spring AOP让你的代码花园绽放》

厌倦了在代码花园中重复种植相同的植物&#xff08;代码&#xff09;吗&#xff1f;Spring AOP将是你的园艺师&#xff0c;帮助你修剪和优化代码&#xff0c;让花园更加丰富多彩&#xff01; 文章目录 面向切面编程&#xff08;AOP&#xff09;主题文章一. 引言1.1 引入面向切面…

添砖Java之路(其八)——继承,final关键字

继承&#xff1a; 意义&#xff1a;让类于类之间产生父类于子类的关系&#xff0c;子类可以直接使用父类中的非私有成员(包括方法与成员变量) 。 extends关键字就是定义声明父类。 格式&#xff1a;public class 子类 extends 父类。 对于基础的我就不赘述了&#xff0c;我…

汇舟问卷:做小生意也依然可以取得成功

冷门小生意之所以能够成功发财&#xff0c;主要是因为竞争相对较少。相较于那些已被大家知晓且看似热门的生意&#xff0c;冷门小生意的利润空间更多且风险更低。 冷门小生意常常具备低成本和高回报的特点。举个例子&#xff0c;与开设一家餐厅或者服装店相比&#xff0c;成立…

【源码】Spring Data JPA原理解析之Repository的自动注入(一)

Spring Data JPA系列 1、SpringBoot集成JPA及基本使用 2、Spring Data JPA Criteria查询、部分字段查询 3、Spring Data JPA数据批量插入、批量更新真的用对了吗 4、Spring Data JPA的一对一、LazyInitializationException异常、一对多、多对多操作 5、Spring Data JPA自定…

电脑没有网络连接怎么办?4招轻松完成网络连接!

“我的电脑开机后发现连接不上网络&#xff0c;尝试了很多次也不行&#xff0c;这是因为什么呢&#xff1f;有什么比较好的解决方法吗&#xff1f;” 当电脑无法连接到网络时&#xff0c;可能会给我们的工作和生活带来诸多不便。然而&#xff0c;大多数网络连接问题都可以通过一…

C#实现长方体棱锥圆柱棱柱圆锥展开折叠旋转缩放

C#实现长方体棱锥圆柱棱柱圆锥展开折叠旋转缩放 C#实现 模型边数 长方体 棱锥 圆柱 棱柱 圆锥 实现功能 展开 折叠 颜色 边框颜色 旋转 缩放 大小 视图方向 项目获取&#xff1a; 项目获取&#xff1a;typora: typora/img (gitee.com) 备用项目获取链接1&#xff1a;yife…

Linux的进程间通信 管道 进程池

目录 前言 进程间通信的基本概念 管道 匿名管道 pipe函数 cfc 管道的四种情况 管道的五种特征 进程池 ProcessPool.cpp&#xff1a; Task.cpp&#xff1a; 前言 ubuntu系统的默认用户名不为root的解决方案&#xff08;但是不建议&#xff09;&#xff1a;轻量应用服…

安卓悬浮窗----可移动的悬浮窗

目录 前言一、添加对悬浮窗功能的支持二、通过service实现悬浮窗2.1 窗口属性和标志2.2 窗口移动 三、完整代码 前言 记录一下基础的悬浮窗实现&#xff0c;分为几个重要的点进行阐述。 一、添加对悬浮窗功能的支持 app要实现悬浮窗功能&#xff0c;首先app要添加对悬浮窗功…

【瑞萨RA6M3】2. UART 实验

https://blog.csdn.net/qq_35181236/article/details/132789258 使用 uart9 配置 打印 void hal_entry(void) {/* TODO: add your own code here */fsp_err_t err;uint8_t c;/* 配置串口 */err g_uart9.p_api->open(g_uart9.p_ctrl, g_uart9.p_cfg);while (1){g_uart9.…

扫码枪与Input的火花

文章目录 前言一、需求&#xff1a;交互细节二、具体实现两个核心的函数&#xff1a;自动聚焦 三&#xff0c;扩展知识input 与 change的区别 前言 在浏览器扫描条形码获取条形的值&#xff0c;再操作对应的逻辑。这是比较常见的业务&#xff0c;这里记录实际操作。 其中PC端…

spacy NER 位置信息不考虑空格!!!

texts ["疫情期间&#xff0c;俄罗斯 联邦军队医疗机构的负责人Saanvi Alia在方城县启动了远程医疗服务。","疫情期间&#xff0c;俄罗斯 联 邦 军队医疗机构的负责人Saanvi Alia在方城县启动了远程医疗服务。","疫情期间&#xff0c;俄罗 斯 联 邦 …

PR对比模板|手机竖屏分辨率视频效果前后对比模板剪辑素材

Premiere Pro前后对比效果模板&#xff0c;适用于化妆前后对比、视频调色效果前后对比、同一地方人物活场景变化等视频制作剪辑使用。 主要特点&#xff1a; 只需将图像或视频导入占位符&#xff0c;编辑前后文本&#xff0c;并使用控件微调动画计时。 可以打开或关闭前后屏幕…

LeetCode2095删除链表的中间节点

题目描述 给你一个链表的头节点 head 。删除 链表的 中间节点 &#xff0c;并返回修改后的链表的头节点 head 。长度为 n 链表的中间节点是从头数起第 ⌊n / 2⌋ 个节点&#xff08;下标从 0 开始&#xff09;&#xff0c;其中 ⌊x⌋ 表示小于或等于 x 的最大整数。对于 n 1、…

Linux防火墙iptalbes

1 iptalbes 1.1 概念 防火墙(Firewall)是一种隔离技术&#xff0c;用于安全管理与筛选的软件和硬件设备&#xff0c;使计算机内网和外网分开&#xff0c;可以防止外部网络用户以非法手段通过外部网络进入内部网络&#xff0c;保护内网免受外部非法用户的侵入。 1.2 SELinux …

Linux文件相关

权限&#xff1a; 超级用户root 可以做任何事情不受限制 普通用户[用户名]做有限的事情 超级用户的命令提示符是“#”&#xff0c;普通用户的命令提示符是“$” 拓展&#xff1a; 用户的切换 su [用户名] 只是简单的换了一个账号&#xff0c;环境没变 su - 改变…

实验十 智能手机互联网程序设计(微信程序方向)实验报告

实验目的和要求 完成以下页面设计。 二、实验步骤与结果&#xff08;给出对应的代码或运行结果截图&#xff09; Wxml <view class"container"> <view class"header"> <view class"logo"…

遇到难题 暗区突围掉宝Twitch绑定关联账号显示404

Twitch作为一个广受欢迎的直播平台&#xff0c;经常会举办各种与游戏相关的互动活动&#xff0c;如“掉宝活动”&#xff0c;其中就包括了与《暗区突围》的合作。这类活动允许观众在观看指定的Twitch直播时&#xff0c;通过将他们的Twitch账号与《暗区突围》游戏账号绑定&#…

2024年3月 电子学会青少年等级考试机器人理论真题六级

202403 青少年等级考试机器人理论真题六级 第 1 题 下列选项中&#xff0c;属于URL的是&#xff1f;&#xff08; &#xff09; A&#xff1a;192.168.1.10 B&#xff1a;www.baidu.com C&#xff1a;http://www.kpcb.org.cn/h-col-147.html D&#xff1a;fe80::7998:ffc8…

springMVC基础使用(示例)

maven依赖&#xff08;javax.servlet-api版本与spring-webmvc班恩要匹配不然会报java.lang.NoSuchMethodError: javax.servlet.http.HttpServletRespons&#xff09;&#xff1a; <dependencies><dependency><groupId>javax.servlet</groupId><arti…

贪心 -力扣860.柠檬水找零力扣2208.将数组和减半的最少操作次数力扣179.最大数力扣376.摆动序列

目录 力扣860.柠檬水找零 力扣2208.将数组和减半的最少操作次数 力扣179.最大数 力扣376.摆动序列 贪心策略&#xff0c;局部最优->全局最优 1.把解决问题的过程分为若干步骤 2.解决每一步的时候&#xff0c;都选择当前看起来“最优秀的”解法 3.希望能够得到全局最优解…