WindowsPE文件格式入门05.PE加载器LoadPE

news2025/4/7 18:41:53

https://bpsend.net/thread-316-1-1.html

LoadPE - pe 加载器 壳的前身

如果想访问一个程序运行起来的内存,一种方法就是跨进程读写内存,但是跨进程读写内存需要来回调用api,不如直接访问地址来得方便,那么如果我们需要直接访问地址,该怎么做呢?.需要把dll注进程,注进去的代码跟他在同一块进程里面,这样我们就可以直接访问这个进程的地址,但是不想注入,也不想跨进程读写地址,就直接读进程地址,有什么方法呢?如果把导入表里面加一个dll,这样很容易检查出来,模块里一遍历,就可容易看到了, 其实我们可以反其道行之,换种思路,不是往他进程里面塞东西,而是把他加载到我们进程里面.,这个时候再去访问进程内存其实就是访问我们自己的内存.
1.系统加载exe的流程
  • 准备一个新的内存;
  • 按照顺序把节表内容映射进内存;
  • 填写导入表。
2.LoadPE的目的
  • 可以在自己进程更改目标PE的内存。
3.LoadPE的重点
  • 1.在自己代码前留出足够空间--目标进程的SizeofImage;
  • 2.更改自己程序的ImageBase加载到目标ImageBase处:/base:0x。

img

这样,目标进程的PE头就占据了我们自己进程的 PE头,他的数据节就覆盖了我们自己的数据节,即目标进程的数据就会覆盖我们自己进程的数据,因此我们需要 把我们的代码往后移,给 目标进程 留出足够的空间

4.LoadPE的实现思路
  • 设置我们进程的 ImageBase 和 目标进程 ImageBase 保持一致
  • 我们需要把我们的代码往后移,腾出来的内存可以放目标程序
  • 读目标进程的数据,按照节表拷贝数据帮他处理导入表
  • 执行目标进程代码。
5.LoadPE的汇编实现
  1. 用winhex查看目标进程的 ImageBase 和 SizeofImage
  2. 新建工程,并且在工程选项设置 自己工程 的 ImageBase 与目标进程的一致
  3. 后移自己的代码,可以在开头定义 SizeofImage 大小的全局变量 或者通过指令 org 偏移调整指令

注意,很多 C 库函数 并不会 保存 ecx , edx 环境,自己使用前记得先保存

进程的模块基址和 数据大小可以通过 winhex看

img

.586
.model flat,stdcall
option casemap:none

   include windows.inc
   include user32.inc
   include kernel32.inc
   include msvcrt.inc

   includelib user32.lib
   includelib kernel32.lib
   includelib msvcrt.lib

IMAGE_SIZE equ 20000h     ;往后移的大小,即目标进程的SizeofImage


.data
    g_szFile db "winmine.exe", 0    ;要读取的进程

.code
    org IMAGE_SIZE 


