PE加载器的实现

Linux内核实现PE加载器——Longene源码分析 Longene是一个源自中国的自由、开源的操作系统项目,目的是要把Linux的内核扩充成一个既支持Linux应用、也支持Windows应用,既支持Linux设备驱动、也支持Windows设备驱动的兼容内核;使用户可以直接在Linux操作系统上高效运行Windows应用。2006年发布了其第一个版本,但是自2014年以来,项目开发已停止,2018年5月其官网无法访问。这里就不多做介绍了,直接开始从源... 阅读详情
来源: http://blog.vckbase.com/windowssky
  对于加壳软件的开发者,掌握PE Loader的实现是最基本的技术;因为壳运行结束后,你要仿照PE加载器去Load映象体,我曾看过UPX的开源代码,全手工打造PE,实现的也是极其复杂,是学习加壳,脱壳和开发加壳软件的上乘资料.

  在ReatOs和Nt4.0上找到了其实现,前者实现的比较清晰,不过还是看看Nt4.0的实现吧

//KiThreadStartup->向Kernel APC插入LdrInitializeThunk->向User APC插入
//LdrInitializeThunk;详请参见PspCreateThread的实现
//
//注:Kernel APC与User APC的区别:
//          1)前者是在APC_LEVEL上运行,后者是在PASSIVE_LEVEL上运行
//          2)只有KTHREAD中的AlertAble或KTHREAD-ApcState-UserApcPending
//              为1的情况下,User APC中的Routine才会被执行
//
//ring0下启动ring3下的程序就是通过kernel下操作User APC实现的(向Explorer.exe中插入一个User APC)
//详请参考: http://www.codeproject.com/useritems/KernelExec.asp


//扯远了,还是来看看LdrInitializeThunk和LdrInitialize的实现吧
;++
;
; VOID
; LdrInitializeThunk(
;    IN PVOID NormalContext,
;    IN PVOID SystemArgument1,
;    IN PVOID SystemArgument2
;    )
;
; Routine Description:
;
;    This function computes a pointer to the context record on the stack
;    and jumps to the LdrpInitialize function with that pointer as its
;    parameter.
;
; Arguments:
;
;    NormalContext - User Mode APC context parameter (ignored).
;
;    SystemArgument1 - User Mode APC system argument 1 (ignored).
;
;    SystemArgument2 - User Mode APC system argument 2 (ignored).
;
; Return Value:
;
;    None.
;
;--

cPublicProc _LdrInitializeThunk , 4

NormalContext  equ [esp + 4]
SystemArgument1 equ [esp + 8]
SystemArgument2 equ [esp + 12]
Context        equ [esp + 16]

        lea    eax,Context            ; Calculate address of context record
        mov    NormalContext,eax      ; Pass as first parameter to
if DEVL
        xor    ebp,ebp                ; Mark end of frame pointer list
endif
IFDEF STD_CALL
        jmp    _LdrpInitialize@12      ; LdrpInitialize
ELSE
        jmp    _LdrpInitialize        ; LdrpInitialize
ENDIF

stdENDP _LdrInitializeThunk

_TEXT  ends
        end



VOID
LdrpInitialize (
    IN PCONTEXT Context,
    IN PVOID SystemArgument1,
    IN PVOID SystemArgument2
    )

/*++

Routine Description:

    This function is called as a User-Mode APC routine as the first
    user-mode code executed by a new thread. It's function is to initialize
    loader context, perform module initialization callouts...

Arguments:

    Context - Supplies an optional context buffer that will be restore
              after all DLL initialization has been completed.  If this
              parameter is NULL then this is a dynamic snap of this module.
              Otherwise this is a static snap prior to the user process
              gaining control.

    SystemArgument1 - Supplies the base address of the System Dll.

    SystemArgument2 - not used.

Return Value:

    None.

--*/

