首页
社区
课程
招聘
MemoryModule x86x64 内存加载DLL
发表于: 2022-3-29 18:31 34786

MemoryModule x86x64 内存加载DLL

2022-3-29 18:31
34786

by devseed,此篇教程同时发在论坛和我的博客上,完整源码见我的github

距离上次我写的SimpleDpack教程(为了理解加壳原理自己写的轻量级压缩壳),已经有一年多了。前几天修复x64IAT载入序号问题,于是想着可以用这个原理自己重写一个解析PE内存加载DLL的功能。虽然已有类似实现功能,如MemoryModule,但是这个项目还是有点复杂,模块间耦合度有些高,没法作为shellcode附加到EXE来引导DLL

因此我决定重写一个低耦合,同时支持x86x64,可以作为shellcode引导”附加到EXE区段上的DLL”的框架

本框架采取与windows加载DLL相似的名称来设计api,可以实现:

参考stbXXX_IMPLEMENTATION宏控制代码实现,使得include单个头文件就能把模块功能全部引入的做法,有着单头文件结成非常容易实用的特点。于是我就用了一周多时间,自己写了个类似的低耦合单头文件winpe.h,用于解析与加载PE。为了便于shellcode引导,系统函数大多用函数指针传入参数,关键函数全部声明为inline。另外,我还用内联汇编写了从ldr中获取kernel32的基地址,从而减少对IAT硬编码的依赖。

libwinpe.c, 与libwinpe.def(引入def是因为stdcall编译后会被修改名称),把winpe.h的声明的导出函数编译为DLL,如下:

对于编写shellcode, 这里为了方便调试,采取用pyhtonkeystone进行jit生成的机器码写入win_injectmemdll.c的全局变量里的做法, 如下:

详见win_injectmemdll_shellcodestub.py

参考https://bbs.pediy.com/thread-252260.htm, windows对于加载DLL调用如下:

a) 当调用LoadLibrary时首先打开文件并将按照PE文件格式解析数据,并以IMAGE方式将PE各段内容

逐块映射到内存中,如果需要并修复重定位:

kernel32!LoadlibraryA

->kernel32!LoadLibraryExA

​ ->kernel32!LoadLibraryExW

​ ->ntdll!LdrLoadDll

​ ->ntdll!LdrpLoadDll

​ ->ntdll!LdrpMapDll

​ ->ntdll!LdrpCreateDllSection

​ ->ntdll!NtOpenFile //打开目标文件*

​ ->ntdll!NtCreateSection //创建映射*

​ ->ntdll!NtMapViewOfSection //映射*

​ ->LdrRelocateImageWithBias //修复重定位

b) 接着处理调入表等,然后调用TLS回调函数和DLLMAN入口函数;

kernel32!LoadlibraryA

->kernel32!LoadLibraryExA

->kernel32!LoadLibraryExW

​ ->ntdll!LdrLoadDll

​ ->ntdll!LdrpLoadDll

​ ->ntdll!LdrpMapDll

​ ->ntdll!LdrpWalkImportDescriptor //处理导入表等

​ ->LdrpRunInitializeRoutines //调用DLLMAN

​ ->LdrpCallTlsInitializers

​ ->LdrpCallInitRoutine

总结为如下流程:

这里为了降低耦合,没有用系统的memsetmemcpy,自己用inline实现的。

手动将以imagebase为基准的va重定向到目标imagebaseva

LoadLibraryAGetProcAddress实现,考虑到shellcode,不能直接调用,应该通过传入函数指针调用。

另外还要考虑OFT中会出现用序号的情况,x86x64判断表中不同,用sizeof(size_t)区分。

前三步都完成后可以来通过DllMain来引导了。

这部分我没有找到有TLS的DLL,所以没法进一步测试了。这部分代码直接借鉴的MemoryModule的相关函数。

首先需要修改exe的区段头,在后面增加一个区段。这里要特别注意区段的对齐,之后还要修正SizeOfImage

这部分内容和winpe_memLoadLibrary函数实现的方式类似,只不过要用汇编来写shellcode,引导完成后跳转到原来exe的oep。 关键地址可以先留空,在注入时候填入对位置。对于相应的函数的shellcode,由win_injectmemdll_shellcodestub.py读取对应的libpe32.dll函数,填入对应的全局变量。下面代码以x86为例:

由于大部分都用的size_tvoid*等与cpu字长相关的变量,大部分代码不用修改就能编译。

其余的差异部分,可以用sizeof(size_t)>4区分,或者_WIN64宏。如下所示

上面的代码我们可以获取kernel32的基址了,之后可以自己通过扫描export表来查找对应的导出函数了。

这里注意有个坑点,有的导出表项会forward到其他dll上,如kernel32!InitializeSListHead -> NTDLL!RtlInitializeSListHead,详见crashing-kernel32-initializeslisthead。通过DirRVA < FuncRVA < DirRVA + ExportSize来判断是否forward。

