目录

EXE 捆绑器

基本思路:

EXE 执行调度机制:

控制进程同步运行实例分析:

字节码转换工具 hex2db:

hex2db 源代码:

运行测试:

执行调度程序 _host.exe:

主要代码:

数据结构分析:

宿主程序 host.exe:

宿主程序的功能:

宿主程序的状态:

遍历文件:

释放文件:

宿主程序主函数:

EXE 捆绑器 bind.exe:

绑定列表定位:

捆绑步骤及主要代码:

测试运行:

小结:


EXE 捆绑器

本书 8.4 节,也就是前面的 "延迟加载导入编程" 目录中介绍了一种通过附加资源文件的方式对文件进行捆绑的例子。本章使用补丁技术编写一个小工具,该工具可以将某个目录中的所有相关文件 (含子目录中的文件) 捆绑在一起,捆绑前还可以定义要运行的 EXE 序列。

EXE 捆绑器允许用户将多个可执行文件及相关文件捆绑到一起,通过运行捆绑程序实现多个可执行文件的依次执行。

基本思路:

EXE 捆绑是指将两个或多个可执行文件和非执行文件捆绑到一起的技术。

捆绑的目的有三个:

口 减少某个待发布系统的独立文件的个数。

口 隐藏某些特殊用途的文件。

口 实现一些特殊功能,如本案例中通过捆绑实现了多个程序的顺序执行。

EXE 捆绑器结合 EXE 加锁器 (本书第 20 章讲述的内容) 可以用于加密文件夹或文件。因为在捆绑过程中,可以指定被捆绑的文件中哪些需要运行,所以,该捆绑器还可以用于运行多个 PE 文件的批处理,通过依次运行多个文件 (结合本书第 19 章讲述的软件安装自动化技术) 则可以实现多个补丁的自动安装。

捆绑的实现方法有很多种,其中最常见有两种方法:

1) 通过编写一个新的 EXE 程序,把要捆绑的所有文件以资源的方式进行,或者直接写在文件末尾来进行,运行时只需将文件提取出来依次运行即可。

2) 通过直接修改第一个 PE 程序,将其他文件作为资源或直接写在文件末尾,通过在第一个 PE 程序中设置补丁程序的方式,依次运行多个程序。

本章将讲解第一种捆绑方法:

以下是本章要用到的几个程序,以及每个程序的相关说明:

口 hex2db:将字节码转变为汇编语言数据定义语句的小工具。

口 _host.exex:调度执行程序的模板,该文件最终嵌入到宿主程序中。

口 hostexe:宿主程序。是补丁程序的目标,用于存储 _host.exe 和其他要捆绑的文件。

口 bind.exe:捆绑器。负责执行捆绑,类似于进阶部分的补丁工具。

EXE 执行调度机制:

大部分情况下,被捆绑的文件集合中只有一个 EXE 文件是主运行文件。但也有例外,比如有的用户会将多个程序捆绑起来,然后依次安装这些程序以提高计算机的安全性能,这时候就要用到 EXE 执行调度。EXE 执行调度就是在捆绑前,指定补丁程序中要安装的程序的运行顺序,当被捆绑的程序被释放出来后,还要有一个进程专门负责调度这些程序按照先后顺序依次运行。

要实现 EXE 同步执行,需要使用两个 Windows API 函数,它们分别是:

口 CreateProcess (创建进程函数)

口 WaitForSingleObject (等待指定进程结束)

控制进程同步运行实例分析:

本节根据对操作系统进程管理的理解,介绍使用 Windows API 函数实现控制进程同步运行的实例,以帮助大家更加深入地理解多个应用程序依次被执行调度的过程。

代码清单 18-1 简单地模拟了捆绑被释放以后,各个程序的同步运行效果:

主程序通过函数 CreateThread 把调度函数 _RunThread 当成一个线程来运行 (行76)。调度函数首先通过 CreateProcess 打开一个程序 (行54) ,然后,调用函数 WaitForSingleObject 等待进程结束 (行 38)。第一个程序结束后,继续使用 CreateProcess 打开第二个程序,使用 WaitForSingleObject 等待第二个程序的结束,依次类推。