{
    NTSTATUS st, InitStatus;
    PPEB Peb;
    PTEB Teb;
    UNICODE_STRING UnicodeImageName;
    MEMORY_BASIC_INFORMATION MemInfo;
    BOOLEAN AlreadyFailed;
    LARGE_INTEGER DelayValue;

    SystemArgument2;

    AlreadyFailed = FALSE;
    Peb = NtCurrentPeb();
    Teb = NtCurrentTeb();

    if (!Peb->Ldr) {
#if defined(MIPS) || defined(_ALPHA_)
        ULONG temp;
#if defined(MIPS)
        Peb->ProcessStarterHelper = (PVOID)LdrProcessStarterHelper;
#endif
        //
        // Set GP register
        //
        LdrpGpValue =(ULONG)RtlImageDirectoryEntryToData(
                Peb->ImageBaseAddress,
                TRUE,
                IMAGE_DIRECTORY_ENTRY_GLOBALPTR,
                &temp
                );
        if (Context != NULL) {
            LdrpSetGp( LdrpGpValue );
#if defined(_MIPS_)
            Context->XIntGp = (LONG)LdrpGpValue;
#else
            Context->IntGp = LdrpGpValue;
#endif
        }
#endif // MIPS || ALPHA

        NtGlobalFlag = Peb->NtGlobalFlag;
#if DBG
        if (TRUE)
#else
        if (Peb->BeingDebugged || Peb->ReadImageFileExecOptions)
#endif
        {
            PWSTR pw;

            pw = (PWSTR)Peb->ProcessParameters->ImagePathName.Buffer;
            if (!(Peb->ProcessParameters->Flags & RTL_USER_PROC_PARAMS_NORMALIZED)) {
                pw = (PWSTR)((PCHAR)pw + (ULONG)(Peb->ProcessParameters));
                }
            UnicodeImageName.Buffer = pw;
            UnicodeImageName.Length = Peb->ProcessParameters->ImagePathName.Length;
            UnicodeImageName.MaximumLength = UnicodeImageName.Length;

            st = LdrQueryImageFileExecutionOptions( &UnicodeImageName,
                                                    L"GlobalFlag",
                                                    REG_DWORD,
                                                    &NtGlobalFlag,
                                                    sizeof( NtGlobalFlag ),
                                                    NULL
                                                  );
            if (!NT_SUCCESS( st )) {
                UnicodeImageName.Length = 0;

                if (Peb->BeingDebugged) {
                    NtGlobalFlag |= FLG_HEAP_ENABLE_FREE_CHECK |
                                    FLG_HEAP_ENABLE_TAIL_CHECK |
                                    FLG_HEAP_VALIDATE_PARAMETERS;
                    }
                }
        }

#if DBG && FLG_HEAP_PAGE_ALLOCS

        if ( NtGlobalFlag & FLG_HEAP_PAGE_ALLOCS ) {

            //
            //  Turn on BOOLEAN RtlpDebugPageHeap to indicate that
            //  new heaps should be created with debug page heap manager
            //  when possible.  Also force off other heap debug flags
            //  that can cause conflicts with the debug page heap
            //  manager.
            //

            RtlpDebugPageHeap = TRUE;

            NtGlobalFlag &= ~( FLG_HEAP_ENABLE_TAGGING |
                              FLG_HEAP_ENABLE_TAG_BY_DLL
                            );

            }

#endif // DBG && FLG_HEAP_PAGE_ALLOCS

    }
#if defined(MIPS) || defined(_ALPHA_)
    else
    if (Context != NULL) {
        LdrpSetGp( LdrpGpValue );
#if defined(_MIPS_)
        Context->XIntGp = (LONG)LdrpGpValue;
#else
        Context->IntGp = LdrpGpValue;
#endif
    }
#endif // MIPS || ALPHA

    ShowSnaps = (BOOLEAN)(FLG_SHOW_LDR_SNAPS & NtGlobalFlag);

    //
    // Serialize for here on out
    //

    Peb->LoaderLock = (PVOID)&LoaderLock;
    if ( !RtlTryEnterCriticalSection(&LoaderLock) ) {
        if ( LoaderLockInitialized ) {
            RtlEnterCriticalSection(&LoaderLock);
            }
        else {

            //
            // drop into a 30ms delay loop
            //

            DelayValue.QuadPart = Int32x32To64( 30, -10000 );
            while ( !LoaderLockInitialized ) {
                NtDelayExecution(FALSE,&DelayValue);
                }
            RtlEnterCriticalSection(&LoaderLock);
            }
        }

    if (Teb->DeallocationStack == NULL) {
        st = NtQueryVirtualMemory(
                NtCurrentProcess(),
                Teb->NtTib.StackLimit,
                MemoryBasicInformation,
                (PVOID)&MemInfo,
                sizeof(MemInfo),
                NULL
                );
        if ( !NT_SUCCESS(st) ) {
            LdrpInitializationFailure(st);
            RtlRaiseStatus(st);
            return;
            }
        else {
            Teb->DeallocationStack = MemInfo.AllocationBase;
        }
    }

    InitStatus = STATUS_SUCCESS;
    try {
        if (!Peb->Ldr) {
            LdrpInLdrInit = TRUE;
#if DBG
            //
            // Time the load.
            //

            if (LdrpDisplayLoadTime) {
                NtQueryPerformanceCounter(&BeginTime, NULL);
            }
#endif // DBG

            try {
                //
                //This function initializes the loader for the process.
                //This includes:

                //    - Initializing the loader data table

                //    - Connecting to the loader subsystem

                //    - Initializing all staticly linked DLLs

                InitStatus = LdrpInitializeProcess( Context,
                                                    SystemArgument1,
                                                    UnicodeImageName.Length ? &UnicodeImageName : NULL
                                                  );
                }
            except ( EXCEPTION_EXECUTE_HANDLER ) {
                InitStatus = GetExceptionCode();
                AlreadyFailed = TRUE;
                LdrpInitializationFailure(GetExceptionCode());
                }
#if DBG
            if (LdrpDisplayLoadTime) {
                NtQueryPerformanceCounter(&EndTime, NULL);
                NtQueryPerformanceCounter(&ElapsedTime, &Interval);
                ElapsedTime.QuadPart = EndTime.QuadPart - BeginTime.QuadPart;
                DbgPrint("/nLoadTime %ld In units of %ld cycles/second /n",
                    ElapsedTime.LowPart,
                    Interval.LowPart
                    );

                ElapsedTime.QuadPart = EndTime.QuadPart - InitbTime.QuadPart;
                DbgPrint("InitTime %ld/n",
                    ElapsedTime.LowPart
                    );
                DbgPrint("Compares %d Bypasses %d Normal Snaps %d/nSecOpens %d SecCreates %d Maps %d Relocates %d/n",
                    LdrpCompareCount,
                    LdrpSnapBypass,
                    LdrpNormalSnap,
                    LdrpSectionOpens,
                    LdrpSectionCreates,
                    LdrpSectionMaps,
                    LdrpSectionRelocates
                    );
            }
#endif // DBG

            if (!NT_SUCCESS(InitStatus)) {
#if DBG
                DbgPrint("LDR: LdrpInitializeProcess failed - %X/n", InitStatus);
#endif // DBG
            }

        } else {
            if ( Peb->InheritedAddressSpace ) {
                InitStatus = LdrpForkProcess();
                }
            else {

#if defined (WX86)
                if (Teb->Vdm) {
                    InitStatus = LdrpInitWx86(Teb->Vdm, Context, TRUE);
                    }
#endif

                //    This function is called by a thread that is terminating cleanly.
                //It's purpose is to call all of the processes DLLs to notify them
                //that the thread is detaching.

                LdrpInitializeThread();
                }
        }
    } finally {
        LdrpInLdrInit = FALSE;
        RtlLeaveCriticalSection(&LoaderLock);
        }

    NtTestAlert();

    if (!NT_SUCCESS(InitStatus)) {

        if ( AlreadyFailed == FALSE ) {
            LdrpInitializationFailure(InitStatus);
            }
        RtlRaiseStatus(InitStatus);
    }


}

