【问题标题】:Calculate CALL offset计算 CALL 偏移量
【发布时间】:2018-04-13 20:02:43
【问题描述】:

我试图通过创建字节数组、分配内存、写入分配的内存,然后创建远程线程来调用 C# 中的进程函数。据我所知,这是通过进程执行 shellcode 的常用方法。

          void WalkFunc()
    {
        byte[] asm = new byte[]
        {
            0x6A, 0x01, //PUSH 1
            0x31, 0xC9, //XOR ECX, ECX
            0xBA, 0x10, 0x00, 0x10, 0x00, //MOV EDX,00+10+00+10
            0xA1, 0xB0, 0x01, 0x83, 0x00, //MOV EAX,DWORD PTR DS:[8301B0]
            0xE8, 0x??, 0x??, 0x??, 0x??, //CALL 0x005378E4
            0xC3 //RETN
        };

        Process proc = Process.GetProcessesByName("process")[0];
        IntPtr hHandle = OpenProcess((int)ProcessAccessFlags.All, false, proc.Id);

        IntPtr hAlloc = VirtualAllocEx(hHandle, IntPtr.Zero, (uint)asm.Length, AllocationType.Commit, MemoryProtection.ExecuteReadWrite);

        UIntPtr bytesWritten = UIntPtr.Zero;

        WriteProcessMemory(hHandle, hAlloc, asm, (uint) asm.Length, out bytesWritten);

        uint iThreadId = 0;

        IntPtr hThread = CreateRemoteThread(hHandle, IntPtr.Zero, 0, hAlloc, IntPtr.Zero, 0, out iThreadId);

    }

如您所见,我找不到调用偏移量。确实,在阅读信息后,我得到那个调用有 no static offset 所以我必须计算跳转地址,如果我没记错的话,就是 CALL 。 在我看来,我的 TO 是 0x005378E4。但我不知道如何找到我的 FROM 知道

VirtualAllocEx 正在分配一个我在运行时无法预测的地址。

谢谢

【问题讨论】:

    标签: c# assembly memory ollydbg


    【解决方案1】:

    直接call uses a rel32 displacement from the end of the call instruction.

    您知道asm[] 的地址,因为您分配了它。 (它不是编译时常量,因为您使用的是动态分配,因此您必须使用从new 获得的指针)。

    你标记了这个[C++] 指针数学很容易。只需转换为intptr_t 并减去得到一个 2 的补码整数(因为此代码仅在 x86 上编译时有效,因此您可以假设),并在转换为 int32_t 之前检查它是否足够小以适应。将其存储到数组中。 (您可能希望将其定义为打包的struct,或者只使用memcpy。)

    但是你的代码是[c#]。 IDK 如何将原始指针值作为整数获取。 It's apparently possible with unsafe。如果您可以静态分配块,那可能会更容易;您可以让链接器在链接时进行重定位以到达给定的绝对地址。 (除非您需要生成重定位,因此将“数据”放在单独的 .asm 文件中会容易得多。您仍然可以将其放在读写数据部分,而不是代码,但您可以使用 asm 助记符来编写代码并让汇编器为绝对 call 目标生成重定位。


    您可以对寄存器或内存中的绝对目标地址使用间接跳转。如果事实证明您的内存块距离目标超过 2GB(在 64 位模式下),这也是必需的。

    您可能只是为了使您的代码与位置无关,因此在找到加载位置后无需对其进行修复。

    ; don't forget to save/restore esi around this
    mov   esi, 0x005378E4       ; pick any reg the callee won't look at.  save/restore if necessary
    call  esi
    

    或者如果你不能打扰寄存器

    push   0x005378E4       ; before pushing args so the callee sees the same stack/
    push   1
    call   [esp+4]
    

    32 位模式确实有一个 call ptr16:32 直接 far 调用,但不要使用它,因为您必须知道正确的 cs 段描述符才能进行硬编码。 (即当前的)。它也很慢,甚至在 64 位模式下都不可用,所以不要这样做。

    【讨论】:

    • 为标记此 C++ 表示歉意。这是一个错误。嗯...确实它是在 x86 上编译的。不知道怎么用绝对间接跳转?
    • 他可以使用unsafefixed在C#中获取数组第一个字节的地址(作为byte*)。或者他可以使用Buffer.BlockCopy 写入数组。在 C# 中进行指针数学运算与在 C++ 中几乎相同。
    • 我不知道不安全和固定。但是我应该得到 0xE8 操作码地址的地址而不是数组的第一个字节,不是吗?
    • @MattisBETOURNE 只需使用该偏移量调整地址即可。
    • @MattisBETOURNE:按照我在上一段中的建议更轻松、更防弹:mov esi, 0x005378E4 / call esi。 (或者如果你不能打扰寄存器,push 0x005378E4 / push 1 / ... / call [esp+4]
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-24
    • 2021-04-10
    • 2021-10-14
    • 2018-08-27
    • 2018-03-31
    • 2011-06-20
    • 1970-01-01
    相关资源
    最近更新 更多