CreateRemoteThread returning ERROR_ACCESS_DENIED -

2019-03-28 12:06发布

问题:

I'm trying to write a program that uses CreateRemoteThread to inject a dll.

The problem is that CreateRemoteThread is refusing to work. GetLastError() is returning 5 which is ERROR_ACCESS_DENIED. I cant figure why!

I am working from this video http://www.youtube.com/watch?v=H3O3hmXkt1I .

#include <iostream>
#include <direct.h>
#include <Windows.h>
#include <TlHelp32.h>

using namespace std;


char* GetCurrentDir()
{
    char*   szRet = (char*)malloc(MAX_PATH);
    _getcwd(szRet, MAX_PATH);
    return szRet;
}

LPCTSTR SzToLPCTSTR(char* szString)
{
    LPTSTR  lpszRet;
    size_t  size = strlen(szString)+1;

    lpszRet = (LPTSTR)malloc(MAX_PATH);
    mbstowcs_s(NULL, lpszRet, size, szString, _TRUNCATE);

    return lpszRet;
}

void WaitForProcessToAppear(LPCTSTR lpcszProc, DWORD dwDelay)
{
    HANDLE          hSnap;
    PROCESSENTRY32  peProc;
    BOOL            bAppeared = FALSE;

    while(!bAppeared)
    {
        if((hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)) != INVALID_HANDLE_VALUE)
        {
            peProc.dwSize = sizeof(PROCESSENTRY32);
            if(Process32First(hSnap, &peProc))
                while(Process32Next(hSnap, &peProc) && !bAppeared)
                    if(!lstrcmp(lpcszProc, peProc.szExeFile))
                        bAppeared = TRUE;
        }
        CloseHandle(hSnap);
        Sleep(dwDelay);
    }
}

DWORD GetProcessIdByName(LPCTSTR lpcszProc)
{
    HANDLE          hSnap;
    PROCESSENTRY32  peProc;
    DWORD           dwRet = -1;

    if((hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)) != INVALID_HANDLE_VALUE)
    {
        peProc.dwSize = sizeof(PROCESSENTRY32);
        if(Process32First(hSnap, &peProc))
            while(Process32Next(hSnap, &peProc))
                if(!lstrcmp(lpcszProc, peProc.szExeFile))
                    dwRet = peProc.th32ProcessID;
    }
    CloseHandle(hSnap);

    return dwRet;
}

BOOL InjectDll(DWORD dwPid, char* szDllPath)
{
    DWORD   dwMemSize;
    HANDLE  hProc;
    LPVOID  lpRemoteMem, lpLoadLibrary;
    BOOL    bRet = FALSE;

    if((hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid)) != NULL)
    {
        dwMemSize = strlen(szDllPath);
        if((lpRemoteMem = VirtualAllocEx(hProc, NULL, dwMemSize, MEM_COMMIT, PAGE_READWRITE)) != NULL)
            if(WriteProcessMemory(hProc, lpRemoteMem, szDllPath, dwMemSize, NULL))
            {
                lpLoadLibrary = GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
                if(CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)lpLoadLibrary, lpRemoteMem, 0, NULL) != NULL)
                {
                    bRet = TRUE;
                }
                cout << GetLastError();
            }
    }
    CloseHandle(hProc);

    return bRet;
}