此处为了找到LoadLibraryAGetProcAddress函数,不考虑forward情况,否则会引入递归问题。

本项目是我实现不加壳vfs(即通过hook nt函数将文件和文件夹等读取重定向到zip文件中)的衍生产物,采取的是尽量单头文件法和内联函数减小耦合,方便集成到代码中的做法。与其他的MemoryModule最大的区别是支持从shellcode引导DLL。由于以前我有了自己写压缩壳的经验,整体上处理起来还算是顺利。强迫症,感觉好多时间都花在了怎么统一化命名api和代码风格规范上了。至于实现内存加载Resource方面,暂时不考虑实现,汉化游戏一般也用不到这方面内容。

另外,这里还有个坑卡了我好长时间,就是x64的堆栈必须要0x10对齐(即调用函数时要sub rsp, 0x28预留空间与对齐),才能在movaps指令上不报错。之前一直不知道这条指令需要对齐,一直以为是少了哪些初始化,走偏了好久。特别感谢@YeLikERs指出了这一点,同时在PEBLDR相关内容上帮助了很多。

经测试兼容性还算不错,windows xp, windows 7, windows 10, windows 11测试example文件都通过了,甚至我连linux上的wine也测试了(即用我汉化的游戏测试shellcode引导附加到exe区段上的DLL)。最后,附上几张测试图:

memdll_x86winetest
memdll_x64test

 
const char *dllpath = "test.dll";
size_t mempesize = 0;
void *memdll = NULL;
 
// load the pe file in memory and align it to memory align
void *mempe = winpe_memload_file(dllpath, &mempesize, TRUE);
 
// memory loadlibrary
memdll = winpe_memLoadLibrary(mempe);
winpe_memFreeLibrary(memdll);
 
// memory loadlibrary at specific address
size_t targetaddr = sizeof(size_t) > 4 ? 0x140030000: 0x90000;
memdll = winpe_memLoadLibraryEx(mempe, targetaddr,
    WINPE_LDFLAG_MEMALLOC, (PFN_LoadLibraryA)winpe_findloadlibrarya(),
    (PFN_GetProcAddress)winpe_memGetProcAddress);
winpe_memFreeLibrary(memdll);
free(mempe);
const char *dllpath = "test.dll";
size_t mempesize = 0;
void *memdll = NULL;
 
// load the pe file in memory and align it to memory align
void *mempe = winpe_memload_file(dllpath, &mempesize, TRUE);
 
// memory loadlibrary
memdll = winpe_memLoadLibrary(mempe);
winpe_memFreeLibrary(memdll);
 
// memory loadlibrary at specific address
size_t targetaddr = sizeof(size_t) > 4 ? 0x140030000: 0x90000;
memdll = winpe_memLoadLibraryEx(mempe, targetaddr,
    WINPE_LDFLAG_MEMALLOC, (PFN_LoadLibraryA)winpe_findloadlibrarya(),
    (PFN_GetProcAddress)winpe_memGetProcAddress);
winpe_memFreeLibrary(memdll);
free(mempe);
win_injectmemdll.exe exepath dllpath [outpath]
win_injectmemdll.exe exepath dllpath [outpath]
 
#define WINPE_SHARED
#define WINPE_IMPLEMENTATION
#include "winpe.h"
#define WINPE_SHARED
#define WINPE_IMPLEMENTATION
#include "winpe.h"
EXPORTS
    winpe_appendsecth
    winpe_findgetprocaddress
    winpe_findkernel32
    winpe_findloadlibrarya
    winpe_findspace
    winpe_findmodulea
    winpe_imagebaseval
    winpe_imagesizeval
    winpe_memFreeLibrary
    winpe_memFreeLibraryEx
    winpe_memGetProcAddress
    winpe_memLoadLibrary
    winpe_memLoadLibraryEx
    winpe_membindiat
    winpe_membindtls
    winpe_memfindexp
    winpe_memfindiat
    winpe_memforwardexp
    winpe_memload
    winpe_memload_file
    winpe_memreloc
    winpe_noaslr
    winpe_oepval
    winpe_overlayload_file
    winpe_overlayoffset
EXPORTS
    winpe_appendsecth
    winpe_findgetprocaddress
    winpe_findkernel32
    winpe_findloadlibrarya
    winpe_findspace
    winpe_findmodulea
    winpe_imagebaseval
    winpe_imagesizeval
    winpe_memFreeLibrary
    winpe_memFreeLibraryEx
    winpe_memGetProcAddress
    winpe_memLoadLibrary
    winpe_memLoadLibraryEx
    winpe_membindiat
    winpe_membindtls
    winpe_memfindexp
    winpe_memfindiat
    winpe_memforwardexp
    winpe_memload
    winpe_memload_file
    winpe_memreloc
    winpe_noaslr
    winpe_oepval
    winpe_overlayload_file
    winpe_overlayoffset
