简体   繁体   中英

CreateRemoteThread - ERROR_ACCES_DENIED

I think my code is finally working now. Only problem is that for some reason, even though I've opened the process with PROCESS_ALL_ACCESS, CreateRemoteThread throws back an error: ERROR_ACCESS_DENIED.

The error was retrieved with GetLastError and it spit out '5', which translates to ERROR_ACCESS_DENIED.

#include <iostream>
#include <windows.h>
#include <TlHelp32.h>

char* dllPath = "C:\\Users\\Kalist\\Desktop\\Projects\\DLL\\bin\\Debug\\DLL.dll";
char* ProcToInject = "calc.exe";

int main(){
    PROCESSENTRY32 pe32;
    pe32.dwSize = sizeof(PROCESSENTRY32);
    HANDLE procSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

    if(procSnap == INVALID_HANDLE_VALUE){
        std::cout << "Snapshot function failed" << std::endl;
    }

    DWORD procID = 0;
        if(Process32First(procSnap, &pe32)){
            do{
               if(!strcmp(pe32.szExeFile, ProcToInject)){
                    procID = pe32.th32ProcessID;
                    break;
               }
            }while(Process32Next(procSnap, &pe32));
        }
    CloseHandle(procSnap);

    if(procID != 0){

        HANDLE procAccess = OpenProcess(PROCESS_ALL_ACCESS, false, procID);
        if(procAccess == NULL){
            std::cout << "OpenProcess error: " << GetLastError() << std::endl;
        }

        LPVOID remoteString = (LPVOID)VirtualAllocEx(procAccess, NULL, strlen(dllPath)+1, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
        if(remoteString == NULL){
            std::cout << "VirtualAllocEx error: " << GetLastError() << std::endl;
        }

        bool memoryWritten = WriteProcessMemory(procAccess, (LPVOID)remoteString, dllPath, strlen(dllPath)+1, NULL);
        if(memoryWritten == 0){
            std::cout << "WriteProcessMemory error: " << GetLastError() << std::endl;
        }

        LPVOID getLibAdd = (LPVOID)GetProcAddress(GetModuleHandle("Kernel32.dll"), "LoadLibraryA");
        if(getLibAdd == NULL){
            std::cout << "GetProcAddress error: " << GetLastError() << std::endl;
        }

        HANDLE remoteThread = CreateRemoteThread(procAccess, NULL, 0, (LPTHREAD_START_ROUTINE)getLibAdd, (LPVOID)remoteString, 0, NULL);
        if(remoteThread == NULL){
            std::cout << "CreateRemoteThread error: " << GetLastError() << std::endl;
        }
        CloseHandle(procAccess);
    }else{
        std::cout << "Failed to retrieve procID" << std::endl;
    }
}

You'll get this error when you attempt to call CreateRemoteThread from a 32 bit process, but where the target process is a 64 bit process. I'm betting that's what you are doing.

In order to inject into a 64 bit process, you need your injector process also to be 64 bit. And obviously, as I am sure you already know, the DLL that you inject must also be 64 bit.

For what it is worth, you don't need to ask for so much when you call OpenProcess . I believe that all you need is:

PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION 
  | PROCESS_VM_WRITE | PROCESS_VM_READ

The code, you have written, assumes that the process, the code is running on, the dll you are injecting, and the calc.exe are all the same bitness.

If this is not statisfied, the call to CreateRemoteThread will fail. This is, due to a constraint of the lpStartAddress parameter.

The following Quote is from the CreateRemoteThread documentation

A pointer to the application-defined function of type LPTHREAD_START_ROUTINE to be executed by the thread and represents the starting address of the thread in the remote process. The function must exist in the remote process. For more information, see ThreadProc.

The assumtion of the code is due, to the following:

The LoadLibraryA function is located at a different rva, when comparing x86 to x64, because a different Kernel32.dll file is loaded, when you have a x86 process vs a x64 process. The different Kernel32.dll files are also loaded at a different base address, when comparing a x86 process to a x64 process. The Address you get back, from GetProcAddr is rva + dll base address .

Currently I am programming an injector, which will be also capable of x86 to x64, and have verified, that all addresses, that are passed to CreateRemoteThread are in the scope, of the target process. Also I am opening the Process with PROCESS_CREATE_THREAD | PROCESS_VM_WRITE | PROCESS_VM_READ| PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION PROCESS_CREATE_THREAD | PROCESS_VM_WRITE | PROCESS_VM_READ| PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION PROCESS_CREATE_THREAD | PROCESS_VM_WRITE | PROCESS_VM_READ| PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION . But I still have this issue.

This is because, the pointer length, of x86 is 32-bit. The parameter lpStartAddress of CreateRemoteThread is a pointer though. This means, that you will never be able to call all functions of a x64 target, because the function pointer will be capped, to 32-bit. That in turn means that you can call at most all function inside the x86 addressable region, from a x86 process, in a x64 target process.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM