前言
如题,就是往程序里面加代码,然后实现一些小功能,演示的话就先从最简单 MessageBox 开始
课堂
MessageBox 介绍
MessageBox()函数:功能是弹出一个标准的 Windows 对话框;它不是 C 函数库的标准函数,而是一个 API,我们可以用 C 语言调用 API 函数。可以理解成我们在 C 中使用 MessageBox 函数就表示调用系统提供的 API 函数–MessageBoxA。包含在头文件 windows.h;如果一个程序中包含 user32.dll,则此程序就有 MessageBoxAAPI 函数
int MessageBox( HWND hWnd,LPCTSTR lpText, LPCTSTR lpCaption = NULL, UINT nType = MB_OK );
四个参数说明:
hWnd:表示窗口句柄,指定该对话框的所有者窗口;如果该参数为空(0/NULL),则该对话框不属于任何窗口
lpText:字符串,指显示在对话框中的内容
lpCaption:字符串,指对话框的标题;如果此参数为空,则默认使用“错误”作为标题
nType:指定显示按钮的数目及形式,表名使用的图标样式、缺省按钮是什么、以及消息框的强制回应等
call 与 jmp 指令的硬编码
-
call 指令的硬编码:E8 后面跟了 4 个字节(转换后的地址)
-
jmp 指令的硬编码:E9 后面跟了 4 个字节(转换后的地址)
由于 call 指令和 jmp 指令后面跟的是我们想要调用的函数地址或者跳转的地址,那 E8 和 E9 后面跟的 4 个字节是不是就是这个地址本身呢?不是!E8 和 E9 后面跟的地址数据是需要转换得到的
下面举例说明:
#include "stdafx.h"
void Function(int a,int b,int c,int d){
}
int main(int argc,char* argv[]){
Function(1,2,3,4);
return 0;
}
因为 E8 的当前地址为 0x00401190,真正要跳转的 Function 函数的地址为 0x00401014,根据公式:X = 要跳转的地址 - (E8 的地址 + 该指令长度) = 0x00401014 - (0x00401190 + 5)= 0xFFFFFE7F,由于内存是低地址向高地址存储,所以为 7F FE FF FF,所以最后 call 指令的硬编码为 E8 7F FE FF FF
给程序开头加个壳子
这个壳子就用 MessageBox 就行,我们没有必要自己去写,因为基本程序都有,这里还是拿 everything 来举例,为什么一直选它呢,第一个原因就是它在文件中和在内存中的对齐方式不一样,不像有的 exe 都是 0x1000h,第二个原因就是它的 imagebase 不会乱跑,默认是啥就是啥,默认不会用到 PIC
首先的话明确一下整体的思路,首先在程序中找一个 MessageBox 的函数,并记下地址,就用 bp MessageBoxA 这条指令就行,然后在代码段最后写上我们的硬编码,即传参和 call 到这个 MessageBox 的函数真正的地址上面,然后再写 jmp 去跳转的程序现有的 OEP,最后把程序的 OEP 改成我们在代码段新添的代码的首地址,啊别听着简单,但做起来得超级细心才行
这个是找到的 MessageBox 的函数
然后咱们是在 FileBuffer 中加,咱们就到代码段最后面去加,因为代码段放到内存中也是不会变的,不存在有未初始化变量等的这种情况,这个怎么找,应该都会吧
然后就开始算哇,上面是算好的,其实就是算 E8 后面 4 个字节和 E9 后面四个字节,但真的得细心才行
说几个注意的点,第一是 E8 的地址是在 ImageBuffer 里面的地址,应该是用相对于相对于代码区.text 开始地址的偏移量,再找.text 节在内存中的起始地址(ImageBase + VirtualAddress),最后加起来,第二个就是 OEP 也是内存中相对于 ImageBase 的偏移地址,如果要从 FileBuffer 开始算的话,应该是先减去 400h 再加 1000
然后再修改 OEP
然后就可以保存楼,双击我们的程序看效果
可以看到咱们上面的操作其实都是在 FileBuffer 中做的,这么去写程序的话,必然会分成两种情况,就是文件和内存对齐尺寸一样的,还有就是文件和内存对齐尺寸不一样的,因为不一样的中间始终要做一个地址转换,那咱们为何不从 Imagebuffer 出发呢,因为咱们之前写过这个函数,这样的话就更方便了
总的来说这个过程是十分麻烦的,正在努力写程序 ing,但这个程序不管怎么写都感觉有问题,当然直接加在代码段结尾的话这个程序没有问题,但是要写在其他段的话,程序不管咋设计都不太对劲,因为其他段的话会有未初始化的变量,由于咱们是模拟内存加载的过程,目前的话复制和粘贴段的大小都是 SizeOfRawData,所以写在其它段必然要满足的一个条件就是 misc 必须小于 SizeOfRawData,而且两者之差还得大于 18 个字节,也就是调用 MessageBoxA 所必须的 18 个字节,OK 写完发
作业
写函数实现加壳子,努力写哇,下篇文章发