效果是这样的,假设一个PE数据在内存里面了,我们利用下面我讲的技术可以直接建立一个进程并运行这个PE,当然直接在本进程运行在可以,这两钟技术在前些时日我都有实现,今天我只说关于建立进程并运行的,当然,为了防止无味的技术剽窃,我不准备给出完整代码,只给出部分关键性代码.

这种技术严格来说没有什么用处,不过对于用到木马病毒上效果缺非常不错,当然我并非是用到木马或者是病毒当中,我是用在直接从网络上同步并运行程序并且磁盘中不会出现任何相关的东西,这样对于保密数据来说有一定的效果.

首先我们要考虑进程问题,由于我们需要一个进程,windows不能平白无故的多出一个进程来,就好比我的钱包不会平白无故的多出几张三头将军一样.于是比较便利的就是直接再运行一个当前程序.

CreateProcess(plpFile,NULL,NULL,NULL,FALSE,DEBUG_ONLY_THIS_PROCESS,NULL,NULL,&pStartInfo,&pProcInfo);

DEBUG_ONLY_THIS_PROCESS表示我们以调试方式运行,这样的好处在于我们可以从DEBUG_EVENT中得到程序的入口,这里要说一下的是如果到了vista这个时代,exe装入有一个Address Space Load Randomization技术,如果有重定位,那么windows将随机基址.

1     while (WaitForDebugEvent(&pdbgEvnt,INFINITE))