详细实现参见:
nt4/private/ntos/dll/ldrinit.c
nt4/private/ntos/dll/ldrapi.c
nt4/private/ntos/dll/ldrsnap.c

reatos实现参见:
ReactOS030/dll/ntdll/ldr/startup.c
ReactOS030/dll/ntdll/ldr/utils.c
ReactOS030/dll/ntdll/ldr/elf.c
PE文件生成原理:从链接器到Windows加载器的工程实现 PE(Portable Executable)是Windows平台可执行文件的标准二进制格式,其本质是一份描述内存映射关系的结构化契约,涵盖磁盘布局与运行时虚拟地址空间的精确对应。其核心原理包括节(Section)语义划分、RVA(相对虚拟地址)空间规划、重定位表构造及入口点绑定机制。该格式支撑了现代链接器的关键技术价值:实现符号解析、地址重定向与跨模块协作,并为CRT初始化、DLL导入、ASLR等安全特性提供底层基础。典型应用场景包括C/C++原生程序构建、嵌入式Windows子系统开发及编译器教学工具链 阅读详情

相关推荐

PEloader——32位PE文件简单加载器

32位PE加载器的简单实现

dawn_ing_的博客 1273

c++注入思路inlink hook,ring3和ring 0

注入DLL的思路步骤: 1. 在目标进程中申请一块内存空间(使用VirtualAllocEx函数) 存放DLL的路径,方便后续执行LoadLibraryA 2. 将DLL路线写入到目标进程(使用WriteProcessMemory函数) 3. 获取LoadLibraryA函数地址(使用GetProcAddress),将其做为线程的回调函数 4. 在目标进程 创建线程并执行(使用CreateRemoteThread) std::string temp = W2Astring(strDllPath); in