int main()
{
    char    szProc[MAX_PATH], szDll[MAX_PATH];
    char*   szDllPath = (char*)malloc(MAX_PATH);
    LPTSTR  lpszProc = NULL;

    for(;;)
    {
        cout << "Process: ";
        cin >> szProc;
        cout << "DLL: ";
        cin >> szDll;

        szDllPath = GetCurrentDir();
        strcat_s(szDllPath, MAX_PATH, "\\");
        strcat_s(szDllPath, MAX_PATH, szDll);

        cout << "Waiting for process.. ." << szDllPath << " " << szDll << endl;
        WaitForProcessToAppear(SzToLPCTSTR(szProc), 100);
        if(InjectDll(GetProcessIdByName(SzToLPCTSTR(szProc)), szDllPath))
            cout << "Injection Succeeded!" << endl;
        else
            cout << "Injection Failed!" << endl;
        cout << "\n";

    }

    return 0;

After a fair amount of googling I cant find a reason why this should not be working.

Does CreateRemoteThread not work under Windows 7 ? If it does, have I made any obvious mistakes ?

回答1:

The reason it fails is because your code is 32-bit and your target process is 64-bit.

It doesn't matter how many privileges you own. Windows won't let that happen.

I had the same problem. Either you spawn a system 32-bit exe and inject that or port your code to 64-bit (which means it won't work on 32-bit systems).

EDIT

A long time ago, I found a nice way of injecting code into and from any processor mode-target. It involves dynamically switching the processor mode to that of (any)the target. Dubbed "heaven's gate". To do this you have to use inline assembly. So basically you can have both 64-bit and 32-bit code in a 32-bit exe, detect if the machine is 64-bit, then jump into 64-bit mode and run the 64-bit code. You'd then walk the imports to find ntdll and load 64-bit kernel.dll and other libraries. Here's a link to examples for any one who would be interested: http://bit.ly/19P0Lh3



回答2:

Immediate problems I see are that you are not getting the access token which should be done as so:

HANDLE hToken; 
TOKEN_PRIVILEGES tp; 
HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId() ); 

tp.PrivilegeCount = 1; 
LookupPrivilegeValue( NULL, _T("SeDebugPrivilege"), &tp.Privileges[0].Luid ); 
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 
OpenProcessToken( hProcess, TOKEN_ADJUST_PRIVILEGES, &hToken ); 

AdjustTokenPrivileges( hToken, FALSE, &tp, NULL, NULL, NULL ); 
CloseHandle( hToken );

I don't have time to look through all your code right now, but here is something I ripped out of one of my previous projects:

// returns open process handle
HANDLE InjectDLL( DWORD dwPID, LPCWSTR szDLLPath, HMODULE* lphInjected ) {
  int     cszDLL;
  LPVOID  lpAddress;
  HMODULE hMod;
  HANDLE  hThread;
  HANDLE  hProcess = OpenProcess( PROCESS_CREATE_THREAD | 
      PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION |
      PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, dwPID );

  if( hProcess == NULL ) {
    return NULL;
  }

  cszDLL = ( wcslen( szDLLPath ) + 1 ) * sizeof( WCHAR );

  // Injection
  lpAddress = VirtualAllocEx( hProcess, NULL, cszDLL, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
  if( lpAddress == NULL ) {
    return NULL;
  }

  WriteProcessMemory( hProcess, lpAddress, szDLLPath, cszDLL, NULL );

  hMod = GetModuleHandle( L"kernel32.dll" );
  if( hMod == NULL ) {
    return NULL;
  }

  hThread = CreateRemoteThread( hProcess, NULL, 0,
        (LPTHREAD_START_ROUTINE)( GetProcAddress( hMod,
        "LoadLibraryW" ) ), lpAddress, 0, NULL );

  // Locate address our payload was loaded
  if( hThread != 0 ) {
    WaitForSingleObject( hThread, INFINITE );
    GetExitCodeThread( hThread, ( LPDWORD )lphInjected );
    VirtualFreeEx( hProcess, lpAddress, 0, MEM_RELEASE );
    CloseHandle( hThread );
  }

  return hThread != 0 ? hProcess : NULL;
}

See if it helps. Will look again later.



回答3:

OK, your code is likely to fail in windows 7 and Vista because of "Protected processes", that is, processes which only can be manipulated by other Protected Processes, like explorer.exe, etc... In Windows 7 x32 there is a way: since you are able to load unsigned drivers,... well, you are done (search for Alex Ionescu in google). In Windows 7 x64, though, you can't (duh!)

"The fourth parameter of the CreateRemoteThread() is an address. In your case it is the LoadLibraryA address. However, in windows 7, Kernel32.dll/LoadLibraryA base address will various in different process;"

Well, that's not remotely true, because DLLs are shared at the same addresses in every process, despite ASLR. DLLs can be rebased, though, but you can call GetProcAddress before calling CreateRemoteThread, so it is very unlikely that the DLL will get rebased meanwhile.



回答4:

I think CreateRemoteThread() dll injection method can not work in windows 7.

The fourth parameter of the CreateRemoteThread() is an address. In your case it is the LoadLibraryA address. However, in windows 7, Kernel32.dll/LoadLibraryA base address will various in different process; Therefore, the CreateRemoteThread() will not work since the address is not what u expected. This is my own opinion, hope it will help. :)



回答5:

CreateRemoteThread function does not work in Win Vista/7. You have to use NTCreateThread function,which is undocumented, for that.