目标:

改动PE导入表,手工给HelloWorld增加一个功能,就是启动的时候写入一条开机启动项,C:\cmd0000000000000000000000000000.exe

实现方法:

直接在注册相关自启动里面添加一个开启启动文件路径就行了。

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run

NewValue   C:\cmd0000000000000000000000000000.exe

代码逻辑相关:

RegCreateA()

RegSetValueExA()

RegClose()

对应汇编代码:

0001  68xxxxxxxx      Push addr @hKey

0002  68xxxxxxxx      Push addr szKey

0003  68xxxxxxxx      Push HKEY_LOCAL_MACHINE

0004  E8xxxxxxxx      Call RegCreateA

0005  6A27            Push 39

0006  68xxxxxxxx      Push addr lpszValue

0007  6A01            Push REG_SZ

0008  6A00            Push NULL

0009  68xxxxxxxx      Push addr lpszValueName

000A  FF35 xxxxxxxx   Push @hKey

000B  E8xxxxxxxx      Call RegSetValueExA

000C  FF35 xxxxxxxx   Push @hKey

000D  E8xxxxxxxx      Call RegClose

.

.

.

000E  FF25xxxxxxxx    JMP DWORD PTR [xxxxxxxx]

000F  FF25xxxxxxxx    JMP DWORD PTR [xxxxxxxx]

0010  FF25xxxxxxxx    JMP DWORD PTR [xxxxxxxx]

细化指令:

(1)64xxxxxxxx push addr @hKey

如果数据在.data段中,而传递的是地址,比如addr @hKey,则push的指令码为64h,后面紧跟着8位的地址,该地址只是了数据所在位置的VA.。即@hKey所在的VA。关于这个值得计算方法如下:

获得程序默认装载地址=0x00400000

获得数据段.data的起始RVA=0x03000

假设数据段的安排如下(注意路径不是***cmd000000.....exe,但是长度一样)

对应字节码为:

根据数据段各变量的位置,从上述所列字节码中找到@hKey所在的位置为0x00403069,所以第一条指令字节码是68 69 30 40 00。

(2)68xxxxxxxx push addr sz1

采用同样的方式 68 0B 30 40 00

(3)68xxxxxxxx push HKEY_LOCAL_MACHINE

因为HKEY_LOCAL_MACHINE是一个双字节常亮,所以压栈的字节码为68h,其后是该常量的值。

So   68 02 00 00 80

(4)E8xxxxxxxx call RgeCreateKeyA

由于这是一个段内调用,所以call的指令字节码为E8,其后跟随的则是距离真正跳转指令的偏移。偏移这么计算:

首先确定HelloWorld.exe的指令长度为24h。

其次,他要跳转过自身后面的所有指令,如下所示:

这些指令加起来长度为26h,两者相加即为call到jmp的偏移量4Ah;所以第四条指令的字节码是 E8 4A 00 00 00。

(5) 6A27  PUSH 27H

如果往栈里推入的双子可以控制在一个字节内,那么需要使用6A指令。后面直接跟一个字节的数值。

根据上面的分析方法,不难得出6-9条指令的字节码依次为:

68 42 30 40 00

6A 01

6A 00

68 39 30 40 00。

(6)FF35xxxxxxxx push @hKey

当要讲数据段制定位置的双字压入栈时,需要使用指令FF35,其跟着制定位置的VA。其实该指令可以解释为: push dword prt ds:[xxxxxxxx]。

所以第十条指令字节码是FF 35 69 30 40 00。

(7)E8xxxxxxxx call RegSetValueExA

同第四条指令,该跳转地址紧跟在第四条指令跳转的后面。现在计算操作数,长度由一下部分组成(call 的话 是直接call的距离,不是直接call VA):

1)该指令下的其他指令如下,总计0Bh个字节

2)原Helloworld.exe指令,总计24个字节。

3)第四条跳转指令FF25xxxxxxxx,总共6h个字节

以上长度加起来后结果是35h。所以第是一条指令字节码为E8 35 00 00 00。

(8) FF35 xxxxxxxx Push @hKey

第十二条指令字节码是 FF 35 69 30 40 00。

(9)E8xxxxxxxx Call RegClose

