Ok, I'm learning about the Windows API and how to create threads/processes and get debug rights etc. Very new so I apologize if this is a stupid problem.
Anyways, I'm creating a .dll injector to play around with, and have successfully been able to inject 32 and 64 bit processes, including explorer.exe by injecting my .dll file. However, I'm trying to test this in a standard user mode and am having problems figuring out how.
Right now I'm compiling as x64 for both the .dll and injector.exe. I'm trying to inject into a x64 process, primarily explorer.exe (which works on admin). Using Visual Studio 2012, with some optimizations, no manifest, no debug(only when needed). OS= Win 7 x64
Also, I have tried to access the .dll from multiple places, E:\ drive is just another partition on my HD.
The NtCreateThreadEx(); call returns a thread that is 0. Thus it did not load correctly.
#include <windows.h>
#include <iostream>
#include <stdlib.h>
#include <tlhelp32.h>
#define CREATE_THREAD_ACCESS (PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ)
using namespace std;
DWORD getPid(string procName);
int privileges();
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING;
typedef UNICODE_STRING *PUNICODE_STRING;
typedef struct _OBJECT_ATTRIBUTES {
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor;
PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES;
typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;
typedef DWORD(WINAPI *NTCREATETHREADEX)
(
PHANDLE ThreadHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
HANDLE ProcessHandle,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
BOOL CreateSuspended,
DWORD dwStackSize,
DWORD dw1,
DWORD dw2,
LPVOID Unknown
);
int main()
{
cout << sizeof(void*) << endl;
privileges(); //don't mind of the result, because maybe it fails because you already have that privilege
DWORD pid = getPid("explorer.exe");
if (pid == 0) return 1; //error
HANDLE p;
p = OpenProcess(CREATE_THREAD_ACCESS, false, pid);
if (p == NULL) return 1; //error
char * dll = "E:\\logger_mailer.dll";
BOOL is32 = FALSE;
BOOL fnWow64Ret = IsWow64Process(p, &is32);
if (!fnWow64Ret)
{
cout<<"Error!!!!!!"<<endl;
return 1;
}
//if (is32) //If true process is 32 bit
// dll = "D:\\logger_mailer.dll";
//else
//{
// dll = "D:\\logger_mailer.dll";
// //cout<<"Error"<<endl;
//}
unsigned long LoadLib = (unsigned long)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
LPVOID DataAddress = VirtualAllocEx(p, NULL, strlen(dll) + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(p, DataAddress, dll, strlen(dll), NULL);
HANDLE thread;
NTCREATETHREADEX NtCreateThreadEx = (NTCREATETHREADEX)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtCreateThreadEx");
if (NtCreateThreadEx) {
NtCreateThreadEx(&thread, GENERIC_ALL, NULL, p, (LPTHREAD_START_ROUTINE)LoadLib, DataAddress, FALSE, NULL, NULL, NULL, NULL);
}
else {
thread = CreateRemoteThread(p, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLib, DataAddress, NULL, NULL);
}
if (thread != 0){
//injection completed
WaitForSingleObject(thread, INFINITE); //this waits untill thread thread has finished
VirtualFree(dll, 0, MEM_RELEASE); //free myFunc memory
VirtualFree(DataAddress, 0, MEM_RELEASE); //free data memory
CloseHandle(thread);
CloseHandle(p); //don't wait for the thread to finish, just close the handle to the process
cout << "Injection completed!" << endl;
}
else{
cout << "Error!" << endl;
}
system("PAUSE");
return EXIT_SUCCESS;
}
DWORD getPid(string procName){
HANDLE hsnap;
PROCESSENTRY32 pt;
hsnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
pt.dwSize = sizeof(PROCESSENTRY32);
do{
if (!strcmp(pt.szExeFile, procName.c_str())){
DWORD pid = pt.th32ProcessID;
CloseHandle(hsnap);
return pid;
}
} while (Process32Next(hsnap, &pt));
CloseHandle(hsnap);
return 0;
}
int privileges(){
HANDLE Token;
TOKEN_PRIVILEGES tp;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &Token))
{
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (AdjustTokenPrivileges(Token, 0, &tp, sizeof(tp), NULL, NULL) == 0){
return 1; //FAIL
}
else{
return 0; //SUCCESS
}
}
return 1;
}
EDIT: So, after David and Harry basically coddled me through stuff, I have found that it is my .dll code that is failing. Also, my use of NtCreateThreadEx() was unneeded as CreateRemoteThread() does indeed work on win 7 x64. Many, posts here on SO and other sites specify otherwise. A simple message box was displayed to verify.
What is weird is that NtCreateThreadEx() works in admin mode, but not in standard.
I can see the following problems:
WriteProcessMemory
you pass the wrong length. You need to pass strlen(...)+1
in order to write the null-terminator.NtCreateThreadEx
. Using CreateRemoteThread
works perfectly well for injection.For what it is worth, I've never had to use AdjustTokenPrivileges
to inject. I believe that you can skip that step.
In a comment you state that you are injecting into a different session. And you find that you need NtCreateThreadEx
rather than CreateRemoteThread
, and that injection only works when elevated. Of course, the requirement to inject into a process in a different session is pretty important. That should be included in the question rather than appearing in comments.
However, you should not be remotely surprised that you need to elevate to inject into a process in a different session. And for that scenario then quite possibly adding SE_DEBUG_NAME
is needed.
In short, it seems to me that the system is telling you to run elevated in order to inject into a process in a different session. That seems quite reasonable.
On the other hand, you also state in comments that CreateRemoteThread
returns a non-zero value. Which indicates success. That seems to say that you are mis-diagnosing the problem. If CreateRemoteThread
is succeeding then the remote thread will run. You next need to work out what fails after that.
And you also say that you are trying to inject into the explorer
process which does not run in session 0. So there is a lot of confusion here. Perhaps I jumped the gun in adding this answer.
In any case, in order for you to proceed I recommend:
WriteProcessMemory
.