>> Hey everybody. Eh, welcome to “Please Inject-Me, a x64 Code Injection”. So let’s start. Eh,
a little about me. Eh, my name is Alon. I’ve been to cybersecurity industry for about
7 years. Ehm, started at the IDF in the Intelligent Division, and now working at Deep Instinct.
Ehm, at Deep Instinct I’m, eh, researching for new attack vectors, doing some heuristics,
ehm, and ehm, finding, eh, new ways to attack. Ehm also reversing malwares, eh, so
that’s pretty much about me. Okay, so any stock, eh, first I’m going to give you a short
introduction about code injections, so it’s going to be really short. I’m going to talk
about what is Inject-Me, eh, the new code inject- injection technique I found. Ehm, then I’m
going to give you a little bit, eh, of technical back -background just to know eh
things that you need to know before you can abuse the method, eh, to do the code injection.
And at the end there’s going to be, ehm, a little flow of how to do the code injection. Okay, so
what is code injection? Code injection is the term of inserting code from one process
to another, and then execute it in the context of the other process. So it looks like this:
first inject code to the target process, eh, message box, and then we execute a code, okay? So
through this presentation I’m going to use the terms, ehm, target process and injecting
process, okay? I’m exit. Okay, so why code injection is important? Okay, ehm, code
injection is important because it can be used for malicious and benign eh, eh, activities, okay?
Ehm, so it can be used for malicious activities like for stealth, okay, if a malware
alpha wants to hide the presence of the malware and make it harder to find it, eh, it can
inject the code into another process, and that would be hard to detect it. Eh, it can be used
for evasions, so we can inject into a security solution, okay, and then we can bypass the
security solution, but if injecting to the solution they want scan the activity of the
malware. It can also, if let’s say one program, only one program is allowed to do
something and we inject to that program, we’re going to be running in that context, and
then we can use that context to do something malicious and bypass the security solution,
and at the end we can steal information, let’s say phone grabbing in browsers, ehm, and
then we can see credit cards, um, data, and things like that. Ehm, for benign users, ehm, we
can use it to in security solutions, we can use it to, ehm, get, ehm, the activity of
malware, okay. Eh, in the malware we can see how it what it does, and if it does
something malicious we can just inform the user and that something bad happened. Eh,
also, it can be used to add some functionality to a program so we can add something new that is
not written in the code. Ehm, and at the end we could also do some monitoring, so a security
researcher can monitor the activity of a malware, and then see eh what’s going on. It’s not
only a malware, it can be for any program. Okay, so how it all started. Eh, I was researching
few methods eh of code injection to do heuristics, ehm and then I thought to myself, why wouldn’t
I do my own code injection technique? Ehm, maybe I should look for it. So, I thought it a
little bit about it, and I had uh a idea, and lucky for me it worked- the idea that I’m
presenting today. Ehm, so this new method is going to be used in x64, okay? Ehm, the idea
about eh behind it is we are going to use ReadProcessMemory in the target process. It’s
going to execute ReadProcessMemory and then read from the injecting process, the
shellcode. Ehm, this why we going to use this the term “injection-less”, because we
really eh not really injecting code into the target process, we make it read from us. Amazing.
Okay, so now a little bit of technical background. ReadProcessMemory, a WINAPI
function in Windows, ehm this function what it does it just reads data from a process, it
gets five parameters hProcess, which is the process we want to read from, lpBaseAddress, which
is the address we want to read from, okay, lpBuffer, which is the address we want to write the
data with to, and nSize is going to be the size we want to read, and lpNumberOfBytes is going to
be the number of bytes that were actually read. Okay, now x64 calling convention. In x64
calling convention, the parameters are passed on the registers, so they pass that
RCX, RDX, R8, and R9. Um, we can pass these four parameter arguments to a function, and
then when we execute the -the function, it’s going to use those arguments. Arguments after
the fourth parameter are passed on the stack so if you see this uh background here, you could
see that if we call ReadProcessMemory, ehm R6 is going to be the hProcess, RD is
going to be the LP based address, R8 is going to be lpbuffer, R9 going to be nSize
and then lpNumberofBytes is going to be on the stack. So if we look at the stack, eh the
return address is going to be at the top of the stack then the four arguments that are ignored,
the data there is not important and then at the end is going to be the fifth parameter at the
stack. Ehm, so again if we use separate contexts, the function and set those registers we can
just manipulate the function to execute with those paraments. Okay, so through this
presentation, you’re going to see this timeline. Ehm, it’s going to show us where we are.
Ehm first we’re going to talk about how to setup ReadProcessMemory then we’re
going to encounter the first problem which is access violation. We then eh encounter
another problem that we will need to create an infinite running thread eh and at the
end, we’re going to execute the whole method. Okay, so let’s start. ReadProcessMemory, okay
as I show you earlier it gets five arguments okay and as I already told you also it only
can get , we can only pass four arguments using the registers. Now, lucky for us, the fifth
parameter can be null, then it is it is ignored. Ehm, and more lucky for us if use
VirtualAllocEx, the allocated memory is going to be all zeroed out. Em, so we can create a
dummy stack that is going to contain that fifth argument ehm, so this is good for us. Okay, so
let’s start setting up ReadProcessMemory. Ehm, so the first parameter we need to setup
is hProcess okay. hProcess we can set it up by using DuplicateHandle. So w’re going
to duplicate the handle of the injecting process into the target process and then we have
the the handle inside the typo so we can use it as hProcess, ehm then we will allocate memory
for -for shellcode okay. The dummy stack that we already allocated earlier, ehm the base
address ehm of the shellcode we already know because it is in the injecting process and the
size of the shellcode we already know because it’s also ehm something we know in the
injecting process. Okay, so let’s say now that we actually read the eh eh called and
executed ReadProcessMemory eh we’re going to execute it and we’re going to have our first
problem which is access violation. So what’s going to happen is we first call
ReadProcessMemory, the memory is read to the buffer, and then we go to the return address. Now
because this stack is all zeroed out, we’re going to return to the address zero which is
invalid and we’re going to get access violation, not nice. Em, but if you put as the return
address a function like like RtlExitUserThread, we just exit the thread in a clean way ehm
when we execute ReadProcessMemory, it will be called memories read to the
buffer, we return to the address on the stack and that thread will execute in a clean way,
amazing. Okay, now we want RtlExitUserThread to be on the return address in the stack.
Okay, so to do this we have two steps. First we need to find a place were RtlExitUserThread
address exists okay. So let’s first talk about kernel32 and ntdll okay those are both dll’s
in Windows that are loaded in each process at the same location so the base address of
of of them is similar in each and every process. Ehm, and kernel32 also imports eh the
function RtlExitUserThread from ntdll. So what that that this means is if we look in at the
import address table and we find in our version, in the injecting process version, em the other
RtlExitUserThread in IAT is going to be at the same place in the target process so we can
copy that there using a method I’m going to discuss eh right now. Okay, so to copy the
address we’re going to use the function NtQueueApcThread. Okay, this function gets uh thread
handle which run to execute our code eh eh in that thread em then it gets the function we
want to execute and we are allowed to to pass three arguments. Okay, so we are going
to use the function RtlCopyMemory okay, give it destination, source, and length
then the target process is going to execute out RTlCopy eh Memory. Now the destination is
going to be the return address eh eh of our dummy stack, the source is going to be the
address of eh RtlExitUserThread. In our version of kernel32 IAT, and the length is going to be i8
byte which is the size of a pointer in F64. Okay, now a little side note, we can use
this method of copying okay. We can use it to recreate the shellcode so we just need to
find ehm in our version of let’s say ntdll the byte of our shellcode one-by-one and then we
can just copy it in the eh target process and we can just recreate the shellcode there.
Okay, now let’s finalize the the ehm execution. Ehm, so my first idea was to set RIP ehm to
ReadProcessMemory set all the other registers and then just execute it. But the truth when
you do so ehm you get you do it on a suspended thread and then you resume it you get exception
status invalid parameter. Ehm and we don’t want that cause that makes the the process crash
and eh even if the something happen it it it it just will crash and won’t work. Ehm, and
if we eh want to do something with the thread, we want to do something eh to copy to it
ReadProcessMemory, eh we need the thread to initialize before we can manipulate it okay? Eh
another thing if we start a thread, eh and it won’t be suspended, it will just run,
terminate before we can manipulate it and that would be bad for us cause we won’t have
time to do our stuff. Ehm, so to do it, we need to create an infinitely running thread. Eh,
we’ll create that thread and then we’ll manipulate it ehm to run eh ReadProcessMemory. Okay,
so when creating what thread is called, ehm the things the first function is going to execute is
RltUserThreadStart ehm this function first called to eh function after that you just do
other stuff and then does jump a bit which is going to be the entry point eh you deliver to
create a multi thread or create thread okay or whatever. And I guess you haven’t seen it but
RBX was never never never used here, never RBX was never changed ehm during this time so
we’re going to abuse that and we’re going to use the opcode jump RBX ehm to do that
infinitely running thread. So what we’re going to do is we’re going to allocate memory for
jump RBX then we will look for jump RBX copicode- upcode in our ntdll version in the injecting
process. We will copy it using the method described earlier to the target process then we’ll
create a remote thread that is suspended and it’s going to point to the jump RBX that we
just copied. Ehm, then using SetThreadContext you are going to set RBX to point to jump RBX
and then resume the thread. So now, what's going to happen is going to execute, get to the
jump RBX we talked about earlier and then this is going to jump to the jump RBX, RBX points to
the same location so just going to jump over and over and over and over and over again. Eh and
that’s how you make it run infinitely. Okay, so now lets eh execute the code, let’s just
execute the code injection. Ehm, so now we will suspend the thread and see the the RIP
really points to our jump RBX opcode so we know that the thread was initialized and
everything is okay. Ehm, and then we’ll start setting the thread okay so RCX is going to
point to the duplicated handle we duplicated. RDX is going to point to the address of the
shellcode in the injecting process. The buffer, the lpbuffer which is R8 going to
point to the location we allocated for the shellcode. Ehm, R9 which is ehm the size is
going to be ehm where we ehm the size of the shellcode. Then RSP is going to point to the dummy
stack we allocated eh so the fifth parameter will be null. Ehm, and RBX is going to point
to ReadProcessMemory so when we are going to resume the thread, jump RBX is going to jump to
ReadProcessMemory. All the other parameters are already setup ehm so we’re going to do that .
We’ll call WaitForSingleObject ehm just to see that the third was finished. When it’s done,
the shellcode is already copied into the ehm target process and now all we have to do is just
use a function like CreateRemoteThread thread and uh execute the shellcode. So, now
for demo. So in this demo, I’m going to open a notepad, execute the code inj- injection method
and you’re going to see at the notepad the command line in in a message box of course ehm, the
command line of the eh notepad that we opened. So here I opened the notepad with inject me
without running the program we find a duplicate handle of our process to remote one, we
allocated memory for shellcode then we allocate memory for our dummy stack. We will find out
RtlExitUserThread and copy it to the dummy stack, we will allocate memory for jump RBX, we
will copy jump RBX into the allocated memory, find ReadProcessMemory then we create
a remote thread that point to jump RBX will set the thread context, context was changed, we
will execute ReadProcessMemory and now execute the shellcode. And when you get the notepad,
you can see the message box with a command line. [Applause] So thank you very much for having
me and I hope you enjoyed the talk. Eh, special thanks for eh Maddy Stone for helping me doing
it. Ehm, the white paper is going to be published in the next few days, it’s still not up
but eh you’re more welcome eh to ask any questions ehm if I have time, I think I have. Ehm, thank
you. [Applause] Are there any questions? Okay, okay thank you very much.