执行程序后,首先打开记事本程序,无论你如何操作,均会等待记事本程序退出后 (选择菜单 “文件”|“退出” 选项或者直接选择标题栏最右端的关闭按钮退出记事本),才打开第二个程序 “helloworld.exe”。

字节码转换工具 hex2db:

执行调度的代码会以字节码定义的方式 (使用伪指令 db 语句) 嵌入到源码中。这些字节码可以通过 FlexHex 复制获得,但转换起来特别麻烦。为了方便后续的开发,本节编写一个小工具 hex2db,该工具实现了将文件中的字节码转换为汇编语言字节定义的方式。

例如,文件中的以下字节码:

00 01 02 03 04 A5

利用小工具 hex2db 最终转换为:

db 00h,01h,02h,03h,04h, 0A5h

数据定义该语句包括三部分:

口 前置空格。本例中有四个空格。

口 数据定义伪指令 db。db 和数据之间有一个空格。

口 数据。以逗号分隔,如果某个字节的高八位超过 0ah,则在该字节前添加一个 “0”。

hex2db 源代码:

hex2db 的编写思路与第 2 章的小工具 PEDump 雷同,两者都是以控制输出格式为核心。

hex2db 的源代码见代码清单 18-2:

运行测试:

编译链接执行文件,打开文件 1.txt,查看对 PE 文件 _hostexe 的执行结果(节选) 如下:

注意:

使用小工具 hex2db 生成的数据定义语句外的最后一行末尾有一个逗号,在将结果引入汇编代码时,必须将该过号去掉,否则编译源文件时会出现错误。

执行调度程序 _host.exe:

前面 "EXE 执行调度机制" 目录中通过一个程序模拟了多个应用程序的执行调度过程。接下来就要编写本章通用的执行调度程序 _hostexe。该程序可以对同步运行更多的应用程序,且定义上会更灵活。

主要代码:

主要代码见代码清单 18-3:

与 18.2.2 小节的例子不同,在线程函数 _RunThread 中,要调度的程序不再是固定的某个 PE 文件,而是通过遍历绑定列表数据结构得到的由用户定义的程序。

将 _hostasm 编译,链接以后,生成可执行文件。使用上一节开发的小工具 hex2db.exe,将可执行代码 _host.exe 转换为汇编语言里的字节码定义语句,保存放在 C:\1.txt 中,以便在后面想整体将可执行代码嵌入到汇编源代码时使用。

数据结构分析:

本章开发的 EXE 捆绑器最大能捆绑 100 个文件,由常量 TOTAL_FILE_COUNT 定义。每个捆绑文件都对应一个结构,用来说明文件的名称、所处的位置、是否加入到最终的可执行序列标志等。

该结构的详细定义如下:

函数参数的解释如下:

1) inExeSequence: 标志字节。如果是 0,则表示该捆绑文件是一般文件,不参与释放后的执行调度过程; 如果是 1,则表示该文件为 PE 文件,且参与释放后的执行调度过程。

2) dwFileOff: 该文件字节码在宿主程序中的偏移。指出了文件在宿主程序中的位置。

3) dwFileSize: 文件的大小。

4) name: 要绑定的文件的名字,含子目录。

特别提示:

BinderFileStructname 不是绝对路径,而是当前路径下的相对路径。该路径中包含子目录,可能的表达形式如 pic\background.gif,指当前目录下的 pic 子目录中的 background.gif 图片文件,子目录允许嵌套。(就是相对目录了啦)

宿主程序 host.exe:

下面将开发宿主程序,即 EXE 捆绑器最终生成的携带了捆绑文件的可执行程序。

宿主程序的功能:

宿主程序 host.exe 是 EXE 捆绑器的核心 PE 文件,它具备以下三个功能:

1) 存储所有要捆绑的文件,包括可运行的文件和不可运行的文件,这些文件将通过程序补丁的方式存储到宿主程序的最后一节。

2) 按原目录结构释放所有文件。

3) 具备调度程序执行的功能。该部分功能由释放的 _host.exe 来完成。而 _host.exe 的添加方法则是直接将指令字节码添加到宿主程序的源程序中。

和 _host.exe 程序一样,宿主程序 host.exe 中也定义了一套绑定列表的数据结构。这两个程序维护了同样的数据实例,_host.exe 的绑定列表中每个字段的值都来自于宿主程序。