LoadPe proc
    LOCAL @dwImageBase:DWORD       ;自己进程的模块基址
    LOCAL @hFile:HANDLE            ;文件句柄
    LOCAL @hFileMap:HANDLE         ;映射句柄
    LOCAL @pPEBuf:LPVOID           ;映射文件的缓冲地址
    LOCAL @pDosHdr:ptr IMAGE_DOS_HEADER      ;目标进程的dos头
    LOCAL @pNTHdr:ptr IMAGE_NT_HEADERS       ;目标进程的NT头
    LOCAL @pSecHdr:ptr IMAGE_SECTION_HEADER  ;目标进程的节表
    LOCAL @dwNumOfSecs:DWORD                 ;目标进程的节表数量
    LOCAL @pImpHdr:ptr IMAGE_IMPORT_DESCRIPTOR   ;目标进程的导入表
    LOCAL @dwSizeOfHeaders:DWORD                 ;目标进程的选项头大小
    LOCAL @dwOldProc:DWORD                       ;旧的内存属性
    LOCAL @hdrZeroImp:IMAGE_IMPORT_DESCRIPTOR    ;导入表结束标志,所有项全0
    LOCAL @hDll:HMODULE                          ;加载dll的句柄
    LOCAL @dwOep:DWORD                           ;进程的入口地址

    ;判断导入表结束的标志清0
    invoke RtlZeroMemory, addr @hdrZeroImp, size IMAGE_IMPORT_DESCRIPTOR

    ;自己的模块基址
    invoke GetModuleHandle, NULL
    mov @dwImageBase, eax


    ;解析PE文件,获取表

    ;打开文件
    invoke CreateFile, offset g_szFile, GENERIC_READ, FILE_SHARE_READ,NULL, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, NULL
    ;check ....
    mov @hFile, eax   ;保存文件句柄

    invoke CreateFileMapping, @hFile, NULL, PAGE_READONLY, 0, 0, NULL   ;创建文件映射
    ;check
    mov @hFileMap, eax    ;创建文件映射句柄

    invoke MapViewOfFile, @hFileMap, FILE_MAP_READ, 0, 0, 0      ;将整个文件映射进内存
    ;check 
    mov @pPEBuf, eax      ;保存映射文件内存的地址

    ;解析目标进程

    ;目标进程的 dos 头
    mov eax, @pPEBuf    
    mov @pDosHdr, eax

    ;目标进程的 nt头
    mov esi, @pDosHdr
    assume esi:ptr IMAGE_DOS_HEADER
    mov eax, @pPEBuf
    add eax, [esi].e_lfanew   ;获取nt头的偏移地址
    mov @pNTHdr, eax


    mov esi, @pNTHdr
    assume esi:ptr IMAGE_NT_HEADERS

    ;选项头信息
    mov eax, [esi].OptionalHeader.SizeOfHeaders    ;获取选项头大小
    mov @dwSizeOfHeaders, eax

    ;进程的入口地址  =  进程的内存偏移地址 + 模块基址
    mov eax, [esi].OptionalHeader.AddressOfEntryPoint
    add eax, @dwImageBase
    mov @dwOep, eax


    ;节表  地址: 选项头地址+大小
    movzx eax, [esi].FileHeader.NumberOfSections
    mov @dwNumOfSecs,eax

    lea ebx, [esi].OptionalHeader

    ;获取选项头大小:用于定位节表位置=选项头地址+选项头大小
    movzx eax, [esi].FileHeader.SizeOfOptionalHeader   ;把 word 转为 dword
    add eax, ebx
    mov @pSecHdr, eax   ;保存节表地址


    ;修改内存属性
    invoke VirtualProtect, @dwImageBase, IMAGE_SIZE, PAGE_EXECUTE_READWRITE, addr @dwOldProc

    ;拷贝PE头  从映射内存拷贝到 自己进程的最开始处 
    invoke crt_memcpy, @dwImageBase, @pPEBuf, @dwSizeOfHeaders


    ;按照节表,拷贝节区数据
    mov esi, @pSecHdr
    assume esi:ptr IMAGE_SECTION_HEADER
    xor ecx, ecx
    .while ecx < @dwNumOfSecs   ;遍历节表
        ;目标
        mov edi, @dwImageBase
        add edi, [esi].VirtualAddress  ;获取节的内存地址 + 模块地址 就是内存中的绝对地址

        ;源
        mov ebx, @pPEBuf
        add ebx, [esi].PointerToRawData  ;获取指定进程的节数据的偏移地址  映射的首地址 + 文件偏移地址

        ;大小[esi].SizeOfRawData

        ;拷贝  注意,很多 C 库函数 并不会 保存 ecx ,edx 环境,自己使用前记得先保存
        push ecx
        push edx
        invoke crt_memcpy, edi, ebx, [esi].SizeOfRawData   ;将目标进程的节数据拷贝进自己的进程
        pop edx
        pop ecx

        inc ecx      ;计数++
        add esi, size IMAGE_SECTION_HEADER  ;指针移动
    .endw

    ;获取导入表  如果在前面获取导入表信息,那么就需要对内存地址和文件地址做转化比较麻烦
                ;但是把数据拷贝到我们进程之后只需要访问内存进程就可以了
    mov esi, @pNTHdr
    assume esi:ptr IMAGE_NT_HEADERS

    ;获取导入表地址 ,数组的第二个元素的第一个成员 
    mov eax, [esi].OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT*8].VirtualAddress
    add eax, @dwImageBase   ;获取导入表在进程的绝对地址  内存偏移 + 模块基址
    mov @pImpHdr, eax       ;保存导入表的地址

    ;处理导入表
    mov esi, @pImpHdr
    assume esi:ptr IMAGE_IMPORT_DESCRIPTOR

    .while TRUE     ;遍历导入表

        ;判断结束,全0项结束
        invoke crt_memcmp, esi, addr @hdrZeroImp
        .if eax == 0
            .break
        .endif


        ;判断字段,为空则结束
        .if [esi].Name1 == NULL || [esi].FirstThunk == NULL
            .break
        .endif 


       ;加载dll
        mov eax, [esi].Name1
        add eax, @dwImageBase
        push ecx
        push edx
        invoke LoadLibrary, eax   ;根据dll名加载 dll 
        pop edx
        pop ecx
        ;check              如果此时为空加说明无法找到dll
        mov @hDll, eax      ;保存dll的模句柄

        ;获取导入地址表,IAT
        mov ebx, [esi].FirstThunk
        add ebx, @dwImageBase

        ;获取导入名称表,INT
        mov edi, ebx
        .if [esi].OriginalFirstThunk != NULL
            mov edi, [esi].OriginalFirstThunk
            add edi, @dwImageBase          
        .endif


        ;遍历导入名称表
        .while dword ptr [edi] != 0

            .if dword ptr [edi] & 80000000h   ;判断最高位是否为1
                ;序号导入,获取序号
                mov edx, dword ptr [edi]
                and edx, 0ffffh               ;获取低 word 
            .else
                ;名称导入
                mov edx, dword ptr [edi]
                add edx, @dwImageBase
                add edx, 2                  ;名称前面有2个无用字节
            .endif

            ;获取dll导入函数进程加载后地址
            push ecx
            push edx
            invoke GetProcAddress, @hDll, edx
            pop edx
            pop ecx
            ;check

            ;把地址存入 INT 表
            mov dword ptr [ebx], eax

            add ebx, 4
            add edi, 4
        .endw


        add esi, size IMAGE_IMPORT_DESCRIPTOR
    .endw

     ;清理
    invoke UnmapViewOfFile,@pPEBuf
    invoke CloseHandle,@hFileMap
    invoke CloseHandle,@hFile

    ; 执行加载的pe的代码
    jmp @dwOep

    ret