同第四条指令,该跳转地址紧跟在是一条指令后,其长度的计算包含以下几个部分:

其后再无添加代码(0h)

原Helloworld指令(24h)

第四条指令的跳转指令FF25xxxxxxxx(6h)

第是一条指令的跳转指令FF25xxxxxxxx(6h)

以上长度加起来后的结果是30h。则第十三条指令字节为E8 30 00 00 00。

(10)跳转指令

跳转指令为FF25,后面跟着要跳转到的VA地址。从前面对导入表的分析看,这三个函数地址是IAT的前三个,也就是最后一个非零IMAGE_IMAPORT_DESCRIPTOR结构中字段FirstThunk只想的位置。其地址依次为00402000 00402004 00402008,所以,最后三个跳转指令依次为:(这个地方看不懂的话就去看下之前总结的导入表那章)

FF 25 00 20 40 00

FF 25 04 20 40 00

FF 25 08 20 40 00

综上所述,新增加代码的字节码如下:

与原Helloworld的字节码相比,代码部分增加了4Ch大小。指令字节码构造完成后,接下来的任务是分析此次修改导致的PE头部的变化。

PE头部变化

1.IMAGE_SECTION_HEADER(.data).VirtualSize

新增加的常量都定义在源码的数据段主要包括以下内容:

(上面路径我改成c下的cmdaaaa...aa.exe了)

共98个字节,所以.data接的尺寸要增加64h。

2.IMAGE_DATA_DIRECORY[IAT].size

由于新增加了一个IMAGE_IMPORT_DESCRIPTOR,所以在IAT中要加入新增加的三个入口函数地址;同时,增加一个结尾的0,共四个双字,16个字节,所以IMAGE_DATA_DIRECTOY[IAT].isize要多加10h。

3.IMAGE_DATA_DIRECOTRY[IT].VirtualAddress

由于导入表的起始地址紧跟在IAT后,IAT多增加的字节数也是导入表起始位置偏移的数量,所以该字段要后移16个字节,即IMAGE_DATA_DIRECORY[IT].VirtualAddress需要多加10h。

4.IMAGE_SECTION_HEADER(.rdata).VirtualSize

1)增加一个动态链接库,就增加一个IMAGE_IMPORT_DESCRIPTOR结构,大小14h。

2)OriginalFiresThunk部分,3个新增注册表操作函数名指针和一个0结尾的指针共10h。

3)“编号/名称”部分包含以下定义:

xxRegCreateKeyA\0xxRegSetValueExA\0xxRegCkiseKey\0advapi32.dll\0\0共61个字节(3Dh)。

4)FirstThrunk部分,3个新增注册表函数名指针和一个0结尾的指针共10h。

综上所述,IMAGE_SECTION_HEADER(.rdata).VirtualSize的值需要多加71h。

5)IMAGE_DATA_DIRECTORY[IT].isize

多了一个动态库,就多出一个IMAGE_IMPORT_DESCRIPTOR结构,该结构大小为14h。即IMAGE_DATA_DIRECTORY[IT].isize多增加14h。

6.IMAGE_SECTION_HEADER(.text).VritualSize

代码段前面已经说过,增加4Ch大小。

由于插入代码而使得PE头部发生变化如下:

上面按顺序依次是:

导入表地址   [IT].VirtualAddress

导入表大小   [IT].isize

数据目录数   [IAT].isize

代码段大小   .text

增加的一些导入表相关,就是上面4说的那些,只读数据 .rdata

数据段大小 .data

手工重组

完成了指令字节码构造,明确了PE头部需要更改的字段,接下来就是手工重组部分。由于新的代码和数据与原来的代码和数据加在一起没有超出文件对其要求得粒度,所以DOS头、PE头的大部分字段不需要修改。以下是手动修改过程:

1.数据段

首先,添加程序中用到的数据。定位到HelloWorld.exe文件的800h处,从第一个字节为0的地方复制以下数据:

为什么从800h开始,因为800h是数据段:

然后修改数据段大小:

到200h的地方找到0B改成6Dh

此时的exe还是可以正常运行的。

2.代码段

找到代码段在400h处:

原来是只有这些:

然后在代码段的开始部分加入我们新增的代码,就是最上面分析的那些代码:

之后再修改

橙色是新增功能代码段,黑色是源代码段,黑色原代码段中红色部分是修改部分,因为新产生的IA被安排在IAR的头部,所以其他的调用地址必须往后调整。在程序中,一共增加了三个函数(来自同一个动态链接库),所以按照导入表的要求,在IAT表头需要增加三个函数入口地址(12个字节)和一个全0(4字节)的地址,这样,原来的入口函数地址都要往后调整10h个字节,所以FF25 JMP的IAT都向后偏移10h。

然后把.text代码段长度修改下:

找到代码段长度位置:

到1B0h处把24h改为70h:

改之后代码段长度显示也就变了:

此时的程序无法运行,因为.rdata处还没改,导入表部分还没有改。上面直接偏移了两个原来函数JMP地址。那个地址是什么还不知道呢!所以目前无法运行。

3. .rdata段

这个地方相对较难,要细心些:

首先看下原始导入表数据字节码:

去FOA=600h地方去找:

原来的样子:

修改后的内容如下(带下划线为待定部分,一会会重新计算)

新增的内容,三个函数加一个0位,是4*4

之前有两个函数,Message,和ExitProcess分别只有一个函数,每个又有一个0位,所以是

2*4+2*4最后一共20h

共涉及到3个Dll加上一个0位,20*3+20=50h

对应IAT,3个函数(3+1)*4  一个函数(1+1)*4 所有的一共4*4+2*4+2*4=20h

以上列出了导入表的四个组成部分,只要知道了代码中调用函数的个数以及链接库的个数,INT、导入表项、IAT三个大部分的大小就是固定的了。实际上,导入表的重组只需要先将第4部分也就是函数编号、函数名和动态库这一部分根据编码设置好,剩下的其他部分的数据就可以按照数据结构自行构造了。

第三个导入表项IMAGE_IMPORT_DESCRIPTOR的OriginalFirstChunk值为00002070h,他是一个RVA,转换为文件偏移地址为0x00000670、FirstChunk的值为00002000h,也是一个RVA,对应的FOA为0x00000600。

文件中IAT和INT维护了两份值相同的双字数组。

000020C6H 来源于表4-2中函数RegCreateKeyA的VA地址。由于是RVA所以要减去基地址0x00400000h。另外两个双字用同样的方法填充。构造好的第三部分代码如下:

4.修改与数据目录表项和节表想相关字段

上面说过了:

5.运行测试:

开机启动项的注册表是加上了,但是没有之前的Messagebox弹窗了。

结果往后看,书中是给了解释的(一开始第一遍做没注意,以为做错了)。

修改之后:

这个地方别改错了,书上没有告诉具体细节,我改了好几次最后找到了,JMP顺序

402018,402010,402000,402004,402008改成402010,402018,402000,402004,402008

OK就这些,所有的都搞定了。这个写了好几天,今天又是一点多了。终于整完了,明天还要上班。酱紫。

