节空白处添加代码

目标:
    往一个exe程序中添加一段代码,运行exe程序时先执行自己添加的代码,然后再开始执行exe程序;
    例如:使桌面程序crackme.exe执行前,先弹一个框之类的;
 
思路:
    1】修改程序入口
        可选pe头中的AddressOfEntryPoint属性决定了程序的入口地址;
        可以将这个值设为目标代码的地址即可;
        目标代码放在代码节空白处的好处是可以直接执行而不需要做其它操作;
 
    2】运行目标代码
        程序以二进制的方式执行的;需要将目标代码转为硬编码;
        例如:弹框需要call指令,call对应的硬编码为->e8 + 4个字节的x;
        x的计算公式:
            真正要跳转的地址 = E8这条指令的下一行地址 + X    
             X = 真正要跳转的地址 - E8这条指令的下一行地址  
        因为call指令本身占用5个字节:
            要跳转的地方 = E8当前的地址 + 5 + X            
            X = 要跳转的地址 - (E8的地址 + 5)     
 
 
    3】目标代码执行完后跳转到真正的入口
        跳到真正的入口程序需要用到jmp指令;
        jmp指令的硬编码为    ->e9+4个字节的x;
        x的计算公式和call指令差不多;
 
    4】注意
        call和jmp硬编码中对应的地址是内存镜像中的地址;
        需要做文件镜像地址和内存镜像地址的转换;
        call指令可能有参数;
        参数的反汇编是push指令;
        push指令的硬编码是:6a+x;
        注意在call指令前加上去;
 
1.相对偏移地址RVA和文件偏移地址FOA
因为call和jmp指令的硬编码跳转地址要用到内存镜像中的地址;
因此需要将FOA转换成RVA,否则跳转地址错误导致无法执行插入的代码;
 
例如:下图节中的代码偏移地址为501234,需要转换成其对应的文件偏移地址;
步骤:
    1】确定是在哪个节;
        在哪个节的条件:相对于ImageBase的偏移地址大于该节的偏移地址;也就是节表中的VirtualAddress;
        相对于该节首地址的偏移要小于该节的大小;也就是misc.VirtualSize;
        判断条件是:
            501234 - 50000 = 1234;
            1234 > VirtualAddress;
            1234 < VirtualAddress + misc.VirtualSize;
    
        2】确定目标代码距离所在节首地址的相对偏移量;
           目标代码的地址 - ImageBase = 距离内存镜像头部的偏移;
            节首距离内存镜像头部的偏移 = 节表中的VirtualSize; 
            1234 - 1000 =234;
 
        3】确定文件镜像中目标代码距离pe头的偏移量;
            也就是节首的偏移量 + 距离节首的偏移量;
            节首的偏移量 = 节表中的PointerToRawData;
            234 + 400 = 634;
 
2.手动添加弹框到exe文件
1)获取弹框函数的地址
在vc6中的main方法中调用弹框函数MessageBox;
int main(int argc, char* argv[])
{
    MessageBox(0,0,0,0);
 
    getchar();
    return 0;
}
在MessageBox函数前断点查看反汇编:
可以确定的代码:
6a 00 6a 00 6a 00 6a 00
e8 xx xx xx xx
e9 xx xx xx xx
可以确定的call指令的目标地址:0042c2c4
 
2)找到代码节区
用pe工具查看代码节信息;
1】
2】
 
3)判断空间是否足够
代码要放入代码节空白区;
需要判断节的空白区是否能够放得下代码;
空白区空间 = SizeOfRawData  - misc;
如果代码空白区的值大于0且大于目标代码的大小则表示有足够的空间插入;
    空白空间大小 = 2ee00 - 2ede0 =20个字节;
    代码大小 = 18个字节;
因此可以放下;
 
4)计算代码添加的位置
节在文件中的偏移PointerToRawData + 文件对齐前的长度misc.VirtualSize;
400 + 2ede0 = 2f1e0;
 
用winhex打开exe文件,将代码插入到空白区:
 
5)计算call指令硬编码e8后面跟的实际地址
需要知道E8指令在内存镜像的偏移RVA;
e8相对于节的偏移= e8指令的文件偏移 -节偏移pointerToRawData;
2f1e8 - 400 = 2ede8;
e8的rva = e8相对于节的偏移 + 节的偏移VirtualAddress
2ede8 + 1000 = 2fde8;
 
根据公式计算出e8指令的地址x;
x + rva + imagebase + e8指令的实际宽度 = messagebox函数的地址;
x + 2fde8 + 400000 + 5 = 42c2c4;
x = ffffc4d7
 
将计算的地址写入程序:
 
6)计算jmp指令e9跟的地址y
要跳转的目标是程序的实际入口地址;
在可选pe头的AddressOfEntryPoint = 2fd68;
根据公式计算:
y + 2fded +400000 + 5 = 400000 + 2fd68;
y = -8a = ffffff76
 
写入程序:
 
7)修改程序入口地址
修改可选pe头中的程序入口地址为插入代码的地方;
也就是:2f1e0;
 
8)结果
修改后的exe文件打不开;
失败了,思路应该是对的;
 
 
 
 
 
 
 
posted @ 2019-10-18 15:21  L丶银甲闪闪  阅读(450)  评论(0编辑  收藏  举报