LoadPe endp

start:
    invoke LoadPe
    invoke ExitProcess,0

end start

需要合并节

.text,ERW

img

C++版:

#include <windows.h>
#include <concrt.h>
#include <iostream>
using namespace std;

#define IMAGE_SIZE 0x5000


//留空的全局变量
char szBuff[IMAGE_SIZE] = { 1 };

#if 1
char g_szExeName[] = "PE.exe";  //需要加载的PE路径




LPVOID lpMapAddr = NULL;

HANDLE LoadPe()
{
    DWORD  dwOldProc = 0;
    PIMAGE_IMPORT_DESCRIPTOR pImpHdr = NULL;
    IMAGE_IMPORT_DESCRIPTOR  zeroImp = { 0 };
    HANDLE hDll = NULL;
    PIMAGE_THUNK_DATA pTmpThunk = NULL;
    DWORD  dwPFNAddr = 0;
    DWORD  dwIAT = 0;

    // 获取模块句柄
    HANDLE hInst = GetModuleHandle(NULL);

    // 读取文件
    HANDLE hFile = CreateFile(g_szExeName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
    {
        return 0;
    }

    // 创建文件映射对象
    HANDLE hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
    if (hFileMap == NULL)
    {
        CloseHandle(hFile);
        return 0;
    }

    void* lpMapAddr = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
    if (lpMapAddr == NULL)
    {
        CloseHandle(hFileMap);
        CloseHandle(hFile);
        return 0;
    }

    // 拷贝PE头
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)lpMapAddr;
    PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((DWORD)lpMapAddr + pDosHeader->e_lfanew);

    DWORD dwSizeOfHeaders = pNtHeader->OptionalHeader.SizeOfHeaders;
    DWORD dwNumOfSection = pNtHeader->FileHeader.NumberOfSections;

    //获取节表首地址  (选项头地址+ 大小)
    PIMAGE_SECTION_HEADER pSecHdr = (PIMAGE_SECTION_HEADER)((DWORD)pNtHeader->FileHeader.SizeOfOptionalHeader + (DWORD)(&pNtHeader->OptionalHeader));

    DWORD dwOep = (DWORD)hInst + pNtHeader->OptionalHeader.AddressOfEntryPoint;

    // 更改内存属性
    VirtualProtect(hInst, IMAGE_SIZE, PAGE_EXECUTE_READWRITE, &dwOldProc);

    //拷贝PE头
    memcpy(hInst, lpMapAddr, dwSizeOfHeaders);

    // 拷贝拷贝节区数据
    DWORD i = 0;
    while (dwNumOfSection > i)
    {
        //拷贝数据
        DWORD pDst = (DWORD)hInst + (DWORD)pSecHdr->VirtualAddress;
        DWORD pSrc = (DWORD)lpMapAddr + (DWORD)pSecHdr->PointerToRawData;
        //DWORD pSrc = (DWORD)pSecHdr;
        memcpy((void*)pDst, (void*)pSrc, pSecHdr->SizeOfRawData);
        int nSecHdrSzie = sizeof(IMAGE_SECTION_HEADER);

        pSecHdr = (PIMAGE_SECTION_HEADER)((DWORD)pSecHdr + (DWORD)nSecHdrSzie);

        i++;
    }

    //获取导入表地址
    pImpHdr = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pNtHeader->OptionalHeader.DataDirectory[1].VirtualAddress 
              + (DWORD)hInst);

    // 处理导入表
    while (TRUE)
    {
        // 遇到全0项,遍历结束 
        int nRet = memcmp(pImpHdr, &zeroImp, sizeof(IMAGE_IMPORT_DESCRIPTOR));
        if (nRet == 0)
        {
            break;
        }

        //判断字段, 为空则结束

        if (pImpHdr->Name == NULL || pImpHdr->FirstThunk == NULL)
        {
            break;
        }


        DWORD pNameAddre = (DWORD)pImpHdr->Name + (DWORD)hInst;
        // 加载dll
        HMODULE hDll = LoadLibrary((LPCSTR)pNameAddre);
        if (hDll == NULL)
        {
            break;
        }

        DWORD pFunAddr = 0;
        DWORD pIAT = (DWORD)pImpHdr->FirstThunk + (DWORD)hInst;
        DWORD pINT = (DWORD)pImpHdr->OriginalFirstThunk;
        if (pINT != 0)
        {
            pFunAddr = pINT + (DWORD)hInst;
        }
        else
        {
            pFunAddr = pIAT;

        }

        // 遍历导入名称表
        while (true){
            DWORD pAddr = *(DWORD*)pFunAddr;
            if (pAddr == 0)
            {
                break;
            }
            DWORD  pFun = 0;
            if (pAddr & 0x80000000)
            {
                //序号导入, 获取序号
                pFun = pAddr & 0xffff;
            }
            else
            {
                pFun = pAddr + 2 + (DWORD)hInst;
            }

            DWORD  dwPFNAddr = (DWORD)GetProcAddress(hDll, (LPCSTR)LOWORD(pFun));
            *(DWORD*)pIAT = dwPFNAddr;
            pIAT += 4;
            pFunAddr+=4;
       }

        pImpHdr = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pImpHdr + (DWORD)sizeof(IMAGE_IMPORT_DESCRIPTOR));
    }

    // 关闭句柄
    UnmapViewOfFile(lpMapAddr);
    CloseHandle(hFileMap);
    CloseHandle(hFile);

    // 返回地址
    return &dwOep;
}


