windowsPE加载器,替换进程内存,

http://topic.csdn.net/u/20091103/11/c38fd755-6ff6-4b8b-a7bc-9aa1c94774c4.html

http://bbs.eyuyan.com/read.php?tid=150015&page=2

 Windows的PE加载器在启动程序的时候,会将磁盘上的文件加载到内存,然后做很多操作,如函数导入表重定位,变量预处理之类的。这位仁兄等于是自己写了一个PE加载器。直接将内存中的程序启动。记得以前的“红色代码”病毒也有相同的特性。
    直接启动内存中的程序相当于加了一个壳,可以把程序加密保存,运行时解密到内存,然后启动,不过对于增加破解难度还要稍微复杂点。否则人家把内存中的进程DUMP出来然后修复导入表就被拖出来了。


#include "stdafx.h" 
 
 
typedef IMAGE_SECTION_HEADER (*PIMAGE_SECTION_HEADERS)[1];  
 
// 计算对齐后的大小  
unsigned long GetAlignedSize(unsigned long Origin, unsigned long Alignment)  
{  
    return (Origin + Alignment - 1) / Alignment * Alignment;  
}  
 
// 计算加载pe并对齐需要占用多少内存  
// 未直接使用OptionalHeader.SizeOfImage作为结果是因为据说有的编译器生成的exe这个值会填0  
unsigned long CalcTotalImageSize(PIMAGE_DOS_HEADER MzH  
                                 , unsigned long FileLen  
                                 , IMAGE_NT_HEADERS peH  
                                 , IMAGE_SECTION_HEADERS peSecH)  
{  
    unsigned long res;  
    // 计算pe头的大小  
    res = GetAlignedSize( peH->OptionalHeader.SizeOfHeaders  
        , peH->OptionalHeader.SectionAlignment  
        );  
 
    // 计算所有节的大小  
    for( int i = 0; i < peH->FileHeader.NumberOfSections; ++i)  
    {  
        // 超出文件范围  
        if(peSecH->ointerToRawData + peSecH->SizeOfRawData > FileLen)  
            return 0;  
        else if(peSecH->VirtualAddress)//计算对齐后某节的大小  
        {  
            if(peSecH->Misc.VirtualSize)  
            {  
                res = GetAlignedSize( peSecH->VirtualAddress + peSecH->Misc.VirtualSize  
                    , peH->OptionalHeader.SectionAlignment  
                    );  
            }  
            else 
            {  
                res = GetAlignedSize( peSecH->VirtualAddress + peSecH->SizeOfRawData  
                    , peH->OptionalHeader.SectionAlignment  
                    );  
            }  
        }  
        else if( peSecH->Misc.VirtualSize < peSecH->SizeOfRawData )  
        {  
            res += GetAlignedSize( peSecH->SizeOfRawData  
                , peH->OptionalHeader.SectionAlignment  
                );  
        }  
        else 
        {  
            res += GetAlignedSize( peSecH->Misc.VirtualSize  
                , peH->OptionalHeader.SectionAlignment  
                );  
        }// if_else  
    }// for  
      
    return res;  
}  
// 加载pe到内存并对齐所有节  
BOOL AlignPEToMem( void *Buf  
                  , long Len  
                  , IMAGE_NT_HEADERS &peH  
                  , IMAGE_SECTION_HEADERS &peSecH  
                  , void *&Mem  
                  , unsigned long &ImageSize)  
{  
    IMAGE_DOS_HEADER SrcMz;// DOS头  
    IMAGE_NT_HEADERS SrcPeH;// E头  
    IMAGE_SECTION_HEADERS SrcPeSecH;// 节表  
      
    SrcMz = (PIMAGE_DOS_HEADER)Buf;  
 
    if( Len < sizeof(IMAGE_DOS_HEADER) )   
        return FALSE;  
      
    if( SrcMz->e_magic != IMAGE_DOS_SIGNATURE )  
        return FALSE;  
      
    if( Len < SrcMz->e_lfanew + (long)sizeof(IMAGE_NT_HEADERS) )  
        return FALSE;  
 
    SrcPeH = (PIMAGE_NT_HEADERS)((int)SrcMz + SrcMz->e_lfanew);  
    if( SrcPeH->Signature != IMAGE_NT_SIGNATURE )  
        return FALSE;  
 
    if( (SrcPeH->FileHeader.Characteristics & IMAGE_FILE_DLL) ||  
        (SrcPeH->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE == 0) ||  
        (SrcPeH->FileHeader.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER)) )  
    {  
        return FALSE;  
    }  
 
 
    SrcPeSecH = (PIMAGE_SECTION_HEADERS)((int)SrcPeH + sizeof(IMAGE_NT_HEADERS));  
    ImageSize = CalcTotalImageSize( SrcMz, Len, SrcPeH, SrcPeSecH);  
 
    if( ImageSize == 0 )  
        return FALSE;  
      
    Mem = VirtualAlloc( NULL, ImageSize, MEM_COMMIT, AGE_EXECUTE_READWRITE); // 分配内存  
    if( Mem != NULL )  
    {  
        // 计算需要复制的PE头字节数  
        unsigned long l = SrcPeH->OptionalHeader.SizeOfHeaders;  
        for( int i = 0; i < SrcPeH->FileHeader.NumberOfSections; ++i)  
        {  
            if( (SrcPeSecH->ointerToRawData) &&  
                (SrcPeSecH->ointerToRawData < l) )  
            {  
                l = SrcPeSecH->ointerToRawData;  
            }  
        }  
        memmove( Mem, SrcMz, l);  
        peH = (PIMAGE_NT_HEADERS)((int)Mem + ((PIMAGE_DOS_HEADER)Mem)->e_lfanew);  
        peSecH = (PIMAGE_SECTION_HEADERS)((int)peH + sizeof(IMAGE_NT_HEADERS));  
 
        void *Pt = (void *)((unsigned long)Mem   
            + GetAlignedSize( peH->OptionalHeader.SizeOfHeaders  
            , peH->OptionalHeader.SectionAlignment)  
            );  
 
        for( i = 0; i < peH->FileHeader.NumberOfSections; ++i)  
        {  
            // 定位该节在内存中的位置  
            if(peSecH->VirtualAddress)  
                t = (void *)((unsigned long)Mem + peSecH->VirtualAddress);  
 
            if(peSecH->SizeOfRawData)  
            {  
                // 复制数据到内存  
                memmove(Pt, (const void *)((unsigned long)(SrcMz) + peSecH->ointerToRawData), peSecH->SizeOfRawData);  
                if(peSecH->Misc.VirtualSize < peSecH->SizeOfRawData)  
                    t = (void *)((unsigned long)Pt + GetAlignedSize(peSecH->SizeOfRawData, peH->OptionalHeader.SectionAlignment));  
                else // pt 定位到下一节开始位置  
                    t = (void *)((unsigned long)Pt + GetAlignedSize(peSecH->Misc.VirtualSize, peH->OptionalHeader.SectionAlignment));  
            }  
            else 
            {  
                t = (void *)((unsigned long)Pt + GetAlignedSize(peSecH->Misc.VirtualSize, peH->OptionalHeader.SectionAlignment));  
            }  
        }  
    }  
    return TRUE;  
}  
 
 
 