2     {
3         if (pdbgEvnt.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT)
4             break;
5         ContinueDebugEvent(pdbgEvnt.dwProcessId,pdbgEvnt.dwThreadId,DBG_CONTINUE); 6     }
我们等待程序的CREATE_PROCESS_DEBUG_EVENT事件,到这里PE已经像大家闺秀出嫁前一样梳妆打扮好了,于是我们可以取其入口的代码并保存,等到后面恢复,当然也可以不恢复,因为我们要hook掉入口的代码,让他转入我们写入的代码
到这里一个进程已经被我们创建了,创建了进程后我们需要在目标进程申请两段空间来把我们需要运行的PE的代码放进去,我们首先想到了VirtualAllocEx ULONG_PTR plprMem = (ULONG_PTR)VirtualAllocEx(pProcInfo.hProcess,NULL,pimNH1->OptionalHeader.SizeOfImage,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
首先申请一段来存放我们想要运行的PE程序代码,大小是Image大小而不是PE的文件大小. 申请好后我们来处理一下需要写入到目标进程的代码       char* plpAlign = (char*)VirtualAlloc(0,pimNH1->OptionalHeader.SizeOfImage,MEM_COMMIT,PAGE_READWRITE);
    if (plpAlign == NULL)
        return NULL;     PIMAGE_SECTION_HEADER    pimSH1 = (PIMAGE_SECTION_HEADER)((ULONG_PTR)pimNH1+sizeof(IMAGE_NT_HEADERS));
    int    psizeHeader = 0x7FFFFFFF;
    for (int i=0;i<pimNH1->FileHeader.NumberOfSections;i++)
    {
        if (pimSH1->PointerToRawData != 0)
            psizeHeader = min(pimSH1->PointerToRawData,psizeHeader);
        memcpy(plpAlign+pimSH1->VirtualAddress,plpImage+pimSH1->PointerToRawData,pimSH1->SizeOfRawData);
        pimSH1++;
    }
    //将PE头复制回去
    memcpy(plpAlign,plpImage,psizeHeader);
    ULONG_PTR    pdelta    = (ULONG_PTR)pNewBase - pimNH1->OptionalHeader.ImageBase;     if (pdelta != 0)//需要重新定位
        LoadVReloc((ULONG_PTR)plpAlign,TRUE,pdelta);
大概思路就是先在本进程申请一段空间,并且把代码按内存对齐,然后把代码重新定位,这样我们的代码放到目标进程就不需要重新定位和对齐了. 1     BOOL pbRet = WriteProcessMemory(pProcInfo.hProcess,(char*)plprMem,plpAlign,pimNH1->OptionalHeader.SizeOfImage,&pszWtd); 2     VirtualFree((void*)plpAlign,0,MEM_RELEASE); 3     if (!pbRet)    return NULL;
这里写入到目标进程空间,到这里还剩下最后一个问题,那就是输入表的处理,因为没有像LoadProcessLibrary这样的说法,所以我们要想办法写入另外一段处理输入表的代码,当然这里你可以写好一段汇编代码然后同样WriteProcessMemory到目标进程空间,我采用的是另外一种方法,因为考虑到x64直接拷贝汇编的麻烦事情,所以我直接又申请了一段空间,并把本进程整个PE Image一起拷贝了过去
  1     char* plpAlign = (char*)VirtualAlloc(0,pimNH1->OptionalHeader.SizeOfImage,MEM_COMMIT,PAGE_READWRITE);
2     if (plpAlign == NULL)
3         return NULL;

5     memcpy(plpAlign,plpImage,pimNH1->OptionalHeader.SizeOfImage);
6     ULONG_PTR    pdelta    = (ULONG_PTR)pNewBase - (ULONG_PTR)plpImage;
7     if (pdelta != 0)//需要重新定位 8         LoadVReloc((ULONG_PTR)plpAlign,TRUE,pdelta);
同样的,首先我们需要重新定位本进程的代码,然后再写入目标进程空间,   1     pbRet = WriteProcessMemory(pProcInfo.hProcess,(char*)plpSelf,plpAlign,pimNH2->OptionalHeader.SizeOfImage,&pszWtd);
2     VirtualFree((void*)plpAlign,0,MEM_RELEASE); 3     if (!pbRet)    return NULL;
这里把代码写入到进程空间,我们本进程代码中留了一个函数, 1 void    InitClientProcess()
2 {
3     
4 }
这是我们将要把目标进程的入口转向的地方,再这里面对需要运行的PE做些必要的处理,正如上面所说的输入表的处理,当然这个时候就牵涉到了一些数据的交换,比如需要运行的PE装入的基址,这些数据只有父进程知道,我的方法是使用全局变量然后同样WriteProcessMemory过去
   1     pbRet = WriteProcessMemory(pProcInfo.hProcess,(char*)((ULONG_PTR)&gxVirtualCfg - pSelfImage + plpSelf),(char*)&gxVirtualCfg,sizeof(gxVirtualCfg),&pszWtd);
 2     if (!pbRet)    return NULL;
 3 
 4     ULONG_PTR plpEntryFunc = (ULONG_PTR)InitClientProcess - pSelfImage + plpSelf;
 5     char pCurBuf[16];
 6 
 7 #ifdef _M_IX86
 8     *pCurBuf = 0x68;
 9     *(DWORD*)(pCurBuf+1) = plpEntryFunc;
10     pCurBuf[5] = 0xC3;
11     pbRet = WriteProcessMemory(pProcInfo.hProcess,(char*)gxVirtualCfg.m_OrgEntry,pCurBuf,6,&pszWtd);
12     if (!pbRet)    return NULL;
13 #else
14 
15     pCurBuf[0] = 0xff;        // jmp [rip+addr]
16     pCurBuf[1] = 0x25;
17     *((DWORD *)(pCurBuf+2)) = 0; // addr = 0
18     *((ULONG_PTR *)(pCurBuf+6)) = plpEntryFunc;
19     pbRet = WriteProcessMemory(pProcInfo.hProcess,(char*)gxVirtualCfg.m_OrgEntry,pCurBuf,14,&pszWtd);
20     if (!pbRet)    return NULL;
21  22 #endif
这里把子进程需要的信息就写过去,并且把入口代码修改为转向我们的InitClientProcess函数
在InitClientProcess函数里面,我们需要做的工作有
   1     PENTRY_LoadLibraryA ppLoadLibraryA = (PENTRY_LoadLibraryA)gxVirtualCfg.m_pLoadLibraryA;
 2     PENTRY_GetProcAddress ppGetProcAddress = (PENTRY_GetProcAddress)gxVirtualCfg.m_pGetProcAddress;
 3     ULONG_PTR phBase = gxVirtualCfg.m_CoreBase;
 4     PIMAGE_NT_HEADERS pimNH = EnterImageNtHeader((char*)phBase);
 5     ULONG_PTR plpImport = pimNH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + phBase;
 6 
 7 处理输入表
 8 
 9 然后转入真正的我们需要运行的PE的入口
10      PENTRY_WinMain    ppWinMain = (PENTRY_WinMain)gxVirtualCfg.m_Entry;
11      ppWinMain((HINSTANCE)phBase,NULL,"",SW_SHOW);    
到这里我们的PE就运行起来了,整个过程都不会牵涉到磁盘操作,当然要想做附加数据这些就要更麻烦点. 有空我上传一个例子,虽然作用不大,但是挺好玩      
 

从内存中直接运行PE程序的更多相关文章

  1. C语言中调用运行python程序

    C语言中调用运行python程序: Python代码如下: 创建test.py. #!/usr/bin/python3 #test.py import sys x = ]) print x*x 注意: ...

  2. 她娇羞道“不用这样细致认真的说啊~~”———详细图解在Linux环境中创建运行C程序

    她娇羞说,不用这样细致认真的说啊———详细图解在Linux环境中创建运行C程序“不,这是对学习的负责”我认真说到 叮叮叮,停车,让我们看看如何在Linux虚拟机环境中,创建运行C程序 详细图解在Lin ...

  3. java成员变量和局部变量的初始化和内存中的运行机制

    成员变量: 当系统加载类或创建类的实例时,系统会自动为成员变量分配内存空间,并在分配内存空间后,自动为成员变量指定初始值. eyeNum是类属性.name是实例属性 所有person实例访问eyeNu ...

  4. Window7中Eclipse运行MapReduce程序报错的问题

    按照文档:http://www.micmiu.com/bigdata/hadoop/hadoop2x-eclipse-mapreduce-demo/安装配置好Eclipse后,运行WordCount程 ...

  5. 【java】使用jsp命令查看系统中java运行的程序及进程号

    对于java独立运行的程序,他们在进程中的名字都是 Java(TM) Platform SE binary,如图 我们想知道这个进程运行的是哪个程序,怎么办呢? 答案是:可以在命令行下,运行:jps命 ...

  6. pycharm中可以运行的程序,在命令行中运行提示模块不存在的问题

    运行模块(包含main函数的模块),在模块开头添加以下代码,原因是pycharm运行python脚本时,会自动添加以下代码,将当前库加入到系统库目录集合中,在命令行中运行需要手动添加import os ...

  7. PyCharm 在django程序中单独运行py文件

    使用PyCharm开发django程序,发现如果不在命令行而在IDE的django项目中直接运行django程序,发现报错,程序如下:   def main(): from people.models ...

  8. 在Docker for Windows中运行GUI程序

    Docker运行GUI原理 Docker目前大多应用在服务器领域,那么在Docker中可以运行GUI程序吗?怀着好奇心google了一番,还真有人写了一篇文章 running-gui-applicat ...

  9. iphone按home键后,正在运行的程序是否退出了呢?

    是否一直有个疑问,当iphone手机正在运行一个APP,如果按Home键后,那么原来正在运行的程序还在运行吗?如果开发过ios程序,可能不是问题,如果没有开发过的,可能会疑惑了,我就简单的说一下.以几 ...

随机推荐

  1. $.queue() 与 $.dequeue() -- 队列

    JQuery 运用队列为动画模块服务,但好像它应该有更多用处,我觉得的,那试试就知道咯. 简单的来讲,它就是形成队列和出列, 也就因此可以进行很有规律的回调和延时了呀(暂停感觉有难度),当然这就是后面 ...

  2. this对象解析

    this在js中有着非常广泛的应用,但其所指的对象也常常让人摸不着头脑,简而言之: this指的就是调用函数的对象,最常见的莫过以下几种 1.直接使用函数,则为window对象 function a( ...

  3. jQuery之DOM操作大全

    jQuery属性操作 获取元素属性的语法:attr(name) 例子:$("#img1").attr("src"); 设置元素单个属性的语法:attr(key, ...

  4. leetcode刷题2:两数相加add_two_numbers

    题目:两数相加 (难度:中等) 给定两个非空链表来表示两个非负整数.位数按照逆序方式存储,它们的每个节点只存储单个数字. 将两数相加返回一个新的链表. 你可以假设除了数字 0 之外,这两个数字都不会以 ...

  5. 【P2361】yyy棋(博弈论+贪心+模拟)

    这个题看上去本来不好处理,然而善意的题面已经基本告诉你做法了,小时候玩的那个游戏就是代码的核心.动动脑子想想,如果长和宽的积是奇数,那么一定要先手,如果是偶数,那么后手就会获胜. 好了,那么怎么处理对 ...

  6. 主席树----POJ 2104(主席树裸题)(转)

    首先来介绍一下我们需求:给你n个数,多次问你某个区间内的第k小是哪个数 主席树: 主席树的全名应该是 函数式版本的线段树.加上附带的一堆 technology.. ..总之由于原名字太长了,而且 “主 ...

  7. HDU 4004 The Frog's Games(2011年大连网络赛 D 二分+贪心)

    其实这个题呢,大白书上面有经典解法  题意是青蛙要跳过长为L的河,河上有n块石头,青蛙最多只能跳m次且只能跳到石头或者对面.问你青蛙可以跳的最远距离的最小值是多大 典型的最大值最小化问题,解法就是贪心 ...

  8. [kuangbin带你飞]专题十 匹配问题 一般图匹配

    过去做的都是二分图匹配 即 同一个集合里的点 互相不联通 但是如果延伸到一般图上去 求一个一般图的最大匹配 就要用带花树来解决 带花树模板 用来处理一个无向图上的最大匹配 看了一会还是不懂  抄了一遍 ...

  9. Python3一些包的下载

    首先在windows的Python扩展包网址:http://www.lfd.uci.edu/~gohlke/pythonlibs/ 这里举例下载opencv3.2.0的安装包 我的电脑是win10,6 ...

  10. windows下如何查看端口占用

    1.查看端口使用情况netstat -aon(以3306为例) 2.根据3306端口号查看对应的进程号(进程号就是进程的唯一标识,根据这个进程号就能找到对应的应用) 3.根据进程号查询相应的应用占用端 ...