#endif // 0

int main()
{

#if 1
    // 加载PE文件,返回原OEP
    void* pOep = LoadPe();
    if (pOep != NULL)
    {
        __asm jmp pOep
    }

#endif // 0

    return 0;
}
#include <iostream>
#include <Windows.h>
#include <stdio.h>

using namespace std;

#define FILESIZE  0x00020000         //目标进程的SizeofImage
#define IMAGEBASE 0x01000000

char szExeDataBuff[FILESIZE] = {1};
char g_szExeName[] = "winmine.exe";   //要加载的进程路径

DWORD g_oep = 0;

void LoadPe()
{

    // 创建文件映射
    //打开文件
    HANDLE hFile = CreateFile(g_szExeName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
    {
        return ;
    }

    // 创建文件映射对象
    HANDLE hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
    if (hFileMap == NULL)
    {
        CloseHandle(hFile);
        return;
    }

    //将文件映射进内存
    LPVOID pView = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
    if (pView == NULL)
    {
        CloseHandle(hFileMap);
        CloseHandle(hFile);
        return;
    }

    // 修改代码节属性
    DWORD nOldProtect = 0;
    VirtualProtect((LPVOID)IMAGEBASE, FILESIZE, PAGE_EXECUTE_READWRITE, &nOldProtect);

    // 处理PE
    PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pView;

    // 获取pe头大小
    PIMAGE_NT_HEADERS32 pNt = (PIMAGE_NT_HEADERS32)((DWORD)pView + pDos->e_lfanew);

    memcpy((void*)IMAGEBASE, (void*)pDos, pNt->OptionalHeader.SizeOfHeaders);

    // OEP
    g_oep = pNt->OptionalHeader.AddressOfEntryPoint + IMAGEBASE;

    // 解析节
    PIMAGE_SECTION_HEADER pSec = (PIMAGE_SECTION_HEADER)((DWORD) & (pNt->OptionalHeader.Magic) + pNt->FileHeader.SizeOfOptionalHeader);

    // 节数量
    unsigned int nNumberOfSections = pNt->FileHeader.NumberOfSections;

    while (nNumberOfSections != 0)
    {
        void* pVirtualAddress = (void*)(pSec->VirtualAddress + IMAGEBASE);
        void* pFileAddress = (void*)(pSec->PointerToRawData + (DWORD)pDos);
        memcpy(pVirtualAddress, pFileAddress, pSec->SizeOfRawData);
        nNumberOfSections--;
        pSec++;
    }

    if (pNt->OptionalHeader.NumberOfRvaAndSizes > 2)
    {
        // 处理导入表
        PIMAGE_IMPORT_DESCRIPTOR pIm = (PIMAGE_IMPORT_DESCRIPTOR)(pNt->OptionalHeader.DataDirectory[1].VirtualAddress + IMAGEBASE);
        while (pIm->Name && pIm->FirstThunk)
        {
            HMODULE hModule = LoadLibraryA((char*)(pIm->Name + IMAGEBASE));
            if (hModule == NULL)
            {
                pIm++;
                continue;
            }

            DWORD dwThunkData = pIm->OriginalFirstThunk ? pIm->OriginalFirstThunk : pIm->FirstThunk;
            if (dwThunkData == 0)
            {
                return ;
            }

            PIMAGE_THUNK_DATA pThunkData = (PIMAGE_THUNK_DATA)(dwThunkData + IMAGEBASE);
            DWORD* pPfn = (DWORD*)(pIm->FirstThunk + IMAGEBASE);
            while (pThunkData->u1.AddressOfData)
            {
                FARPROC farProc = 0;
                LPCSTR lpParam2 = 0;

                // 最高位判断
                if (pThunkData->u1.AddressOfData & 0x80000000)
                {
                    // 序号
                    lpParam2 = LPCSTR(LOWORD(pThunkData->u1.AddressOfData));
                }
                else
                {
                    // 函数名
                    lpParam2 = LPCSTR(pThunkData->u1.AddressOfData + IMAGEBASE + 2);
                }
                farProc = GetProcAddress(hModule, lpParam2);

                // 填充IAT
                *pPfn = (DWORD)farProc;
                pThunkData++;
                pPfn++;
            }

            pIm++;
        }
    }

    //取消映射
    UnmapViewOfFile(pView);
    //关闭文件映射对象
    CloseHandle(hFileMap);
    //关闭文件
    CloseHandle(hFile);
}

int main()
{
    LoadPe();
    if (g_oep != 0)
    {
        __asm
        {
            jmp g_oep;
        }
    }

    return 0;
}

思路: 主要难点是代码后移,留出空间

方法1: 内联 汇编 开始 nop

方法2: 把代码放到dll中

方法3: 合并节,全局变量是放在未初始化的节内合并后就会在第一个节

合并节代码:

#include <Windows.h>
#pragma bss_seg (".mySec")
char g_aryImageSize[0x200000];

#pragma bss_seg()
#pragma comment(linker,"/MERGE:.mySec=.textbss")

const char* g_szExe = "mspaint.exe";

int main()
{

    HANDLE hFile = NULL;
    HANDLE hFileMap = NULL;
    LPVOID pFileBuf = NULL;
    IMAGE_DOS_HEADER* pDosHdr = NULL;
    IMAGE_NT_HEADERS* pNtHdr = NULL;
    IMAGE_FILE_HEADER* pFileHdr = NULL;
    IMAGE_OPTIONAL_HEADER* pOptHdr = NULL;
    IMAGE_SECTION_HEADER* pSecHdr = NULL;
    IMAGE_IMPORT_DESCRIPTOR* pImpDes = NULL;
    DWORD dwSizeOfOptHdr = 0;
    DWORD dwNumOfSecs = 0;
    HANDLE hMod = NULL;
    DWORD  dwSizeOfHeader = 0;
    DWORD dwOldProc = 0;
    DWORD dwEntry = 0;
    HMODULE hDll = NULL;
    LPDWORD pINT = NULL;
    LPDWORD pIAT = NULL;
    DWORD dwAddrOfFunc = 0;
    IMAGE_IMPORT_DESCRIPTOR zeroImp;

    memset(&zeroImp, 0, sizeof(IMAGE_IMPORT_DESCRIPTOR));

    //1、创建文件
    hMod = GetModuleHandle(NULL);

    hFile = CreateFile(g_szExe,
        GENERIC_READ,
        FILE_SHARE_READ,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL);
    if (hFile == INVALID_HANDLE_VALUE)
    {
        OutputDebugString("Could not open file.");
        return -1;
    }
    //2、创建文件映射
    hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);

    if (hFileMap == NULL)
    {
        OutputDebugString("Could not create file-mapping object.");
        return -1;
    }
    //3、映射文件内容到内存
    pFileBuf = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
    if (pFileBuf == NULL)
    {
        OutputDebugString("Could not map view of file.");
        return -1;
    }
    //4、解析DOS头
    pDosHdr = (IMAGE_DOS_HEADER*)pFileBuf;
    //5、解析NT头
    pNtHdr = (IMAGE_NT_HEADERS*)(pDosHdr->e_lfanew + (char*)pFileBuf);
    //6、解析文件头
    pFileHdr = &(pNtHdr->FileHeader);
    //7、解析选项头
    pOptHdr = &(pNtHdr->OptionalHeader);
    //8、获取节表个数和选项头大小
    dwSizeOfOptHdr = pFileHdr->SizeOfOptionalHeader;
    dwNumOfSecs = pFileHdr->NumberOfSections;
    //9、解析节表
    pSecHdr = (IMAGE_SECTION_HEADER*)((char*)pOptHdr + dwSizeOfOptHdr);
    //10、获取PE头大小和入口点(RVA)
    dwSizeOfHeader = pOptHdr->SizeOfHeaders;
    dwEntry = pOptHdr->AddressOfEntryPoint + (DWORD)hMod;
    //11、获取导入表入口
    pImpDes = (IMAGE_IMPORT_DESCRIPTOR*)pOptHdr->DataDirectory[1].VirtualAddress;
    pImpDes = (IMAGE_IMPORT_DESCRIPTOR*)((DWORD)pImpDes + (DWORD)hMod);

    //12、拷贝PE头
    VirtualProtect(hMod, dwSizeOfHeader, PAGE_EXECUTE_READWRITE, &dwOldProc);
    memcpy(hMod, pDosHdr, dwSizeOfHeader);

    //13、拷贝节数据
    IMAGE_SECTION_HEADER* pSecTmpHdr = pSecHdr;
    for (size_t i = 0; i < dwNumOfSecs; i++)
    {
        LPVOID pSecDataFileOffset = (char*)pFileBuf + pSecTmpHdr->PointerToRawData;

        LPVOID pSecDataMemory = (LPVOID)((DWORD)hMod + pSecTmpHdr->VirtualAddress);

        VirtualProtect(pSecDataMemory, pSecTmpHdr->Misc.VirtualSize, PAGE_EXECUTE_READWRITE, &dwOldProc);

        memcpy(pSecDataMemory, pSecDataFileOffset, pSecTmpHdr->SizeOfRawData);

        pSecTmpHdr = (IMAGE_SECTION_HEADER*)((char*)pSecTmpHdr + sizeof(IMAGE_SECTION_HEADER));
    }

    //14、拷贝导入表信息
    while (true)
    {
        if (pImpDes->Characteristics == 0 &&
            pImpDes->FirstThunk == 0 &&
            pImpDes->Name == 0)
        {
            break;
        }

        if (pImpDes->Name == NULL)
        {
            break;
        }
        LPSTR pDllName = (LPSTR)((DWORD)hMod + pImpDes->Name);
        hDll = LoadLibrary(pDllName);

        if (pImpDes->FirstThunk == NULL)
        {
            break;
        }

        //获取导入名称表
        pINT = (LPDWORD)((DWORD)hMod + pImpDes->OriginalFirstThunk);
        if (pINT == NULL)
        {
            pINT = (LPDWORD)((DWORD)hMod + pImpDes->FirstThunk);
        }
        //获取导入地址表
        pIAT = (LPDWORD)((DWORD)hMod + pImpDes->FirstThunk);

        //
        while (true)
        {
            DWORD dwINT = *pINT;
            if (dwINT == 0)
            {
                break;
            }

            //判断是符号导入还是名称导入
            LPSTR pApiName = NULL;
            if (dwINT & 0x80000000)
            {
                pApiName = (LPSTR)dwINT;
                pApiName = LPSTR((DWORD)pApiName & 0x0000ffff);
            }
            else
            {
                pApiName = LPSTR(dwINT + (DWORD)hMod + sizeof(WORD));
            }
            *pIAT = (DWORD)GetProcAddress(hDll, pApiName);

            pINT++;
            pIAT++;
        }
        pImpDes++;
    }

    __asm jmp dwEntry;
    return 0;
}

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

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