def inject_shellcodestubs(srcpath, libwinpepath, targetpath):
    pedll = lief.parse(libwinpepath)
    pedll_oph = pedll.optional_header
 
    # generate oepint shellcode
    if pedll_oph.magic == lief.PE.PE_TYPE.PE32_PLUS:
        oepinit_code = gen_oepinit_code64()
        pass
    elif pedll_oph.magic == lief.PE.PE_TYPE.PE32:
        oepinit_code = gen_oepinit_code32()
        pass
    else:
        print("error invalid pe magic!", pedll_oph.magic)
        return
 
    # find necessary functions
    FUNC_SIZE =0x400
    codes = {"winpe_memreloc": 0,
        "winpe_membindiat": 0,
        "winpe_membindtls": 0,
        "winpe_findloadlibrarya": 0,
        "winpe_findgetprocaddress": 0}
    for k in codes.keys():
        func = next(filter(lambda e : e.name == k,
            pedll.exported_functions))
        codes[k] = pedll.get_content_from_virtual_address(
            func.address, FUNC_SIZE)
    codes['winpe_oepinit'] = oepinit_code
 
    # write shellcode to c source file
    with open(srcpath, "rb") as fp:
        srctext = fp.read().decode('utf8')
    for k, v in codes.items():
        k = k.replace("winpe_", "")
        _codetext = ",".join([hex(x) for x in v])
        srctext = re.sub("g_" + k + r"_code(.+?)(\{0x90\})",
            "g_" + +  r"_code\1{" + _codetext +"}", srctext)
    with open(targetpath, "wb") as fp:
        fp.write(srctext.encode('utf8'))
def inject_shellcodestubs(srcpath, libwinpepath, targetpath):
    pedll = lief.parse(libwinpepath)
    pedll_oph = pedll.optional_header
 
    # generate oepint shellcode
    if pedll_oph.magic == lief.PE.PE_TYPE.PE32_PLUS:
        oepinit_code = gen_oepinit_code64()
        pass
    elif pedll_oph.magic == lief.PE.PE_TYPE.PE32:
        oepinit_code = gen_oepinit_code32()
        pass
    else:
        print("error invalid pe magic!", pedll_oph.magic)
        return
 
    # find necessary functions
    FUNC_SIZE =0x400
    codes = {"winpe_memreloc": 0,
        "winpe_membindiat": 0,
        "winpe_membindtls": 0,
        "winpe_findloadlibrarya": 0,
        "winpe_findgetprocaddress": 0}
    for k in codes.keys():
        func = next(filter(lambda e : e.name == k,
            pedll.exported_functions))
        codes[k] = pedll.get_content_from_virtual_address(
            func.address, FUNC_SIZE)
    codes['winpe_oepinit'] = oepinit_code
 
    # write shellcode to c source file
    with open(srcpath, "rb") as fp:
        srctext = fp.read().decode('utf8')
    for k, v in codes.items():
        k = k.replace("winpe_", "")
        _codetext = ",".join([hex(x) for x in v])
        srctext = re.sub("g_" + k + r"_code(.+?)(\{0x90\})",
            "g_" + +  r"_code\1{" + _codetext +"}", srctext)
    with open(targetpath, "wb") as fp:
        fp.write(srctext.encode('utf8'))
 
