PE程序底层结构与恶意代码插入与执行的研究

2024-04-14 22:36

本文主要是介绍PE程序底层结构与恶意代码插入与执行的研究,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Windows PE程序底层结构分析

PE(Portable Executable)是一种Windows操作系统下可执行文件的标准格式

pe101-64.png
Windows PE程序结构和Linux的elf程序结构类似,首先一个名为simple64.exe程序里有一个头文件和一个段文件,头文件里主要存放的是可执行文件的技术详细信息,段文件里主要存放的是可执行文件的内容
image.png
在头文件里的内容有DOS头信息,PE的头信息,optional头信息,数据目录,节表
image.png
头文件里信息的详细内容
image.png
而段文件里主要存放的是程序代码,导入,数据信息
image.png
为了更好的理解,这里写一个简单的exe程序来进行分析

#include <stdio.h>
int main()
{printf("Hello, World!");return 0;
}

安装编译工具:

apt-get install g++-mingw-w64-x86-64

编译程序:

x86_64-w64-mingw32-g++ --static test.cpp -o helloword.exe

image.png
将编译好的helloword.exe文件拖入到010 Editor里分析,如果没有010 Editor,也可以用linux里的xxd工具分析
010 Editor下载:

https://www.sweetscape.com/010editor/

图中的4D 5A是一个DOS头数据
image.png
图中紫色的地方提示系统这个程序不是以DOS模式运行的
image.png
50 45就是程序的PE头数据
image.png
在下面有.text .data .rdata .bss段,这些都是程序的节表名称

.text段:存储可执行代码(机器指令),即程序的指令部分
.data段:存储已初始化的全局变量和静态变量
.rdata段:存储只读数据,例如常量字符串等
.bss段:存储未初始化的全局变量和静态变量

image.png
使用pe-bear工具可以查看更详细的PE程序结构

https://github.com/hasherezade/pe-bear/releases/tag/v0.6.7.3

image.png
比如,这里我就可以查看.rdata段存储的字符串hello world,还可以看到程序当前的汇编指令
image.png
点击.text节,选择导入表,可以看到程序使用的一些dll文件名称,dll相当于是一个库,程序使用的函数都是从这个库里导入的
image.png
无论是PE或者ELF文件,里面都有一个entry函数,这个函数很重要,它是程序的入口函数,在分析恶意程序的时候,通常都找不到main函数,这里就需要看entry函数来定位程序主函数
入口函数的作用是指示程序从何处开始执行。它通常包含程序的主要逻辑,初始化代码以及程序的控制流程。在程序运行时,操作系统或运行时环境会找到入口函数,并从该函数开始执行程序的代码
image.png

恶意代码插入与执行

用xdbg导入可执行程序,在最下面,程序有一段都是0的部分,有些文件格式或文件类型在设计时可能会留有预留空间,以便将来添加或扩展文件内容。这些空白区域可能在文件创建时被填充为0,这部分是程序的一块空字节空间,攻击者可以在这个空间里写入恶意代码,通过汇编指令,达到正常运行程序和恶意代码的一个效果,这里用系统的calc.exe程序举例
image.png
image.png
这个区域就是程序的空字节空间,我们先用msf生成一段shellcode代码
启动msf,使用payload/windows/exec模块,如果要生成64位的shellcode就使用payload/windows/x64/exec模块,这里calc.exe程序是32位的,所以要用32位的模块
image.png
可生成cmd执行的命令,设置完成后用generate -f raw -o 命令输出内容到指定文件里,这里我的shellcode是打开一个文本文档
image.png
使用xxd可以看到shellcode的十六进制
image.png
回到xdbg,启动程序到entry point处,无论是PE或者ELF文件,里面都有一个entry函数,这个函数很重要,它是程序的入口函数,入口函数的作用是指示程序从何处开始执行。它通常包含程序的主要逻辑,初始化代码以及程序的控制流程。在程序运行时,操作系统或运行时环境会找到入口函数,并从该函数开始执行程序的代码
image.png
复制这一行,记录下来

003C1CE0 <c | E8 3EFCFFFF                        | call calc.3C1923                                        |

然后去到程序空字节区域,复制记录第一行
image.png

003C20C4    | 0000                               | add byte ptr ds:[eax],al                                |

回到entry函数处,选中entry函数,按下空格编辑汇编指令,jmp到0x003C20C4空字节空间处

jmp 0x003C20C4

image.png
双击函数,会自动跳转到指定的内存地址,现在我们要先push两个寄存器,之后才能写入shellcode

pushad

push ad指令在32位程序下有用,它的作用是将所有通用寄存器push到栈中,比如EAX, ECX, EDX, EBX这些32位寄存器

pushfd