相关文章

使用Cusor 生成 Figma UI 设计稿

一、开发环境 系统&#xff1a;MacOS 软件版本&#xff1a; Figma&#xff08;网页或APP版&#xff09; 注&#xff1a;最好是app版&#xff0c;网页版figma 没有选项 import from manifest app下载地址&#xff1a;Figma Downloads | Web Design App for Desktops & …

Golang的文件同步与备份

Golang的文件同步与备份 一、Golang介绍 也称为Go语言&#xff0c;是谷歌开发的一种编程语言&#xff0c;具有高效的并发编程能力和出色的内存管理。由于其快速的编译速度和强大的标准库&#xff0c;Golang在网络应用、云平台和大数据等领域得到了广泛应用。 二、文件同步与备份…

如何用人工智能大模型,进行作业批改?

今天我们学习人工智能大模型如何进行作业批改。手把手学习视频请访问https://edu.csdn.net/learn/40402/666452 第一步&#xff0c;进入讯飞星火。打开google浏览器&#xff0c;输入百度地址后&#xff0c;搜索”讯飞星火”&#xff0c;在搜索的结果中&#xff0c;点第一个讯飞…

MATLAB之数据分析图系列 三

三维堆叠柱状图 Bar3StackPlot.m文件 clc; clear; close all; %三维堆叠柱状图 %% 数据准备 % 读取数据 load data.mat % 初始化 dataset X; s 0.4; % 柱子宽度 n size(dataset,3); % 堆叠组数%% 图片尺寸设置&#xff08;单位&#xff1a;厘米&#xff09; figureUnits c…