举个简单例子,如果文件夹中有以下 5 个文件待绑定:

口 A1.exe

口 A2.exe

口 Config.ini

口 dat\abc.dat (注意含子目录)

口 db\abc.mdb (注意含子目录 )

其中 A1、A2 为可执行程序,要求绑定后的程序在运行时先执行 A1,然后执行 A2。

以下数字模拟了宿主程序的绑定列表可能的数据排列方式:(对应的是前面的数据结构)

宿主程序维护了这样的一套数据,用它来释放捆绑文件,嵌入到宿主程序源代码中的 _host.exe 字节码中也维护了这样的一套数据,用它来执行调度。

宿主程序的状态:

由于宿主程序完成了对捆绑文件的存储,所以,在捆绑文件前后不同时期,宿主程序存在不同的状态。

如图 18-1 所示:

如图所示,捆绑前,宿主程序是轻身的,与捆绑文件没有任何的关联; 捆绑后 (执行前),宿主程序已经包含了所有的捆绑文件数据; 执行时,宿主程序会释放捆绑的所有文件。所以,除了宿主程序不发生任何变化外,磁盘上还多出了 _host.exe 和所有绑定的文件。

_host.exe 为进程调度指挥长,释放出的可执行文件就是在它的调度指挥下实现了顺序执行的。该程序包含在捆绑前的宿主程序中。那么,对文件的捆绑工作由谁来完成呢? 答案是由捆绑器来完成。捆绑器类似于 PE 进阶部分的补丁工具。

遍历文件:

为了确认当前目录要捆绑的文件,程序需要首先遍历当前目录下的文件和文件夹,获取当前目录下所有的文件名称,以及每个文件的大小。

遍历文件的代码见代码清单 18-4:

函数 _FindFile 是个递归函数,入口参数是目录名。行6一78是一个循环,通过调用函数 FindNextFile 获得下一个文件或文件夹。行 69 ~ 73 判断 : 得到的如果是一个子文件夹,则继续调用函数 _FindFile 遍历下一个文件夹的内容,如果是文件,则调用函数 _ProcessFile 输出文件名及长度。

释放文件:

文件的释放比较容易。在宿主程序中,根据功能的不同分类,共有两种文件需要释放;

第一种:只有一个文件,它就是进程调度程序 _host.exe。该文件是事先通过将程序字节码 (前面生成的 C\1.txt 文件) 写和到数据段的方法嵌入宿主程序的。

另一种:是捆绑文件,这些文件是通过后面介绍的打补丁方法,把所有相关文件的数据附加到宿主文件的最后一个节来实现的。

1. 释放 _host.exe

由于进程调度程序所有的字节码均写入到了宿主程序的数据段中,数据定义如下:

所以,释放该文件非常容易,只需要将这些字节码原样写回文件即可,代码如下:

2. 释放捆绑文件:

补丁工具在打补丁时,将所有待捆绑的文件的相关信息记录到宿主程序的绑定列表中。这些信息包括: 每个文件在宿主中的偏移、文件大小和释放后所在目录位置及文件名。

所以,释放捆绑文件时,只需根据绑定列表的描述释放每一个文件即可,具体包括以下四步:

步骤1:确定捆绑文件在宿主中的偏移。

步骤2:确定捆绑文件的大小。

步骤3:确定该文件释放以后的绝对路径。

步骤4:执行释放操作。

释放捆绑文件的主要代码见代码清单 18-5:

行 47 一 94 根据绑定列表结构 BinderFileStruct 中定义的值,对每一个文件进行释放处理。因为文件在宿主程序中的起始地址和大小都有记录,文件内容唾手可得。

程序首先根据 BinderFileStructname 一次性完成文件所在目录的创建操作 (如果目录存在嵌套则循环创建名字中所有嵌套的子目录),然后在目录中用结构指定的名称新建文件,并调用函数 writeToFile 将宿主程序中指定位置、指定大小数据写入,从而完成对捆绑文件的释放工作。

宿主程序主函数:

宿主程序的主函数只有三个调用,这三个调用很明晰地展示出该函数的三个主要作用,它们依次是:

口 writeToFile (用以释放 _host.exe 文件)

口 releaseFiles (用以释放捆绑的文件)