inline size_t STDCALL winpe_memload(
    const void *rawpe, size_t rawsize,
    void *mempe, size_t memsize,
    bool_t same_align)
{
    // load rawpe to memalign
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)rawpe;
    PIMAGE_NT_HEADERS  pNtHeader = (PIMAGE_NT_HEADERS)
        ((void*)rawpe + pDosHeader->e_lfanew);
    PIMAGE_FILE_HEADER pFileHeader = &pNtHeader->FileHeader;
    PIMAGE_OPTIONAL_HEADER pOptHeader = &pNtHeader->OptionalHeader;
    PIMAGE_SECTION_HEADER pSectHeader = (PIMAGE_SECTION_HEADER)
        ((void *)pOptHeader + pFileHeader->SizeOfOptionalHeader);
    WORD sectNum = pFileHeader->NumberOfSections;
    size_t imagesize = pOptHeader->SizeOfImage;
    if(!mempe) return imagesize;
    else if(memsize!=0 && memsize<imagesize) return 0;
 
    _inl_memset(mempe, 0, imagesize);
    _inl_memcpy(mempe, rawpe, pOptHeader->SizeOfHeaders);
 
    for(WORD i=0;i<sectNum;i++)
    {
        _inl_memcpy(mempe+pSectHeader[i].VirtualAddress,
            rawpe+pSectHeader[i].PointerToRawData,
            pSectHeader[i].SizeOfRawData);
    }
 
    // adjust all to mem align
    if(same_align)
    {
        pDosHeader = (PIMAGE_DOS_HEADER)mempe;
        pNtHeader = (PIMAGE_NT_HEADERS)((void*)mempe + pDosHeader->e_lfanew);
        pFileHeader = &pNtHeader->FileHeader;
        pOptHeader = &pNtHeader->OptionalHeader;
        pSectHeader = (PIMAGE_SECTION_HEADER)
            ((void *)pOptHeader + pFileHeader->SizeOfOptionalHeader);
        sectNum = pFileHeader->NumberOfSections;
 
        pOptHeader->FileAlignment = pOptHeader->SectionAlignment;
 
        for(WORD i=0;i<sectNum;i++)
        {
            pSectHeader[i].PointerToRawData = pSectHeader[i].VirtualAddress;
        }
    }
    return imagesize;
}
inline size_t STDCALL winpe_memload(
    const void *rawpe, size_t rawsize,
    void *mempe, size_t memsize,
    bool_t same_align)
{
    // load rawpe to memalign
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)rawpe;
    PIMAGE_NT_HEADERS  pNtHeader = (PIMAGE_NT_HEADERS)
        ((void*)rawpe + pDosHeader->e_lfanew);
    PIMAGE_FILE_HEADER pFileHeader = &pNtHeader->FileHeader;
    PIMAGE_OPTIONAL_HEADER pOptHeader = &pNtHeader->OptionalHeader;
    PIMAGE_SECTION_HEADER pSectHeader = (PIMAGE_SECTION_HEADER)
        ((void *)pOptHeader + pFileHeader->SizeOfOptionalHeader);
    WORD sectNum = pFileHeader->NumberOfSections;
    size_t imagesize = pOptHeader->SizeOfImage;
    if(!mempe) return imagesize;
    else if(memsize!=0 && memsize<imagesize) return 0;
 
    _inl_memset(mempe, 0, imagesize);
    _inl_memcpy(mempe, rawpe, pOptHeader->SizeOfHeaders);
 
    for(WORD i=0;i<sectNum;i++)
    {
        _inl_memcpy(mempe+pSectHeader[i].VirtualAddress,
            rawpe+pSectHeader[i].PointerToRawData,
            pSectHeader[i].SizeOfRawData);
    }
 
    // adjust all to mem align
    if(same_align)
    {
        pDosHeader = (PIMAGE_DOS_HEADER)mempe;
        pNtHeader = (PIMAGE_NT_HEADERS)((void*)mempe + pDosHeader->e_lfanew);
        pFileHeader = &pNtHeader->FileHeader;
        pOptHeader = &pNtHeader->OptionalHeader;
        pSectHeader = (PIMAGE_SECTION_HEADER)
            ((void *)pOptHeader + pFileHeader->SizeOfOptionalHeader);
        sectNum = pFileHeader->NumberOfSections;
 
        pOptHeader->FileAlignment = pOptHeader->SectionAlignment;
 
        for(WORD i=0;i<sectNum;i++)
        {
            pSectHeader[i].PointerToRawData = pSectHeader[i].VirtualAddress;
        }
    }
    return imagesize;
}
inline size_t STDCALL winpe_memreloc(
    void *mempe, size_t newimagebase)
{
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mempe;
    PIMAGE_NT_HEADERS  pNtHeader = (PIMAGE_NT_HEADERS)
        ((void*)mempe + pDosHeader->e_lfanew);
    PIMAGE_FILE_HEADER pFileHeader = &pNtHeader->FileHeader;
    PIMAGE_OPTIONAL_HEADER pOptHeader = &pNtHeader->OptionalHeader;
    PIMAGE_DATA_DIRECTORY pDataDirectory = pOptHeader->DataDirectory;
    PIMAGE_DATA_DIRECTORY pRelocEntry = &pDataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
 
    DWORD reloc_count = 0;
    DWORD reloc_offset = 0;
    int64_t shift = (int64_t)newimagebase -
        (int64_t)pOptHeader->ImageBase;
    while (reloc_offset < pRelocEntry->Size)
    {
        PIMAGE_BASE_RELOCATION pBaseReloc = (PIMAGE_BASE_RELOCATION)
            ((void*)mempe + pRelocEntry->VirtualAddress + reloc_offset);
        PRELOCOFFSET pRelocOffset = (PRELOCOFFSET)((void*)pBaseReloc
            + sizeof(IMAGE_BASE_RELOCATION));
        // RELOCOFFSET block num
        DWORD item_num = (pBaseReloc->SizeOfBlock -
            sizeof(IMAGE_BASE_RELOCATION)) / sizeof(RELOCOFFSET);
        for (size_t i = 0; i < item_num; i++)
        {
            if (!pRelocOffset[i].type &&
                !pRelocOffset[i].offset) continue;
            DWORD targetoffset = pBaseReloc->VirtualAddress +
                    pRelocOffset[i].offset;
            size_t *paddr = (size_t *)((void*)mempe + targetoffset);
            size_t relocaddr = (size_t)((int64_t)*paddr + shift);
            *paddr = relocaddr;
        }
        reloc_offset += sizeof(IMAGE_BASE_RELOCATION) +
            sizeof(RELOCOFFSET) * item_num;
        reloc_count += item_num;
    }
    pOptHeader->ImageBase = newimagebase;
    return reloc_count;
}
inline size_t STDCALL winpe_memreloc(
    void *mempe, size_t newimagebase)
{
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mempe;
    PIMAGE_NT_HEADERS  pNtHeader = (PIMAGE_NT_HEADERS)
        ((void*)mempe + pDosHeader->e_lfanew);
    PIMAGE_FILE_HEADER pFileHeader = &pNtHeader->FileHeader;
    PIMAGE_OPTIONAL_HEADER pOptHeader = &pNtHeader->OptionalHeader;
    PIMAGE_DATA_DIRECTORY pDataDirectory = pOptHeader->DataDirectory;
    PIMAGE_DATA_DIRECTORY pRelocEntry = &pDataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
 
    DWORD reloc_count = 0;
    DWORD reloc_offset = 0;
    int64_t shift = (int64_t)newimagebase -
        (int64_t)pOptHeader->ImageBase;
    while (reloc_offset < pRelocEntry->Size)
    {
        PIMAGE_BASE_RELOCATION pBaseReloc = (PIMAGE_BASE_RELOCATION)
            ((void*)mempe + pRelocEntry->VirtualAddress + reloc_offset);
        PRELOCOFFSET pRelocOffset = (PRELOCOFFSET)((void*)pBaseReloc
            + sizeof(IMAGE_BASE_RELOCATION));
        // RELOCOFFSET block num
        DWORD item_num = (pBaseReloc->SizeOfBlock -
            sizeof(IMAGE_BASE_RELOCATION)) / sizeof(RELOCOFFSET);
        for (size_t i = 0; i < item_num; i++)
        {
            if (!pRelocOffset[i].type &&
                !pRelocOffset[i].offset) continue;
            DWORD targetoffset = pBaseReloc->VirtualAddress +
                    pRelocOffset[i].offset;
            size_t *paddr = (size_t *)((void*)mempe + targetoffset);
            size_t relocaddr = (size_t)((int64_t)*paddr + shift);
            *paddr = relocaddr;
        }
        reloc_offset += sizeof(IMAGE_BASE_RELOCATION) +
            sizeof(RELOCOFFSET) * item_num;
        reloc_count += item_num;
    }
    pOptHeader->ImageBase = newimagebase;
    return reloc_count;
}
 