typedef void *(__stdcall *pfVirtualAllocEx)(unsigned long, void *, unsigned long, unsigned long, unsigned long);  
pfVirtualAllocEx MyVirtualAllocEx = NULL;  
 
BOOL IsNT()  
{  
    return MyVirtualAllocEx!=NULL;  
}  
 
// 生成外壳程序命令行  
char *PrepareShellExe(char *CmdParam, unsigned long BaseAddr, unsigned long ImageSize)  
{  
    if(IsNT())  
    {  
        char *Buf = new char[256];  
        memset(Buf, 0, 256);  
        GetModuleFileName(0, Buf, 256);  
        strcat(Buf, CmdParam);  
        return Buf; // 请记得释放内存;-)  
    }  
    else 
    {  
        // Win98下的处理请参考原文;-)  
        // http://community.csdn.net/Expert/topic/4416/4416252.xml?temp=8.709133E-03  
        return NULL;  
    }  
}  
 
// 是否包含可重定向列表  
BOOL HasRelocationTable(PIMAGE_NT_HEADERS peH)  
{  
    return (peH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)  
        && (peH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);  
}  
#pragma pack(push, 1)  
typedef struct{  
    unsigned long VirtualAddress;  
    unsigned long SizeOfBlock;  
} *PImageBaseRelocation;  
#pragma pack(pop)  
 
// 重定向PE用到的地址  
void DoRelocation(PIMAGE_NT_HEADERS peH, void *OldBase, void *NewBase)  
{  
    unsigned long Delta = (unsigned long)NewBase - peH->OptionalHeader.ImageBase;  
    ImageBaseRelocation p = (PImageBaseRelocation)((unsigned long)OldBase   
        + peH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);  
    while(p->VirtualAddress + p->SizeOfBlock)  
    {  
        unsigned short *pw = (unsigned short *)((int)p + sizeof(*p));  
        for(unsigned int i=1; i <= (p->SizeOfBlock - sizeof(*p)) / 2; ++i)  
        {  
            if((*pw) & 0xF000 == 0x3000){  
                unsigned long *t = (unsigned long *)((unsigned long)(OldBase) + p->VirtualAddress + ((*pw) & 0x0FFF));  
                *t += Delta;  
            }  
            ++pw;  
        }  
        p = (PImageBaseRelocation)pw;  
    }  
}  
 
