C#实现64位进程代码注入时E9跳转地址计算错误问题求解
问题根源
- E9相对跳转的64位架构限制:x64下
E9操作码对应的相对近跳转,偏移量仍为32位有符号整数,仅支持±2GB范围内的跳转。你给出的跳转源地址0x7FFBA13F52EE与目标地址0x7FF95BBD0000的差值已经超出2GB范围,强行计算偏移会触发整数溢出,最终得到错误的跳转地址。 - 原Jmp方法逻辑缺陷:使用无符号
ulong计算偏移,没有处理有符号负数的场景,且强制截断为4字节的逻辑本身就不适用于超出范围的64位跳转场景。 - 补充:你原有代码调用Jmp方法时存在参数拼写错误,
ConeInjectionAddress应为CodeInjectionAddress,请注意修正。
修复方案
方案1:使用x64绝对远跳转(推荐,无地址范围限制)
x64下可通过FF 25 00 00 00 00 + 8字节绝对地址的指令序列实现任意地址跳转,无需计算偏移,直接填入目标地址即可,指令总长度14字节。
对应C#实现代码:
public static byte[] Jmp64(ulong jumpTo, bool addNop = false) { List<byte> result = new List<byte>(); if (addNop) { result.Add(0x90); // 按需添加NOP } // 绝对跳转指令前缀 result.AddRange(new byte[] { 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00 }); // 写入小端序的64位目标地址 result.AddRange(BitConverter.GetBytes(jumpTo)); return result.ToArray(); }
使用注意:需要确保跳转源地址处有至少14字节的可改写空间。如果原有空间不足,可将被覆盖的原始指令先复制到你的注入代码块末尾,注入逻辑执行完成后再跳回原地址后续位置即可。
方案2:保留E9相对跳转(仅适用于±2GB范围内的跳转)
如果确认跳转源和目标地址的偏移在2GB以内,可修正原偏移计算逻辑,适配有符号整数计算:
public static byte[] Jmp64Relative(ulong jumpTo, ulong jumpFrom, bool addNop = false) { // 计算相对偏移,E9跳转长度为5字节,需减去5 long offset = (long)jumpTo - (long)jumpFrom - 5; // 校验偏移是否在32位有符号整数范围内 if (offset < int.MinValue || offset > int.MaxValue) { throw new InvalidOperationException("跳转偏移超出32位范围,无法使用E9相对跳转"); } List<byte> result = new List<byte>(); if (addNop) { result.Add(0x90); } result.Add(0xE9); // 写入小端序的32位偏移 result.AddRange(BitConverter.GetBytes((int)offset)); return result.ToArray(); }
内容的提问来源于stack exchange,提问作者N3nntr0n
相关产品推荐
相关产品推荐