WINPEDEF WINPE_EXPORT
inline size_t STDCALL winpe_membindiat(void *mempe,
    PFN_LoadLibraryA pfnLoadLibraryA,
    PFN_GetProcAddress pfnGetProcAddress)
{
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mempe;
    PIMAGE_NT_HEADERS  pNtHeader = (PIMAGE_NT_HEADERS)
        ((void*)mempe + pDosHeader->e_lfanew);
    PIMAGE_FILE_HEADER pFileHeader = &pNtHeader->FileHeader;
    PIMAGE_OPTIONAL_HEADER pOptHeader = &pNtHeader->OptionalHeader;
    PIMAGE_DATA_DIRECTORY pDataDirectory = pOptHeader->DataDirectory;
    PIMAGE_DATA_DIRECTORY pImpEntry = 
        &pDataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
    PIMAGE_IMPORT_DESCRIPTOR pImpDescriptor = 
        (PIMAGE_IMPORT_DESCRIPTOR)(mempe + pImpEntry->VirtualAddress);
 
    PIMAGE_THUNK_DATA pFtThunk = NULL;
    PIMAGE_THUNK_DATA pOftThunk = NULL;
    LPCSTR pDllName = NULL;
    PIMAGE_IMPORT_BY_NAME pImpByName = NULL;
    size_t funcva = 0;
    char *funcname = NULL;
 
    // origin GetProcAddress will crash at InitializeSListHead
    if(!pfnLoadLibraryA) pfnLoadLibraryA =
        (PFN_LoadLibraryA)winpe_findloadlibrarya();
    if(!pfnGetProcAddress) pfnGetProcAddress =
        (PFN_GetProcAddress)winpe_findgetprocaddress();
 
    DWORD iat_count = 0;
    for (; pImpDescriptor->Name; pImpDescriptor++)
    {
        pDllName = (LPCSTR)(mempe + pImpDescriptor->Name);
        pFtThunk = (PIMAGE_THUNK_DATA)
            (mempe + pImpDescriptor->FirstThunk);
        pOftThunk = (PIMAGE_THUNK_DATA)
            (mempe + pImpDescriptor->OriginalFirstThunk);
        size_t dllbase = (size_t)pfnLoadLibraryA(pDllName);
        if(!dllbase) return 0;
 
        for (int j=0; pFtThunk[j].u1.Function
            &&  pOftThunk[j].u1.Function; j++)
        {
            size_t _addr = (size_t)(mempe + pOftThunk[j].u1.AddressOfData);
            if(sizeof(size_t)>4) // x64
            {
                if((_addr>>63) == 1)
                {
                    funcname = (char *)(_addr & 0xffff);
                }
                else
                {
                    pImpByName=(PIMAGE_IMPORT_BY_NAME)_addr;
                    funcname = pImpByName->Name;
                }
            }
            else
            {
                if(((size_t)pImpByName>>31) == 1)
                {
                    funcname = (char *)(_addr & 0xffff);
                }
                else
                {
                    pImpByName=(PIMAGE_IMPORT_BY_NAME)_addr;
                    funcname = pImpByName->Name;
                }
            }
 
            funcva = (size_t)pfnGetProcAddress(
                (HMODULE)dllbase, funcname);
            if(!funcva) continue;
            pFtThunk[j].u1.Function = funcva;
            assert(funcva == (size_t)GetProcAddress(
                (HMODULE)dllbase, funcname));
            iat_count++;
        }
    }
    return iat_count;
}
WINPEDEF WINPE_EXPORT
inline size_t STDCALL winpe_membindiat(void *mempe,
    PFN_LoadLibraryA pfnLoadLibraryA,
    PFN_GetProcAddress pfnGetProcAddress)
{
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mempe;
    PIMAGE_NT_HEADERS  pNtHeader = (PIMAGE_NT_HEADERS)
        ((void*)mempe + pDosHeader->e_lfanew);
    PIMAGE_FILE_HEADER pFileHeader = &pNtHeader->FileHeader;
    PIMAGE_OPTIONAL_HEADER pOptHeader = &pNtHeader->OptionalHeader;
    PIMAGE_DATA_DIRECTORY pDataDirectory = pOptHeader->DataDirectory;
    PIMAGE_DATA_DIRECTORY pImpEntry = 
        &pDataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
    PIMAGE_IMPORT_DESCRIPTOR pImpDescriptor = 
        (PIMAGE_IMPORT_DESCRIPTOR)(mempe + pImpEntry->VirtualAddress);
 
    PIMAGE_THUNK_DATA pFtThunk = NULL;
    PIMAGE_THUNK_DATA pOftThunk = NULL;
    LPCSTR pDllName = NULL;
    PIMAGE_IMPORT_BY_NAME pImpByName = NULL;
    size_t funcva = 0;
    char *funcname = NULL;
 
    // origin GetProcAddress will crash at InitializeSListHead
    if(!pfnLoadLibraryA) pfnLoadLibraryA =
        (PFN_LoadLibraryA)winpe_findloadlibrarya();
    if(!pfnGetProcAddress) pfnGetProcAddress =
        (PFN_GetProcAddress)winpe_findgetprocaddress();
 
    DWORD iat_count = 0;
    for (; pImpDescriptor->Name; pImpDescriptor++)
    {
        pDllName = (LPCSTR)(mempe + pImpDescriptor->Name);
        pFtThunk = (PIMAGE_THUNK_DATA)
            (mempe + pImpDescriptor->FirstThunk);
        pOftThunk = (PIMAGE_THUNK_DATA)
            (mempe + pImpDescriptor->OriginalFirstThunk);
        size_t dllbase = (size_t)pfnLoadLibraryA(pDllName);
        if(!dllbase) return 0;
 
        for (int j=0; pFtThunk[j].u1.Function
            &&  pOftThunk[j].u1.Function; j++)
        {
            size_t _addr = (size_t)(mempe + pOftThunk[j].u1.AddressOfData);
            if(sizeof(size_t)>4) // x64
            {
                if((_addr>>63) == 1)
                {
                    funcname = (char *)(_addr & 0xffff);
                }
                else
                {
                    pImpByName=(PIMAGE_IMPORT_BY_NAME)_addr;
                    funcname = pImpByName->Name;
                }
            }
            else
            {
                if(((size_t)pImpByName>>31) == 1)
                {
                    funcname = (char *)(_addr & 0xffff);
                }
                else
                {
                    pImpByName=(PIMAGE_IMPORT_BY_NAME)_addr;
                    funcname = pImpByName->Name;
                }
            }
 
            funcva = (size_t)pfnGetProcAddress(
                (HMODULE)dllbase, funcname);
            if(!funcva) continue;
            pFtThunk[j].u1.Function = funcva;
            assert(funcva == (size_t)GetProcAddress(
                (HMODULE)dllbase, funcname));
            iat_count++;
        }
    }
    return iat_count;
}
// initial memory module
if(!winpe_memreloc((void*)imagebase, imagebase))
    return NULL;
