第12节 第二种shellcode编写实战(1)

news2024/12/24 9:48:16

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

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

一、C语言方式编写shellcode​

1. 新建0.createshellcode.cpp文件:用于生成整个项目的shellcode文件,便于其他项目加载执行shellcode。

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

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

int EntryMain()
{
    // 获取shellcode片段大小
    DWORD dwShellcodeSize = (DWORD)ShellCodeEnd - (DWORD)ShellCodeStart;

    DWORD   dwWriten = 0;
    HANDLE  hFile = NULL;

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

    // 将shellcode写入到文件
    if (WriteFile(hFile, ShellCodeStart, dwShellcodeSize, &dwWriten, NULL) == FALSE)
    {
        CloseHandle(hFile);
        return -1;
    }

    CloseHandle(hFile);

    return 0;
}

2. 新建a.start.h、z.end.h,以及对应的a.start.cpp、z.end.cpp,分别用于标记shellcode的开始和结束。

a.start.h:

#pragma once

// 用于标记shellcode开始
void ShellCodeStart();

a.start.cpp:

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

// 用于标记shellcode开始
void ShellCodeStart()
{
    // shellcode执行的主要功能
    ShellcodeMain();
}

z.end.h:

#pragma once

// 用于标记shellcode结束
void ShellCodeEnd();

z.end.cpp:

// 次函数仅用来标记shellcode结尾
void ShellCodeEnd()
{

}

3. 新建shellcode.h,以及对应的shellcode.cpp,用于编写shellcode执行的主要功能代码。

shellcode.h:

#pragma once

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

HMODULE GetKernel32BaseAddress();
FARPROC _GetPorcAddress();

int ShellcodeMain();

// 创建文件
int DoCreateFile();
// 弹框提示
int DoMessageBox();

shellcode.cpp:

#include "shellcode.h"

// shellcode主要执行的功能
int ShellcodeMain()
{
    // 创建文件
    DoCreateFile();

    // 弹框提示
    DoMessageBox();

    // 其他功能...

    return 0;
}

// 功能:创建文件 D:\1.txt
int DoCreateFile()
{
    // 获取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 };
        typedef HMODULE(WINAPI* FN_LoadLibraryA)(__in LPCSTR lpLibFileName);
        FN_LoadLibraryA fn_LoadLibraryA = (FN_LoadLibraryA)fn_GetProcAddress(GetKernel32BaseAddress(), szLoadLibraryA);
        if (fn_LoadLibraryA)
        {
            // 获取CreateFileA函数地址
            char szCreateFileA[] = { 'C','r','e','a','t','e','F','i','l','e','A',0 };
            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_GetProcAddress(GetKernel32BaseAddress(), szCreateFileA);
            // 执行CreateFileA
            char szFilePath[] = { 'D',':','\\','1','.','t','x','t',0 };
            fn_CreateFileA(szFilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
        }
    }

    return 0;
}

// 功能:弹框提示
int DoMessageBox()
{
    // 获取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 };
        typedef HMODULE(WINAPI* FN_LoadLibraryA)(__in LPCSTR lpLibFileName);
        FN_LoadLibraryA fn_LoadLibraryA = (FN_LoadLibraryA)fn_GetProcAddress(GetKernel32BaseAddress(), szLoadLibraryA);
        if (fn_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 };
            typedef int (WINAPI* FN_MessageBoxA)(__in_opt HWND hWnd, __in_opt LPCSTR lpText, __in_opt LPCSTR lpCaption, __in UINT uType);
            FN_MessageBoxA fn_MessageBoxA = (FN_MessageBoxA)fn_GetProcAddress(fn_LoadLibraryA(szUser32), szMessageBoxA);
            // 执行MessageBoxA
            char szCaption[] = { 't','i','t','l','e',0 };
            char szText[] = { 'H','e','l','l','o',' ','W','o','r','l','d', 0 };
            fn_MessageBoxA(0, szText, szCaption, MB_OK | MB_ICONINFORMATION);
        }
    }

    return 0;
}

// 获取kernel32基址
HMODULE 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 _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;
}

最后的框架结构如下图:

后续开发所有功能都可以在遵循shellcode编写原则的基础上,以新的.h头文件.cpp源文件进行扩展。


二、C++类方式编写shellcode​

也可以使用C++类的方式进行编写,比如将shellcode.cpp改为CDoShellcode类的方式实现:

shellcode.h:

#pragma once

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

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

public:
     // 创建文件
     int DoCreateFile();
     // 弹框提示
     int DoMessageBox();
};

shellcode.cpp:

#include "shellcode.h"