// 卸载原外壳占用内存  
BOOL UnloadShell(HANDLE rocHnd, unsigned long BaseAddr)  
{  
    typedef unsigned long (__stdcall *pfZwUnmapViewOfSection)(unsigned long, unsigned long);  
    pfZwUnmapViewOfSection ZwUnmapViewOfSection = NULL;  
    BOOL res = FALSE;  
    HMODULE m = LoadLibrary("ntdll.dll");  
    if(m){  
        ZwUnmapViewOfSection = (pfZwUnmapViewOfSection)GetProcAddress(m, "ZwUnmapViewOfSection");  
        if(ZwUnmapViewOfSection)  
            res = (ZwUnmapViewOfSection((unsigned long)ProcHnd, BaseAddr) == 0);  
        FreeLibrary(m);  
    }  
    return res;  
}  
 
// 创建外壳进程并获取其基址、大小和当前运行状态  
BOOL CreateChild(char *Cmd, CONTEXT &Ctx, HANDLE &rocHnd, HANDLE &ThrdHnd,   
                 unsigned long &rocId, unsigned long &BaseAddr, unsigned long &ImageSize)  
{  
    STARTUPINFOA si;  
    ROCESS_INFORMATION pi;  
    unsigned long old;  
    MEMORY_BASIC_INFORMATION MemInfo;  
    memset(&si, 0, sizeof(si));  
    memset(&pi, 0, sizeof(pi));  
    si.cb = sizeof(si);  
      
    BOOL res = CreateProcess(NULL, Cmd, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi); // 以挂起方式运行进程;  
    if(res){  
        rocHnd = pi.hProcess;  
        ThrdHnd = pi.hThread;  
        rocId = pi.dwProcessId;  
        // 获取外壳进程运行状态,[ctx.Ebx+8]内存处存的是外壳进程的加载基址,ctx.Eax存放有外壳进程的入口地址  
        Ctx.ContextFlags = CONTEXT_FULL;  
        GetThreadContext(ThrdHnd, &Ctx);  
        ReadProcessMemory(ProcHnd, (void *)(Ctx.Ebx+8), &BaseAddr, sizeof(unsigned long), &old); // 读取加载基址  
        void *p = (void *)BaseAddr;  
        // 计算外壳进程占有的内存  
        while(VirtualQueryEx(ProcHnd, p, &MemInfo, sizeof(MemInfo)))  
        {  
            if(MemInfo.State = MEM_FREE) break;  
            p = (void *)((unsigned long)p + MemInfo.RegionSize);  
        }  
        ImageSize = (unsigned long)p - (unsigned long)BaseAddr;  
    }  
    return res;  
}  
 