qq_35490522的博客 1992

pe-loader:Windows PE格式的文件加载器

Windows可执行文件加载器 这是Windows PE格式的文件加载器应用程序,提供与OS内部可执行文件加载器类似的功能,但从用户模式运行。 它将可执行文件映射到内存,打补丁并初始化几种机制,然后将控制流传递给加载的映像。 该项目是为教育目的而开发的。 用法 可以使用Visual Studio 2013/2015或MSBuild构建该项目。 编译的可执行文件可以在build\(Debug|Release)用法示例中找到: loader.exe " C:\WINDOWS\system32\ping.exe " -t 127.0.0.1 局限性 大部分与Windows XP兼容(已在Windows XP,7、8上测试) 仅32位图像 根据官方PE格式文档进行图像验证 支持 影像记忆体对应 Craft.io信息修补 激活上下文 崔 API重定向(EAT修补) 图像重定位 IAT处理 T

【梅哥的Ring0湿润插入教程】重磅第三课:Ring0下的PE Loader及重加载内核秒杀一切内核级钩子(上篇)...

【梅哥的Ring0湿润插入教程】Email:mlkui@163.com 转载请注明出处,谢绝喷子记者等,如引起各类不适请自觉滚J8蛋!第三课:Ring0下PE Loader及重加载内核绕过一切内核级钩子(上篇) 随着驱动保护技术的逐步成熟,诸如网络游戏公司等越来越多的商业软件公司开始使用Ring0级保护技术保护自己的产品,以起到反用户级调试、反RootKit、反各类钩子、反各...

aejtu5698的博客 1621

LoadPE源代码

LoadPE源代码

PE加载器1.7版(PeLoader_fne.fne)-易语言

PeLoader。 操作系统支持: Windows

ring0层下实现的文件强制删除

文件强删 在日常生活使用电脑的过程中,遇到删不掉的文件的时候,我们总会通过一些软件提供的强制删除文件功能来删除顽固的文件。文件强删技术对于杀软来说是清楚病毒木马的武器,在扫描器检测出恶意文件的时候,就需要强删功能来清除恶意文件。而对于病毒木马来说,反过来可以用强删技术来强制删除系统保护文件或是受杀软保护的文件。 本文将会介绍文件强删技术,即使文件正在运行,也能强制删除本地文件。 实现过程 当文件是PE文件而且已经被加载到内存中的时候,正常情况下是无法通过资源管理器explorer.exe来删除本地文件的,因

LYSM 1700

易语言学习-PE加载器(PeLoader)支持库版.zip

易语言学习-PE加载器(PeLoader)支持库版.zip

写一个简单的PELoader

刚开始写其实不太明白peloader到底是在干什么,以及它是怎么实现的,在参考了几个别人的loader后了解到,其实就是把pe文件的相关知识用代码实现出来。用它可以打开pe文件.

LAOdark的博客 819

别再乱提MR了!手把手教你配置GitLab的CI/CD与分支保护规则,让团队协作更丝滑

本文详细介绍了如何配置GitLab的CI/CD与分支保护规则,以优化团队协作流程。通过设置Protected Branches、MR流水线检查和自动化审批规则,有效防止不规范操作和合并冲突,提升开发效率与代码质量。特别强调MR(Merge Request)的正确使用,确保团队协作更丝滑。

