首页
社区
课程
招聘
[旧帖] [讨论]内存加载PE文件,win7挂起外部进程,不能替换进程问题 0.00雪花
发表于: 2015-12-19 21:55 2193

[旧帖] [讨论]内存加载PE文件,win7挂起外部进程,不能替换进程问题 0.00雪花

2015-12-19 21:55
2193
内存加载PE文件

win7挂起外部进程,PE文件实现messagebox 可以运行
win7挂起外部进程,PE文件实现其他复杂功能 不可运行
win7挂起本进程,PE文件均可运行。

调试API函数并无调用失败现象。
请问什么原因呢?

//**********************************************************************************************************
//
// This function calculates the aligned size of a section
//
//**********************************************************************************************************

unsigned long getAlignedSize(unsigned long curSize, unsigned long alignment)
{
        if (curSize % alignment == 0)
                return curSize;
        else
        {
                int val = curSize / alignment;
                val++;
                return (val * alignment);
        }
}

//**********************************************************************************************************
//
// This function loads a PE file into memory with proper alignment.
// Enough memory must be allocated at ptrLoc.
//
//**********************************************************************************************************

bool loadPE( char* lpProgramBuffer, DWORD dwProgramSize,
        MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH,
        SectionHeader *inSecHdr, LPVOID ptrLoc)
{
        char *outPtr = (char *)ptrLoc;
        int i;
        unsigned long headerSize, toRead;
        //unsigned long readSize;
        //_llseek((HFILE)hOpenFile, 0, FILE_BEGIN);
        headerSize = inpeXH->sizeOfHeaders;

        // certain PE files have sectionHeaderSize value > size of PE file itself.  
        // this loop handles this situation by find the section that is nearest to the
        // PE header.

        for (i = 0; i < inPE->numSections; i++)
        {
                if (inSecHdr[i].pointerToRawData < headerSize)
                        headerSize = inSecHdr[i].pointerToRawData;
        }

        // read the PE header
        //ReadFile(hOpenFile, outPtr, headerSize, &readSize, NULL);
        memcpy(outPtr, lpProgramBuffer, headerSize);
        printf("HeaderSize = %d ", headerSize);
        /*
        if (readSize != headerSize)
        {
                printf("Error reading headers (%d %d) ", readSize, headerSize);
                return false;
        }*/

        outPtr += getAlignedSize(inpeXH->sizeOfHeaders, inpeXH->sectionAlignment);

        // read the sections
        for (i = 0; i < inPE->numSections; i++)
        {
                if (inSecHdr[i].sizeOfRawData > 0)
                {
                        toRead = inSecHdr[i].sizeOfRawData;
                        if (toRead > inSecHdr[i].virtualSize)
                                toRead = inSecHdr[i].virtualSize;
                        //_llseek((HFILE)hOpenFile, inSecHdr[i].pointerToRawData, FILE_BEGIN);
                        //ReadFile(hOpenFile, outPtr, toRead, &readSize, NULL);
                        memcpy(outPtr, lpProgramBuffer + inSecHdr[i].pointerToRawData, toRead);
                        /*
                        if (readSize != toRead)
                        {
                                printf("Error reading section %d ", i);
                                return false;
                        }*/
                        outPtr += getAlignedSize(inSecHdr[i].virtualSize, inpeXH->sectionAlignment);
                }
                else
                {
                        // this handles the case where the PE file has an empty section. E.g. UPX0 section
                        // in UPXed files.

                        if (inSecHdr[i].virtualSize)
                                outPtr += getAlignedSize(inSecHdr[i].virtualSize, inpeXH->sectionAlignment);
                }
        }

        return true;
}

//**********************************************************************************************************
//
// This function reads the MZ, PE, PE extended and Section Headers from an EXE file.
//
//**********************************************************************************************************