python爬虫:DrissionPage实战教程

如果本文章看不懂可以看看上一篇文章&#xff0c;加强自己的基础&#xff1a;爬虫自动化工具&#xff1a;DrissionPage-CSDN博客 案例解析&#xff1a; 前提&#xff1a;我们以ChromiumPage为主&#xff0c;写代码工具使用Pycharm&#xff08;python环境3.9-3.10&#xff09; …

一、STM32简介

一、实验器材介绍 二、STM32简介 1.STM32 名词解释 STM32是ST公司基于ARM Cortex-M内核开发的32位微控制器。 ST&#xff0c;指ST公司&#xff08;意法半导体&#xff09;;M&#xff0c;MicroController 微控制器&#xff08;MCU,MicroController Unit 微控制器单元/单片机&…

[ctfshow web入门] web2

前置知识 js是可以写在网页中&#xff0c;用于控制网页行为&#xff0c;例如现在表现出无法使用F12&#xff0c;常见用法校验前台登录时输入的邮箱格式是否正确 ‌view-source‌协议是一种早期就存在的协议&#xff0c;基本上所有主流浏览器都支持这一协议&#xff0c;因此用户…

PyQt5和OpenCV车牌识别系统

有需要请加文章底部Q哦 可远程调试 PyQt5和OpenCV车牌识别系统 一 介绍 此车牌识别系统基于PyQt5和OpenCV开发&#xff0c;蓝牌&#xff0c;新能源(绿牌)&#xff0c;黄牌&#xff0c;白牌均可以准确识别&#xff0c;支持中文识别&#xff0c;可以导出识别结果(Excel格式)。此…