口 _RunThread (用以调度执行程序的线程函数,执行的是 _host.exe 文件)

主函数代码如下所示:

EXE 捆绑器 bind.exe:

EXE 捆绑器的主要任务是,将要捆绑的文件附加到宿主程序 host.exe 文件的最后一节。这类似于 PE 进阶部分讲的补丁工具 bind.exe。除了打补丁,捆绑器还要完成对宿主程序 host.exe 中的两套绑定列表数据的修正,以便用于后期的释放捆绑文件和调度运行程序。要完成对补丁列表数据的修正,首先需要完成对绑定列表数据的定位。

绑定列表定位:

绑定列表在 host.exe 和要释放的 _host.exe 中均保留了一份,那么这个位置在宿主程序 host.exe 的哪个偏移处呢? 使用十六进制编辑器 FlexHex 打开 host.exe,查找 .data 中两个 0xFFFFFFFFFFFF 双字的位置(标志变量,仅做标志作用),其后紧跟着的就是绑定列表数据结构。

如下所示:(根目录由 c:\ql 改成 ql,所以位置与原文件不一样)

通过查找可以找到这两套绑定列表数据所在文件的偏移:

口 由 host.exe 维护的第一套绑定列表起始位置: 13a9h

口 由 _host.exe 维护的第二套绑定列表起始位置: 8be2h

最终运行时,绑定列表的数据结构排列看起来类似以下字节码所示:

加框部分是捆绑的文件个数,每个文件都由结构 BinderFileStruct 定义。结构中包含的字段在前面已经进行了介绍,如文件路径、是否可执行、文件长度、所在位置等。

捆绑步骤及主要代码:

捆绑器使用了本书第 17 章介绍的,在 PE 最后一节附加数据的方法;由于不需要调整指令指针的值,所以相对简单。

以下是对捆绑步骤的简单描述:

步骤1:打开宿主程序,将宿主程序映射到内存文件。获取要捆绑目录下所有文件的长度,并按照文件对齐粒度对齐。将现有宿主程序的大小加上对齐后的大小,重新映射宿主程序。

步骤2:将宿主程序,要捆绑的文件复制到新映射的内存文件中,记录每个文件的相对位置,同时,将这些信息写入宿主程序中的两处捆绑列表所在位置。

步骤3:修改最后一节的相关参数。

捆绑过程的主要代码见代码清单 18-6:

测试运行:

为了查看程序执行效果,请按照以下步骤进行测试:

步骤1:编译 _hostasm,生成 _host.exe 可执行代码。

步骤2:编译 hex2db.asm,运行 hex2db,生成 _host.exe 的字节码 1.txt。

步骤3:编译 host.asm,将上一步生成的 _host.exe 字节码加入到数据段中。

步骤4:通过十六进制查看器查看生成的 host.exe 字节码,查找两个捆绑表所在位置。记录这个位置并将结果写到 bind.asm 中 。

步骤5:编译 bind.asm 并运行,生成最终的 D:\桌面\host.exe 程序。

图 18-2 是对本节中部分文件进行捆绑的示意图。其中各按钮的解释如下:

开始测试:

小结:

本章通过在目标 PE 文件未尾追加补丁的方式 (参见第 17 章),演示了一种将用户指定目录下的所有文件捆绑在一起的编程方法。实例中的补丁程序完成了释放宿主程序、释放相关捆绑文件、运行调度程序、实施绑定列表中指定可运行 PE 文件的批量同步运行。

EXE 捆绑器可应用于对指定 目录或文件进行加密,也可用于对批量 EXE 文件的执行,特别是在升级多个补丁工具时比较有用。