if(!winpe_membindiat((void*)imagebase,
    pfnLoadLibraryA, pfnGetProcAddress)) return NULL;
winpe_membindtls(mempe, DLL_PROCESS_ATTACH);
PFN_DllMain pfnDllMain = (PFN_DllMain)
    (imagebase + winpe_oepval((void*)imagebase, 0));
pfnDllMain((HINSTANCE)imagebase, DLL_PROCESS_ATTACH, NULL);
return (void*)imagebase;
// initial memory module
if(!winpe_memreloc((void*)imagebase, imagebase))
    return NULL;
if(!winpe_membindiat((void*)imagebase,
    pfnLoadLibraryA, pfnGetProcAddress)) return NULL;
winpe_membindtls(mempe, DLL_PROCESS_ATTACH);
PFN_DllMain pfnDllMain = (PFN_DllMain)
    (imagebase + winpe_oepval((void*)imagebase, 0));
pfnDllMain((HINSTANCE)imagebase, DLL_PROCESS_ATTACH, NULL);
return (void*)imagebase;
inline size_t STDCALL winpe_membindtls(void *mempe, DWORD resaon)
{
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mempe;
    PIMAGE_NT_HEADERS  pNtHeader = (PIMAGE_NT_HEADERS)
        ((void*)mempe + pDosHeader->e_lfanew);
    PIMAGE_FILE_HEADER pFileHeader = &pNtHeader->FileHeader;
    PIMAGE_OPTIONAL_HEADER pOptHeader = &pNtHeader->OptionalHeader;
    PIMAGE_DATA_DIRECTORY pDataDirectory = pOptHeader->DataDirectory;
    PIMAGE_DATA_DIRECTORY pTlsDirectory =
        &pDataDirectory[IMAGE_DIRECTORY_ENTRY_TLS];
    if(!pTlsDirectory->VirtualAddress) return 0;
 
    size_t tls_count = 0;
    PIMAGE_TLS_DIRECTORY pTlsEntry = (PIMAGE_TLS_DIRECTORY)
        (mempe + pTlsDirectory->VirtualAddress);
    PIMAGE_TLS_CALLBACK *tlscb= (PIMAGE_TLS_CALLBACK*)
        pTlsEntry->AddressOfCallBacks;
    if(tlscb)
    {
        while(*tlscb)
        {
            (*tlscb)(mempe, reason, NULL);
            tlscb++;
            tls_count++;
        }
    }
    return tls_count;
}
inline size_t STDCALL winpe_membindtls(void *mempe, DWORD resaon)
{
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mempe;

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 21
支持
分享
最新回复 (30)
雪    币: 7309
活跃值: (3788)
能力值: (RANK:1130 )
在线值:
发帖
回帖
粉丝
2
x64里面的dll,支持异常处理嘛?
2022-3-29 21:24
0
雪    币: 1641
活跃值: (3601)
能力值: (RANK:15 )
在线值:
发帖
回帖
粉丝
3
海风月影 x64里面的dll,支持异常处理嘛?
按帖子内容来看并没有,应该追求的基本就是能用就ok
2022-3-29 21:39
0
雪    币: 6296
活跃值: (4962)
能力值: ( LV12,RANK:250 )
在线值:
发帖
回帖
粉丝
4
海风月影 x64里面的dll,支持异常处理嘛?
seh异常处理我没试过,因为主要目标是为了汉化直接把dll付在exe附加段上,你可以试试seh有没有问题。
2022-3-29 22:35
0
雪    币: 6296
活跃值: (4962)
能力值: ( LV12,RANK:250 )
在线值:
发帖
回帖
粉丝
5
はつゆき 按帖子内容来看并没有,应该追求的基本就是能用就ok
我也不太清楚异常是不是需要特殊处理。就我自己的测试,64位yuzu模拟器的exe,把dll附加到exe程序里测试通过。
2022-3-29 22:36
0
雪    币: 6664
活跃值: (957)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
学习占位
2022-3-30 06:30
0
雪    币: 6124
活跃值: (4646)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
7
汉化竟然也这么卷了吗
2022-3-30 09:08
0
雪    币: 1641
活跃值: (3601)
能力值: (RANK:15 )
在线值:
发帖
回帖
粉丝
8
devseed 我也不太清楚异常是不是需要特殊处理。就我自己的测试,64位yuzu模拟器的exe,把dll附加到exe程序里测试通过。
异常是需要额外处理的,不过相比之下,资源的处理才是最麻烦的
2022-3-30 09:35
0
雪    币: 1102
活跃值: (4182)
能力值: ( LV5,RANK:69 )
在线值:
发帖
回帖
粉丝
9
汉化都这么高级了,666
2022-3-30 11:21
0
雪    币: 4
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
10
博主优秀啊
2022-3-30 12:01
0
雪    币: 576
活跃值: (2035)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
开源的貌似就MemoryModulePP最全,支持异常和线程局部存储,但是代码不简洁。不管线程局部存储的话,改改MemoryModule原版处理下异常就好。
2022-3-30 12:58
0
雪    币: 1042
活跃值: (495)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
那个py不太会用 没环境
2022-3-30 13:01
0
雪    币: 300
活跃值: (2447)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
mark
2022-3-30 13:53
0
雪    币: 6296
活跃值: (4962)
能力值: ( LV12,RANK:250 )
在线值:
发帖
回帖
粉丝
14
Rookietp 那个py不太会用 没环境[em_5]
py只是为了方便生成shellcode,只是内存加载dll,其实只用winpe.h就行了。
2022-3-30 14:52
0
雪    币: 6296
活跃值: (4962)
能力值: ( LV12,RANK:250 )
在线值:
发帖
回帖
粉丝
15
kakasasa 开源的貌似就MemoryModulePP最全,支持异常和线程局部存储,但是代码不简洁。不管线程局部存储的话,改改MemoryModule原版处理下异常就好。
是的,我一开始也想改github上的MemoryModule,但是发现他里面好多直接用系统api调用的,想改成shellcode引导不太方便。
2022-3-30 14:55
0
雪    币: 1795
活跃值: (3995)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
不错不错

这里注意有个坑点,有的导出表项会forward到其他dll上,如kernel32!InitializeSListHead -> 
NTDLL!RtlInitializeSListHead,详见crashing-kernel32-initializeslisthead。通过DirRVA < FuncRVA < DirRVA + ExportSize来判断是否forward。

这种 forward 很讨厌,曾经也被坑过...



2022-3-31 12:48
0
雪    币: 1541
活跃值: (1613)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
内存加载MFC的DLL好像还需要特殊处理一下吧,要挂钩几个API
2022-3-31 13:54
0
雪    币: 2325
活跃值: (4863)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
msvc 报错啊··········
2022-4-4 12:08
0
雪    币: 2325
活跃值: (4863)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
1>\winpe.h(708,76): error C2036: “void *”: 未知的大小
1>\winpe.h(712,68): error C2036: “void *”: 未知的大小
1>\winpe.h(731,45): error C2036: “void *”: 未知的大小
1>\winpe.h(744,57): error C2036: “void *”: 未知的大小
winpe.h(775,45): error C2036: “void *”: 未知的大小

很多这个···
2022-4-4 12:28
0
雪    币: 23
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
20

    说到降低耦合,嘿嘿,我可有精神了

    只需要继承CMappingPe类,并覆盖protect里的几个虚函数,即可在r3 or r0使用。不过跨进程不会选在R3。

    话说R0 怎么处理seh啊。

2022-4-6 11:45
0
雪    币: 6296
活跃值: (4962)
能力值: ( LV12,RANK:250 )
在线值:
发帖
回帖
粉丝
21
大魔法狮子 &nbsp;&nbsp;&nbsp;&nbsp;说到降低耦合,嘿嘿,我可有精神了&nbsp;&nbsp;&nbsp;&nbsp;只需要继 ...
一般来说内核态很少用c++开发吧? 用c++有个麻烦事,动态LoadLibrary的符号问题不好解决。seh我也想知道怎么处理的,没有遇到过对应的样本。
2022-4-9 17:54
0
雪    币: 6296
活跃值: (4962)
能力值: ( LV12,RANK:250 )
在线值:
发帖
回帖
粉丝
22
值得怀疑 1>\winpe.h(708,76): error C2036: “void *”: 未知的大小 1>\winpe.h(712,68): error C2036: “void *”: 未 ...
我开发是用clang编译的,还没试过msvc,是不是msvc不支持void*指针相加?
2022-4-9 18:02
0
雪    币: 23
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
23
devseed 一般来说内核态很少用c++开发吧? 用c++有个麻烦事,动态LoadLibrary的符号问题不好解决。seh我也想知道怎么处理的,没有遇到过对应的样本。
这简单,同样内存加载一份,计算rva,然后取模块地址。我说的是顺便r0加载驱动。
2022-4-14 10:50
0
雪    币: 23
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
24
devseed 我开发是用clang编译的,还没试过msvc,是不是msvc不支持void*指针相加?
支持吧
2022-4-14 10:51
0
雪    币: 10585
活跃值: (2274)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
py没有这个环境 能不能用C实现下 生成shellcode 谢谢
2022-10-22 17:11
0
游客
登录 | 注册 方可回帖
返回
//