bool readPEInfo(char* lpProgramBuffer, DWORD dwProgramSize,
        MZHeader *outMZ, PE_Header *outPE, PE_ExtHeader *outpeXH,
        SectionHeader **outSecHdr)
{
        MZHeader mzH;
        PE_Header peH;
        PE_ExtHeader peXH;
        SectionHeader *secHdr;
        long fileSize;
        fileSize = dwProgramSize;

        if (fileSize < sizeof(MZHeader))
        {
                return false;
        }

        // read MZ Header
        //ReadFile(hOpenFile, &mzH, sizeof(MZHeader), &readSize, NULL);
        memcpy(&mzH, lpProgramBuffer, sizeof(MZHeader));

        if (mzH.signature != 0x5a4d)        // MZ
        {
                printf("File does not have MZ header ");
                return false;
        }

        printf("Offset to PE Header = %X ", mzH.offsetToPE);

        if ((unsigned long)fileSize < mzH.offsetToPE + sizeof(PE_Header))
        {
                printf("File size too small ");
                return false;
        }

        // read PE Header
        //_llseek((HFILE)hOpenFile, mzH.offsetToPE, FILE_BEGIN);
        memcpy(&peH, lpProgramBuffer + mzH.offsetToPE, sizeof(PE_Header));
        //ReadFile(hOpenFile, &peH, sizeof(PE_Header), &readSize, NULL);

        printf("Size of option header = %d ", peH.sizeOfOptionHeader);
        printf("Number of sections = %d ", peH.numSections);

        if (peH.sizeOfOptionHeader != sizeof(PE_ExtHeader))
        {
                return false;
        }

        // read PE Ext Header
        memcpy(&peXH, lpProgramBuffer + mzH.offsetToPE + sizeof(PE_Header), sizeof(PE_ExtHeader));
        //ReadFile(hOpenFile, &peXH, sizeof(PE_ExtHeader), &readSize, NULL);

        printf("Import table address = %X ", peXH.importTableAddress);
        printf("Import table size = %X ", peXH.importTableSize);
        printf("Import address table address = %X ", peXH.importAddressTableAddress);
        printf("Import address table size = %X ", peXH.importAddressTableSize);

        // read the sections
        //secHdr = new SectionHeader[peH.numSections];
        secHdr = (SectionHeader*)VirtualAlloc(NULL, sizeof(SectionHeader)*peH.numSections,
                MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
        //ReadFile(hOpenFile, secHdr, sizeof(SectionHeader)* peH.numSections, &readSize, NULL);
        memcpy(secHdr, lpProgramBuffer + mzH.offsetToPE + sizeof(PE_Header)+sizeof(PE_ExtHeader),
                sizeof(SectionHeader)* peH.numSections);
        *outMZ = mzH;
        *outPE = peH;
        *outpeXH = peXH;
        *outSecHdr = secHdr;
        return true;
}

//**********************************************************************************************************
//
// This function calculates the size required to load an EXE into memory with proper alignment.
//
//**********************************************************************************************************

int calcTotalImageSize(MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH,
        SectionHeader *inSecHdr)
{
        int result = 0;
        int alignment = inpeXH->sectionAlignment;

        if (inpeXH->sizeOfHeaders % alignment == 0)
                result += inpeXH->sizeOfHeaders;
        else
        {
                int val = inpeXH->sizeOfHeaders / alignment;
                val++;
                result += (val * alignment);
        }

        for (int i = 0; i < inPE->numSections; i++)
        {
                if (inSecHdr[i].virtualSize)
                {
                        if (inSecHdr[i].virtualSize % alignment == 0)
                                result += inSecHdr[i].virtualSize;
                        else
                        {
                                int val = inSecHdr[i].virtualSize / alignment;
                                val++;
                                result += (val * alignment);
                        }
                }
        }

        return result;
}

typedef struct _PROCINFO
{
        DWORD baseAddr;
        DWORD imageSize;
} PROCINFO;

//**********************************************************************************************************
//
// Creates the original EXE in suspended mode and returns its info in the PROCINFO structure.
//
//**********************************************************************************************************

BOOL createChild(PPROCESS_INFORMATION pi,
        PCONTEXT ctx, PROCINFO *outChildProcInfo)
{
        DWORD curAddr, *pebInfo, read;
        MEMORY_BASIC_INFORMATION memInfo;
        STARTUPINFO si;
        char filename[MAX_PATH];
        memset(&si, 0, sizeof(si));
        GetSystemDirectory(filename,MAX_PATH);
        strcat(filename,"\\msg.exe");       
        //GetModuleFileNameA(GetModuleHandleA(NULL), filename, MAX_PATH);

        if (CreateProcessA(NULL, filename,
                NULL, NULL, 0, CREATE_SUSPENDED, NULL, NULL, &si, pi))
        {
                ctx->ContextFlags = CONTEXT_FULL;
                GetThreadContext(pi->hThread, ctx);

                pebInfo = (DWORD *)ctx->Ebx;
                ReadProcessMemory(pi->hProcess, &pebInfo[2], (LPVOID)&(outChildProcInfo->baseAddr), sizeof(DWORD), &read);

                curAddr = outChildProcInfo->baseAddr;
                while (VirtualQueryEx(pi->hProcess, (LPVOID)curAddr, &memInfo, sizeof(memInfo)))
                {
                        if (memInfo.State == MEM_FREE)
                                break;
                        curAddr += memInfo.RegionSize;
                }
                outChildProcInfo->imageSize = (DWORD)curAddr - (DWORD)outChildProcInfo->baseAddr;

                return TRUE;
        }
        return FALSE;
}
//**********************************************************************************************************
//
// Returns true if the PE file has a relocation table
//
//**********************************************************************************************************

BOOL hasRelocationTable(PE_ExtHeader *inpeXH)
{
        if (inpeXH->relocationTableAddress && inpeXH->relocationTableSize)
        {
                return TRUE;
        }
        return FALSE;
}
struct FixupBlock
{
        unsigned long pageRVA;
        unsigned long blockSize;
};
//**********************************************************************************************************
//
// This function loads a PE file into memory with proper alignment.
// Enough memory must be allocated at ptrLoc.
//
//**********************************************************************************************************

void doRelocation(MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH,
        SectionHeader *inSecHdr, LPVOID ptrLoc, DWORD newBase)
{
        if (inpeXH->relocationTableAddress && inpeXH->relocationTableSize)
        {
                FixupBlock *fixBlk = (FixupBlock *)((char *)ptrLoc + inpeXH->relocationTableAddress);
                long delta = newBase - inpeXH->imageBase;

                while (fixBlk->blockSize)
                {
                        printf("Addr = %X ", fixBlk->pageRVA);
                        printf("Size = %X ", fixBlk->blockSize);

                        int numEntries = (fixBlk->blockSize - sizeof(FixupBlock)) >> 1;
                        printf("Num Entries = %d ", numEntries);

                        unsigned short *offsetPtr = (unsigned short *)(fixBlk + 1);

                        for (int i = 0; i < numEntries; i++)
                        {
                                DWORD *codeLoc = (DWORD *)((char *)ptrLoc + fixBlk->pageRVA + (*offsetPtr & 0x0FFF));

                                int relocType = (*offsetPtr & 0xF000) >> 12;

                                printf("Val = %X ", *offsetPtr);
                                printf("Type = %X ", relocType);

                                if (relocType == 3)
                                        *codeLoc = ((DWORD)*codeLoc) + delta;
                                /*
                                else
                                {
                                        printf("Unknown relocation type = %d ", relocType);
                                }*/
                                offsetPtr++;
                        }

                        fixBlk = (FixupBlock *)offsetPtr;
                }
        }
}
//**********************************************************************************************************
//
// To replace the original EXE with another one we do the following.
// 1) Create the original EXE process in suspended mode.
// 2) Unmap the image of the original EXE.
// 3) Allocate memory at the baseaddress of the new EXE.
// 4) Load the new EXE image into the allocated memory.  
// 5) Windows will do the necessary imports and load the required DLLs for us when we resume the suspended
//    thread.
//
// When the original EXE process is created in suspend mode, GetThreadContext returns these useful
// register values.
// EAX - process entry point
// EBX - points to PEB
//
// So before resuming the suspended thread, we need to set EAX of the context to the entry point of the
// new EXE.
//
//**********************************************************************************************************

void doFork(MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH,
        SectionHeader *inSecHdr, LPVOID ptrLoc, DWORD imageSize)
{
        STARTUPINFO si;
        PROCESS_INFORMATION pi;
        CONTEXT ctx;
        PROCINFO childInfo;
        DWORD oldProtect, *pebInfo, wrote;
        PE_ExtHeader *peXH;
        LPVOID v;
        PFNNtUnmapViewOfSection pZwUnmapViewOfSection;
        char szNtdll[] = { 'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', '\x00'};
        char szZwUnmapViewOfSection[] = { 'Z', 'w', 'U', 'n', 'm', 'a', 'p',
                'V', 'i', 'e', 'w', 'O', 'f', 'S', 'e', 'c', 't', 'i', 'o', 'n', '\x00'};
        memset(&si, 0, sizeof(si));
        if (createChild(&pi, &ctx, &childInfo))
        {
                printf("Original EXE loaded (PID = %d). ", pi.dwProcessId);
                printf("Original Base Addr = %X, Size = %X ", childInfo.baseAddr, childInfo.imageSize);

                v = (LPVOID)NULL;

                if (inpeXH->imageBase == childInfo.baseAddr && imageSize <= childInfo.imageSize)
                {
                        // if new EXE has same baseaddr and is its size is <= to the original EXE, just
                        // overwrite it in memory
                        v = (LPVOID)childInfo.baseAddr;
                        VirtualProtectEx(pi.hProcess, (LPVOID)childInfo.baseAddr, childInfo.imageSize,
                                PAGE_EXECUTE_READWRITE, &oldProtect);

                        printf("Using Existing Mem for New EXE at %X ", (unsigned long)v);
                }
                else
                {
                        // get address of ZwUnmapViewOfSection
                        pZwUnmapViewOfSection = (PFNNtUnmapViewOfSection)GetProcAddress(GetModuleHandleA(szNtdll),
                                szZwUnmapViewOfSection);

                        // try to unmap the original EXE image
                        if (pZwUnmapViewOfSection(pi.hProcess, (LPVOID)childInfo.baseAddr) == 0)
                        {
                                // allocate memory for the new EXE image at the prefered imagebase.
                                v = VirtualAllocEx(pi.hProcess, (LPVOID)inpeXH->imageBase, imageSize,
                                        MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
                                if (v)
                                        printf("Unmapped and Allocated Mem for New EXE at %X ", (unsigned long)v);
                        }
                }

                if (!v && hasRelocationTable(inpeXH))
                {
                        // if unmap failed but EXE is relocatable, then we try to load the EXE at another
                        // location
                        v = VirtualAllocEx(pi.hProcess, (void *)NULL, imageSize,
                                MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
                        if (v)
                        {
                                printf("Allocated Mem for New EXE at %X. EXE will be relocated. ", (unsigned long)v);

                                // we've got to do the relocation ourself if we load the image at another
                                // memory location               
                                doRelocation(inMZ, inPE, inpeXH, inSecHdr, ptrLoc, (DWORD)v);
                        }
                }

               
                printf("EIP = %X ", ctx.Eip);
                printf("EAX = %X ", ctx.Eax);
                printf("EBX = %X ", ctx.Ebx);        // EBX points to PEB
                printf("ECX = %X ", ctx.Ecx);
                printf("EDX = %X ", ctx.Edx);

                if (v)
                {
                        printf("New EXE Image Size = %X ", imageSize);

                        // patch the EXE base addr in PEB (PEB + 8 holds process base addr)
                        pebInfo = (DWORD *)ctx.Ebx;
                        WriteProcessMemory(pi.hProcess, &pebInfo[2], &v, sizeof(DWORD), &wrote);

                        // patch the base addr in the PE header of the EXE that we load ourselves
                        peXH = (PE_ExtHeader *)((DWORD)inMZ->offsetToPE + sizeof(PE_Header)+(DWORD)ptrLoc);
                        peXH->imageBase = (DWORD)v;

                        if (WriteProcessMemory(pi.hProcess, v, ptrLoc, imageSize, NULL))
                        {
                                printf("New EXE image injected into process. ");

                                ctx.ContextFlags = CONTEXT_FULL;
                                //ctx.Eip = (DWORD)v + ((DWORD)dllLoaderWritePtr - (DWORD)ptrLoc);
                                //ctx.Eip = 0x007B9640;

                                if ((DWORD)v == childInfo.baseAddr)
                                {
                                        ctx.Eax = (DWORD)inpeXH->imageBase + inpeXH->addressOfEntryPoint;        // eax holds new entry point
                                }
                                else
                                {
                                        // in this case, the DLL was not loaded at the baseaddr, i.e. manual relocation was
                                        // performed.
                                        ctx.Eax = (DWORD)v + inpeXH->addressOfEntryPoint;        // eax holds new entry point
                                }

                                printf("********> EIP = %X ", ctx.Eip);
                                printf("********> EAX = %X ", ctx.Eax);

                                SetThreadContext(pi.hThread, &ctx);

                                ResumeThread(pi.hThread);
                                printf("Process resumed (PID = %d). ", pi.dwProcessId);
                        }
                        else
                        {
                                printf("WriteProcessMemory failed ");
                                TerminateProcess(pi.hProcess, 0);
                        }
                }
                else
                {
                        printf("Load failed.  Consider making this EXE relocatable. ");
                        TerminateProcess(pi.hProcess, 0);
                }
        }
        /*else
        {
                printf("Cannot load %s ", TARGETPROC);
        }*/
}

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

收藏
免费 0
支持
分享
最新回复 (4)
雪    币: 38
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
在线等待中。。。。。
2015-12-19 21:57
0
雪    币: 191
活跃值: (848)
能力值: ( LV12,RANK:530 )
在线值:
发帖
回帖
粉丝
3
不懂帮顶
2015-12-19 22:07
0
雪    币: 38
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
多谢青蛙兄弟了
2015-12-20 10:26
0
雪    币: 38
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
今天调试结果:
可挂起外部进程,加载PE文件执行,但不能执行PE文件的线程部分。
在线坐等。
2015-12-20 23:03
0
游客
登录 | 注册 方可回帖
返回
//