WindowsPE文件格式入门05.PE加载器LoadPE

https://bpsend.net/thread-316-1-1.html

LoadPE - pe 加载器 壳的前身

如果想访问一个程序运行起来的内存,一种方法就是跨进程读写内存,但是跨进程读写内存需要来回调用api,不如直接访问地址来得方便,那么如果我们需要直接访问地址,该怎么做呢?.需要把dll注进程,注进去的代码跟他在同一块进程里面,这样我们就可以直接访问这个进程的地址,但是不想注入,也不想跨进程读写地址,就直接读进程地址,有什么方法呢?如果把导入表里面加一个dll,这样很容易检查出来,模块里一遍历,就可容易看到了, 其实我们可以反其道行之,换种思路,不是往他进程里面塞东西,而是把他加载到我们进程里面.,这个时候再去访问进程内存其实就是访问我们自己的内存.
1.系统加载exe的流程
  • 准备一个新的内存;
  • 按照顺序把节表内容映射进内存;
  • 填写导入表。
2.LoadPE的目的
  • 可以在自己进程更改目标PE的内存。
3.LoadPE的重点
  • 1.在自己代码前留出足够空间--目标进程的SizeofImage;
  • 2.更改自己程序的ImageBase加载到目标ImageBase处:/base:0x。

img

这样,目标进程的PE头就占据了我们自己进程的 PE头,他的数据节就覆盖了我们自己的数据节,即目标进程的数据就会覆盖我们自己进程的数据,因此我们需要 把我们的代码往后移,给 目标进程 留出足够的空间

4.LoadPE的实现思路
  • 设置我们进程的 ImageBase 和 目标进程 ImageBase 保持一致
  • 我们需要把我们的代码往后移,腾出来的内存可以放目标程序
  • 读目标进程的数据,按照节表拷贝数据帮他处理导入表
  • 执行目标进程代码。
5.LoadPE的汇编实现
  1. 用winhex查看目标进程的 ImageBase 和 SizeofImage
  2. 新建工程,并且在工程选项设置 自己工程 的 ImageBase 与目标进程的一致
  3. 后移自己的代码,可以在开头定义 SizeofImage 大小的全局变量 或者通过指令 org 偏移调整指令

注意,很多 C 库函数 并不会 保存 ecx , edx 环境,自己使用前记得先保存

进程的模块基址和 数据大小可以通过 winhex看

img

.586
.model flat,stdcall
option casemap:none

   include windows.inc
   include user32.inc
   include kernel32.inc
   include msvcrt.inc

   includelib user32.lib
   includelib kernel32.lib
   includelib msvcrt.lib

IMAGE_SIZE equ 20000h     ;往后移的大小,即目标进程的SizeofImage


.data
    g_szFile db "winmine.exe", 0    ;要读取的进程

.code
    org IMAGE_SIZE 


LoadPe proc
    LOCAL @dwImageBase:DWORD       ;自己进程的模块基址
    LOCAL @hFile:HANDLE            ;文件句柄
    LOCAL @hFileMap:HANDLE         ;映射句柄
    LOCAL @pPEBuf:LPVOID           ;映射文件的缓冲地址
    LOCAL @pDosHdr:ptr IMAGE_DOS_HEADER      ;目标进程的dos头
    LOCAL @pNTHdr:ptr IMAGE_NT_HEADERS       ;目标进程的NT头
    LOCAL @pSecHdr:ptr IMAGE_SECTION_HEADER  ;目标进程的节表
    LOCAL @dwNumOfSecs:DWORD                 ;目标进程的节表数量
    LOCAL @pImpHdr:ptr IMAGE_IMPORT_DESCRIPTOR   ;目标进程的导入表
    LOCAL @dwSizeOfHeaders:DWORD                 ;目标进程的选项头大小
    LOCAL @dwOldProc:DWORD                       ;旧的内存属性
    LOCAL @hdrZeroImp:IMAGE_IMPORT_DESCRIPTOR    ;导入表结束标志,所有项全0
    LOCAL @hDll:HMODULE                          ;加载dll的句柄
    LOCAL @dwOep:DWORD                           ;进程的入口地址

    ;判断导入表结束的标志清0
    invoke RtlZeroMemory, addr @hdrZeroImp, size IMAGE_IMPORT_DESCRIPTOR

    ;自己的模块基址
    invoke GetModuleHandle, NULL
    mov @dwImageBase, eax


    ;解析PE文件,获取表

    ;打开文件
    invoke CreateFile, offset g_szFile, GENERIC_READ, FILE_SHARE_READ,NULL, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, NULL
    ;check ....
    mov @hFile, eax   ;保存文件句柄

    invoke CreateFileMapping, @hFile, NULL, PAGE_READONLY, 0, 0, NULL   ;创建文件映射
    ;check
    mov @hFileMap, eax    ;创建文件映射句柄

    invoke MapViewOfFile, @hFileMap, FILE_MAP_READ, 0, 0, 0      ;将整个文件映射进内存
    ;check 
    mov @pPEBuf, eax      ;保存映射文件内存的地址

    ;解析目标进程

    ;目标进程的 dos 头
    mov eax, @pPEBuf    
    mov @pDosHdr, eax

    ;目标进程的 nt头
    mov esi, @pDosHdr
    assume esi:ptr IMAGE_DOS_HEADER
    mov eax, @pPEBuf
    add eax, [esi].e_lfanew   ;获取nt头的偏移地址
    mov @pNTHdr, eax


    mov esi, @pNTHdr
    assume esi:ptr IMAGE_NT_HEADERS

    ;选项头信息
    mov eax, [esi].OptionalHeader.SizeOfHeaders    ;获取选项头大小
    mov @dwSizeOfHeaders, eax

    ;进程的入口地址  =  进程的内存偏移地址 + 模块基址
    mov eax, [esi].OptionalHeader.AddressOfEntryPoint
    add eax, @dwImageBase
    mov @dwOep, eax


    ;节表  地址: 选项头地址+大小
    movzx eax, [esi].FileHeader.NumberOfSections
    mov @dwNumOfSecs,eax

    lea ebx, [esi].OptionalHeader

    ;获取选项头大小:用于定位节表位置=选项头地址+选项头大小
    movzx eax, [esi].FileHeader.Si
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

游戏安全实验室_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值