// 创建外壳进程并用目标进程替换它然后执行  
HANDLE AttachPE(char *CmdParam, IMAGE_NT_HEADERS peH, IMAGE_SECTION_HEADERS peSecH,   
                void *Ptr, unsigned long ImageSize, unsigned long &rocId)  
{  
    HANDLE res = INVALID_HANDLE_VALUE;  
    CONTEXT Ctx;  
    HANDLE Thrd;  
    unsigned long Addr, Size;  
    char *s = repareShellExe(CmdParam, peH->OptionalHeader.ImageBase, ImageSize);  
    if(s==NULL) return res;  
    if(CreateChild(s, Ctx, res, Thrd, rocId, Addr, Size)){  
        void *p = NULL;  
        unsigned long old;  
        if((peH->OptionalHeader.ImageBase == Addr) && (Size >= ImageSize)){// 外壳进程可以容纳目标进程并且加载地址一致  
            p = (void *)Addr;  
            VirtualProtectEx(res, p, Size, AGE_EXECUTE_READWRITE, &old);  
        }  
        else if(IsNT()){  
            if(UnloadShell(res, Addr)){// 卸载外壳进程占有内存  
                p = MyVirtualAllocEx((unsigned long)res, (void *)peH->OptionalHeader.ImageBase, ImageSize, MEM_RESERVE | MEM_COMMIT, AGE_EXECUTE_READWRITE);  
            }  
            if((p == NULL) && HasRelocationTable(peH)){// 分配内存失败并且目标进程支持重定向  
                p = MyVirtualAllocEx((unsigned long)res, NULL, ImageSize, MEM_RESERVE | MEM_COMMIT, AGE_EXECUTE_READWRITE);  
                if(p) DoRelocation(peH, tr, p); // 重定向  
            }  
        }  
        if(p){  
            WriteProcessMemory(res, (void *)(Ctx.Ebx+8), &p, sizeof(DWORD), &old); // 重置目标进程运行环境中的基址  
            peH->OptionalHeader.ImageBase = (unsigned long)p;  
            if(WriteProcessMemory(res, p, tr, ImageSize, &old)){// 复制PE数据到目标进程  
                Ctx.ContextFlags = CONTEXT_FULL;  
                if((unsigned long)p == Addr)  
                    Ctx.Eax = peH->OptionalHeader.ImageBase + peH->OptionalHeader.AddressOfEntryPoint; // 重置运行环境中的入口地址  
                else 
                    Ctx.Eax = (unsigned long)p + peH->OptionalHeader.AddressOfEntryPoint;  
                SetThreadContext(Thrd, &Ctx);// 更新运行环境  
                ResumeThread(Thrd);// 执行  
                CloseHandle(Thrd);  
            }  
            else{// 加载失败,杀掉外壳进程  
                TerminateProcess(res, 0);  
                CloseHandle(Thrd);  
                CloseHandle(res);  
                res = INVALID_HANDLE_VALUE;  
            }  
        }  
        else{// 加载失败,杀掉外壳进程  
            TerminateProcess(res, 0);  
            CloseHandle(Thrd);  
            CloseHandle(res);  
            res = INVALID_HANDLE_VALUE;  
        }  
    }  
    delete[] s;  
    return res;  
}  
/**//*******************************************************/ 
{ ******************************************************* } 
{ *                 从内存中加载并运行exe               * } 
{ ******************************************************* } 
{ * 参数:                                                } 
{ * Buffer: 内存中的exe地址                               } 
{ * Len: 内存中exe占用长度                                } 
{ * CmdParam: 命令行参数(不包含exe文件名的剩余命令行参数)} 
{ * rocessId: 返回的进程Id                               } 
{ * 返回值: 如果成功则返回进程的Handle(ProcessHandle),   } 
{            如果失败则返回INVALID_HANDLE_VALUE           } 
{ ******************************************************* } 
 /*******************************************************/ 
HANDLE MemExecute(void *ABuffer, long Len, char *CmdParam, unsigned long *ProcessId)  
{  
    HANDLE res = INVALID_HANDLE_VALUE;  
    IMAGE_NT_HEADERS peH;  
    IMAGE_SECTION_HEADERS peSecH;  
    void *Ptr;  
    unsigned long peSz;  
    if(AlignPEToMem(ABuffer, Len, peH, peSecH, tr, peSz))  
    {  
        res = AttachPE(CmdParam, peH, peSecH, tr, peSz, *ProcessId);  
        VirtualFree(Ptr, peSz, MEM_DECOMMIT);  
    }  
    return res;  
}  
 
// 初始化  
class CInit  
{  
public:  
    CInit()  
    {  
        MyVirtualAllocEx = (pfVirtualAllocEx)GetProcAddress(GetModuleHandle("Kernel32.dll"), "VirtualAllocEx");  
    }  
}Init;  
 
 
 
 
int APIENTRY WinMain(HINSTANCE hInstance,  
                     HINSTANCE hPrevInstance,  
                     LPSTR     lpCmdLine,  
                     int       nCmdShow)  
{  
    HANDLE hFile = NULL;  
    hFile = ::CreateFile( "f://SourceFromCsdn2.exe" 
        , FILE_ALL_ACCESS  
        , 0  
        , NULL  
        , OPEN_EXISTING  
        , FILE_ATTRIBUTE_NORMAL  
        , NULL  
        );  
    if( hFile == INVALID_HANDLE_VALUE )  
        return -1;  
 
    ::SetFilePointer( hFile, 0, NULL, FILE_BEGIN);  
    DWORD dwFileSize = ::GetFileSize( hFile, NULL);  
 
    LPBYTE pBuf = new BYTE[dwFileSize];  
    memset( pBuf, 0, dwFileSize);  
 
    DWORD dwNumberOfBytesRead = 0;  
    ::ReadFile( hFile  
        , pBuf  
        , dwFileSize  
        , &dwNumberOfBytesRead  
        , NULL  
        );  
 
    ::CloseHandle(hFile);  
      
    unsigned long ulProcessId = 0;  
    MemExecute( pBuf, dwFileSize, "", &ulProcessId);  
    delete[] pBuf;  
 
      
    return 0;  
}

你可能感兴趣的:(windowsPE加载器,替换进程内存,)