weixin_28840591的博客 236

普通人如何上岸华为OD-面试总结

总共有3道算法题,100分值的两道,200分值的一道,不同的毕业院校和专业,通过机试的分值不一样,最少需要150分通过,提前和hr联系,了解自己需要多少分通过。重中之重:哪怕你是背的题库,也请你一定不要直接抄原来的,最好是变更下方法名,否则会判定你重复率过高,从而失去后面的面试机会(实在是不会做再用此方法,凑分数所用,面试官能看到你的代码,会影响你的面试评价)本人女,所以还问道了婚育计划,有对象这点可以说,没有问题,但是如果可以的话,生孩子的时间,可以给hr说这几年不考虑。如果说没有难题,直接就挂了。

weixin_47767264的博客 5457

DarkArmour JMP加载器实现原理:深入理解PE内存映射技术

DarkArmour是一款专注于Windows平台的反病毒规避工具,其核心功能之一就是通过JMP加载器实现PE文件的内存映射与执行。本文将深入解析DarkArmour JMP加载器的实现原理,帮助读者理解PE内存映射技术在反病毒规避中的关键作用。 ## PE文件内存映射的基本概念 PE(Portable Executable)文件是Windows平台下的可执行文件格式,包括EXE、DLL等类型

gitblog_00089的博客 851

PLC编程进阶:结构体(UDT)与功能块(FB)的模块化实践指南

本文深入探讨了PLC编程中实现模块化的核心方法,重点解析了结构体(UDT)与功能块(FB)的协同应用。通过将零散数据封装为UDT,并将控制逻辑打包为可复用的FB,能够构建出结构清晰、易于维护和调试的PLC程序。文章结合拧紧枪、电机控制等实战案例,提供了从设计原则到分层架构的完整实践指南,旨在帮助工程师将混乱的‘面条式’代码改造为高效的‘正规军’。

s3t4u的博客 222

如何实现一个(PE 文件)内存加载器(来自ChatGPT)

实现一个内存加载器(通常指的是一个PE Loader,用于在内存中加载和执行Windows可执行文件)是一项复杂的工作,它涉及对PE文件格式的深入了解以及对Windows操作系统内部工作机制的理解。下面是一个简化版本的概述,用于描述在Windows平台上实现一个内存加载器的一般步骤。

BlackNight168的博客 907

STM32+ESP8266+MQTT协议连接阿里云物联网平台

一、环境介绍 单片机采用:STM32F103C8T6 上网方式:采用ESP8266,也可以使用其他设备代替,只要支持TCP协议即可。比如:GSM模块、有线网卡等。 开发软件:keil5 二、实现功能 通过阿里云物联网服务器实现设备数据远程上传、下发,实现数据交互。 在当前使用的开发板上有4盏LED灯、一个蜂鸣器、4个按键。 三、阿里云物联网服务器创建步骤 说明:如果没有账号的话,先点击网页右上角,注册一个账号,并完成实名认证再继续下一步。 产品名称根据自己情况填...

6万+

【气候极端指数】MATLAB计算各种气候极端指数

简介各类气候极端指数,及其MATLAB计算代码

WW、forever的博客 4917

PE 文件加载器实现

/** * peLoader.cpp * Windows APT Warfare * by aaaddress1@chroot.org */ #include <stdio.h> #include <windows.h> #pragma warning(disable : 4996) #define getNtHdr(buf) ((IMAGE_NT_HEADERS *)((size_t)buf + ((IMAGE_DOS_HEADER *)buf)->e_lfanew.

pureman_mega的博客 978

Carla中如何渲染opendrive车道线和车道标识(全网独家,附代码)

carla是可以单独加载opendrive并渲染路面的,但是无法把车道线渲染出来,这是一个大坑,因为没有车道线就无法给感知输入。楼主已经实现,直接渲染车道线或者带PBR贴图的车道标识。实现起来非常简单,但必须对carla源码以及ue的开发足够了解。在carla源码中有一个很重要的类opendrivegenerator,它是关于opendrive渲染的全部方法,但是你是找不到它实例化的地方的,因为它被定义在蓝图关卡中。网上包括carla官方关于carla源码的分析少之又少,楼主将自己的经验写出来供大家参考。

