代码节空白区添加代码(手动)(含C练习代码)【基础函数的实现的源代码在这里面】

1、用OD 在命令行输入 bp MessageBoxW ,找到754EF280 是Messgebox函数开始执行的位置,这个地址每台电脑都不一样,每次开机也会变化。

在这里插入图片描述

2、我们的目的就是要手动在文件修改OEP,指向自己手动添加的CALL 代码地址,然后用JMP跳回到原来OEP指向的地址让EXE继续正常运行 ,向文件中添加的代码都是编译后的代码,也就是硬编码。

3、6A 00 6A 00 6A 00 6A 00 E8 00 00 00 00 E9 00 00 00 00 ,这一段就是CALL 和JMP的硬编码模板,6A00 都是 PUSH的四个参数,MessageBox四个参数都是0,E8 后面的 00 00 00 00 就是要修改为OD找到的MessageBox 地址 754EF280 的硬编码,E9 后面的00 00 00 00 修改为OEP原先的地址

4、计算E8和E9硬编码的公式,下图X 表示 E8 或E9后面的硬编码

	注意:E8当前地址是在4GB空间,拉伸后的地址,不是在文件中的地址。

在这里插入图片描述

5、E8后面的硬编码是计算文件中的还是4GB拉伸以后的?

答案是:是计算拉伸后在4GB中的地址

6、通过 SizeofRawData-VirtualSize 可以知道添加代码的空间是否足够。

在这里插入图片描述

7、通过VirtualSize+PointerToRawData 相加可以知道需要添加代码的位置

在这里插入图片描述

8、找到空闲区域,把空闲区域改为我们需要的代码

在这里插入图片描述

9、根据上面第4条提供的公式,现在要找(E8的地址+5),要注意的是这个E8的地址要转换为在内存运行时的地址.

ImageBase+161ABD
问题现在161ABD是文件中对齐后的地址,要转换为再内存中对齐的地址,这就要回顾一下前面的拉伸规则了。
现在要计算出dwRVA,就是代码在内存中的地址,这样才能算出在内存中Call需要跳转的地址:

dwRva代码的RVA地址=VirtualOffset代码地址到内存节的偏移 +pSectionHeader->VirtualAddress节的内存RVA地址;
VirtualOffset代码地址到内存节的偏移=foa代码在文件中的地址 - pSectionHeader->PointerToRawData节在文件中的地址 ;

现在有两个地址要计算,一个是E8 一个E9
VirtualOffset代码地址到内存节的偏移= E8地址 00161AB8-0x400=16 16B8‬

VirtualOffset代码地址到内存节的偏移= E9地址 00161AB8+5-0x400=16 16BD‬

E8 dwRva代码的RVA地址=1616B8‬+0x1000=1626B8‬
E9 dwRva代码的RVA地址=1616BD+0x1000=1626BD

计算出E8 和 E9 后面的硬编码

E8后的硬编码= 内存实际要跳转的地址754EF280-(1626B8‬+5+400000)= 74F8 CBC3‬
E8 C3 CB F8 74
E9后的硬编码= 内存实际要跳转的地址(AddressOfEntryPoint 程序入口地址 0013BB20 + ImageBase 400000 ) -(1626BD‬+5+400000)
53BB20-5626C2 (计算器要设置DWORD 双字运算)
=FFFD945E
E9 5E 94 FD FF
在这里插入图片描述

最后修改为
在这里插入图片描述

入口地址改为6A00 PUSH 参数开始的位置

在这里插入图片描述

用同样的计算方法 把入口地址改为 16 26B0‬,这个地址是不用加imageBase 400000的
在这里插入图片描述

运行效果

先弹出 对话框

在这里插入图片描述
点确定后 程序继续正常运行

在这里插入图片描述

用C语言实现自动修改,修改完后存盘(以下代码测试可以正确执行)

//主程序 在PE空白区域添加代码,并且从改代码执行,执行完添加的代码后再从原来的入口执行
#include <stdio.h>
#include <stdlib.h>
#include "func.h"

int main(void)
{
   
	PrintNTHeaders();//打印PE头信息

	TestAddCodeIncodeSec();

	getchar();
	return 1;

}
//func.h  头文件
#pragma once
#include <Windows.h>
#define FILEPATH "D:/ipmsg.exe"
#define FILEPATH_NEW "D:/ipmsg_new.exe"
//函数声明								

//**************************************************************************								
//ReadPEFile:将文件读取到缓冲区								
//参数说明:								
//lpszFile 文件路径								
//pFileBuffer 缓冲区指针								
//返回值说明:								
//读取失败返回0  否则返回实际读取的大小								
//**************************************************************************								
DWORD ReadPEFile(IN LPSTR lpszFile, OUT LPVOID* pFileBuffer);

//CopyFileBufferToImageBuffer:将文件从FileBuffer复制到ImageBuffer								
//参数说明:								
//pFileBuffer  FileBuffer指针								
//pImageBuffer ImageBuffer指针								
//返回值说明:								
//读取失败返回0  否则返回复制的大小								
//**************************************************************************								
DWORD CopyFileBufferToImageBuffer(IN LPVOID pFileBuffer, OUT LPVOID* pImageBuffer);

//**************************************************************************								
//CopyImageBufferToNewBuffer:将ImageBuffer中的数据复制到新的缓冲区								
//参数说明:								
//pImageBuffer ImageBuffer指针								
//pNewBuffer NewBuffer指针								
//返回值说明:								
//读取失败返回0  否则返回复制的大小								
//**************************************************************************								
DWORD CopyImageBufferToNewBuffer(IN LPVOID pImageBuffer, OUT LPVOID* pNewBuffer);

//MemeryTOFile:将内存中的数据复制到文件								
//参数说明:								
//pMemBuffer 内存中数据的指针								
//size 要复制的大小								
//lpszFile 要存储的文件路径								
//返回值说明:								
//读取失败返回0  否则返回复制的大小								
//**************************************************************************								
BOOL MemeryTOFile(IN LPVOID pMemBuffer, IN size_t size, OUT LPSTR lpszFile);


//**************************************************************************						
//RvaToFileOffset:将内存偏移转换为文件偏移						
//参数说明:						
//pFileBuffer FileBuffer指针						
//dwRva RVA的值						
//返回值说明:						
//返回转换后的FOA的值  如果失败返回0						
//**************************************************************************						
DWORD RvaToFileOffset(IN LPVOID pFileBuffer, IN DWORD dwRva);

//**************************************************************************						
//添加代码到节的空白区域											
//**************************************************************************
VOID TestAddCodeIncodeSec();

//打印PE文件信息
VOID PrintNTHeaders();
//func.c 函数的实现

#include "func.h"
#include <stdio.h>


#define FILEPATH_IN
#define FILEPATH_OUT
#define SHELLCODELENGTH  0x12 //添加代码长度
#define MESSAGEBOXADDR  0x754EF280  //执行代码的函数入口地址,就是实际要跳转的地址

//全局变量声明
BYTE shellCode[] =
{
   
   0x6A,00,0x6A,00,0x6A,00,0x6A,00,
   0xE8,00,00,00,00,
   0xE9,00,00,00,00,
};

DWORD ReadPEFile(LPSTR lpszFile, OUT LPVOID* pFileBuffer)
{
   
	FILE* pFile = NULL;
	DWORD fileSize = 0;
	//LPVOID pFileBuffer = NULL;

	//打开文件	
	pFile = fopen(lpszFile, "rb");
	if (!pFile)
	{
   
		printf(" 无法打开 EXE 文件! ");
		return NULL;
	}
	//读取文件大小		
	fseek(pFile, 0, SEEK_END);
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值