【Android Studio 下载 Gradle 失败】

路虽远行则将至&#xff0c;事虽难做则必成 一、事故现场 下载Gradle下载不下来&#xff0c;没有Gradle就无法把项目编译为Android应用。 二、问题分析 观察发现下载时长三分钟&#xff0c;进度条半天没动&#xff0c;说明这个是国外的东西&#xff0c;被墙住了&#xff0c;需…

Xshell Plus 6下载与安装

文章目录 Xshell Plus 6 简介&#xff08;一&#xff09;网络连接与协议支持&#xff08;二&#xff09;会话管理&#xff08;三&#xff09;安全特性&#xff08;四&#xff09;文件传输功能&#xff08;因集成Xftp 6 &#xff09;&#xff08;五&#xff09;个性化与便捷功能…

九、重学C++—类和函数

上一章节&#xff1a; 八、重学C—动态多态&#xff08;运行期&#xff09;-CSDN博客https://blog.csdn.net/weixin_36323170/article/details/147004745?spm1001.2014.3001.5502 本章节代码&#xff1a; cpp/cppClassAndFunc.cpp CuiQingCheng/cppstudy - 码云 - 开源中国…

使用MCP服务器实现AI任务完成通知:让Cursor更智能

0. 简介 在使用AI工具进行长时间任务时&#xff0c;常常需要等待结果。MCP&#xff08;Model Context Protocol&#xff09;服务器"mcp_server_notify"提供了一个优雅的解决方案&#xff0c;让AI在完成任务后通过系统通知提醒你。本文将介绍如何在Cursor中配置和使用…