u013998156的博客 1091

Nim-RunPE: Nim语言实现的内存反射PE加载器

Nim-RunPE: Nim语言实现的内存反射PE加载器 1. 项目基础介绍与主要编程语言 Nim-RunPE 是一个开源项目,旨在通过 Nim 编程语言实现内存中的反射PE(Portable Executable)加载功能。Nim 是一种效率高、表达力强的编程语言,它结合了 Python 的易读性和 C 的性能。本项目利用 Nim 的这些特性,为开发者提供了一个安全、灵活的PE文件加载解决方案。...

gitblog_00766的博客 364

KEPServerEX物联网网关(IoT Gateway)REST客户端代理(非原创)

(中文版)资料来源于【OPC-KEPServerEX学习KEPWare交流】905485143群的【455196383】【零下一度】 一。KEPServerEX物联网网关REST客户端代理演示 在KSE中,首先构建一个带有通道/设备/标签的模拟器系统。 例如,下面是三个随机项目。 直接到IoT网关插件,添加新代理。 从类型列表中选择REST Client。 终结点...

-雲飛兄-博客 5809

DeepSeek在实时计算与流处理系统中的突破性实践

对于技术决策者而言,现在正是将DeepSeek实时计算技术纳入企业架构蓝图的关键时机,那些能够率先构建实时智能能力的企业,将在数据驱动的商业竞争中赢得决定性优势。DeepSeek通过创新的流处理架构,成功将复杂事件处理(CEP)的延迟降低到亚秒级,同时保证了计算结果的精确性。DeepSeek研发的神经架构搜索(NAS)与知识蒸馏联合优化框架,可在保持模型精度的前提下,将参数量压缩至原始模型的1/100,实现边缘设备的实时AI推理。随着5G和物联网技术的普及,对实时处理能力的需求将呈指数级增长。

Programming Talk 291

SafetyKatz深度解析:如何通过.NET PE加载器实现LSASS内存凭证提取

SafetyKatz是一款结合了Mimikatz项目与.NET PE加载器技术的安全工具,专门用于从LSASS内存中提取凭证信息。本文将深入剖析其工作原理、核心功能及使用方法,帮助安全从业者理解这一工具的技术细节与应用场景。 ## 什么是SafetyKatz? SafetyKatz本质上是[@gentilkiwi](https://twitter.com/gentilkiwi)的Mimikat

gitblog_00463的博客 909

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

后渗透与免杀艺术:从Mimikatz到PE转ShellCode的加载器实现

摘要: 本文深入探讨红队行动与渗透测试中的高级攻防技术,聚焦权限维持、提权与绕过EDR的核心方法。内容涵盖: Mimikatz原理与绕过:解析LSASS内存读取机制,探讨CredentialGuard绕过(如降级攻击、DPAPI利用)及免杀加载(反射DLL、PowerShell内存加载)。 提权漏洞实战:分析令牌窃取、PrintNightmare(驱动加载漏洞)等提权技术,结合非源码修改(PE头篡改、API重定向)实现免杀。 无文件攻击链:详解PE转Shellcode技术(如Donut工具),通过内存加载器

油墨香^-^的博客 960

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

深入解析 Rust 编译器错误 E0767:不可达标签(unreachable label)的成因、修复与编译原理

E0767 是 rustc 在名称解析(name resolution)阶段报告的一类编译错误,提示程序员**使用了一个虽然在代码中定义、但当前作用域内不可达(unreachable)的标签(label)**。本文以 rustc 官方错误说明文档 [E0767.md](https://link.gitcode.com/i/7d77981d0b8945bd1a452c6a3dd47b6e) 为核心,

gitblog_00616的博客 291

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

module-federation-examples 实战:用 Vite + Solid 搭建模块联邦 host/remote 微前端

本篇文章基于 module-federation-examples 仓库中的 `module-federation-vite-solid` 示例,完整讲解如何让 Solid 应用通过 Vite 与 `@module-federation/vite` 插件实现模块联邦(Module Federation)。示例以"host(宿主)+ remote(远程)"双应用结构演示了远程组件的运行时加载、`so

gitblog_00785的博客 860
上一篇: Smss.exe进程分析
下一篇: Recognizer & FS & Filter
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值