Thread32First returns true so I know the function isn't failing. However, it keeps returning the same value for the th32ThreadID data member of THREADENTRY32, 0. Doesn't matter what process I try it on, it continues to be the same thread id: 0.
Here's my code:
#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>
BOOL EnableDebugPriv(HANDLE proc);
int main()
{
HANDLE hSnapshot;
HANDLE hThread;
THREADENTRY32 thread32;
DWORD dwPid = 15404;
EnableDebugPriv(OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid));
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, dwPid);
if(hSnapshot == INVALID_HANDLE_VALUE)
{
printf("Error getting snapshot: %lu\n", GetLastError());
return 1;
}
thread32.dwSize = sizeof(THREADENTRY32);
if(!Thread32First(hSnapshot, &thread32))
{
printf("Error thread32first\n");
return 1;
}
printf("Thread Id: %lu\n", thread32.th32ThreadID);
hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, thread32.th32ThreadID);
if(hThread == NULL)
{
printf("Error getting handle: %lu\n", GetLastError());
return 1;
}
return 0;
}
BOOL EnableDebugPriv(HANDLE proc)
{
HANDLE hToken;
LUID sedebugnameValue;
TOKEN_PRIVILEGES tkp;
// pass our opened process handle
OpenProcessToken(proc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue);
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = sedebugnameValue;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if(AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof tkp, NULL, NULL))
{
CloseHandle(hToken);
return TRUE;
}
else
{
MessageBox(NULL,"Bro, you gotta be an admin to set privs like this", "Shit", MB_OK);
CloseHandle(hToken);
return FALSE;
}
}
Note: I am aware that using a static process ID like I am could cause problems. However, I make sure the process is still running with the same process ID. That's not the problem.
Related
#include <windows.h>
#include <iostream>
#include <Lmcons.h>
#include <conio.h>
BOOL SetPrivilege(
HANDLE hToken, // access
token handle
LPCTSTR lpszPrivilege, // name of
privilege to enable/disable
BOOL bEnablePrivilege // to
enable or disable privilege
)
{
TOKEN_PRIVILEGES tp;
LUID luid;
if (!LookupPrivilegeValue(
NULL, // lookup
privilege on local system
lpszPrivilege, // privilege
to lookup
&luid)) // receives
LUID of privilege
{
printf("[-]
LookupPrivilegeValue error: %u\n",
GetLastError());
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if (bEnablePrivilege)
tp.Privileges[0].Attributes =
SE_PRIVILEGE_ENABLED;
else
tp.Privileges[0].Attributes =
0;
// Enable the privilege or disable
all privileges.
if (!AdjustTokenPrivileges(
hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES)NULL,
(PDWORD)NULL))
{
printf("[-]
AdjustTokenPrivileges error:
%u\n",
GetLastError());
return FALSE;
}
if (GetLastError() ==
ERROR_NOT_ALL_ASSIGNED)
{
printf("[-] The token does not
have the specified privilege.
\n");
return FALSE;
}
return TRUE;
}
int main(int argc, char** argv) {
// Print whoami to compare to
thread later
printf("[+] Current user is:
%s\n"); //
(get_username()).c_str());
system("whoami");
// Grab PID from command line
argument
char *pid_c = argv[1];
DWORD PID_TO_IMPERSONATE = 900;
// Initialize variables and
structures
HANDLE tokenHandle = NULL;
HANDLE duplicateTokenHandle =
NULL;
STARTUPINFOW startupInfo;
PROCESS_INFORMATION
processInformation;
ZeroMemory(&startupInfo,
sizeof(STARTUPINFO));
ZeroMemory(&processInformation,
sizeof(PROCESS_INFORMATION));
startupInfo.cb =
sizeof(STARTUPINFO);
// Add SE debug privilege
HANDLE currentTokenHandle =
NULL;
BOOL getCurrentToken =
OpenProcessToken
(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES,
¤tTokenHandle);
if
(SetPrivilege
(currentTokenHandle,
"SeDebugPrivilege", TRUE))
{
printf("[+] SeDebugPrivilege
enabled!\n");
}
// Call OpenProcess(), print
return code and error code
HANDLE processHandle =
OpenProcess
(PROCESS_QUERY_INFORMATION,
true, PID_TO_IMPERSONATE);
if (GetLastError() == NULL)
printf("[+] OpenProcess()
success!\n");
else
{
printf("[-] OpenProcess()
Return Code: %i\n",
processHandle);
printf("[-] OpenProcess()
Error: %i\n",
GetLastError());
}
// Call OpenProcessToken(),
print return code and error
code
BOOL getToken =
OpenProcessToken
(processHandle,
TOKEN_DUPLICATE |
TOKEN_ASSIGN_PRIMARY |
TOKEN_QUERY, &tokenHandle);
if (GetLastError() == NULL)
printf("[+]
OpenProcessToken()
success!\n");
else
{
printf("[-]
OpenProcessToken() Return
Code: %i\n", getToken);
printf("[-] OpenProcessToken()
Error: %i\n",
GetLastError());
}
// Impersonate user in a
thread
BOOL impersonateUser =
ImpersonateLoggedOnUser
(tokenHandle);
if (GetLastError() == NULL)
{
printf("[+]
ImpersonatedLoggedOnUser()
success!\n");
// printf("[+] Current
user is: %s\n",
(get_username()).c_str());
system("whoami");
printf("[+] Reverting thread
to original user context\n");
RevertToSelf();
}
else
{
printf("[-]
ImpersonatedLoggedOnUser()
Return Code: %i\n", getToken);
printf("[-]
ImpersonatedLoggedOnUser()
Error: %i\n", GetLastError());
}
// Call DuplicateTokenEx(),
print return code and error
code
BOOL duplicateToken =
DuplicateTokenEx(tokenHandle,
TOKEN_ADJUST_DEFAULT |
TOKEN_ADJUST_SESSIONID |
TOKEN_QUERY | TOKEN_DUPLICATE
| TOKEN_ASSIGN_PRIMARY, NULL,
SecurityImpersonation,
TokenPrimary,
&duplicateTokenHandle);
if (GetLastError() == NULL)
printf("[+] DuplicateTokenEx()
success!\n");
else
{
printf("[-] DuplicateTokenEx()
Return Code: %i\n",
duplicateToken);
printf("[-] DupicateTokenEx()
Error: %i\n", GetLastError());
}
// Call
CreateProcessWithTokenW(),
print return code and error
code
BOOL createProcess =
CreateProcessWithTokenW
(duplicateTokenHandle,
LOGON_WITH_PROFILE,
L"C:\\Windows\
\System32\\cmd.exe", NULL,
0, NULL, NULL, &startupInfo,
&processInformation);
if (GetLastError() == NULL)
printf("[+] Process
spawned!\n");
else
{
printf("[-]
CreateProcessWithTokenW
Return Code: %i\n",
createProcess);
printf("[-]
CreateProcessWithTokenW Error:
%i\n", GetLastError());
}
getch();
return 0;
}
This is a code that impersonates Winlogon Access token on Windows to give me System rights but it requires me to run the program as administrator before I'm able to impersonate Winlogon...
I believe the reason is based on lack of privileges my program access token has.
If there's anyone that can give me an idea to do this without running as administrator first I'll appreciate.
What it actually requires is that the account holds the SE_IMPERSONATE_NAME privilege and the particular process having it enabled. Normally only highly trusted accounts (an elevated Administrator token or Local System used by default for services) have this privilege but you can assign it to others through the "Local Users and Groups" (or "Active Directory Users and Computers" if using AD) MMC snap-in.
I have a problem, I want to read some values with ReadProcessMemory from a process, this process blocks OpenProcess, now I heard that I just need to Privilege the file who want to do OpenProcess with SE_DEBUG_NAME.
I googled and found this function :
BOOL SetPrivilege(
HANDLE hToken, // access token handle
LPCTSTR lpszPrivilege, // name of privilege to enable/disable
BOOL bEnablePrivilege){
TOKEN_PRIVILEGES tp;
LUID luid;
if (!LookupPrivilegeValue(
NULL, // lookup privilege on local system
lpszPrivilege, // privilege to lookup
&luid)) // receives LUID of privilege
{
printf("LookupPrivilegeValue error: %u\n", GetLastError());
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if (bEnablePrivilege)
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
tp.Privileges[0].Attributes = 0;
// Enable the privilege or disable all privileges.
if (!AdjustTokenPrivileges(
hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES)NULL,
(PDWORD)NULL))
{
printf("AdjustTokenPrivileges error: %u\n", GetLastError());
return FALSE;
}
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
{
printf("The token does not have the specified privilege. \n");
return FALSE;
}
return TRUE;}
Now i tried the following :
bool bStart(std::string szProcessName)
{
if (szProcessName.empty())
return false;
HANDLE hToken;
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken);
SetPrivilege(hToken, SE_DEBUG_NAME, true);
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
return FALSE;
if (!SetPrivilege(hToken, SE_DEBUG_NAME, TRUE))
{
std::cout << "SetPrivilege";
// close token handle
CloseHandle(hToken);
// indicate failure
return false;
}
std::cout << "hi";
HANDLE hSnapshot = (CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
if (hSnapshot == INVALID_HANDLE_VALUE)
return false;
bool bFoundProcess = false;
PROCESSENTRY32 PE32 = { sizeof(PROCESSENTRY32) };
if (Process32First(hSnapshot, &PE32))
{
do
{
if (!szProcessName.compare(PE32.szExeFile))
{
m_dwProcessId = (XOR(PE32.th32ProcessID));
bFoundProcess = true;
break;
}
} while (Process32Next(hSnapshot, &PE32));
}
CloseHandle(m_hProcess);
if (!bFoundProcess)
return false;
m_hProcess = (XOR(OpenProcess(PROCESS_ALL_ACCESS, FALSE, m_dwProcessId)));
if (m_hProcess == INVALID_HANDLE_VALUE)
return false;
return true;
}
I don't get any error or anything, but for any reason, the OpenProcess doesn't work. Can someone please help me?
Thanks in advance!
this process blocks OpenProcess
This means the game's anticheat is blocking process handle creation via a kernel mode anticheat.
There is nothing you can do to bypass this from usermode, you must also make a kernel driver and disable their protection.
The most simple way for them to prevent handle creation is with ObRegisterCallbacks so you will need to reverse engineer their implementation of that.
Keep in mind this technique is from 5+ years ago, they have much more complicated protection now.
I have an elevated process that has been started after the user has answered "Yes" in the UAC dialog.
The process is started fine, everything works as expected.
Now I need to "unelevate" that process at some point, in other words the process should become not elevated exactly as if it had been launched normally by the user.
Sample scenario
User A is logged on
User A launches process P1 which will be elevated via UAC
Elevated process P1 lauchches process P2 and P2 should'nt be elevated and should run again under user A.
Is there a way to do this?
the elevated process have linked token - it refers to non elevated user session. we can use this linked token in 2 ways:
first way:
get it as TokenPrimary (for this we need have SE_TCB_PRIVILEGE
when we query this token)
call CreateProcessAsUser with this token. for this we need also
SE_ASSIGNPRIMARYTOKEN_PRIVILEGE and SE_INCREASE_QUOTA_PRIVILEGE
for get all this privileges - enumerate processes, query it tokens,
and if process token have all this 3 privileges - impersonate with
it, before call CreateProcessAsUser. because elevated token have
SE_DEBUG_PRIVILEGE the task is possible
second way:
query the logon session id from linked token (AuthenticationId
from TOKEN_STATISTICS)
found process with the same AuthenticationId in process token.
use this process as parent process by help
PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
implementation for way 1:
static volatile UCHAR guz;
ULONG RunNonElevated(HANDLE hToken, HANDLE hMyToken, PCWSTR lpApplicationName, PWSTR lpCommandLine)
{
ULONG err;
PVOID stack = alloca(guz);
ULONG cb = 0, rcb = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[SE_MAX_WELL_KNOWN_PRIVILEGE]);
union {
PVOID buf;
PTOKEN_PRIVILEGES ptp;
};
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (GetTokenInformation(hToken, TokenPrivileges, buf, cb, &rcb))
{
if (ULONG PrivilegeCount = ptp->PrivilegeCount)
{
int n = 3;
BOOL fAdjust = FALSE;
PLUID_AND_ATTRIBUTES Privileges = ptp->Privileges;
do
{
switch (Privileges->Luid.LowPart)
{
case SE_ASSIGNPRIMARYTOKEN_PRIVILEGE:
case SE_INCREASE_QUOTA_PRIVILEGE:
case SE_TCB_PRIVILEGE:
if (!(Privileges->Attributes & SE_PRIVILEGE_ENABLED))
{
Privileges->Attributes |= SE_PRIVILEGE_ENABLED;
fAdjust = TRUE;
}
if (!--n)
{
err = NOERROR;
if (DuplicateTokenEx(hToken,
TOKEN_ADJUST_PRIVILEGES|TOKEN_IMPERSONATE,
0, SecurityImpersonation, TokenImpersonation,
&hToken))
{
if (fAdjust)
{
AdjustTokenPrivileges(hToken, FALSE, ptp, rcb, NULL, NULL);
err = GetLastError();
}
if (err == NOERROR)
{
if (SetThreadToken(0, hToken))
{
TOKEN_LINKED_TOKEN tlt;
if (GetTokenInformation(hMyToken, TokenLinkedToken, &tlt, sizeof(tlt), &rcb))
{
STARTUPINFO si = { sizeof (si) };
PROCESS_INFORMATION pi;
if (!CreateProcessAsUserW(tlt.LinkedToken, lpApplicationName, lpCommandLine,
NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
{
err = GetLastError();
}
CloseHandle(tlt.LinkedToken);
if (err == NOERROR)
{
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
}
else
{
err = GetLastError();
}
SetThreadToken(0, 0);
}
else
{
err = GetLastError();
}
}
CloseHandle(hToken);
}
else
{
err = GetLastError();
}
return err;
}
}
} while (Privileges++, --PrivilegeCount);
}
return ERROR_NOT_FOUND;
}
} while ((err = GetLastError()) == ERROR_INSUFFICIENT_BUFFER);
return err;
}
ULONG RunNonElevated(HANDLE hMyToken, PCWSTR lpApplicationName, PWSTR lpCommandLine)
{
static TOKEN_PRIVILEGES tp = {
1, { { { SE_DEBUG_PRIVILEGE } , SE_PRIVILEGE_ENABLED } }
};
AdjustTokenPrivileges(hMyToken, FALSE, &tp, sizeof(tp), NULL, NULL);
ULONG err = NOERROR;
// much more effective of course use NtQuerySystemInformation(SystemProcessesAndThreadsInformation) here
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0), hToken;
if (hSnapshot != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32W pe = { sizeof(pe) };
if (Process32FirstW(hSnapshot, &pe))
{
err = ERROR_NOT_FOUND;
do
{
if (pe.th32ProcessID && pe.th32ParentProcessID)
{
if (HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pe.th32ProcessID))
{
if (OpenProcessToken(hProcess, TOKEN_QUERY|TOKEN_DUPLICATE, &hToken))
{
err = RunNonElevated(hToken, hMyToken, lpApplicationName, lpCommandLine);
CloseHandle(hToken);
}
else
{
err = GetLastError();
}
CloseHandle(hProcess);
}
else
{
err = GetLastError();
}
}
} while (err && Process32NextW(hSnapshot, &pe));
}
else
{
err = GetLastError();
}
CloseHandle(hSnapshot);
}
return err;
}
ULONG RunNonElevated(PCWSTR lpApplicationName, PWSTR lpCommandLine)
{
HANDLE hToken;
ULONG err = NOERROR;
if (OpenProcessToken(NtCurrentProcess(), TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES, &hToken))
{
TOKEN_ELEVATION_TYPE tet;
ULONG rcb;
if (GetTokenInformation(hToken, ::TokenElevationType, &tet, sizeof(tet), &rcb))
{
if (tet == TokenElevationTypeFull)
{
RunNonElevated(hToken, lpApplicationName, lpCommandLine);
}
else
{
err = ERROR_ALREADY_ASSIGNED;
}
}
else
{
err = GetLastError();
}
CloseHandle(hToken);
}
else
{
err = GetLastError();
}
return err;
}
implementation for way 2:
ULONG CreateProcessEx(HANDLE hProcess,
PCWSTR lpApplicationName,
PWSTR lpCommandLine)
{
SIZE_T Size = 0;
STARTUPINFOEX si = { sizeof(si) };
PROCESS_INFORMATION pi;
InitializeProcThreadAttributeList(0, 1, 0, &Size);
ULONG err = GetLastError();
if (err = ERROR_INSUFFICIENT_BUFFER)
{
si.lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)alloca(Size);
if (InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &Size))
{
if (UpdateProcThreadAttribute(si.lpAttributeList, 0,
PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &hProcess, sizeof(hProcess), 0, 0) &&
CreateProcessW(lpApplicationName, lpCommandLine, 0, 0, 0,
EXTENDED_STARTUPINFO_PRESENT, 0, 0, &si.StartupInfo, &pi))
{
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
else
{
err = GetLastError();
}
DeleteProcThreadAttributeList(si.lpAttributeList);
}
else
{
err = GetLastError();
}
}
else
{
err = GetLastError();
}
return err;
}
ULONG CreateProcessEx(LUID AuthenticationId,
PCWSTR lpApplicationName,
PWSTR lpCommandLine)
{
ULONG err = ERROR_NOT_FOUND;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32W pe = { sizeof(pe) };
ULONG rcb;
if (Process32First(hSnapshot, &pe))
{
err = ERROR_NOT_FOUND;
BOOL found = FALSE;
do
{
if (pe.th32ProcessID && pe.th32ParentProcessID)
{
if (HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION|PROCESS_CREATE_PROCESS, FALSE, pe.th32ProcessID))
{
HANDLE hToken;
if (OpenProcessToken(hProcess, TOKEN_QUERY, &hToken))
{
TOKEN_STATISTICS ts;
if (GetTokenInformation(hToken, TokenStatistics, &ts, sizeof(ts), &rcb))
{
if (ts.AuthenticationId.LowPart == AuthenticationId.LowPart &&
ts.AuthenticationId.HighPart == AuthenticationId.HighPart)
{
found = TRUE;
err = CreateProcessEx(hProcess,
lpApplicationName,
lpCommandLine);
}
}
CloseHandle(hToken);
}
CloseHandle(hProcess);
}
}
} while (!found && Process32Next(hSnapshot, &pe));
}
else
{
err = GetLastError();
}
CloseHandle(hSnapshot);
}
else
{
err = GetLastError();
}
return err;
}
ULONG CreateProcessEx(PCWSTR lpApplicationName,
PWSTR lpCommandLine)
{
HANDLE hToken;
ULONG err = NOERROR;
if (OpenProcessToken(NtCurrentProcess(), TOKEN_QUERY, &hToken))
{
union {
TOKEN_ELEVATION_TYPE tet;
TOKEN_LINKED_TOKEN tlt;
};
ULONG rcb;
if (GetTokenInformation(hToken, TokenElevationType, &tet, sizeof(tet), &rcb))
{
if (tet == TokenElevationTypeFull)
{
if (GetTokenInformation(hToken, TokenLinkedToken, &tlt, sizeof(tlt), &rcb))
{
TOKEN_STATISTICS ts;
BOOL fOk = GetTokenInformation(tlt.LinkedToken, TokenStatistics, &ts, sizeof(ts), &rcb);
CloseHandle(tlt.LinkedToken);
if (fOk)
{
err = CreateProcessEx(ts.AuthenticationId,
lpApplicationName,
lpCommandLine);
}
else
{
err = GetLastError();
}
}
else
{
err = GetLastError();
}
}
else
{
err = ERROR_ALREADY_ASSIGNED;
}
}
else
{
err = GetLastError();
}
CloseHandle(hToken);
}
else
{
err = GetLastError();
}
return err;
}
and test:
WCHAR ApplicationName[MAX_PATH];
if (GetEnvironmentVariableW(L"ComSpec", ApplicationName, RTL_NUMBER_OF(ApplicationName)))
{
WCHAR cmdline[] = L"cmd.exe /k whoami /priv /groups\r\n";
CreateProcessEx(ApplicationName, cmdline);
RunNonElevated(ApplicationName, cmdline);
}
for way #2 theoretical we can not found process with same logon id (AuthenticationId) as in our linked token. but way #1 always must work. always exist system process which have SeTcbPrivilege (for get primary form of linked token) + SeAssignPrimaryTokenPrivilege (for CreateProcessAsUser) (SeIncreaseQuotaPrivilege listen in msdn as typical require for CreateProcessAsUser but in my test this worked even if this privilege not enabled ). however all system processes (running as LocalSystem) have this 3 privilege in token (begin from smss.exe) and some system processes always run in system.
so way #1 must never fail and preferred. also we can here use for example inherited handles from our process, for interact with child process. this is impossible in way #2. it shown rather for completeness of the picture
at begin we check TOKEN_ELEVATION_TYPE and do job, only if it is TokenElevationTypeFull. in case TokenElevationTypeLimited we not elevated process - so nothing todo.
case TokenElevationTypeDefault mean or UAC if off (LUA disabled) or we run as built-in Administrator, and lua not filter tokens for this account (so all processes is "elevated" or more exactly it tokens not filtered via CreateRestrictedToken(..LUA_TOKEN..) ) - in this case also no sense try run "not elevated" process under this user
I need to log off a user from a C++ program. I use ExitWindowsEx API for that, but I'm not sure from the documentation if I need any special privileges for that?
You do. Here's an example
bool ShutdownWindows(void)
{
HANDLE hToken = NULL;
TOKEN_PRIVILEGES tkp = {0};
bool bRet = false;
// Get a token for this process.
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
if (LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid)) {
tkp.PrivilegeCount = 1; // one privilege to set
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// Get the shutdown privilege for this process.
if (AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, NULL, 0)) {
::CloseHandle(hToken);
if (ERROR_SUCCESS == GetLastError()) {
DWORD dwFlags = EWX_POWEROFF;
DWORD dwReason = SHTDN_REASON_MAJOR_SYSTEM;
if (ExitWindowsEx(dwFlags, dwReason)) {
bRet = true;
}
}
}
}
}
return bRet;
} // ShutdownWindows
I'm in the process of making a security program for my network. One of it's instances is to check and monitor what api's and libraries are called. The dll to do that and the program that go along with it are already finished. But there is a problem that I cant seem to fix.
When trying to inject my dll into system processes (such as explorer.exe, my main test system process) with NtCreateThreadEx I get the return value: C0000022, it means something along the lines of: Status_Access_Denied (it returns in NTSTATUS, but DWORD will do)
I have no idea what to do, I'm running as Administrator, I raised my privileges, and used the proper functions, still I get c0000022
Here's the code I'm using to inject
#include "main.h"
typedef DWORD NTSTATUS;
struct NtCreateThreadExBuffer{
ULONG Size;
ULONG Unknown1;
ULONG Unknown2;
PULONG Unknown3;
ULONG Unknown4;
ULONG Unknown5;
ULONG Unknown6;
PULONG Unknown7;
ULONG Unknown8;
};
typedef NTSTATUS (WINAPI *LPFUN_NtCreateThreadEx)
(
OUT PHANDLE hThread,
IN ACCESS_MASK DesiredAccess,
IN LPVOID ObjectAttributes,
IN HANDLE ProcessHandle,
IN LPTHREAD_START_ROUTINE lpStartAddress,
IN LPVOID lpParameter,
IN BOOL CreateSuspended,
IN ULONG StackZeroBits,
IN ULONG SizeOfStackCommit,
IN ULONG SizeOfStackReserve,
OUT LPVOID lpBytesBuffer
);
using namespace std;
//#define CREATE_THREAD_ACCESS (PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ)
#define CREATE_THREAD_ACCESS ( PROCESS_ALL_ACCESS )
BOOL LoadDll(char *procName, char *dllName);
BOOL InjectDLL(DWORD dwProcessID, char *dllName);
BOOL LoadDll(char *dllName, DWORD dwProcID){
printf("Process Id to Inject: %d",dwProcID);
if(!dwProcID){
printf("No vailid PID\n");
return false;
}
FILE* FileCheck = fopen(dllName, "r");
if(FileCheck==NULL){
printf("\nUnable to inject %s", dllName);
return false;
}
fclose(FileCheck);
if(!InjectDLL(dwProcID, dllName)){
printf("injection failed\n");
return false;
} else {
return true;
}
}
BOOL InjectDLL(DWORD dwProcessID, char *dllName){
HANDLE hProc;
HANDLE hToken;
char buf[50]={0};
LPVOID RemoteString, LoadLibAddy;
if(!dwProcessID)return false;
HANDLE hCurrentProc = GetCurrentProcess();
if (!OpenProcessToken(hCurrentProc,TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,&hToken)){
printf("OpenProcessToken Error:%d\n", GetLastError());
} else {
if (!RaisePrivleges(hToken, (char*)SE_DEBUG_NAME)){
printf("SetPrivleges SE_DEBUG_NAME Error:%d\n", GetLastError());
}
}
if (hToken)CloseHandle(hToken);
hProc = OpenProcess(CREATE_THREAD_ACCESS, FALSE, dwProcessID);
printf("\nHandle to process: %x\n", hProc);
if(!hProc){
printf("OpenProcess() failed: %d", GetLastError());
return false;
}
LoadLibAddy = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
if(!LoadLibAddy){
printf("GetProcAddress() failed: %d", GetLastError());
return false;
}
RemoteString = (LPVOID)VirtualAllocEx(hProc, NULL, strlen(dllName), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
if(RemoteString == NULL){
printf("VirtualAllocEx() failed: %d", GetLastError());
return false;
}
printf("\nRemote address: %x\n", RemoteString);
if(WriteProcessMemory(hProc, (LPVOID)RemoteString, dllName, strlen(dllName), NULL) == NULL){
printf("WriteProcessMemory() failed: %d", GetLastError());
return false;
}
/*
if(!CreateRemoteThread(hProc, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibAddy, (LPVOID)RemoteString, NULL, NULL)){
printf("CreateRemoteThread() failed: %d", GetLastError());
return false;
}
*/
HMODULE modNtDll = GetModuleHandle("ntdll.dll");
if( !modNtDll )
{
printf("n failed to get module handle for ntdll.dll, Error=0x%.8x", GetLastError());
return 0;
}
LPFUN_NtCreateThreadEx funNtCreateThreadEx =
(LPFUN_NtCreateThreadEx) GetProcAddress(modNtDll, "NtCreateThreadEx");
if( !funNtCreateThreadEx )
{
printf("n failed to get function (NTCreateThreadEx) address from ntdll.dll, Error=0x%.8x\nTrying CreateRemoteThread api\n", GetLastError());
if(!CreateRemoteThread(hProc, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibAddy, (LPVOID)RemoteString, NULL, NULL)){
printf("CreateRemoteThread() failed: %d", GetLastError());
return false;
} else {
printf("CreateRemoteThread success!\n");
return true;
}
return 0;
}
NtCreateThreadExBuffer ntbuffer;
memset (&ntbuffer,0,sizeof(NtCreateThreadExBuffer));
DWORD temp1 = 0;
DWORD temp2 = 0;
HANDLE pRemoteThread = NULL;
ntbuffer.Size = sizeof(NtCreateThreadExBuffer);
ntbuffer.Unknown1 = 0x10003;
ntbuffer.Unknown2 = 0x8;
ntbuffer.Unknown3 = &temp2;
ntbuffer.Unknown4 = 0;
ntbuffer.Unknown5 = 0x10004;
ntbuffer.Unknown6 = 4;
ntbuffer.Unknown7 = &temp1;
ntbuffer.Unknown8 = 0;
NTSTATUS status = funNtCreateThreadEx(
&pRemoteThread,
0x1FFFFF,
NULL,
hProc,
(LPTHREAD_START_ROUTINE) LoadLibAddy,
(LPVOID)RemoteString,
FALSE, //start instantly
NULL,
NULL,
NULL,
&ntbuffer
);
printf("NTCreateThreadEx return: %x\n", status);
// Resume the thread execution
WaitForSingleObject(pRemoteThread, INFINITE);
//Check the return code from remote thread function
DWORD dwExitCode;
if( GetExitCodeThread(pRemoteThread, (DWORD*) &dwExitCode) )
{
printf("\n Remote thread returned with status = %d\n", dwExitCode);
}
CloseHandle(pRemoteThread);
CloseHandle(hProc);
return true;
}
BOOL RaisePrivleges( HANDLE hToken, char *pPriv ){
TOKEN_PRIVILEGES tkp;
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
tkp.Privileges[0].Luid.HighPart = 0;
tkp.Privileges[0].Luid.LowPart = 0;
if (!LookupPrivilegeValue(NULL, pPriv, &tkp.Privileges[0].Luid)){
printf("LookupPrivilegeValue Error:%d\n", GetLastError());
return FALSE;
}
int iRet = AdjustTokenPrivileges(hToken, FALSE, &tkp, 0x10, (PTOKEN_PRIVILEGES)NULL, 0);
if (iRet == NULL){
printf( "AdjustTokenPrivileges Error:%d\n", GetLastError());
return TRUE;
} else {
iRet = GetLastError();
switch (iRet){
case ERROR_NOT_ALL_ASSIGNED:
printf("AdjustTokenPrivileges ERROR_NOT_ALL_ASSIGNED\n" );
return FALSE;
case ERROR_SUCCESS:
return TRUE;
default:
printf("AdjustTokenPrivileges Unknow Error:%d\n", iRet);
return FALSE;
}
}
}
1) If you're running on VISTA or later then you're possibly trying to inject into a 'protected process' from a 'non protected process'. See Process Security and Access Rights in MSDN. Non protected processes can't create threads in protected processes; though I must admit I'd expect the call to open process to fail when you request the inappropriate access rights rather than the subsequent create thread call to fail.
2) Why are you using NtCreateThreadEx() rather than simply calling CreateRemoteThread()?
3) This probably isn't the cause of your problem, but... You're failing to allocate memory for the null terminator in the string, you should be allocating strlen(dllName) + 1.
4) I assume that the process that is doing the injecting and the process that you're injecting into are both the same architecture, you're not running an x86 exe on x64 and expecting to inject into an x64 exe?
Since it's hard to find the right answer to this problem, I am posting even though the thread is old.
I was trying to inject into x64 service on Win7 x64 and kept running into same problems. My solution was:
Compile both the injector and injection dll as x64.
Instead of CreateRemoteThread & NtCreateThreadEx (both failing) use RtlCreateUserThread.
You must specify the full path to the injected DLL, otherwise it will not be found.