解决 Hugging Face SentenceTransformer 下载失败的完整指南:ProxyError、SSLError与手动下载方案

问题背景 在使用 Hugging Face 的 SentenceTransformer 加载预训练模型 all-MiniLM-L6-v2 时&#xff0c;遇到了以下错误&#xff1a; 代理连接失败&#xff08;ProxyError / SSLError: KRB5_S_TKT_NYV&#xff09;大文件下载中断&#xff08;unexpected EOF while reading&a…

Linux | I.MX6ULL开发板固件烧录所需文件详述(9)

01 搞清楚手里的开发板是 EMMC 还是 NAND FLASH 。默认我的商业级是EMMC ,开关:10011010 终结者i.MX6ULL 开卡板分为工业级和商业级两种不同的开发板。 商业级的核心板,它的存储是 EMMC 的,EMMC 的存储是类似于正方形的芯片,旁边是 NAND FLASH的一个封装,因为我们这里…

论文阅读笔记:Denoising Diffusion Implicit Models (5)

0、快速访问 论文阅读笔记&#xff1a;Denoising Diffusion Implicit Models &#xff08;1&#xff09; 论文阅读笔记&#xff1a;Denoising Diffusion Implicit Models &#xff08;2&#xff09; 论文阅读笔记&#xff1a;Denoising Diffusion Implicit Models &#xff08…

【AI论文】GPT-ImgEval:一个用于诊断GPT4o在图像生成方面的综合基准

摘要&#xff1a;OpenAI的GPT4o模型最近的突破在图像生成和编辑方面展现了令人惊讶的良好能力&#xff0c;引起了社区的极大兴奋。 本技术报告介绍了第一眼评估基准&#xff08;名为GPT-ImgEval&#xff09;&#xff0c;定量和定性诊断GPT-4o在三个关键维度的性能&#xff1a;&…

Java虚拟机面试题:内存管理(中)

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…

游戏无法启动?XINPUT1_3.dll 丢失的终极解决方案

当你兴奋地启动一款新游戏时&#xff0c;突然弹出一个错误提示——‘程序无法启动&#xff0c;因为计算机中丢失 XINPUT1_3.dll’。这种问题在 PC 玩家中非常常见&#xff0c;尤其是运行一些较老的游戏时。XINPUT1_3.dll 是 DirectX 运行库的关键组件&#xff0c;缺失会导致游戏…

嵌入式硬件如何在PADS中将原理图转换为PCB详解

本文旨在讲述如何在PADS中将原理图转换为PCB。 本文以C51原理图作为例子。 1.首先在桌面上打开PADS Logic 2.找到菜单栏的文件选项,然后点击新建。 点击新建之后出现如下界面。

软件工程-UML

例图&#xff0c;类图&#xff0c;状态图&#xff0c;顺序图&#xff0c;活动图 目录 例图 类图 状态图 顺序图 活动图 例图 例图由四个元素组成&#xff0c;参与者、用例、系统边界、参与者和用例之间的关系 参与者用一个小人表示&#xff0c;用例用椭圆表示&#xff…