// 功能:创建文件 D:\1.txt
int CDoShellcode::DoCreateFile()
{
    // 获取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 };
        typedef HMODULE(WINAPI* FN_LoadLibraryA)(__in LPCSTR lpLibFileName);
        FN_LoadLibraryA fn_LoadLibraryA = (FN_LoadLibraryA)fn_GetProcAddress(GetKernel32BaseAddress(), szLoadLibraryA);
        if (fn_LoadLibraryA)
        {
            // 获取CreateFileA函数地址
            char szCreateFileA[] = { 'C','r','e','a','t','e','F','i','l','e','A',0 };
            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_GetProcAddress(GetKernel32BaseAddress(), szCreateFileA);
            // 执行CreateFileA
            char szFilePath[] = { 'D',':','\\','1','.','t','x','t',0 };
            fn_CreateFileA(szFilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
        }
    }

    return 0;
}

// 功能:弹框提示
int CDoShellcode::DoMessageBox()
{
    // 获取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 };
        typedef HMODULE(WINAPI* FN_LoadLibraryA)(__in LPCSTR lpLibFileName);
        FN_LoadLibraryA fn_LoadLibraryA = (FN_LoadLibraryA)fn_GetProcAddress(GetKernel32BaseAddress(), szLoadLibraryA);
        if (fn_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 };
            typedef int (WINAPI* FN_MessageBoxA)(__in_opt HWND hWnd, __in_opt LPCSTR lpText, __in_opt LPCSTR lpCaption, __in UINT uType);
            FN_MessageBoxA fn_MessageBoxA = (FN_MessageBoxA)fn_GetProcAddress(fn_LoadLibraryA(szUser32), szMessageBoxA);
            // 执行MessageBoxA
            char szCaption[] = { 't','i','t','l','e',0 };
            char szText[] = { 'H','e','l','l','o',' ','W','o','r','l','d', 0 };
            fn_MessageBoxA(0, szText, szCaption, MB_OK | MB_ICONINFORMATION);
        }
    }

    return 0;
}

// 获取kernel32基址
HMODULE CDoShellcode::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 CDoShellcode::_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;
}

然后将a.start.cpp中的ShellCodeStart函数改为:

void ShellCodeStart()
{
    CDoShellcode shellcode;

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

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

    // 其他功能...
}

这样即可实现类的方式执行shellcode功能。

测试:运行以上代码对应生成的exe文件,会在当前路径下生成shellcode.bin文件,该文件就是我们最后得到的shellcode文件。使用编写shellcode加载器加载执行shellcode.bin测试效果。


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

图片​​

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


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一文扫盲(12):公寓/酒店管理系统的功能模块和界面设计

大千UI工场本次带来第12期&#xff1a;酒店管理系统&#xff0c;从系统定义、功能模块、界面构成和设计方向四个方面讲解&#xff0c;大千UI工场愿意持续和大家分享&#xff0c;欢迎关注、点赞、转发。 公寓管理系统是一种用于管理和运营公寓的软件系统。它通过集成各种功能模…

基于SpringBoot+Vue的笔记共享平台 免费获取源码

项目源码获取方式放在文章末尾处 项目技术 数据库&#xff1a;Mysql5.7/8.0 数据表&#xff1a;10张 开发语言&#xff1a;Java(jdk1.8) 开发工具&#xff1a;idea 前端技术&#xff1a;vue 后端技术&#xff1a;SpringBoot 功能简介 (有文档) 项目获取关键字&#…

使用vant-ui+vue3实现一个可复用的评星组件

如图所示 有两种情况 一种是5颗星 一种是3颗星 官网上只提供了图标类型的 并没有加文字 https://femessage-vant.netlify.app/#/zh-CN/ 自己结合两种情况 在全局注册了此组件(后续还会持续更新代码~) <template><div class"vant_rate_wrapper"><van…

Substrate 入门课第 14 期圆满结束,岗位内推直达知名 Web3 项目!

Substrate&#xff0c;一个完全免费且开源的框架&#xff0c;利用 Rust 语言的强大功能和安全性&#xff0c;为全球开发者提供了一个高效和灵活的开发环境。借助其模块化的设计&#xff0c;即使是新手开发者也能在短短 15 分钟内搭建起定制化的区块链。自 2020 年以来&#xff…

Att论文解读|ICLR 2018 《Graph attention networks》图注意力网络

论文地址 论文地址&#xff1a;https://arxiv.org/abs/1710.10903 github:PetarV-/GAT: Graph Attention Networks (https://arxiv.org/abs/1710.10903) (github.com) gordicaleksa/pytorch-GAT: My implementation of the original GAT paper (Veličković et al.). Ive addi…

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

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

Java线程池:当核心线程数为 0 时,任务来了的执行流程

先说结论&#xff1a;创建一个临时线程直接执行 ThreadPoolExecutor.excute() public void execute(Runnable command) {if (command null)throw new NullPointerException();int c ctl.get();if (workerCountOf(c) < corePoolSize) {if (addWorker(command, true)) retu…

python + word文本框中文字识别并替换【真替换,不只是识别】

1. 简单描述 在一些转换场景下&#xff0c;文本框不会被转换&#xff0c;需要先识别成文字内容。 【识别的文字段落可能会和实际看到的效果有些差异&#xff0c;后续还需校对&#xff0c;如下图】。 不足&#xff1a;除了上面说的那个情况&#xff08;上图说的问题&#xff0…

