-2

How can I inject 32-bit CodeCave into a 64-bit application?

I've seen some implementations like this:

App.exe+CA5F6 - 4C 89 15 D37D5B01     - mov [App.exe+16823D0],r10
App.exe+CA5FD - E9 FE59CA82           - jmp 7FF748DA0000
App.exe+CA602 - 90                    - nop 
App.exe+CA603 - 90                    - nop 
App.exe+CA604 - 4C 03 C1              - add r8,rcx

Then I follow this address and see this:

7FF748D9FFFF -                       - ?? 
7FF748DA0000 - FF25 00000000 00001A0500000000 - jmp 051A0000
7FF748DA000E - 00 00                 - add [rax],al

I follow this address:

051A0000 - 50                    - push rax
051A0001 - 53                    - push rbx
051A0002 - 52                    - push rdx
051A0003 - 4D 63 82 94000000     - movsxd  r8,dword ptr [r10+00000094]

How did he do it? How should I implement this in C#?

I can inject CodeCave, but if the application is 64-bit then it will always refer to a 64-bit address, how can I inject CodeCave so it will refer to a 32-bit address?

hex X
  • 11
  • 1
  • 1
    You can't use 32-bit addresses in a 64-bit process, or vice versa. The address width is essentially what defines the difference between the two process types. – 500 - Internal Server Error Aug 16 '21 at 13:38
  • I understand, but please tell me how that person did it? He created CodeCave, and then from this CodeCave created a link to a 32-bit address – hex X Aug 16 '21 at 14:09
  • @500-InternalServerError: It's not just the address width, it's other encoding differences like `0x4?` being REX prefixes instead of 1-byte inc/dec, and the default operand-size for `push`/`pop` being 8 bytes. Also that the shorter encoding for `[disp32]` addressing modes is interpreted as `[RIP + rel32]` in 64-bit mode. (Although position-independent 32-bit code wouldn't use that addressing mode in the first place, instead using something less efficient like call/pop to get EIP.) – Peter Cordes Aug 16 '21 at 14:17
  • I don't see why one would want to inject machine code with lesser bitness at all, though. Since the target is a 64-bit executable, you don't need to use obsolete 32-bit for anything. IDK if it's possible to do a far jump or call to 32-bit mode, but you'd only be able to access memory in the low 4GiB of virtual address space. Sounds like unnecessary complexity vs. just writing 64-bit asm in the first place. – Peter Cordes Aug 16 '21 at 14:19
  • @hexX: What exactly is CodeCave in this context? – 500 - Internal Server Error Aug 16 '21 at 14:20
  • [Mixing 32bit and 64bit](https://stackoverflow.com/questions/9292345/) • [Mixing 32-bit and 64-bit](https://stackoverflow.com/questions/4393012/) • [Mixing 32 and 64 bit](https://social.msdn.microsoft.com/Forums/en-US/06176268-79b1-4b2b-a981-eba89b578949/) • [IL](https://www.codeproject.com/Articles/362076/Understanding-Common-Intermediate-Language-CIL) • [Assembly](https://www.tutorialspoint.com/assembly_programming/index.htm) • [CPU](https://www.tutorialspoint.com/microprocessor/index.htm) • [Intel](https://software.intel.com/content/www/us/en/develop/articles/intel-sdm.html) –  Aug 16 '21 at 15:14
  • @PeterCordes: I need this for the following: I have an "iced" for my C # application - this is instruction decoder, disassembler and assembler. I have a 64 bit application. So, for example, I need to compare a number with a value from an absolute address: `cmp qword ptr [0x7FF7C60100FB], 0x01`, but this cannot be done because the cmp instruction can only work with 32-bit absolute addresses, and of this I forced to do this: `mov rax, 0x7FF7C60100FB; cmp [rax], rdx`, but it is too long for me, and this method is not always suitable for me. – hex X Aug 16 '21 at 16:16
  • @500-InternalServerError: Well, for example, I create a CodeCave in a 64-bit application, of course it refers to a 64-bit address, I need that after the first CodeCave it would be possible to create a new CodeCave from it with jmp to a 32-bit address, as that person did, but how he did it I cannot understand – hex X Aug 16 '21 at 16:24
  • Oh, okay, thx, I thought - because of the capitalization - that it might be the name of a specific tool you were using. – 500 - Internal Server Error Aug 16 '21 at 16:25
  • `FF25 00000000 00001A0500000000 - jmp 051A0000` is incorrect disassembly (or incorrect machine code for that instruction). That sequence of bytes is actually `jmp QWORD PTR [rip+0x0]` / `00 00 add [rax],al` / `1a 05 00 00 00 00 sbb al, [rip+0x0]` (https://defuse.ca/online-x86-assembler.htm#disassembly2). Or as 32-bit machine code, basically the same thing but with absolute instead of RIP-relative. – Peter Cordes Aug 16 '21 at 17:00
  • In any case, FF 25 is a *near* indirect jump (https://www.felixcloutier.com/x86/jmp), so it doesn't jump to 32-bit mode. That would require a far `jmp` that loads a new CS as well. The fact that the memory operand (from which a new RIP is loaded) is in the low 32 bits of virtual address space is irrelevant. – Peter Cordes Aug 16 '21 at 17:01

1 Answers1

-2

.NET MSIL is bitness agnostic. The same MSIL can be run as x32 or x64. Or even x128 or x16 if we ever get a runtime for those binarities.

Non .NET/native is generally designed for a very specific binarity. You got two ways to deal with the inevitable conflicts:

  1. Yet set the CPU Target of the .NEt Programm to allow only x32 or x64 execution for your MSIL. Note that generally x64 is prefereable whenever availible and x32 should not be used anymore for the whole process. Also you may have to deal with one code that needs x32 and one that needs x64.
  2. You wrap the code that has the "wrong" binarity into a helper process. Your main process and the helper talk via any of the IPC approaches - you get to "pick your poison" here. That way the code can run as it is designed, while your process is not tied to it's binarity.
Christopher
  • 9,634
  • 2
  • 17
  • 31
  • I get you, but how can I find 32-bit CodeCave in a 64-bit process? Or how to create it? – hex X Aug 16 '21 at 14:06
  • 1
    @hexX In .NET we do not work with Code Caves, unmanaged resources, Naked pointers and the like if we can at all avoid. | The goal is to make a _seperate_ helper process. One that can be whatever binarity the native code needs. And then use IPC to have the main process talk to that helper process. Code Caves - I have no idea how they work cross-binarity or if they even can work here. – Christopher Aug 16 '21 at 17:13