手动添加导入表修改EXE功能的更多相关文章

  1. (菜鸟要飞系列)五,基于Asp.Net MVC5的后台管理系统(添加数据表的分页功能)

    献上代码 ) { List<UserModel> arrayUserModel = new List<UserModel>(); string strText = Reques ...

  2. Angular实现动态添加删除表单输入框功能

    <div class="form-group form-group-sm" *ngFor="let i of login"> <label c ...

  3. C#中缓存的使用 ajax请求基于restFul的WebApi(post、get、delete、put) 让 .NET 更方便的导入导出 Excel .net core api +swagger(一个简单的入门demo 使用codefirst+mysql) C# 位运算详解 c# 交错数组 c# 数组协变 C# 添加Excel表单控件(Form Controls) C#串口通信程序

    C#中缓存的使用   缓存的概念及优缺点在这里就不多做介绍,主要介绍一下使用的方法. 1.在ASP.NET中页面缓存的使用方法简单,只需要在aspx页的顶部加上一句声明即可:  <%@ Outp ...

  4. 如何手动添加Windows服务和如何把一个服务删除

    windows 手动添加服务方法一:修改注册表 在注册表编辑器,展开分支"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services" ...

  5. 注册表的作用、bat文件中REG ADD命令添加注册表项以及bat

    注册表的用途与设置 注册表是windows的核心,里面储存着大量的系统信息,说白了就是一个庞大的数据库.如果你不懂什么是数据库,那没关系,不影响你了解注册表,不过最好对数据库有所了解.注册表里面所有的 ...

  6. windows 手动添加服务

    windows 手动添加服务方法一:修改注册表 在注册表编辑器,展开分支"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services" ...

  7. Windows服务的手动添加和删除方法

    Windows服务的手动添加和删除方法 服务,是指执行指定系统功能的程序.例程或进程,以便支持其他程序,尤其是低层(接近硬件)程序.其实,服务就是一种特殊的应用程序,它从服务启动开始就一直处于运行状态 ...

  8. PE格式第五讲,手工添加节表

    PE格式第五讲,手工添加节表 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) 首先我们要用汇编编写一段汇编代码,用来生成 ...

  9. C/C++ 手工实现IAT导入表注入劫持

    DLL注入有多种方式,今天介绍的这一种注入方式是通过修改导入表,增加一项导入DLL以及导入函数,我们知道当程序在被运行起来之前,其导入表中的导入DLL与导入函数会被递归读取加载到目标空间中,我们向导入 ...

随机推荐

  1. CVE-2018-2628-WLS Core Components 反序列化

    漏洞参考 https://blog.csdn.net/csacs/article/details/87122472 漏洞概述:在 WebLogic 里,攻击者利用其他rmi绕过weblogic黑名单限 ...

  2. 从零学脚手架(二)---初识webpack

    在上一篇中,介绍了 webpack 的 entry . output . plugins 属性. 在这一篇,接着介绍其它配置属性. mode 这个属性在上一篇中使用过一次:设置 webpack 编译模 ...

  3. 顺序表及基本操作(C语言)

    #include <stdio.h> #include <stdlib.h> //基本操作函数用到的状态码 #define TRUE 1; #define FALSE 0; # ...

  4. HDU_6695 Welcome Party 【思维】

    一.题目 Welcome Party 二.分析 最开始的时候分析错了,认为只要找两个类型中的最小差值就可以了,忽略了是求两个类型中最大值的最小差值. 那么可以对第一个类型进行从大到小排序,枚举这个类型 ...

  5. flutter简易教程

    跟Java等很多语言不同的是,Dart没有public protected private等关键字,如果某个变量以下划线 _ 开头,代表这个变量在库中是私有的.Dart中变量可以以字母或下划线开头,后 ...

  6. reverseLinkedList(翻转链表)

    ReverseLinkedList(翻转链表) 链表是一种物理存储单元上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的.非连续.非顺序指的是,通过指针把一组零散的内存块串 ...

  7. clickhouse 亿级数据性能测试

    clickhouse 在数据分析技术领域早已声名远扬,如果还不知道可以 点这里 了解下. 最近由于项目需求使用到了 clickhouse 做分析数据库,于是用测试环境做了一个单表 6 亿数据量的性能测 ...

  8. java连接sql server--关于登录验证及对数据库增删改查应用

    一:步骤## 1.sql server建立数据库和相关表 2.建立数据源  (1).打开控制面板找到管理,打开ODBC选项或直接搜索数据源  (2).打开数据源配置后点击添加,选择sql server ...

  9. java例题_50 题目:有五个学生,每个学生有 3 门课的成绩,从键盘输入以上数据(包括学生号,姓名,三门课成 绩),计算出平均成绩,将原有的数据和计算出的平均分数存放在磁盘文件"stud"中。

    1 /*50 [程序 50 文件 IO] 2 题目:有五个学生,每个学生有 3 门课的成绩,从键盘输入以上数据(包括学生号,姓名,三门课成 3 绩),计算出平均成绩,将原有的数据和计算出的平均分数存放 ...

  10. 14、运行Django时浏览器中遇到Refused to display 'url' in a frame because it set 'X-Frame-Options' to 'deny'

    问题:Refused to display 'url' in a frame because it set 'X-Frame-Options' to 'deny' 解决办法: 只需要在 Djagno ...