pgAdmin 4 使用

瀚高数据库 目录 环境 文档用途 详细信息 环境 系统平台&#xff1a;Linux x86-64 Red Hat Enterprise Linux 7,Microsoft Windows (64-bit) 10 版本&#xff1a;14 文档用途 本文介绍pgAdmin4使用技巧和工具所具有的比较好的功能。 详细信息 pgAdmin4是用于设计、维护和管理…

简单的表单初始密码验证的实现

目录 简单示例&#xff1a;表单初始密码验证 1.1准备工作(图1&#xff09; 1.2 index部分 1.3 css部分 1.3.1先把css部分链接到index.html中&#xff0c;注意链接的地址。 1.3.2添加样式 1.4 JS部分 1.4.1 先把js部分链接到index.html中&am…

Android APP读写外置SD卡无权限 java.io.IOException: Permission denied

在物联网应用里&#xff0c;app需要对挂载SD卡读写文件&#xff0c;从 Android 4.4&#xff08;KitKat&#xff09;版本开始&#xff0c;Google 引入了一项名为 "Storage Access Framework" 的新功能&#xff0c;该功能限制了应用对外部存储的直接读写权限,要不然就是…

Html + Express 实现大文件分片上传、断点续传、秒传

在日常的网页开发中&#xff0c;文件上传是一项常见操作。通过文件上传技术&#xff0c;用户可以将本地文件方便地传输到Web服务器上。这种功能在许多场景下都是必不可少的&#xff0c;比如上传文件到网盘或上传用户头像等。 然而&#xff0c;当需要上传大型文件时&#xff0c;…

构建第一个ArkTS应用之@AppStorage:应用全局的UI状态存储

AppStorage是应用全局的UI状态存储&#xff0c;是和应用的进程绑定的&#xff0c;由UI框架在应用程序启动时创建&#xff0c;为应用程序UI状态属性提供中央存储。 和AppStorage不同的是&#xff0c;LocalStorage是页面级的&#xff0c;通常应用于页面内的数据共享。而AppStora…

Apache Flume概述

Apache Flume概述 1.Flume定义 ​ Flume是cloudera(CDH版本的hadoop) 开发的一个分布式、可靠、高可用的海量日志收集系统。 它将各个服务器中的数据收集起来并送到指定的地方去&#xff0c;比如说送到HDFS、Hbase&#xff0c;简单来说flume就是收集日志的。 2.Flume基础架构…

导出QQ好友列表、群列表、群员列表

MENU 准备工作在浏览器地址栏中输入地址使用F12快捷键打开开发者工具(浏览器控制台)点击头像登入网站(推荐)或手机扫码登录获取群列表获取好友列表获取群员列表 准备工作 一台带有浏览器的电脑 在浏览器地址栏中输入地址 https://qun.qq.com/member.html 使用F12快捷键打开开发…

手机同步与数据安全:让手机和电脑完美结合!

在当今这个高度信息化的社会&#xff0c;手机和电脑不仅为我们提供了丰富的信息资源&#xff0c;让我们能够随时随地获取所需的信息&#xff0c;还为我们的生活带来了极大的便利。无论是工作、学习还是娱乐&#xff0c;手机和电脑都发挥着至关重要的作用。 然而&#xff0c;随…

阿里云服务器在线安装nginx

⛰️个人主页: 蒾酒 &#x1f525;系列专栏&#xff1a;《nginx实战》 目录 内容简介 安装步骤 1.root用户登录连接阿里云服务器 2.在usr/local下新建nginx目录 3.安装 1安装下载工具 2下载nginx压缩包 3解压 4安装nginx依赖的库 5编译并安装 6启动nginx 7开启…

【数据结构】顺序表(一)

✨✨✨专栏&#xff1a;数据结构 &#x1f9d1;‍&#x1f393;个人主页&#xff1a;SWsunlight 不怕别人看不起&#xff0c;就怕自己不争气。路是人走出来的&#xff0c;关键要靠自己闯。振作起来&#xff0c;生活的含义就是前进。 目录 一、顺序表的概念&#xff1a; 二…

东南亚服务器租用托管的优势

东南亚地区在国际贸易领域展现出了巨大的潜力和吸引力&#xff0c;其未来的外贸发展前景被认为是广阔且充满了无限商机。这一地区以其人口众多、经济快速发展的特点&#xff0c;结合独特的地理优势和丰富的自然资源&#xff0c;正在吸引全球企业的目光。今天我们一起来看看东南…

YOLOv8火焰与烟雾智能检测系统

项目概述&#xff1a; 本项目旨在开发一款高效、实时的火焰与烟雾检测系统&#xff0c;利用先进的深度学习技术——YOLOv8&#xff0c;为安全监控领域提供智能化解决方案。系统不仅能够准确识别视频流或静态图像中的火焰与烟雾&#xff0c;还配备了用户友好的图形界面&#xff…