Injecting 64 Bit DLL using code cave
Asked Answered
P

2

7

I'm trying to inject a 64 Bit DLL into 64 Bit Process (explorer for the matter).
I've tried using Remote-thread\Window Hooks techniques but some Anti-Viruses detects my loader as a false positive.
After reading this article : Dll Injection by Darawk, I decided to use code caves.
It worked great for 32bit but because VS doesn't support inline assembly for 64 Bit I had to write the op-codes and operands explicitly.
I looked at this article : 64Bit injection using code cave, as the article states, there are some differences:

There are several differences that had to be incorporated here:

  1. MASM64 uses fastcall, so the function's argument has to be passed in a register and not on the stack.
  2. The length of the addresses - 32 vs. 64 bit - must be taken into account.
  3. MASM64 has no instruction that pushes all registers on the stack (like pushad in 32bit) so this had to be done by pushing all the registers explicitly.

I followed those guidelines and ran the article's example but none of what I did worked.
The target process just crashed at the moment I resumed the main thread and I don't know how to really look into it because ollydbg has no 64 bit support.

This is how the code looks before I injected it:

   codeToInject:  
000000013FACD000  push        7741933Ah  
000000013FACD005  pushfq  
000000013FACD006  push        rax  
000000013FACD007  push        rcx  
000000013FACD008  push        rdx  
000000013FACD009  push        rbx  
000000013FACD00A  push        rbp  
000000013FACD00B  push        rsi  
000000013FACD00C  push        rdi  
000000013FACD00D  push        r8  
000000013FACD00F  push        r9  
000000013FACD011  push        r10  
000000013FACD013  push        r11  
000000013FACD015  push        r12  
000000013FACD017  push        r13  
000000013FACD019  push        r14  
000000013FACD01B  push        r15  
000000013FACD01D  mov         rcx,2CA0000h  
000000013FACD027  mov         rax,76E36F80h  
000000013FACD031  call        rax  
000000013FACD033  pop         r15  
000000013FACD035  pop         r14  
000000013FACD037  pop         r13  
000000013FACD039  pop         r12  
000000013FACD03B  pop         r11  
000000013FACD03D  pop         r10  
000000013FACD03F  pop         r9  
000000013FACD041  pop         r8  
000000013FACD043  pop         rdi  
000000013FACD044  pop         rsi  
000000013FACD045  pop         rbp  
000000013FACD046  pop         rbx  
000000013FACD047  pop         rdx  
000000013FACD048  pop         rcx  
000000013FACD049  pop         rax  
000000013FACD04A  popfq  
000000013FACD04B  ret   

Seems fine to me but I guess I'm missing something.
My complete code can be found here : Source code

Any ideas\suggestions\alternatives?

Paraboloid answered 7/3, 2012 at 18:51 Comment(6)
What's wrong with using WinDbg for debugging? It supports native x64 processes just fine, and I find it to be far more stable and reliable than OllyDbg.Clingstone
Are you injecting from a 64-bit process? If not, you can't use its address of LoadLibrary.Nurserymaid
Also, make sure the stack is 16-byte aligned upon calling LoadLibrary.Nurserymaid
@Clingstone nothing wrong, just never used it :) I'm used to VS. I'll try looking into it, ThanksParaboloid
@Nurserymaid - The injecting process is 64 bit and as for the stack alignment I don't really understand what you mean.Paraboloid
What am I missing? Code caves as described in this article looks like a really bad idea unless you check where the IP stands. Because if you happen to inject your code into a thread that holds the loader lock (in the midst of a call to LoadLibrary for example) you'll not have a lot of fun.Vigilante
P
3

Apparently, The main problem was that I allocated the code cave data without the EXECUTE_PAGE_READWRITE permission and therefore the chunk of data was treated as data and not as opcodes.

Paraboloid answered 8/3, 2012 at 15:7 Comment(2)
Omer, what was the fix precisely? I tried to reuse your code by adding the PAGE_EXECUTE_READWRITE flag for the code cave allocation on line 97, but the crash persisted for me. Can you share your final code?Bernadette
Nevermind, got it fixed by applying all of the pezcode suggestions: pastebin.com/34xCSrL2Bernadette
N
5

The first push that stores the return value only pushes a 32-bit value. dwOldIP in your code is a DWORD as well, it should be a DWORD64. Having to cast to DWORD from ctx.Rip should've been enough of a hint ;)

Also, make sure the stack is 16-byte aligned upon entering the call to LoadLibrary. Some APIs throw exceptions if the stack is not aligned properly.

Nurserymaid answered 7/3, 2012 at 19:8 Comment(3)
Stack alignment means, RSP must be a multiple of 16. It's your responsibility to ensure that, e.g. by setting up a proper stack frame.Nurserymaid
It did seem weird to me why the author chose the take only the lower DWORD of the IP, I tried to fix it, I am very rusty @ ASM so I'm not sure what I did is right. There's no way to push a 64 bit number directly so I've pushed 2 X DWORD Placeholders and copied the whole RIP register but it still crashes, I also looked if there's sort of stack alignment code before the call and there isn't any. any other thoughts? ThanksParaboloid
You can also just use mov rax, old_eip; push rax, maybe you're somehow not copying into the two parts correctly. Honestly though, please debug your code. We can go on guessing what your problem is or you could just look where it crashes.Nurserymaid
P
3

Apparently, The main problem was that I allocated the code cave data without the EXECUTE_PAGE_READWRITE permission and therefore the chunk of data was treated as data and not as opcodes.

Paraboloid answered 8/3, 2012 at 15:7 Comment(2)
Omer, what was the fix precisely? I tried to reuse your code by adding the PAGE_EXECUTE_READWRITE flag for the code cave allocation on line 97, but the crash persisted for me. Can you share your final code?Bernadette
Nevermind, got it fixed by applying all of the pezcode suggestions: pastebin.com/34xCSrL2Bernadette

© 2022 - 2024 — McMap. All rights reserved.