push fd指令作用是将标志寄存器压入堆栈,这个寄存器包含了各种处理器状态和控制标志位,比如条件码、中断允许位等
image.png
然后用010 Editor或者win hex工具打开刚刚msf生成的shellcode文件,复制文件里的十六进制值,回到xdbg的空字节空间,在刚刚添加汇编指令的下一行长按鼠标,框选一段区域,然后按下ctrl+e,将十六进制值粘贴进去
image.png
点击确定后,就能看到shellcode的汇编指令
image.png
为了使程序正常运行,我们还需要jmp回之前entry函数调用的地址,首先需要pop出之前push进去的寄存器指令,使堆栈平衡,在程序最后一行的后一行写入,因为程序最后一行的空指令处代表的是shellcode的结束地址

popfd
popad

image.png
然后写入之前entry原来的指令,让程序正常运行

call 0x003C1923

跳转到entry函数下一行指令处,正常执行程序
image.png

jmp 0x003C1CE5

image.png
最后用jmp指令替换掉shellcode后的退出指令,因为我们要正常打开calc.exe程序
image.png
跳转到popfd处

jmp 0x00F9218B

image.png
选择xdbg任务栏里的创可贴图标,保存修改后的文件
image.png
image.png
运行保存后的文件,程序会运行计算器和文本文档
image.png
这里还是推荐自己写汇编指令,用msf生成的shellcode特征太明显,容易被查杀

这篇关于PE程序底层结构与恶意代码插入与执行的研究的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/904206

相关文章

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

maven 编译构建可以执行的jar包

💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」👈,「stormsha的知识库」👈持续学习,不断总结,共同进步,为了踏实,做好当下事儿~ 专栏导航 Python系列: Python面试题合集,剑指大厂Git系列: Git操作技巧GO

自定义类型:结构体(续)

目录 一. 结构体的内存对齐 1.1 为什么存在内存对齐? 1.2 修改默认对齐数 二. 结构体传参 三. 结构体实现位段 一. 结构体的内存对齐 在前面的文章里我们已经讲过一部分的内存对齐的知识,并举出了两个例子,我们再举出两个例子继续说明: struct S3{double a;int b;char c;};int mian(){printf("%zd\n",s

EMLOG程序单页友链和标签增加美化

单页友联效果图: 标签页面效果图: 源码介绍 EMLOG单页友情链接和TAG标签,友链单页文件代码main{width: 58%;是设置宽度 自己把设置成与您的网站宽度一样,如果自适应就填写100%,TAG文件不用修改 安装方法:把Links.php和tag.php上传到网站根目录即可,访问 域名/Links.php、域名/tag.php 所有模板适用,代码就不粘贴出来,已经打

顺序表之创建,判满,插入,输出

文章目录 🍊自我介绍🍊创建一个空的顺序表,为结构体在堆区分配空间🍊插入数据🍊输出数据🍊判断顺序表是否满了,满了返回值1,否则返回0🍊main函数 你的点赞评论就是对博主最大的鼓励 当然喜欢的小伙伴可以:点赞+关注+评论+收藏(一键四连)哦~ 🍊自我介绍   Hello,大家好,我是小珑也要变强(也是小珑),我是易编程·终身成长社群的一名“创始团队·嘉宾”

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。

跨系统环境下LabVIEW程序稳定运行

在LabVIEW开发中,不同电脑的配置和操作系统(如Win11与Win7)可能对程序的稳定运行产生影响。为了确保程序在不同平台上都能正常且稳定运行,需要从兼容性、驱动、以及性能优化等多个方面入手。本文将详细介绍如何在不同系统环境下,使LabVIEW开发的程序保持稳定运行的有效策略。 LabVIEW版本兼容性 LabVIEW各版本对不同操作系统的支持存在差异。因此,在开发程序时,尽量使用

CSP 2023 提高级第一轮 CSP-S 2023初试题 完善程序第二题解析 未完

一、题目阅读 (最大值之和)给定整数序列 a0,⋯,an−1,求该序列所有非空连续子序列的最大值之和。上述参数满足 1≤n≤105 和 1≤ai≤108。 一个序列的非空连续子序列可以用两个下标 ll 和 rr(其中0≤l≤r<n0≤l≤r<n)表示,对应的序列为 al,al+1,⋯,ar​。两个非空连续子序列不同,当且仅当下标不同。 例如,当原序列为 [1,2,1,2] 时,要计算子序列 [

哈希表的底层实现(1)---C++版

目录 哈希表的基本原理 哈希表的优点 哈希表的缺点 应用场景 闭散列法 开散列法 开放定值法Open Addressing——线性探测的模拟实现 超大重点部分评析 链地址法Separate Chaining——哈希桶的模拟实现 哈希表(Hash Table)是一种数据结构,它通过将键(Key)映射到值(Value)的方式来实现快速的数据存储与查找。哈希表的核心概念是哈希