- UID
- 2198
注册时间2005-6-29
阅读权限255
最后登录1970-1-1
副坛主
  
该用户从未签到
|
Baymax v2.5 加入了对函数返回值的修改。
支持对模块的导出函数设置断点,支持将断点地址(RVA模式,特征码模式,导出表模式)解析为函数。
勾选【修改返回值】后,可从断点地址对应的ESP偏移处读取函数返回地址,并在函数返回后进行补丁。
可以补丁以下三种情况:
1>保存当前上下文并在返回时修改
2>函数返回时修改上下文
3>函数直接返回后修改上下文
1. 【保存当前上下文并在返回时修改】(主要是针对传参时候参数可能在寄存器中)
补丁类型这一行设置的为中断时保存的内存地址。替换值设置的数据,将在函数返回后对保存的内存地址进行复制。
2. 【函数返回时修改上下文】中断地址所在的函数返回后修改环境上下文。
补丁数据作用于函数返回时的地址,所设置的补丁数据为函数返回后才解析寄存器的数据
3. 【函数直接返回后修改上下文】
某些函数中可能是网络验证,此时我们不希望执行该函数,则可设置直接返回模式。
补丁数据作用于函数返回时的地址,比如需要返回EAX=1。
?当勾选了【修改返回值】功能后,我们设置的条件断点是中断处还是函数返回后。
条件断点和“修改返回值”功能无关,判断的是中断处的条件,若条件不满足是不会在函数返回后执行操作的。
< 实例讲解>
我们以固定硬盘序列号为例。
- 0025E65C 0092DD88 /CALL DeviceIoControl
- 0025E660 000000E4 |hDevice = 000000E4 (window)
- 0025E664 0007C088 |IoControlCode = SMART_RCV_DRIVE_DATA // 条件为 [ESP+8] == 0007C088
- 0025E668 0025E9D8 |InBuffer = 0025E9D8
- 0025E66C 00000021 |InBufferSize = 21 (33.)
- 0025E670 0025E7C0 |OutBuffer = 0025E7C0 // 函数返回时数据存放于该内存
- 0025E674 00000210 |OutBufferSize = 210 (528.)
- 0025E678 0025EC40 |pBytesReturned = 0025EC40
- 0025E67C 00000000 \pOverlapped = NULL
复制代码
第一种方案:保存当前上下文并在返回时修改
该方案要求:在中断处选择参数地址即可。
我们在模块栏从 system32 目录下选择 kernel32.dll 模块,在导出函数栏中找到 DeviceIoControl。我们先用“保存当前上下文并在返回时修改”,通过OD分析得知,
我们要修改的参数为:ESP+14。补丁的目标地址为 ESP ,偏移为 14,0,24
- $ ==> > 0092DD88 GetPcInf.0092DD88
- $+4 > 000000E4
- $+8 > 0007C088
- $+C > 0025E9D8
- $+10 > 00000021
- $+14 > 0025E7C0 // 参数 lpOutBuffer
- $+18 > 00000210
- $+1C > 0025EC40
- $+20 > 00000000
- $+24 > 0025EE78
- 0025E7C0 00 02 00 00 00 00 01 00 00 A0 EC 00 00 00 00 00
- 0025E7D0 40 00 FF 3F 37 C8 10 00 00 00 00 00 3F 00 00 00
- 0025E7E0 00 00 00 00 30 33 32 31 30 33 32 31 30 33 32 31 ....032103210321 // 偏移0x24
- 0025E7F0 30 33 32 31 20 20 20 20 00 00 F0 4E 00 00 41 53 0321 ..
复制代码
然后设置条件断点(获取机器码传入的第二个参数): [ESP+8] == 0x7C088
方案二:在API+N地址处设置中断
为防止检测 API入口地址代码是否被修改,我们在 API+N 处设置中断。
01.BPT // API 偏移5处设置断点 (修改值为字符串,大家可以用HEX值,测试用例是从内存读取20个字节)
- // 这是 Baymax Patcher Tools 创建的补丁方案,请勿修改!!!
- [BAYMAX]
- PROCESS = D:\NsStudio\TestCode\WTL\GetPcInfo\GetPcInfo\Debug\GetPcInfo.exe
- TITLE =
- AUTHOR =
- ITEMCOUNT = 1
- VERSION = 2
- OPTION = 0
- [ITEM_0]
- PATCHTYPE = 异常中断补丁
- PROCESS = D:\NsStudio\TestCode\WTL\GetPcInfo\GetPcInfo\Debug\GetPcInfo.exe
- MODULE = C:\Windows\System32\kernel32.dll
- PROCESSCHECK = 0
- MODULECHECK = 1
- SHOWNAME = GetPcInfo.exe(kernel32.dll)
- SHOWINFO = ESP,18,0,24:[V:2,R:1,B:0,T:1,F:0,4,C:QzpFU1AsQzpELDAsN0MwODg=]:I,A,11223344556677
- HOOKTYPE = 0
- PATCHCOUNT = 1
- PATCH_VA_0 = 5
- PATCH_SRC_0 = ::DeviceIoControl
- PATCH_DEST_0 = ESP,18,0,24:[V:2,R:1,B:0,T:1,F:0,4,C:QzpFU1AsQzpELDAsN0MwODg=]:I,A,11223344556677
- PATCH_NOTE_0 =
复制代码
当然该题也可以直接设置为【函数返回时修改上下文】,设置好对应的地址偏移即可。
感兴趣的话可以下载附件的测试用例来试一下(XP下可能不加载劫持DLL,测试用例代码有一处LoadLibrary操作,把version.dll修改为PYG.DLL即可测试INT3断点)。
方案三:函数返回时修改上下文
注意:补丁数据为函数返回地址中断后的寄存器偏移。
函数返回时堆栈数据如下,ESP=0093EEE8:
- $-24 > 744C11A0 kernel32.744C11A0
- $-20 > 000004F8
- $-1C > 0007C088
- $-18 > 0093EE9C
- $-14 > 00000021
- $-10 > 0093EEE8 // 这里是调用API时传入的参数
- $-C > 00000210
- $-8 > 0093EEC8
- $-4 > 00000000
- $ ==> > 0093EEE8
复制代码
02.BPT // 修改函数返回值
- // 这是 Baymax Patcher Tools 创建的补丁方案,请勿修改!!!
- [BAYMAX]
- PROCESS = D:\NsStudio\TestCode\WTL\GetPcInfo\GetPcInfo\Debug\GetPcInfo.exe
- TITLE =
- AUTHOR =
- ITEMCOUNT = 1
- VERSION = 2
- OPTION = 0
- [ITEM_0]
- PATCHTYPE = 异常中断补丁
- PROCESS = D:\NsStudio\TestCode\WTL\GetPcInfo\GetPcInfo\Debug\GetPcInfo.exe
- MODULE = C:\Windows\System32\kernel32.dll
- PROCESSCHECK = 0
- MODULECHECK = 1
- SHOWNAME = GetPcInfo.exe(kernel32.dll)
- SHOWINFO = ESP,FFFFFFF0,0,24:[V:2,R:0,B:0,T:0,F:1,0,C:QzpFU1AsODpELDAsN0MwODg=]:I,A,12345678901234567890
- HOOKTYPE = 0
- PATCHCOUNT = 1
- PATCH_VA_0 = 0
- PATCH_SRC_0 = ::DeviceIoControl
- PATCH_DEST_0 = ESP,FFFFFFF0,0,24:[V:2,R:0,B:0,T:0,F:1,0,C:QzpFU1AsODpELDAsN0MwODg=]:I,A,12345678901234567890
- PATCH_NOTE_0 =
复制代码
对于修改API返回值固定机器码,补丁方案不单适用于该程序,同样适用于所有调用该API的程序,基本是通杀。
总结:
修改函数返回值,本来可以全部归结为在函数返回后设置修改数据。但是由于如果使用寄存器传参,函数返回时就不一定方便在上下文中找到参数。
所以设置了以下几类:
1. 保存当前上下文并在返回时修改 :
中断时获取 补丁地址 进行保存,函数返回后直接修改我们保存地址的数据。
Baymax 中设置的补丁数据为中断时的寄存器环境。
2. 函数返回时修改上下文:
函数返回时获取 补丁数据,然后进行修改。
Baymax 中设置的补丁数据为函数返回时的寄存器环境。
3. 函数直接返回后修改上下文
某些函数函数我们不希望其执行(如网络验证),需要直接返回值即可。
函数在断点处从堆栈获取返回地址并平衡ESP,不再执行函数体,函数返回后可设置EAX等返回值。
延伸:
1. 任意一条指令,都处于某个函数中,(基本)都存在函数返回。
2. 并非只有API函数才可以设置返回,补丁工具中设置的补丁地址均支持修改函数返回值。
3. Baymax 提供由补丁制作者设置返回地址,所以我们再堆栈中看到的地址均可设置为返回值。不一定为当前函数的返回值,可以设置上上层函数的返回地址。
4. 更多技巧请自由发挥。
|
评分
-
查看全部评分
|