When I was trying to use Detours in order to hook CreateFile, when my hooked function is called I get a stack overflow error. I am trying to write the filename to a file and then call the original, but it fails on the fopen call with a stack overflow error. I am injecting the dll via CreateRemoteThread call. Is there some special stack allocation we have to do in the target process. I am fairly new to Windows development and detours, but I know C/C++ fairly well but by no means an expert.
#include "stdafx.h"
#include "detours.h"
#include <cstdio>
#include <ws2tcpip.h>
#include <windows.h>
#include <stdio.h>
#pragma comment(lib, "detours.lib")
//#pragma comment(lib, "detoured.lib")
#pragma comment(lib, "ws2_32.lib")
HANDLE (WINAPI *oldCreate)(LPCTSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD,DWORD, HANDLE ) = CreateFile;
HANDLE WINAPI myCreate(LPCTSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD,DWORD,HANDLE);
INT APIENTRY DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved)
{
switch(Reason)
{
case DLL_PROCESS_ATTACH:
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)oldCreate, myCreate);
DetourTransactionCommit();
break;
case DLL_PROCESS_DETACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
HANDLE WINAPI myCreate(LPCTSTR lpFileName , DWORD dwDesiredAccess, DWORD dwShareMode , LPSECURITY_ATTRIBUTES lpSecurityAttributes , DWORD dwCreationDisposition ,DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
{
int x= 3;
FILE *file = fopen("C:\\test.txt", "a+");
fprintf(file, "%s \n", lpFileName);
fclose(file);
return oldCreate(lpFileName,dwDesiredAccess,dwShareMode,lpSecurityAttributes,dwCreationDisposition,dwFlagsAndAttributes,hTemplateFile);
}
extern "C" __declspec(dllexport) void dummy(void){`enter code here`
return;
}
Here is the injector Code I am using
Also, here is the injector code I am using
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include "detours.h"
#pragma comment (lib, "detours.lib")
#define MAX_COMBINED 8192
BOOL SetPrivilege(
HANDLE hToken, // token handle
LPCTSTR Privilege, // Privilege to enable/disable
BOOL bEnablePrivilege // TRUE to enable. FALSE to disable
);
LPTSTR GetArguments(void)
{
LPWSTR *szArglist = NULL;
int nArgs;
LPWSTR wbuf = NULL;
wbuf = new WCHAR[MAX_COMBINED];
if (wbuf == NULL)
return NULL;
memset(wbuf, 0, MAX_COMBINED*sizeof(WCHAR));
szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
if(NULL == szArglist)
{
return NULL;
}
else {
for(int i=2; i<nArgs; i++) {
wcscat_s(wbuf, MAX_COMBINED, szArglist[i]);
wcscat_s(wbuf, MAX_COMBINED, L" ");
}
}
LocalFree(szArglist);
#ifdef _UNICODE
return wbuf;
#else
LPSTR abuf = new CHAR[MAX_COMBINED];
if (abuf == NULL)
return NULL;
memset(abuf, 0, MAX_COMBINED);
WideCharToMultiByte(CP_ACP, 0, wbuf, -1, abuf, MAX_COMBINED, NULL, NULL);
delete[] wbuf;
return abuf;
#endif
}
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hToken;
if(argc < 2)
{
printf("pass just pid]\n");
return 0;
}
char* DirPath = new char[MAX_PATH];
char* FullPath = new char[MAX_PATH];
GetCurrentDirectoryA(MAX_PATH, (LPSTR)DirPath);
sprintf_s(FullPath, MAX_PATH, "%s\\injector3.dll", DirPath);
printf("FullPath %s \n",FullPath);
if(!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken))
{
if (GetLastError() == ERROR_NO_TOKEN)
{
if (!ImpersonateSelf(SecurityImpersonation))
return 1;
if(!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken)){
printf("OpenThreadToken\n");
return 1;
}
}
else
return 1;
}
// enable SeDebugPrivilege
if(!SetPrivilege(hToken, SE_DEBUG_NAME, TRUE))
{
printf("SetPrivilege");
// close token handle
CloseHandle(hToken);
// indicate failure
return 2;
}
HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION |
PROCESS_VM_WRITE, FALSE, _wtoi(argv[1]));
if(hProcess == NULL)
{
DWORD x = GetLastError();
printf("HANDLE TO PROCESS FAILED on PID %d with error %d\n",_wtoi(argv[1]),x);
return 1;
}
LPVOID LoadLibraryAddr = (LPVOID)GetProcAddress(GetModuleHandleA("kernel32.dll"),
"LoadLibraryA");
if(LoadLibraryAddr == NULL)
{
printf("GET PROC ADDRESS FAILED on PID %s\n",argv[1]);
return 1;
}
LPVOID LLParam = (LPVOID)VirtualAllocEx(hProcess, NULL, strlen(FullPath),
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if(LLParam == NULL)
{
printf("VirtualAllocEx on PID %s\n",argv[1]);
return 1;
}
WriteProcessMemory(hProcess, LLParam, FullPath, strlen(FullPath), NULL);
CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibraryAddr,
LLParam, NULL, NULL);
CloseHandle(hProcess);
delete [] DirPath;
delete [] FullPath;
}
BOOL SetPrivilege(
HANDLE hToken, // token handle
LPCTSTR Privilege, // Privilege to enable/disable
BOOL bEnablePrivilege // TRUE to enable. FALSE to disable
)
{
TOKEN_PRIVILEGES tp;
LUID luid;
TOKEN_PRIVILEGES tpPrevious;
DWORD cbPrevious=sizeof(TOKEN_PRIVILEGES);
if(!LookupPrivilegeValue( NULL, Privilege, &luid )) return FALSE;
//
// first pass. get current privilege setting
//
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = 0;
AdjustTokenPrivileges(
hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
&tpPrevious,
&cbPrevious
);
if (GetLastError() != ERROR_SUCCESS) return FALSE;
//
// second pass. set privilege based on previous setting
//
tpPrevious.PrivilegeCount = 1;
tpPrevious.Privileges[0].Luid = luid;
if(bEnablePrivilege) {
tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED);
}
else {
tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED &
tpPrevious.Privileges[0].Attributes);
}
AdjustTokenPrivileges(
hToken,
FALSE,
&tpPrevious,
cbPrevious,
NULL,
NULL
);
if (GetLastError() != ERROR_SUCCESS) return FALSE;
return TRUE;
}
/*
BOOL SetPrivilege(
HANDLE hToken, // token handle
LPCTSTR Privilege, // Privilege to enable/disable
BOOL bEnablePrivilege // TRUE to enable. FALSE to disable
)
{
TOKEN_PRIVILEGES tp = { 0 };
// Initialize everything to zero
LUID luid;
DWORD cb=sizeof(TOKEN_PRIVILEGES);
if(!LookupPrivilegeValue( NULL, Privilege, &luid ))
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;
}
AdjustTokenPrivileges( hToken, FALSE, &tp, cb, NULL, NULL );
if (GetLastError() != ERROR_SUCCESS)
return FALSE;
return TRUE;
}
*/
You are replacing CreateFile with your myCreate.
When fopen calls CreateFile to open the file, it will instead call your myCreate again, which will call fopen, which will call CreateFile and so on until you run out of stack.
You could call oldCreateFile to open the file for outputting, but you won't be able to use fprintf etc with it.
Related
I'm trying some DLL injections but I have some problems :/
When I run this program I get the message "Remote Thread Created", so everything should works ok and the DLL should be loaded. But the DLL doesn't show any messageBox (it should just show a message box when loaded)
This is the code:
#include <windows.h>
#include <stdio.h>
int main(int argc, TCHAR* argv[]){
char buffer[] = "C:\\drivers\\inject.dll";
int procID = 1056;
HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, false, procID);
if(process == NULL){
printf("Cannot get handle to process.");
getchar();
return -0x1;
}
LPVOID addr = (LPVOID) GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
if(addr == NULL){
prinf("Cannot get address of function \'LoadLibraryA\'.");
getchar();
return -0x1;
}
LPVOID arg = (LPVOID) VirtualAllocEx(process, NULL, strlen(buffer), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if(arg == NULL){
printf("Cannote write memory.");
getchar();
return -0x1;
}
int n = WriteProcessMemory(process, arg, buffer, strlen(buffer), NULL);
if(n == 0x0){
printf("Cannot write on process address space.");
getchar();
return -0x1;
}
HANDLE threadID = CreateRemoteThread(process, NULL, 0x0, (LPTHREAD_START_ROUTINE) addr, arg, NULL, NULL);
if(threadID == NULL){
printf("Cannot create remote thread.");
getchar();
return -0x1;
} else {
printf("Remote Thread Created.\n");
}
CloseHandle(process);
getchar();
return 0x0;
}
DLL (.cpp):
#define BUILD_DLL
#include "simple_dll.h"
// a sample exported function
void DLL_EXPORT SomeFunction(const LPCSTR sometext)
{
MessageBoxA(0, sometext, "DLL Message", MB_OK | MB_ICONINFORMATION);
}
extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
SomeFunction("DLL_PROCESS_ATTACH");
break;
case DLL_PROCESS_DETACH:
SomeFunction("DLL_PROCESS_DETACH");
break;
case DLL_THREAD_ATTACH:
SomeFunction("DLL_THREAD_ATTACH");
break;
case DLL_THREAD_DETACH:
SomeFunction("DLL_THREAD_DETACH");
break;
}
return TRUE; // succesful
}
DLL (.h):
#ifndef __MAIN_H__
#define __MAIN_H__
#include <windows.h>
/* To use this exported function of dll, include this header
* in your project.
*/
#ifdef BUILD_DLL
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C"
{
#endif
void DLL_EXPORT SomeFunction(const LPCSTR sometext);
#ifdef __cplusplus
}
#endif
#endif // __MAIN_H__
Can someone please explain me why I don't get the messagebox?
First off, MessageBoxA() is not safe to call in DllMain().
You should never perform the following tasks from within DllMain:
...
Call functions in User32.dll or Gdi32.dll. Some functions load another DLL, which may not be initialized.
...
In any case, just because CreateRemoteThread() succeeds in creating a remote thread does not guarantee that LoadLibraryA() will succeed when the remote thread calls it. Which, in this situation, is likely the culprit, because the DLL path string you are allocating in the remote process is not null-terminated properly, so LoadLibraryA() is likely failing. You need to use strlen(buffer)+1 when allocating the string and when copying the characters into it.
Also, not related to your problem, but if VirtualAllocEx() succeeds, regardless of whatever happens with the remote thread, you need to free the allocated string when you are done using it, or else it will be leaked. Also, don't use PROCESS_ALL_ACCESS, that is way too many permissions to ask for, you should request only the specific permissions you actually need.
Try something more like this:
#include <windows.h>
#include <stdio.h>
int main(int argc, TCHAR* argv[]){
const char buffer[] = "C:\\drivers\\inject.dll";
const size_t bufferSize = strlen(buffer) + 1;
int procID = 1056;
HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, procID);
if (hProcess == NULL){
printf("Cannot get handle to process.");
getchar();
return -1;
}
LPVOID addr = (LPVOID) GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
if (addr == NULL){
prinf("Cannot get address of function \'LoadLibraryA\'.");
CloseHandle(hProcess);
getchar();
return -1;
}
LPVOID arg = (LPVOID) VirtualAllocEx(hProcess, NULL, bufferSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (arg == NULL){
printf("Cannote allocate memory in process address space.");
CloseHandle(hProcess);
getchar();
return -1;
}
BOOL n = WriteProcessMemory(hProcess, arg, buffer, bufferSize, NULL);
if (n == FALSE){
printf("Cannot write to process address space.");
VirtualFreeEx(hProcess, arg, 0, MEM_RELEASE);
CloseHandle(hProcess);
getchar();
return -1;
}
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE) addr, arg, NULL, NULL);
if (hThread == NULL){
printf("Cannot create remote thread.");
VirtualFreeEx(hProcess, arg, 0, MEM_RELEASE);
CloseHandle(hProcess);
getchar();
return -1;
}
printf("Remote Thread Created.\n");
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
VirtualFreeEx(hProcess, arg, 0, MEM_RELEASE);
CloseHandle(hProcess);
getchar();
return 0;
}
Well, basically I need to write a DLL in C++ that I will inject into notepad.exe.
This DLL suppose to open a pop-out message or a window with my name in it.
The problem is that I'm kinda new with DLL and I started a week ago. I'm having trouble opening a window or a message with a DLL using "windows.h".
I did try using MessageBox but it's not working.
that's my injector
that i took from: https://www.fxp.co.il/showthread.php?t=15051062
#include <iostream>
#include <direct.h>
#include <windows.h>
#include <Tlhelp32.h>
LPCTSTR SzToLPCTSTR(char* szString);
char* GetCurrentDir();
void WaitForProcessToAppear(LPCTSTR lpcszProc, DWORD dwDeley);
DWORD GetProcessIdByName(LPCTSTR lpcszProc);
BOOL InjectDll(DWORD dwPid, char* szDllPath);
int main()
{
char szProc[MAX_PATH], szDll[MAX_PATH];
char* szDllPath = (char*)malloc(MAX_PATH);
LPTSTR lpszProc = NULL;
while (true)
{
std::cout << "Process: ";
std::cin >> szProc;
std::cout << "DLL Injection: ";
std::cin >> szDll;
szDllPath = GetCurrentDir();
strcat_s(szDllPath, MAX_PATH, "\\");
strcat_s(szDllPath, MAX_PATH, szDll);
std::cout << "Waiting for process..." << std::endl;
WaitForProcessToAppear(SzToLPCTSTR(szProc), 100);
if (InjectDll(GetProcessIdByName(SzToLPCTSTR(szProc)), szDllPath)) std::cout << "Injection succeeded!" << std::endl;
else std::cout << "Injection failed!" << std::endl;
std::cout << "\n";
}
return 0;
}
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 dwDeley)
{
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(dwDeley);
}
}
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_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD, FALSE, dwPid)) != NULL)
{
dwMemSize = strlen(szDllPath) + 1;
if ((lpRemoteMem = VirtualAllocEx(hProc, NULL, dwMemSize, MEM_COMMIT, PAGE_READWRITE)) != NULL)
if (WriteProcessMemory(hProc, lpRemoteMem, (LPCVOID)szDllPath, dwMemSize, NULL))
{
lpLoadLibrary = GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
if (CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)lpLoadLibrary, lpRemoteMem, 0, NULL) != NULL)
bRet = TRUE;
}
}
CloseHandle(hProc);
return bRet;
}
And that's my DLL:
#include <windows.h>
BOOL WINAPI DllMain( HMODULE hModule,
DWORD fdwReason,
LPVOID lpvReserved
)
{
if (fdwReason == DLL_PROCESS_ATTACH)
MessageBox(NULL, L"Injected by Matan Oshri", L"Hello World", MB_OK);
return TRUE;
}
Please let me know if u see any kind of mistake.
I appreciate all the help I can get.
Thank you.
First I can inject the DLL with the sample code, make sure the Dll, injector.exe and notepad.exe are in the same bits(Usually, notepad.exe starts with 64-bit).
I am getting the error code = 5 if I use 32-bits of DLL or injector.exe with 64-bits notepad.exe
Second, According to the CreateRemoteThread document:
hProcess
A handle to the process in which the thread is to be created. The
handle must have the PROCESS_CREATE_THREAD, PROCESS_QUERY_INFORMATION,
PROCESS_VM_OPERATION, PROCESS_VM_WRITE, and PROCESS_VM_READ access
rights, and may fail without these rights on certain platforms. For
more information, see Process Security and Access Rights.
(Although the above sample works for me with out PROCESS_QUERY_INFORMATION and PROCESS_VM_READ)
Third, There is something worth improving in your code:
char* szDllPath = (char*)malloc(MAX_PATH);
szDllPath = GetCurrentDir();
/*{
char* szRet = (char*)malloc(MAX_PATH);
_getcwd(szRet, MAX_PATH);
return szRet;
}*/
This will cause the memory of the first application to be leaked.
LPCTSTR SzToLPCTSTR(char* szString);
We could use Unicode string directly.
sample:
#include <iostream>
#include <direct.h>
#include <windows.h>
#include <Tlhelp32.h>
//LPCWSTR SzToLPCTSTR(char* szString);
//char* GetCurrentDir();
void WaitForProcessToAppear(LPCWSTR lpcszProc, DWORD dwDeley);
DWORD GetProcessIdByName(LPCWSTR lpcszProc);
BOOL InjectDll(DWORD dwPid, LPCWSTR szDllPath);
int main()
{
while (true)
{
std::wstring szProc, szDll;
std::wstring szDllPath;
std::wcout << L"Process: ";
std::wcin >> szProc;
std::wcout << L"DLL Injection: ";
std::wcin >> szDll;
WCHAR dir[MAX_PATH] = { 0 };
GetCurrentDirectoryW(MAX_PATH, dir);
szDllPath = dir;
szDllPath += L"\\";
szDllPath += szDll;
std::wcout << L"Waiting for process..." << std::endl;
WaitForProcessToAppear(szProc.c_str(), 100);
if (InjectDll(GetProcessIdByName(szProc.c_str()), szDllPath.c_str())) std::wcout << L"Injection succeeded!" << std::endl;
else std::wcout << L"Injection failed!" << std::endl;
std::wcout << L"\n";
}
return 0;
}
//char* GetCurrentDir()
//{
// char* szRet = (char*)malloc(MAX_PATH);
// _getcwd(szRet, MAX_PATH);
// return szRet;
//}
//LPCWSTR 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(LPCWSTR lpcszProc, DWORD dwDeley)
{
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;
break;
}
}
CloseHandle(hSnap);
Sleep(dwDeley);
}
}
DWORD GetProcessIdByName(LPCWSTR 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;
break;
}
}
CloseHandle(hSnap);
return dwRet;
}
BOOL InjectDll(DWORD dwPid, LPCWSTR szDllPath)
{
DWORD dwMemSize;
HANDLE hProc;
LPVOID lpRemoteMem, lpLoadLibrary;
BOOL bRet = FALSE;
if ((hProc = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, dwPid)) != NULL)
{
dwMemSize = (wcslen(szDllPath) + 1) * sizeof(WCHAR);
if ((lpRemoteMem = VirtualAllocEx(hProc, NULL, dwMemSize, MEM_COMMIT, PAGE_READWRITE)) != NULL)
if (WriteProcessMemory(hProc, lpRemoteMem, (LPCVOID)szDllPath, dwMemSize, NULL))
{
lpLoadLibrary = GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "LoadLibraryW");
if (CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)lpLoadLibrary, lpRemoteMem, 0, NULL) != NULL)
bRet = TRUE;
}
}
CloseHandle(hProc);
return bRet;
}
Finally, according to the limitations in DllMain:
Call functions in User32.dll or Gdi32.dll. Some functions load
another DLL, which may not be initialized.
You cannot use MessageBox in DllMain, but you could use OutputDebugStringW instead to show a message, and use DebugView to check the debug string.
DLL:
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
OutputDebugStringW(L"Injected DLL_PROCESS_ATTACH by Matan Oshri");
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Or use Console API to pop up a console:
DWORD dwSize;
WCHAR string[] = L"Hello World";
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
AllocConsole();
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), string, 12, &dwSize, NULL);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
This program enumerate all handles and get their names.
For pID 4 OpenProcess gets error 5 with SeDebugPrivilege.
UAC off. Running from Admin.
Enable SeDebugPrivilege
BOOL EnableDebugPrivilege(BOOL bEnable)
{
HANDLE hToken = nullptr;
LUID luid;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) return FALSE;
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) return FALSE;
TOKEN_PRIVILEGES tokenPriv;
tokenPriv.PrivilegeCount = 1;
tokenPriv.Privileges[0].Luid = luid;
tokenPriv.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;
if (!AdjustTokenPrivileges(hToken, FALSE, &tokenPriv, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) return FALSE;
_tprintf(_T("Privileges error: %d\n", GetLastError()));
return TRUE;
}
Enumerate handles
DWORD EnumerateFileHandles(ULONG pid)
{
HINSTANCE hNtDll = LoadLibrary(_T("ntdll.dll"));
assert(hNtDll != NULL);
PFN_NTQUERYSYSTEMINFORMATION NtQuerySystemInformation =
(PFN_NTQUERYSYSTEMINFORMATION)GetProcAddress(hNtDll,
"NtQuerySystemInformation");
assert(NtQuerySystemInformation != NULL);
PFN_NTQUERYINFORMATIONFILE NtQueryInformationFile =
(PFN_NTQUERYINFORMATIONFILE)GetProcAddress(hNtDll,
"NtQueryInformationFile");
DWORD nSize = 4096, nReturn;
PSYSTEM_HANDLE_INFORMATION pSysHandleInfo = (PSYSTEM_HANDLE_INFORMATION)
HeapAlloc(GetProcessHeap(), 0, nSize);
while (NtQuerySystemInformation(SystemExtendedHandleInformation, pSysHandleInfo,
nSize, &nReturn) == STATUS_INFO_LENGTH_MISMATCH)
{
HeapFree(GetProcessHeap(), 0, pSysHandleInfo);
nSize += 4096;
pSysHandleInfo = (SYSTEM_HANDLE_INFORMATION*)HeapAlloc(
GetProcessHeap(), 0, nSize);
}
DWORD dwFiles = 0;
_tprintf(_T("Handles Number: %d\n"), pSysHandleInfo->NumberOfHandles);
for (ULONG i = 0; i < pSysHandleInfo->NumberOfHandles; i++)
{
PSYSTEM_HANDLE pHandle = &(pSysHandleInfo->Handles[i]);
if (pHandle->ProcessId == 4)
{
HANDLE hProcess = OpenProcess(
PROCESS_DUP_HANDLE, FALSE, pHandle->ProcessId);
if (hProcess == NULL)
{
_tprintf(_T("OpenProcess failed w/err 0x%08lx\n"), GetLastError());
continue;
}
HANDLE hCopy;
if (!DuplicateHandle(hProcess, (HANDLE)pHandle->Handle,
GetCurrentProcess(), &hCopy, MAXIMUM_ALLOWED, FALSE, 0))
continue;
TCHAR buf[MAX_PATH];
if (GetFinalPathNameByHandle(hCopy, buf, sizeof(buf), VOLUME_NAME_DOS))
wprintf(L"p%d:h%d:t%d:\t%s\n", pHandle->ProcessId, pHandle->Handle, pHandle->ObjectTypeNumber, buf);
CloseHandle(hProcess);
CloseHandle(hCopy);
}
}
HeapFree(GetProcessHeap(), 0, pSysHandleInfo);
return dwFiles;
}
On windows 7 x64 it's work fine.
But on Windows 10 x64 OpenProcess returns error 5 with SeDebugPrivilege.
How open system process(pID 4) on windows 10.
You can't open a handle for it as the documentation for OpenProcess specifically says it'll fail:
If the specified process is the Idle process or one of the CSRSS
processes, this function fails and the last error code is
ERROR_ACCESS_DENIED because their access restrictions prevent
user-level code from opening them.
If you want to get system process names, you could try to use CreateToolhelp32Snapshot() to get the snapshot of the process, then use Process32First() and Process32Next() to enumerate the all process.
Here is an example:
#include <iostream>
#include <stdio.h>
#include <windows.h>
#include <string>
#include <TlHelp32.h>
using namespace std;
int main()
{
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(pe32);
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);//get the snapshot
if (hProcessSnap == INVALID_HANDLE_VALUE)
{
cout << "CreateToolhelp32Snapshot Error!" << endl;
return false;
}
BOOL bResult = Process32First(hProcessSnap, &pe32);
int num(0);
while(bResult)
{
cout << "[" << ++num << "] : " << "Process Name:"<< pe32.szExeFile << " " << "ProcessID:" << pe32.th32ProcessID << endl;
bResult = Process32Next(hProcessSnap, &pe32);
}
CloseHandle(hProcessSnap);
}
Hope it could help you!
My Windows has several accounts like "test1", "test2" and "test3" that belong to the Administrators group. I am developing an application program and I want that program to know if itself is run under an account that belong to the Administrators group by designing a boolean function: isCurrentUserAdminMember(), the isCurrentUserAdminMember() funtion should only return TRUE if the process is run by "test1", "test2", "test3" or the built-in Administrator account no matter whether the process is elevated.
I found some code in http://www.codeproject.com/Articles/320748/Haephrati-Elevating-during-runtime as below, but it seems only to check if the current process is elevated as an Administrator. I don't care if the process is elevated, I just want to know if the start account of the process is a member of Administrators group. And I hope the determination itself is not privilege required. Is that possible? thanks.
BOOL IsAppRunningAsAdminMode()
{
BOOL fIsRunAsAdmin = FALSE;
DWORD dwError = ERROR_SUCCESS;
PSID pAdministratorsGroup = NULL;
// Allocate and initialize a SID of the administrators group.
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
if (!AllocateAndInitializeSid(
&NtAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&pAdministratorsGroup))
{
dwError = GetLastError();
goto Cleanup;
}
// Determine whether the SID of administrators group is enabled in
// the primary access token of the process.
if (!CheckTokenMembership(NULL, pAdministratorsGroup, &fIsRunAsAdmin))
{
dwError = GetLastError();
goto Cleanup;
}
Cleanup:
// Centralized cleanup for all allocated resources.
if (pAdministratorsGroup)
{
FreeSid(pAdministratorsGroup);
pAdministratorsGroup = NULL;
}
// Throw the error if something failed in the function.
if (ERROR_SUCCESS != dwError)
{
throw dwError;
}
return fIsRunAsAdmin;
}
At last, we achieved the goal to check the Administrators group membership as the code below, however it is USELESS as the answer and comment said, just leave here for reference in case anybody needs it for other use.
// PermTest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "stdio.h"
#include "iostream"
using namespace std;
#include "windows.h"
#include <lm.h>
#pragma comment(lib, "netapi32.lib")
BOOL IsUserInGroup(const wchar_t* groupe)
{
BOOL result = FALSE;
SID_NAME_USE snu;
WCHAR szDomain[256];
DWORD dwSidSize = 0;
DWORD dwSize = sizeof szDomain / sizeof * szDomain;
if ((LookupAccountNameW(NULL, groupe, 0, &dwSidSize, szDomain, &dwSize, &snu) == 0)
&& (ERROR_INSUFFICIENT_BUFFER == GetLastError()))
{
SID* pSid = (SID*)malloc(dwSidSize);
if (LookupAccountNameW(NULL, groupe, pSid, &dwSidSize, szDomain, &dwSize, &snu))
{
BOOL b;
if (CheckTokenMembership(NULL, pSid, &b))
{
if (b == TRUE)
{
result = TRUE;
}
}
else
{
result = FALSE;
}
}
//Si tout vas bien (la presque totalitée des cas), on delete notre pointeur
//avec le bon operateur.
free(pSid);
}
return result;
}
void getUserInfo(WCHAR *domainName, WCHAR *userName)
{
LPUSER_INFO_3 pBuf = NULL;
int j = 0;
DWORD nStatus = NetUserGetInfo(domainName, userName, 3, (LPBYTE *) &pBuf);
LPUSER_INFO_2 pBuf2 = NULL;
pBuf2 = (LPUSER_INFO_2) pBuf;
if (pBuf)
{
wprintf(L"User account name: %s\\%s\n", domainName, pBuf2->usri2_name);
wprintf(L"Privilege level: %d\n\n", pBuf2->usri2_priv);
}
// wprintf(L"\tPassword: %s\n", pBuf2->usri2_password);
// wprintf(L"\tPassword age (seconds): %d\n",
// pBuf2->usri2_password_age);
// wprintf(L"Privilege level: %d\n\n", pBuf2->usri2_priv);
// #define USER_PRIV_GUEST 0
// #define USER_PRIV_USER 1
// #define USER_PRIV_ADMIN 2
// wprintf(L"\tHome directory: %s\n", pBuf2->usri2_home_dir);
// wprintf(L"\tComment: %s\n", pBuf2->usri2_comment);
// wprintf(L"\tFlags (in hex): %x\n", pBuf2->usri2_flags);
// wprintf(L"\tScript path: %s\n", pBuf2->usri2_script_path);
// wprintf(L"\tAuth flags (in hex): %x\n",
// pBuf2->usri2_auth_flags);
// wprintf(L"\tFull name: %s\n", pBuf2->usri2_full_name);
// wprintf(L"\tUser comment: %s\n", pBuf2->usri2_usr_comment);
// wprintf(L"\tParameters: %s\n", pBuf2->usri2_parms);
// wprintf(L"\tWorkstations: %s\n", pBuf2->usri2_workstations);
// wprintf
// (L"\tLast logon (seconds since January 1, 1970 GMT): %d\n",
// pBuf2->usri2_last_logon);
// wprintf
// (L"\tLast logoff (seconds since January 1, 1970 GMT): %d\n",
// pBuf2->usri2_last_logoff);
// wprintf
// (L"\tAccount expires (seconds since January 1, 1970 GMT): %d\n",
// pBuf2->usri2_acct_expires);
// wprintf(L"\tMax storage: %d\n", pBuf2->usri2_max_storage);
// wprintf(L"\tUnits per week: %d\n",
// pBuf2->usri2_units_per_week);
// wprintf(L"\tLogon hours:");
// for (j = 0; j < 21; j++)
// {
// printf(" %x", (BYTE) pBuf2->usri2_logon_hours[j]);
// }
// wprintf(L"\n");
// wprintf(L"\tBad password count: %d\n",
// pBuf2->usri2_bad_pw_count);
// wprintf(L"\tNumber of logons: %d\n",
// pBuf2->usri2_num_logons);
// wprintf(L"\tLogon server: %s\n", pBuf2->usri2_logon_server);
// wprintf(L"\tCountry code: %d\n", pBuf2->usri2_country_code);
// wprintf(L"\tCode page: %d\n", pBuf2->usri2_code_page);
}
#include <comdef.h>
#define MAX_NAME 256
BOOL GetLogonFromToken (HANDLE hToken, _bstr_t& strUser, _bstr_t& strdomain)
{
DWORD dwSize = MAX_NAME;
BOOL bSuccess = FALSE;
DWORD dwLength = 0;
strUser = "";
strdomain = "";
PTOKEN_USER ptu = NULL;
//Verify the parameter passed in is not NULL.
if (NULL == hToken)
goto Cleanup;
if (!GetTokenInformation(
hToken, // handle to the access token
TokenUser, // get information about the token's groups
(LPVOID) ptu, // pointer to PTOKEN_USER buffer
0, // size of buffer
&dwLength // receives required buffer size
))
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
goto Cleanup;
ptu = (PTOKEN_USER)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY, dwLength);
if (ptu == NULL)
goto Cleanup;
}
if (!GetTokenInformation(
hToken, // handle to the access token
TokenUser, // get information about the token's groups
(LPVOID) ptu, // pointer to PTOKEN_USER buffer
dwLength, // size of buffer
&dwLength // receives required buffer size
))
{
goto Cleanup;
}
SID_NAME_USE SidType;
char lpName[MAX_NAME];
char lpDomain[MAX_NAME];
if( !LookupAccountSidA( NULL , ptu->User.Sid, lpName, &dwSize, lpDomain, &dwSize, &SidType ) )
{
DWORD dwResult = GetLastError();
if( dwResult == ERROR_NONE_MAPPED )
strcpy (lpName, "NONE_MAPPED" );
else
{
printf("LookupAccountSid Error %u\n", GetLastError());
}
}
else
{
// printf( "Current user is %s\\%s\n",
// lpDomain, lpName );
strUser = lpName;
strdomain = lpDomain;
bSuccess = TRUE;
}
Cleanup:
if (ptu != NULL)
HeapFree(GetProcessHeap(), 0, (LPVOID)ptu);
return bSuccess;
}
HRESULT GetUserFromProcess( _bstr_t& strUser, _bstr_t& strdomain)
{
//HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,FALSE,procId);
HANDLE hProcess = GetCurrentProcess();
if(hProcess == NULL)
return E_FAIL;
HANDLE hToken = NULL;
if( !OpenProcessToken( hProcess, TOKEN_QUERY, &hToken ) )
{
CloseHandle( hProcess );
return E_FAIL;
}
BOOL bres = GetLogonFromToken (hToken, strUser, strdomain);
CloseHandle( hToken );
CloseHandle( hProcess );
return bres?S_OK:E_FAIL;
}
int _tmain(int argc, _TCHAR* argv[])
{
//cout << IsUserInGroup(L"administrators");
getUserInfo(L"adtest.net", L"Administrator");
getUserInfo(NULL, L"Administrator");
getUserInfo(NULL, L"test");
getUserInfo(NULL, L"test2");
getUserInfo(NULL, L"testnormal");
_bstr_t username;
_bstr_t domain;
GetUserFromProcess(username, domain);
cout << "Current account running this program is: " << endl << domain << "\\" << username << endl;
getchar();
return 0;
}
You can do this by opening your process token (OpenProcessToken, listing the SIDs using GetTokenInformation and comparing each SID to the Administrators SID.
Microsoft have sample code here: Searching for a SID in an Access Token in C++
However, this is rarely a useful thing to do. Even if the user is not a member of the Administrators group, they can still elevate by providing an administrative username and password, so you should not (for example) only offer elevation if the user is in the Administrators group.
bool IsMemberOfGroup(const char *pszGroupName){
bool bFound = false;
HANDLE hToken=INVALID_HANDLE_VALUE;
BOOL bSuccess = OpenProcessToken( GetCurrentProcess(),
TOKEN_QUERY,//|TOKEN_QUERY_SOURCE,
&hToken);
if ( bSuccess )
{
DWORD dwSizeToken=0;
DWORD dwSizeName=0;
DWORD dwSizeReferencedDomainName = 0;
// Get group information:
GetTokenInformation(hToken, TokenGroups, NULL, dwSizeToken, &dwSizeToken);
{
const int MAX_NAME = 256;
char *psName = new char[MAX_NAME];
char *psDomain = new char[MAX_NAME];
char *pBuf = new char[dwSizeToken+10];
TOKEN_GROUPS *pGroupInfo = (TOKEN_GROUPS *)pBuf;
bSuccess = GetTokenInformation(hToken, TokenGroups, pGroupInfo, dwSizeToken, &dwSizeToken);
if ( bSuccess )
{
// find the group name we are looking for
for ( UINT uiGroupNdx = 0; uiGroupNdx < pGroupInfo->GroupCount && !bFound; uiGroupNdx++ )
{
SID_NAME_USE SidType;
dwSizeName = MAX_NAME;
dwSizeReferencedDomainName = MAX_NAME;
bSuccess = LookupAccountSid(NULL, // local system,
pGroupInfo->Groups[uiGroupNdx].Sid,
psName,
&dwSizeName,
psDomain,
&dwSizeReferencedDomainName,
&SidType);
if ( bSuccess )
{
if ( SidTypeGroup == SidType )
{
if ( !lstrcmpi(pszGroupName, psName) )
{
bFound = true;
}
}
}
}
}
delete [] pBuf;
delete [] psName;
delete [] psDomain;
}
CloseHandle(hToken);
}
return bFound;
}
//writing to mailslot
#include <windows.h>
#include <stdio.h>
LPTSTR SlotName = TEXT("\\\\.\\mailslot\\sample_mailslot");
BOOL WriteSlot(HANDLE hSlot, LPTSTR lpszMessage)
{
BOOL fResult;
DWORD cbWritten;
fResult = WriteFile(hSlot,
lpszMessage,
(DWORD) (lstrlen(lpszMessage)+1)*sizeof(TCHAR),
&cbWritten,
(LPOVERLAPPED) NULL);
if (!fResult)
{
printf("WriteFile failed with %d.\n", GetLastError());
return FALSE;
}
printf("Slot written to successfully.\n");
return TRUE;
}
int main()
{
HANDLE hFile;
hFile = CreateFile(SlotName,
GENERIC_WRITE,
FILE_SHARE_READ,
(LPSECURITY_ATTRIBUTES) NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
(HANDLE) NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
printf("CreateFile failed with %d.\n", GetLastError());
return FALSE;
}
WriteSlot(hFile, TEXT("Message one for mailslot."));
WriteSlot(hFile, TEXT("Message two for mailslot."));
Sleep(5000);
WriteSlot(hFile, TEXT("Message three for mailslot."));
CloseHandle(hFile);
return TRUE;
}
//reading from mailslot
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
HANDLE hSlot;
LPTSTR SlotName = TEXT("\\\\.\\mailslot\\sample_mailslot");
BOOL ReadSlot()
{
DWORD cbMessage, cMessage, cbRead;
BOOL fResult;
LPTSTR lpszBuffer;
TCHAR achID[80];
DWORD cAllMessages;
HANDLE hEvent;
OVERLAPPED ov;
cbMessage = cMessage = cbRead = 0;
hEvent = CreateEvent(NULL, FALSE, FALSE, TEXT("ExampleSlot"));
if( NULL == hEvent )
return FALSE;
ov.Offset = 0;
ov.OffsetHigh = 0;
ov.hEvent = hEvent;
fResult = GetMailslotInfo( hSlot, // mailslot handle
(LPDWORD) NULL, // no maximum message size
&cbMessage, // size of next message
&cMessage, // number of messages
(LPDWORD) NULL); // no read time-out
if (!fResult)
{
printf("GetMailslotInfo failed with %d.\n", GetLastError());
return FALSE;
}
if (cbMessage == MAILSLOT_NO_MESSAGE)
{
printf("Waiting for a message...\n");
return TRUE;
}
cAllMessages = cMessage;
while (cMessage != 0) // retrieve all messages
{
// Create a message-number string.
StringCchPrintf((LPTSTR) achID,
80,
TEXT("\nMessage #%d of %d\n"),
cAllMessages - cMessage + 1,
cAllMessages);
// Allocate memory for the message.
lpszBuffer = (LPTSTR) GlobalAlloc(GPTR,
lstrlen((LPTSTR) achID)*sizeof(TCHAR) + cbMessage);
if( NULL == lpszBuffer )
return FALSE;
lpszBuffer[0] = '\0';
fResult = ReadFile(hSlot,
lpszBuffer,
cbMessage,
&cbRead,
&ov);
if (!fResult)
{
printf("ReadFile failed with %d.\n", GetLastError());
GlobalFree((HGLOBAL) lpszBuffer);
return FALSE;
}
// Concatenate the message and the message-number string.
StringCbCat(lpszBuffer,
lstrlen((LPTSTR) achID)*sizeof(TCHAR)+cbMessage,
(LPTSTR) achID);
// Display the message.
_tprintf(TEXT("Contents of the mailslot: %s\n"), lpszBuffer);
GlobalFree((HGLOBAL) lpszBuffer);
fResult = GetMailslotInfo(hSlot, // mailslot handle
(LPDWORD) NULL, // no maximum message size
&cbMessage, // size of next message
&cMessage, // number of messages
(LPDWORD) NULL); // no read time-out
if (!fResult)
{
printf("GetMailslotInfo failed (%d)\n", GetLastError());
return FALSE;
}
}
CloseHandle(hEvent);
return TRUE;
}
BOOL WINAPI MakeSlot(LPTSTR lpszSlotName)
{
hSlot = CreateMailslot(lpszSlotName,
0, // no maximum message size
MAILSLOT_WAIT_FOREVER, // no time-out for operations
(LPSECURITY_ATTRIBUTES) NULL); // default security
if (hSlot == INVALID_HANDLE_VALUE)
{
printf("CreateMailslot failed with %d\n", GetLastError());
return FALSE;
}
return TRUE;
}
void main()
{
MakeSlot(SlotName);
while(TRUE)
{
ReadSlot();
Sleep(3000);
}
}
Go through the Visual Studio C++ Guided Tour on MSDN or watch this introductory video explaining how to create a basic Win32 application in C++. They should be enough of a starting point. From there on just browse the MSDN library to advance your knowledge or search for issues you encounter.