• 滴水逆向-代码节空白区添加代码(手动)


    相关笔记代码测试验证记录

    手动在代码空白区添加代码
    
    1.获取MessageBox地址,构造ShellCode代码.
    
    下面是测试代码
    
    #include "stdafx.h"
    #include <windows.h>
    
    void fun()
    {
        printf("Hello Cntf
    ");
        MessageBox(0,0,0,0);
    }
    
    int main(int argc, char* argv[])
    {
        fun();
        return 0;
    }
    
    
    将上面代码编译执行,发现弹框,说明就是成功验证确认了MessageBox的功能;
    
    上面完成之后,我们再找到一个正常的应用程序设置断点,找出MessageBox在程序执行的起始位置;
    
    在OD工具里面设置断点,bp MessageBoxA,然后在菜单栏找到"B" 点击进去就发现了设置的断点;
    然后双击即可查看MessageBox的断点位置,如下:
    
    77D5050B >  8BFF            MOV EDI,EDI
    
    最终确认MessageBox在程序中执行的地址如下:
    0x77D5050B
    
    2.E8 E9计算公式
    
    公式一:
    
    真正要跳转的地址 = E8这条指令的下一行地址 + X
    
    下面是变形公式:
    
    X = 真正要跳转的地址 - E8这条指令的下一行地址
    
    下面是上面写的简单代码进行编译,调试,进入反汇编得到的结果
    
    15:       fun();
    00401098 E8 68 FF FF FF       call        @ILT+0(fun) (00401005)
    16:       return 0;
    0040109D 33 C0                xor         eax,eax
    
    解释:
    E8  --->  call的硬编码
    E8后面的4个字节是通过计算的出来的,我们上面的公式就是要验证确认他们的计算方式
    
    根据公式,已知:真正要跳转的地址和E8这条指令的下一行地址;
    
    开始计算
    
    X = 真正要跳转的地址 - E8这条指令的下一行地址
    X = 0x00401005 - 0x0040109D = 0xFFFFFF68
    
    开始比对代码中反汇编的地址和计算出来的地址
    
    00401098 E8 68 FF FF FF       call        @ILT+0(fun) (00401005)
    
    0xFFFFFF68   ---> FF FF FF FF 68
    E8 68 FF FF FF
    
    通过上面对比得知他们是一样的;所以最终结果如下:
    
    E8 68 FF FF FF
    
    @ILT+0(?fun@@YAXXZ):
    00401005 E9 16 00 00 00       jmp         fun (00401020)
    
    
    开始E9这个jmp汇编指令后面的4个字节验证
    
    生成的反汇编代码
    
    @ILT+0(?fun@@YAXXZ):
    00401005 E9 16 00 00 00       jmp         fun (00401020)
    @ILT+5(_main):
    0040100A E9 71 00 00 00       jmp         main (00401080)
    
    开始计算
    
    X = 0x00401020 - 0x0040100A = 0x00000016
    
    通过对比生成的反汇编代码,同样可以确认结果是一样的
    
    00401005 E9 16 00 00 00
    0x16000000
    
    最终的结果:
    
    E9 16 00 00 00
    
    
    公式二:
    
    要跳转的地方 = (E8当前的地址 + 5) + X
    
    X = 要跳转的地址 - (E8的地址 + 5)
    
    下面是反汇编代码生成的关于MessageBox的信息
    
    10:       MessageBox(0,0,0,0);
    00401045 8B F4                mov         esi,esp
    00401047 6A 00                push        0
    00401049 6A 00                push        0
    0040104B 6A 00                push        0
    0040104D 6A 00                push        0
    0040104F FF 15 8C 52 42 00    call        dword ptr [__imp__MessageBoxA@16 (0042528c)]
    00401055 3B F4                cmp         esi,esp
    00401057 E8 F4 00 00 00       call        __chkesp (00401150)
    11:   }
    
    通过上面的反汇编代码得知,在程序执行MessageBox的时候有4个push 0
    
    00401047 6A 00                push        0
    00401049 6A 00                push        0
    0040104B 6A 00                push        0
    0040104D 6A 00                push        0
    
    所以总结下来,需要向程序的代码区域插入如下18个字节的代码即可
    
    6A 00 6A 00 6A 00 6A 00 E8 00 00 00 00 E9 00 00 00 00     --->  18个字节大小
    
    3.在代码区手动添加代码
    
    
    VirtualSize:            0x000001f8     000440A2     [V(VS),内存中大小(对齐前的长度).]
    VirtualAddress:         0x000001fc     00001000     [V(VO),内存中偏移(该块的RVA).]
    SizeOfRawData:          0x00000200     00045000     [R(RS),文件中大小(对齐后的长度).]
    PointerToRawData:       0x00000204     00001000     [R(RO),文件中偏移.]
    
    00045000 - 000440A2 = F5E  --->  此处计算结果必须大于我们上面要插入的18个字节大小,不然会出问题
    
    6A 00 6A 00 6A 00 6A 00 E8 00 00 00 00 E9 00 00 00 00
    
    打开winhex或者ultraedit编辑器,使用她们打开二进制文件,我们的目的是针对二进制文件;
    ipmsg.exe的第一个节后面的代码空白区域添加我们的代码;就是在SizeOfRawData -> 0x00045000的后面
    
    理解:
    第一个节从PointerToRawData 文件偏移开始--> 0x00001000开始向后数,数到0x00045000结束;
    然后根据对齐宽度是1000H,所以向后再加上1000H就是0x00046000是第二个节的开始位置;
    这里需要注意,我使用编辑器打开ipmsg.exe文件之后,找到0x00045000的位置发现还有数据;
    向后扩展1000H到了0x00046000位置是对的,刚好是下一个节的开始位置,而这期间;
    0x00045000 - 0x00046000这里面开头一点还是有数据的,到了一定的位置发现都是00,那么确认此处;
    到0x00046000开始的上一个字节位置都是空白区域,都是可以填充数据的;
    
    我这里找到代码空白区域的位置是0x000450a2开始,从这里开始的,我们从此处的下一行开始填充代码;
    
    也就是从0x000450b0位置开始,具体如下:
    
    000450b0h: 6A 00 6A 00 6A 00 6A 00 E8 00 00 00 00 E9 00 00
    000450c0h: 00 00
    
    到了上面,就算完成了一部分了,我们要开始添加执行函数call汇编指令和jmp汇编指令后面的硬编码数据;
    
    需要的MessageBox数据 ---->  0x77D5050B
    
    要使用到的公式
    
    公式二:
    
    要跳转的地址 = (E8当前的地址 + 5) + X
    
    变形:
    X = 要跳转的地址 - (E8当前的地址 + 5)
    
    根据上面的公式,我们最要确定的是算出要跳转的地址,所以需要使用公式:
    X = 要跳转的地址 - (E8当前的地址 + 5)
    
    现在我们对比公式填充数据:
    要跳转的地址 = 0x77D5050B
    E8当前的地址 + 5  = 下一个jmp的汇编指令开头 ---> E9的位置 ---> 0x000450bd
    
    得到上面的地址,一定要再考虑(ImageBuffer里面的偏移)内存偏移和 因为我们加入的代码;
    最终是要在内存中运行,所以一定是要考虑在内存中偏移和对齐;
    要考虑这两个 ---> VirtualAddress和PointerToRawData
    
    VirtualAddress:         0x000001fc     00001000     [V(VO),内存中偏移(该块的RVA).]
    PointerToRawData:       0x00000204     00001000     [R(RO),文件中偏移.]
    
    下面是可选PE头的ImageBase内容
    ImageBase:              [地址(RAW):0x0000012c] [长度:04h] [偏移量:e_lfanew+0x34]
    [数据:0x00400000] [基址,程序默认装入的基地址.]
    
    但是本次测试使用的程序很巧,刚好文件和内存中的偏移是一样的,都是1000H
    
    根据ImageBase和内存偏移地址1000H得出地址:0x000450bd + 0x00400000 = 0x004450bd
    
    所以根据公式计算最终地址:
    
    X = 要跳转的地址 - (E8当前的地址 + 5)
    
    要跳转的地址       --> 0x77D5050B (这里要跳转的地址就是上面我们找到的MessageBox的地址)
    
    (E8当前的地址 + 5) --> 0x004450bd
    
    X = 0x77D5050B - 0x004450bd = 0x7790B44E
    
    0x7790B44E  --> 77 90 B4 4E  --> 小端模式 --> 4E B4 90 77 --> 放入E8的后面
    
    000450b8h: E8 4E B4 90 77  ----> 这就是最终的E8后面的数据
    
    我们开始计算E9后面的数据,要清楚,我们加入代码之后,需要再回到程序的入口处;
    所以E9要跳转的地址就是OEP的地址,但OEP的地址更改完成之后需要再将程序执行的OEP地址;
    更改为上面为我们添加代码的开始地址;
    
    需要用到的OEP地址信息:
    
    AddressEntryPoint  --> 0x000441EC
    ImageBase             --> 0x00400000
    
    得到最终的OEP地址   --> 0x000441EC + 0x00400000 = 0x004441EC
    
    X = 要跳转的地址 - (E9当前的地址 + 5)
    
    要跳转的地址       --> 0x004441EC
    (E9当前的地址 + 5) --> 0x004450C2
    
    X = 0x004441EC - 0x004450C2 = 0xFFFFF12A
    
    0xFFFFF12A  --> FF FF F1 2A -->  小端模式 --> 2A F1 FF FF --> 放入E9的后面
    
    000450bdh: E9 2A F1 FF FF  ----> 这就是最终的E9后面的数据;
    
    上面完成了之后到了最后一步了,修改OEP的值,在修改的时候我们不需要再加上ImageBase的值;
    因为程序在运行的时候会帮我们加上,所以我们只要填充我们代码里面的初始值即可,这里我们;
    添加了18个字节的代码,开头的还是6A 00 打头的,就是MessageBox的起始地址,添加这个地址;
    
    需要跟OEP对应的地址为:0x000450b0
    
    我们找到原来的OEP地址位置:0x000441EC (这个地址是没加ImageBase的地址,我们直接更改保存);
    
    对应位置是可选PE文件头里面 --> 00000120h: EC 41 04 00
    
    将其更改为这个地址内容     --> 0x000450b0  --> B0 50 04 00
    
    更改后的最终OEP地址:
    
    00000120h: B0 50 04 00
    
    保存执行测试;
    
    测试执行成功;
    
    4.修改OEP,指向ShellCode.
    
    上面第3步已经操作完成;

    相关更改后的二进制文件内容信息:

    更改的OEP的地址位置

    保存运行后的结果

    迷茫的人生,需要不断努力,才能看清远方模糊的志向!
  • 相关阅读:
    Java之字符串String,StringBuffer,StringBuilder
    去除前后空格,Oracle和SQLSERVER都适用。ltrim(rtrim(’ ‘))
    java IO,bufferedReader类
    Python与操作系统有关的模块
    u盘引导制作工具
    Shell中判断语句if中-z至-d的意思
    shell脚本输出带颜色字体
    MySQL数据库权限管理
    vi/vim使用进阶: 文件浏览和缓冲区浏览
    (转载)跟我一起学习VIM
  • 原文地址:https://www.cnblogs.com/autopwn/p/15241984.html
Copyright © 2020-2023  润新知