WINDOWS+PE权威指南读书笔记(26)相关推荐

  1. WINDOWS+PE权威指南读书笔记(20)

    目录 PE补丁技术 动态补丁: 进程间的通信机制: 读写进程内存: 目标进程枚举: 执行远程线程: 静态补丁: 整体替换 PE 文件: 整体替换 DLL 文件: 部分修改 PE 文件 嵌入补丁程序: ...

  2. WINDOWS+PE权威指南读书笔记(27)

    目录 软件安装自动化 基本思路: 补丁程序 patch.exe: 执行线程函数: 简单测试: 消息发送器 _Message.exe: 窗口枚举回调函数: 调用窗口枚举函数: 向指定窗口发送消息: 消息 ...

  3. [读书][笔记]WINDOWS PE权威指南《零》PE基础

    参考: https://zhuanlan.zhihu.com/p/47075612 https://docs.microsoft.com/zh-cn/windows/win32/debug/pe-fo ...

  4. mysql数据库权威指南_MySQL_MySQL权威指南读书笔记(三),第二章:MYSQL数据库里面的数 - phpStudy...

    MySQL权威指南读书笔记(三) 第二章:MYSQL数据库里面的数据 用想用好MYSQL,就必须透彻理解MYSQL是如何看待和处理数据的.本章主要讨论了两个问题:一是SQL所能处理的数据值的类型:二是 ...

  5. MongoDB权威指南读书笔记——CRUD

    插入并保存文档 插入是向MongoDB中添加数据的基本方法.可以使用Insert方法向目标集合插入一个文档:db.foo.insert({"bar" : "baz&quo ...

  6. HTTP权威指南读书笔记

    <<HTTP权威指南>>读书笔记 第一部分:Web的基础 第1章:HTTP概述 主要内容 1.什么是HTTP 2.HTTP的基本组件 HTTP HTTP:HTTP(Hypert ...

  7. HTML5权威指南----读书笔记

    <!DOCTYPE html> <html> <head><meta name = 'keywords' content="HTML5权威指南--- ...

  8. [读书][笔记]WINDOWS PE权威指南《一》PE的原理和基础 之 第一章 环境搭建及简单破解

    文章目录 前言 前期准备 1.1 开发语言MASM32 1.1.1 设置开发环境 下载安装masm 环境变量配置 测试是否配置成功 1.1.2 开发第一个源程序HelloWorld.asm 配置 代码 ...

  9. 计算机网络和http权威指南 读书笔记

    计算机网络笔记 网络层 网络层向上提供无连接的,尽最大努力交付的数据报服务 网络层不提供数据质量承诺 物理层使用的中间设备叫转发器repeater 数据链路层叫网桥bridge 网络层叫路由器rout ...

最新文章

  1. 【Java】基本二叉搜索树讲解
  2. php中implode()和explode()的应用
  3. Python FastApi:快速建立docker容器/挂载共享文件夹/导入导出
  4. linux中匿名用户怎么登陆_南京课工场IT培训:Linux中vsftpd服务配置(匿名,用户,虚拟用户)...
  5. DEVC++编译奇怪报错问题解决
  6. 定义字符串 && 字符串数组
  7. 另菜单或工具栏按钮失效的mfc处理方法
  8. linux下交叉编译ffmpeg,并加入H264编码支持
  9. 大数据时代,CRM帮助企业进行升级转型
  10. Google退出中国 Mark
  11. android切图规范,APP切图详细规范终极指南
  12. 好好搭搭机器人编程视频_机器人编程搭建 | 乐创世界学员作品展示第4期!
  13. 篇1:如何为FPGA选择合适的电源管理方案
  14. PLC中ST语言的几种程序流程控制语句
  15. 软件行业职位英文缩写介
  16. 计算机主机的是指什么,电脑基本操作包括哪些 电脑的基本的操作是指什么
  17. 做汽车工程师需要哪些计算机语言,做好汽车研发工程师,需要懂哪些?
  18. 国内外开源分析及实践
  19. vue2.x使用jodit富文本编辑器,并配置自定义字体和中文
  20. MICROSOFT HYPER-V SERVER 2019 许可协议

热门文章

  1. 超强阵容!2022亚马逊云科技 re:Invent 全球大会主题演讲嘉宾揭晓
  2. 1995-2022年中国经济政策不确定性指数
  3. 声音识别入门经典模型实践-基于大数据训练CNN14网络实现食物咀嚼声音识别
  4. 上海西门子培训-第四天(周三)
  5. Educational Codeforces Round 133 (Rated for Div. 2)
  6. python整理桌面,让桌面干净清爽井井有条。
  7. 光耦继电器工作原理与参数详解
  8. 制作一个简单的Android版的音乐播放器
  9. 安全siem_当时和现在的安全相关性是关于siem的可悲事实
  10. dw支持css3 html,通过DW设计网页时组织CSS的建议