-4

I'm trying to call a process function in C# by creating an array of bytes, allocating memory, writing to allocated memory, then Creating Remote thread. As far as I know it's the usual way to execute shellcode through a process.

          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);

    }

As you can see, I'm unable to find the call offset. Indeed, after reading information, I got that call has no static offset so I have to calculate the jump address which is, if I'm not wrong, CALL . In my opinio, my TO is 0x005378E4. But I don't get how to find my FROM knowing that

VirtualAllocEx is assigning an address I can not predict at run time.

Thanks

1 Answers1

0

Direct call uses a rel32 displacement from the end of the call instruction.

You know the address of asm[] because you allocated it. (It's not a compile-time constant because you're using dynamic allocation, so you'll have to use the pointer you get from new).

You tagged this [C++] where pointer math is easy. Just cast to intptr_t and subtract to get a 2's complement integer (because this code only works when compiled on x86 so you can assume that), and check that it's small enough to fit before casting to int32_t. Store that into the array. (You might want to define it as a packed struct, or just use memcpy.)

But your code is [c#]. IDK how to get the raw pointer value as an integer there. It's apparently possible with unsafe. If you can statically allocate your block, that might be easier; you could have the linker do the relocation at link time to reach the given absolute address. (except you'd need to get a relocation generated, so it would just be a lot easier to put your "data" in a separate .asm file. You can still put it in the read-write data section, rather than code, but you could use asm mnemonics to write the code and let the assembler generate a relocation for an absolute call target.


You can use an indirect jump with the absolute target address in a register or memory. This is also required anyway if it turns out your block of memory is more than 2GB away from your target (in 64-bit mode).

You might do this just to make your code position-independent so it doesn't need to be fixed up after finding where it's loaded.

; 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

Or if you can't disturb registers

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

32-bit mode does have a call ptr16:32 direct far call, but don't use that because you'd have to know the correct cs segment descriptor to hard-code. (i.e. the current one). It's also slow, and isn't even available in 64-bit mode, so just don't.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • Apologizes for tagging this C++. It's a mistake. Well... Indeed its compiled on x86. I'm not sure how to use absolute indirect jump ? – Mattis BETOURNE Nov 01 '17 at 13:53
  • 1
    He can use `unsafe` and `fixed` to get the address of the first byte of the array (as a `byte*`) in C#. Or he can probably use `Buffer.BlockCopy` to write into the array. Doing pointer math is pretty much the same in C# as in C++. – xxbbcc Nov 01 '17 at 13:55
  • I didn't know unsafe and fixed. But I should get the address of the 0xE8 opcode address instead of the first byte of the array, shouldn't I? – Mattis BETOURNE Nov 01 '17 at 14:01
  • @MattisBETOURNE Just adjust the address with that offset. – xxbbcc Nov 01 '17 at 14:07
  • @MattisBETOURNE: easier and more bulletproof to do what I suggested in the last paragraph: `mov esi, 0x005378E4` / `call esi`. (Or if you can't disturb registers, `push 0x005378E4` / `push 1` / ... / `call [esp+4]`) – Peter Cordes Nov 01 '17 at 15:31
  • @PeterCordes: Well I've tried to write with the second metho through cheat engine in order to see if I was able to execute the shellcode, but it failed though : `push 5378E4 / push 1 / xor ecx,ecx / mov edx, 00100010 / mov eax, dword ptr ds:[8301B0] / call [esp+4] / ret` – Mattis BETOURNE Nov 01 '17 at 15:48
  • @MattisBETOURNE: single-step your shellcode in a debugger to see if 1) it was executed in the first place 2) `[esp+4]` and registers have the right values before the `call`. If they do, then maybe you picked the wrong absolute address. – Peter Cordes Nov 01 '17 at 15:55
  • However, the first method worked as a charm. I moved my adress to esi register, then call it. Awesome Peter, thanks you very much. I learnt a lot in asm today. Definetely by trying to set up the code instead of modifying the one I found only. – Mattis BETOURNE Nov 01 '17 at 15:55
  • @MattisBETOURNE: you forgot to save/restore `esi`, so you return after clobbering the caller's value. – Peter Cordes Nov 01 '17 at 15:57
  • I set a ret as last instruction, any other way to restore? – Mattis BETOURNE Nov 01 '17 at 16:00
  • @MattisBETOURNE: oh wait, did you forget to pop `0x5378E4` off the stack before returning? That looks like why that version didn't work. Look at compiler output sometime. Notice how they push/pop call-preserved registers to save/restore them. Google `calling convention`. – Peter Cordes Nov 01 '17 at 16:05
  • I don't know why, I'm unable to pop a value `pop 0x5378E4` doesn't work. Should I `push ebp / mov ebp, 0x5378E4 / .... / pop ebp / ret /` ? – Mattis BETOURNE Nov 01 '17 at 16:21
  • @MattisBETOURNE: an immediate can't be a destination, obviously. What should `mov 123, eax` assemble to? I meant you forgot to balance the stack to remove the data you pushed, e.g. with `add esp,4`. But yes, saving/restoring `ebp` and using `call ebp` is correct. (Unless you're using ebp as a frame pointer, in which case you should pick a different register to save/restore for your temporary, like edi.) – Peter Cordes Nov 01 '17 at 16:30