A follow-up to this question, I have the following CerberusNative.idl file (this is an ATL project written in Visual C++ which exposes a COM object):
[
object,
uuid(AECE8D0C-F902-4311-A374-ED3A0EBB6B49),
nonextensible,
pointer_default(unique)
]
interface ICallbacks : IUnknown
{
[id(1)] HRESULT UserExit([in] int errorCode, [in] BSTR errorMessage);
[id(2)] HRESULT UserAttemptingReconnection();
[id(3)] HRESULT UserReconnected();
};
[
object,
uuid(B98A7D3F-651A-49BE-9744-2B1D8C896E9E),
dual,
nonextensible,
pointer_default(unique)
]
interface ICerberusSession : IDispatch {
...
[id(5)] HRESULT SetCallbacks([in] ICallbacks* callbacks);
};
I am attempting to create an interface for setting up callback methods which route from the COM object back to an implementation of said methods from the caller.
I am trying to run the following code:
HRESULT prolonguedDisconnection(int code, BSTR *message) {
std::wcout << code << ": " << message << std::endl;
}
HRESULT reconnecting() {
std::wcout << "Reconnecting." << std::endl;
}
HRESULT reconnected() {
std::wcout << "Reconnected." << std::endl;
}
...
CoInitialize(NULL);
CerberusNativeLib::ICallbacksPtr callbacks;
callbacks.CreateInstance(__uuidof(CerberusNativeLib::ICallbacks));
callbacks->UserExit = prolonguedDisconnection;
callbacks->UserAttemptingReconnection = reconnecting;
callbacks->UserReconnected = reconnected;
CerberusNativeLib::ICerberusSessionPtr session;
session.CreateInstance(__uuidof(CerberusNativeLib::CerberusSession));
session->SetCallbacks(callbacks);
However, I am not sure how to properly set up the callback methods. Any ideas on how to do this? I get this compiler error on lines such as callbacks->UserExit = prolonguedDisconnection;:
Error C2659 '=': function as left operand
You defined ICallbacks as an interface and the object that implements ICerberusSession accepts a ICallbacks pointer so that it could invoke calls back on certain events. This is a good design and works well. However, it usually assumes that your code (last code snippet at the bottom) instantiates session object via CreateInstance as you do, and the other interface with callback methods is implemented on your side.
Your code implements a COM object, which in turn implements ICallbacks. You create an instance of such COM object (esp. without CoCreateInstace - it's typically client code on your side) and you pass ICallbacks interface as an argument in SetCallbacks call. Note that there is no assignment involved. Session object is expected to do a call, e.g. ICallbacks::UserExit on supplied pointer and this is how your code receives control through the callback interface - your client side code implementation of ICallbacks has its UserExit method called.
I needed simply to implement the interface in a separate class:
class Callbacks : public CerberusNativeLib::ICallbacks {
#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
MIDL_DEFINE_GUID(IID, IID_ICallbacks, 0xAECE8D0C, 0xF902, 0x4311, 0xA3, 0x74, 0xED, 0x3A, 0x0E, 0xBB, 0x6B, 0x49);
public:
HRESULT(*user_exit) (int, BSTR) = NULL;
HRESULT(*user_attempting_reconnection) () = NULL;
HRESULT(*user_reconnected) () = NULL;
Callbacks::Callbacks(HRESULT(*disconnected)(int, BSTR), HRESULT(*reconnecting)(), HRESULT(*reconnected)()) : m_cRef(0) {
user_exit = disconnected;
user_attempting_reconnection = reconnecting;
user_reconnected = reconnected;
}
HRESULT __stdcall UserExit(int ErrorCode, BSTR ErrorMessage) {
return user_exit(ErrorCode, ErrorMessage);
}
HRESULT __stdcall UserAttemptingReconnection() {
return user_attempting_reconnection();
}
HRESULT __stdcall UserReconnected() {
return user_reconnected();
}
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, _COM_Outptr_ void __RPC_FAR *__RPC_FAR *ppvObject) {
if (!ppvObject)
return E_INVALIDARG;
*ppvObject = NULL;
if (riid == IID_IUnknown || riid == IID_ICallbacks)
{
*ppvObject = (LPVOID)this;
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE AddRef() {
InterlockedIncrement(&m_cRef);
return m_cRef;
}
ULONG STDMETHODCALLTYPE Release() {
ULONG ulRefCount = InterlockedDecrement(&m_cRef);
if (0 == m_cRef)
delete this;
return ulRefCount;
}
private:
ULONG m_cRef;
};
Then, to use it:
HRESULT result = CoInitialize(NULL);
if (result != S_OK)
{
std::wcout << "Failed to initialize the COM library on the current thread or to identify the concurrency model as single-thread apartment (STA)." << std::endl;
std::wcout << result << ": " << _com_error(result).ErrorMessage() << std::endl;
std::wcout << "Press the enter key to exit." << std::endl;
std::cin.get();
return 0;
}
Callbacks *callbacks = new Callbacks(&prolonguedDisconnection, &reconnecting, &reconnected);
CerberusNativeLib::ICerberusSessionPtr session;
result = session.CreateInstance(__uuidof(CerberusNativeLib::CerberusSession));
if (result != S_OK)
{
std::wcout << "Failed to create a new Cerberus session." << std::endl;
std::wcout << result << ": " << _com_error(result).ErrorMessage() << std::endl;
std::wcout << "Press the enter key to exit." << std::endl;
std::cin.get();
return 0;
}
result = session->SetCallbacks(callbacks);
if (result != S_OK)
{
std::wcout << "Failed to set Cerberus session callbacks." << std::endl;
std::wcout << result << ": " << _com_error(result).ErrorMessage() << std::endl;
std::wcout << "Press the enter key to exit." << std::endl;
std::cin.get();
return 0;
}
Related
So I'm trying to read Memory out of a running exe with ReadProcessMemory() as you can see in the code provided below.
The only problem I constantly run into is that I receive the Error 3E6 / 998 which seems to be NOACCESS but I cant find a solution to fix this.
And yes I tried to run the exe in Admin Mode without success...
#include <Windows.h>
#include <iostream>
#include <string>
#include <tlhelp32.h>
#include <Psapi.h>
#include <tchar.h>
using namespace std;
int id = NULL;
HANDLE hProcess = NULL;
int getPID(const string name);
bool setHandle(int id, HANDLE &out);
DWORD64 GetModule(const string name);
int main()
{
bool success = false;
id = getPID("sample.exe");
string name = "SAMPLE";
cout << "Process Name: " << name << endl;
cout << "Process ID: " << id << endl;
success = setHandle(id, hProcess);
if (success)
{
cout << "Handle set..." << endl;
}
else if (!success)
{
cout << "You need to have SOMETHING opened..." << endl;
cout << "ERROR CODE: " << GetLastError() << endl;
system("pause");
return 1;
}
success = false;
DWORD64 baseAddress = GetModule("sample.exe");
DWORD64 ammo = 0x24ED13273A8;
DWORD64 addr = baseAddress + ammo;
cout << "Base Address: " << hex << uppercase << "0x" << baseAddress << endl;
cout << "Ammo Address: " << hex << uppercase << "0x" << ammo << endl;
cout << "Complete Address: " << hex << uppercase << "0x" << addr << endl;
int buffer = 0;
success = ReadProcessMemory(hProcess, (LPCVOID)addr, (LPVOID)&buffer, sizeof(&buffer), NULL);
if (success)
{
cout << "ReadProccess succeeded..." << endl;
system("pause");
return 0;
}
else if (!success)
{
cout << "ERROR CODE: " << GetLastError() << endl;
system("pause");
return 1;
}
system("pause");
return 0;
}
bool setHandle(int id, HANDLE &out)
{
out = OpenProcess(PROCESS_ALL_ACCESS, FALSE, id);
if (!out) return false;
return true;
}
int getPID(const string name)
{
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (!Process32First(snapshot, &entry)) return NULL;
do
{
if (strcmp(entry.szExeFile, name.c_str()) == 0)
{
CloseHandle(snapshot);
return entry.th32ProcessID;
}
} while (Process32Next(snapshot, &entry));
CloseHandle(snapshot);
return NULL;
}
DWORD64 GetModule(const string name)
{
HMODULE hMods[1024];
DWORD cbNeeded;
if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
{
for (int i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
{
TCHAR szModName[MAX_PATH];
if (GetModuleFileNameEx(hProcess, hMods[i], szModName, sizeof(szModName) / sizeof(TCHAR)))
{
string modName = szModName;
if (modName.find(name) != string::npos)
{
return (DWORD64)hMods[i];
}
}
}
}
return NULL;
}
I'm kinda new to c++... so sry? :)
There are actually two basic mistakes in your code, both of which, unfortunately for you, me and the rest of the civilised world, generate the same error code. Was it ever thus. There is also a logic error, but you are lucky enough to be getting away with it (just about). I commented the fix in the code I posted below.
There are also a number of 'good practise' shortcomings in your code, specifically:
NULL should not be used to represent integer zero
All error conditions should be checked for and (sensibly!) reported
You use the same string literal in two different places (so if you ever change it, you would need to change it in both places, and you might forget). So don't do that.
using namespace std; is widely frowned upon (because it causes such a lot of namespace pollution)
Why are id and hProcess global variables? This is just plain unnecessary.
You should give your functions more descriptive names, setHandle being the one I particularly have in mind. I got rid of that one completely.
When passing a std::string as a read-only function parameter, it is usually best to pass it as const ref, then it doesn't need to be copied.
Only use std::endl when you actually want to flush the buffer. It is inefficient.
Clean up after you (in this case, close any open handles). I know this is just a throwaway program but it's a good habit to get into.
OK, so here's some code that works (I have posted my own because I cleaned up all of the above). The substantive changes are:
To read the memory of another process, you need to give your user token the SE_DEBUG_NAME privilege. This in turn means you need to run your program as Administrator (aka elevated).
You cannot (obviously) read from a nonsense address in the target process so I just quietly fixed that.
Like I say, both of these generate the same error code. Huh!
OK, here you go. Enjoy:
#include <Windows.h>
#include <iostream>
#include <string>
#include <tlhelp32.h>
#include <Psapi.h>
#include <tchar.h>
int getPID(const std::string& name);
DWORD64 GetModule(HANDLE hProcess, const std::string& name);
// Stolen from: https://learn.microsoft.com/en-gb/windows/desktop/SecAuthZ/enabling-and-disabling-privileges-in-c--
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;
}
constexpr const char* theProcess = "notepad.exe";
int main()
{
HANDLE hToken;
BOOL ok = OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken);
if (!ok)
{
std::cout << "OpenProcessToken failed, error " << GetLastError() << "\n";
return 255;
}
ok = SetPrivilege (hToken, SE_DEBUG_NAME, TRUE);
if (!ok)
{
CloseHandle (hToken);
return 1;
}
int pid = getPID (theProcess);
HANDLE hProcess = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
if (hProcess == NULL)
{
std::cout << "OpenProcess failed, error " << GetLastError() << "\n";
CloseHandle (hToken);
return 1;
}
DWORD64 baseAddress = GetModule(hProcess, theProcess);
std::cout << "Base Address: " << std::hex << std::uppercase << "0x" << baseAddress << "\n";
int buffer = 0; // Note: sizeof (buffer) below, not sizeof (&buffer)
ok = ReadProcessMemory(hProcess, (LPCVOID)baseAddress, (LPVOID)&buffer, sizeof(buffer), NULL);
CloseHandle (hProcess);
CloseHandle (hToken);
if (ok)
{
std::cout << "ReadProcessMemory succeeded, buffer = " << buffer << "\n";
system("pause");
return 0;
}
std::cout << "ReadProcessMemory failed, error " << GetLastError() << "\n";
system("pause");
return 1;
}
int getPID(const std::string& name)
{
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (!Process32First(snapshot, &entry)) return NULL;
do
{
if (strcmp(entry.szExeFile, name.c_str()) == 0)
{
CloseHandle(snapshot);
return entry.th32ProcessID;
}
} while (Process32Next(snapshot, &entry));
CloseHandle(snapshot);
return NULL;
}
DWORD64 GetModule(HANDLE hProcess, const std::string& name)
{
HMODULE hMods[1024];
DWORD cbNeeded;
if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
{
for (int i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
{
TCHAR szModName[MAX_PATH];
if (GetModuleFileNameEx(hProcess, hMods[i], szModName, sizeof(szModName) / sizeof(TCHAR)))
{
std::string modName = szModName;
if (modName.find(name) != std::string::npos)
{
return (DWORD64)hMods[i];
}
}
}
}
return NULL;
}
Output (when run as Administrator):
Base Address: 0x7FF6D8470000
ReadProcessMemory succeeded, buffer = 905A4D
Output (when run as a normal user):
The token does not have the specified privilege.
You can also grab some code over at GitHub.
Im looking for a method/function that i can use to get base address of "program.exe"+03262C08 -> B4895A0. This address is from Cheat Engine and base address has been found with Pointer scanner. In pointer scanner i can press show module list and there is address of program.exe starting at address 00400000 program.exe. Pointer scanner was scanned for address 09c3000(The address which i want to reach after base address+many offsets[the final address]). This address is base for certain object but i cant reach the address. I'm able to get only base address of exe file at 00400000. I'm trying to add offsets from pointer 03262C08(and the others) but i cant still reach the address. I cant use function FindWindow(). Becouse a name of the program will be changing and it will be redundant to stick with it. I'm using OpenProcess(), EnumProcessModulesEx(), GetModuleFileNameEx() functions. I have tried others as well like GetModuleInformation(),... with the same result. GetModuleHandle() ended with result 0x126 [ERROR_MOD_NOT_FOUND]. I'm using 64 bit OS and I'm trying to get base address of another process.
I can see all processes on local machine and modules of "program" process.
if (!K32EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) {
return 1;
}
cProcesses = cbNeeded / sizeof(DWORD);
cout << setw(15) << left << "Process ID" << setw(10) << left << "Modules";
cout << setw(30) << left << "Process Name" << endl;
for (i = 0; i < cProcesses; i++) {
if (aProcesses[i] != 0) {
ProcessView::GetProccesses(aProcesses[i], modules, sizeModules, &cModules, &hCurrProcess);
if (hCurrProcess != NULL) {
cout << endl << setw(15) << left << aProcesses[i] << setw(10) << left << cModules;
ProcessView::PrintModuleName(hCurrProcess, modules);
CloseHandle(hCurrProcess);
}
}
}
ProcessView::GetProccesses(cProcesses, modules, sizeModules, &cModules, &hCurrProcess);
system("cls");
ProcessView::PrintModuleNameAll(hCurrProcess, modules, cModules);
I added here definition of function in example from ProcessView.h file that i have created.
static void GetProccesses(_In_ DWORD processID, _Inout_ HMODULE ahModules[], _In_ int sizeModules, _Out_ DWORD* cModules, _Out_ HANDLE* hProcess);
static void PrintModuleName(_In_ HANDLE processID, _In_ HMODULE* modules);
static void PrintModuleNameAll(_In_ HANDLE hProcess, _In_ HMODULE * modules, _In_ DWORD cModules);
Windows has been using Address Space Layout Randomization for about a decade now, but the module base in EXE's is far older than that. Simply ignore it, it's now meaningless.
And don't forget: each process has its own address space. A pointer in one process is meaningless in the other.
To use ReadProcessMemory or WriteProcessMemory on an address which is found via pointer chain on a process and dynamically get the module base address at runtime you need to accomplish these steps:
Find the Process with ToolHelp32Snapshot
Find the Module with ToolHelp32Snapsho
Get a handle to the process with correct permissions
Walk the pointer chain, de-referencing and adding offsets
Then you can Call ReadProcessMemory or WriteProcessMemory
You must run as administrator
For this example I will use a simple assault cube cheat I've made
#include <iostream>
#include <vector>
#include <Windows.h>
#include "proc.h"
int main()
{
//Get ProcId of the target process
DWORD procId = GetProcId(L"ac_client.exe");
//Getmodulebaseaddress
uintptr_t moduleBase = GetModuleBaseAddress(procId, L"ac_client.exe");
//Get Handle to Process
HANDLE hProcess = 0;
hProcess = OpenProcess(PROCESS_ALL_ACCESS, NULL, procId);
//Resolve base address of the pointer chain
uintptr_t dynamicPtrBaseAddr = moduleBase + 0x10f4f4;
std::cout << "DynamicPtrBaseAddr = " << "0x" << std::hex << dynamicPtrBaseAddr << std::endl;
//Resolve our ammo pointer chain
std::vector<unsigned int> ammoOffsets = { 0x374, 0x14, 0x0 };
uintptr_t ammoAddr = FindDMAAddy(hProcess, dynamicPtrBaseAddr, ammoOffsets);
std::cout << "ammoAddr = " << "0x" << std::hex << ammoAddr << std::endl;
//Read Ammo value
int ammoValue = 0;
ReadProcessMemory(hProcess, (BYTE*)ammoAddr, &ammoValue, sizeof(ammoValue), nullptr);
std::cout << "Curent ammo = " << std::dec << ammoValue << std::endl;
//Write to it
int newAmmo = 1337;
WriteProcessMemory(hProcess, (BYTE*)ammoAddr, &newAmmo, sizeof(newAmmo), nullptr);
//Read out again
ReadProcessMemory(hProcess, (BYTE*)ammoAddr, &ammoValue, sizeof(ammoValue), nullptr);
std::cout << "New ammo = " << std::dec << ammoValue << std::endl;
getchar();
return 0;
}
The header file proc.cpp:
DWORD GetProcId(const wchar_t* procName)
{
DWORD procId = 0;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32 procEntry;
procEntry.dwSize = sizeof(procEntry);
if (Process32First(hSnap, &procEntry))
{
do
{
if (!_wcsicmp(procEntry.szExeFile, procName))
{
procId = procEntry.th32ProcessID;
break;
}
} while (Process32Next(hSnap, &procEntry));
}
}
CloseHandle(hSnap);
return procId;
}
uintptr_t GetModuleBaseAddress(DWORD procId, const wchar_t* modName)
{
uintptr_t modBaseAddr = 0;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procId);
if (hSnap != INVALID_HANDLE_VALUE)
{
MODULEENTRY32 modEntry;
modEntry.dwSize = sizeof(modEntry);
if (Module32First(hSnap, &modEntry))
{
do
{
if (!_wcsicmp(modEntry.szModule, modName))
{
modBaseAddr = (uintptr_t)modEntry.modBaseAddr;
break;
}
} while (Module32Next(hSnap, &modEntry));
}
}
CloseHandle(hSnap);
return modBaseAddr;
}
uintptr_t FindDMAAddy(HANDLE hProc, uintptr_t ptr, std::vector<unsigned int> offsets)
{
uintptr_t addr = ptr;
for (unsigned int i = 0; i < offsets.size(); ++i)
{
ReadProcessMemory(hProc, (BYTE*)addr, &addr, sizeof(addr), 0);
addr += offsets[i];
}
return addr;
}
I have written DLL injector. I used CreateRemoteThread to inject my DLL to process and all was good.
Now i am trying inject DLL to process by undocumented function - NtCreateThreadEx. I have written injector but he is not working.
When i use 32 bit injector to inject 32 bit DLL to 32 bit process
all working good.
Problem is when i use 64 bit injector to inject 64 bit DLL to 64 bit process.
My DLL code:
#include <windows.h>
///Compilation with option -m64
extern "C" BOOL __stdcall DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved)
{
MessageBox( NULL, "MESSAGE FROM 64 BIT DLL", "Lorem ipsum", MB_ICONINFORMATION | MB_OKCANCEL );
return 0;
}
My TestApp code
#include <iostream>
#include <windows.h>
int main()
{
std::cout << " Lorem IPSUM" << std::endl;
//HMODULE HDLL = LoadLibraryA("dll64.dll");
//std::cout << "Error: " << GetLastError() << std::endl;
while(1)
{
std::cout << "petla" << std::endl;
Sleep(5000);
}
return 0;
}
My injector code:
#include <iostream>
#include <string>
#include <windows.h>
/// 64 bit OS - Windows 7
///=====================
///* In this same user context ("User")
///TYPE OF(32/64 bits)
///INJECTOR===DLL===PROCESS===RESULT
/// 32 32 32 -SUCESS
/// 64 64 64 -FALIED (error: 1300)
//Handle to process,Address of'LoadLibraryA',see DllAdr
///TO DO
///* Inject DLL to process from normal user context ("User") to higher user context (Zarzadca)
///* Inject DLL to process from normal user context ("User") to other normal user context (User1)
HANDLE NtCreateThreadEx(HANDLE hProcess,LPVOID lpBaseAddress, LPVOID lpSpace);
int privileges();
int main()
{
int PIDOfProcess = 0;
std::string pathToDLL = "dll64.dll\0"; ///find DLL in local directory
DWORD PID = (DWORD)PIDOfProcess; ///PID
HANDLE HProcess = NULL; ///Handle to process
LPVOID LibAddr = NULL; ///Address of procedure 'LoadLibraryA'
LPVOID DllAdr = NULL; ///Address of memory in other process
HANDLE hThread = NULL; ///Handle to remote thread
int WirteStatus = 0; ///Status of writing to memory of other process
std::cout << "ptr size = " << sizeof(void *) << std::endl;
std::cout << "Get PID of process" << std::endl;
std::cin >> PIDOfProcess;
PID = (DWORD)PIDOfProcess;
///std::cout << "Get path to DLL" << std::endl;
///std::cin >> pathToDLL;
if( privileges() != 0 )
{
std::cout << "Cannot get the right privileges" << std::endl;
}
HProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
if(HProcess == NULL)
{
std::cout << "Could not find process" << std::endl;
std::cout << GetLastError() << std::endl;
system("pause");
return GetLastError();
}
DllAdr = (LPVOID)VirtualAllocEx(HProcess, NULL, pathToDLL.size() +1, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if(DllAdr == NULL)
{
std::cout <<"Can not allocate memory." << std::endl;
std::cout << GetLastError() << std::endl;
system("pause");
return GetLastError();
}
WirteStatus = WriteProcessMemory(HProcess, (LPVOID)DllAdr, pathToDLL.c_str() ,pathToDLL.size()+1, NULL);
if(WirteStatus == 0)
{
std::cout << "Could not write to process's address space" << std::endl;
std::cout << GetLastError() << std::endl;
system("pause");
return GetLastError();
}
LibAddr = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
if(LibAddr == NULL)
{
std::cout << "Unable to locate LoadLibraryA" << std::endl;
std::cout << GetLastError() << std::endl;
system("pause");
return GetLastError();
}
hThread = NtCreateThreadEx(HProcess,LibAddr,DllAdr);
///DWORD threadId = 0;
///hThread = CreateRemoteThread(HProcess, NULL, 0, (LPTHREAD_START_ROUTINE)LibAddr, DllAdr, 0, &threadId);
if(hThread == NULL)
{
std::cout << "Error: ";
std::cout << GetLastError() << std::endl;
system("pause");
return GetLastError();
}
system("pause");
}
HANDLE NtCreateThreadEx(HANDLE hProcess,LPVOID lpBaseAddress,LPVOID lpSpace)
{
///The prototype of NtCreateThreadEx from undocumented.ntinternals.com
typedef DWORD (WINAPI * functypeNtCreateThreadEx)(
PHANDLE ThreadHandle,
ACCESS_MASK DesiredAccess,
LPVOID ObjectAttributes,
HANDLE ProcessHandle,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
BOOL CreateSuspended,
DWORD dwStackSize,
DWORD Unknown1,
DWORD Unknown2,
LPVOID Unknown3
);
HANDLE hRemoteThread = NULL;
HMODULE hNtDllModule = NULL;
functypeNtCreateThreadEx funcNtCreateThreadEx = NULL;
//Get handle for ntdll which contains NtCreateThreadEx
hNtDllModule = GetModuleHandle( "ntdll.dll" );
if ( hNtDllModule == NULL )
{
std::cout << "Cannot get module ntdll.dll error: " << GetLastError() << std::endl;
return NULL;
}
funcNtCreateThreadEx = (functypeNtCreateThreadEx)GetProcAddress( hNtDllModule, "NtCreateThreadEx" );
if ( !funcNtCreateThreadEx )
{
std::cout << "Cannot get procedure address error: " << GetLastError() << std::endl;
return NULL;
}
funcNtCreateThreadEx( &hRemoteThread, /*GENERIC_ALL*/0x1FFFFF, NULL, hProcess, (LPTHREAD_START_ROUTINE)lpBaseAddress, lpSpace, FALSE, NULL, NULL, NULL, NULL );
std::cout << "Status NtCreateThreadEx " << GetLastError() << std::endl;
std::cout << "hRemoteThread: " << hRemoteThread << std::endl;
std::cout << "hNtDllModule: " << hNtDllModule << std::endl;
std::cout << "funcNtCreateThreadEx: " << funcNtCreateThreadEx << std::endl;
return hRemoteThread;
}
int privileges()
{
HANDLE Token;
TOKEN_PRIVILEGES tp;
if(OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,&Token)) ///It opens the access token associated with a process.
{
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);///Function retrieves the locally unique identifier (LUID)
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (AdjustTokenPrivileges(Token, false, &tp, sizeof(tp), NULL, NULL) != 0)///Function enables or disables privileges in the specified access token.
{
return 0; //OK
}
}
return 1;
}
When i use 64 bit injector to inject 64 bit DLL to 64 bit process, function NtCreateThreadEx return code of error 1300 and my DLL doesn't execute.
I use to compile on 64 bit architecture: g++ (tdm64-1) 5.1.0
I am working on Virus Windows 7 64 bit as normal user. Run as administrator doesn't help.
I dont know why it doesn't work, what i doing wrong.
PS: When i use 32 bit injector to inject 32 bit DLL to 32 bit process, function NtCreateThreadEx return code of error 1300 but my DLL execute.
In 32 bit version TestApp GetLastError return code 1114.
I use to compile on 32 bit architecture: g++ (tdm-2) 4.8.1
I include image
I based on:
http://www.p-programowanie.pl/cpp/dll-injection/ - Dll Injection (polish)
====
http://www.codeproject.com/Questions/369890/Ask-about-NtCreateThreadEx-in-Window-x
- Ask about NtCreateThreadEx in Window 7 x64!
=====
http://www.rohitab.com/discuss/topic/39535-code-injections-beginner-and-advanced/ Code Injections [beginner and advanced]
=====
http://securityxploded.com/ntcreatethreadex.php Remote Thread Execution in System Process using NtCreateThreadEx for Vista & Windows7
=====
http://cpp0x.pl/dokumentacja/WinAPI/Systemowe-kody-bledow-1300-1699/1470 Systemowe kody błędów (1300-1699) (polish)
Link to my topic on other forum (polish): http://forum.4programmers.net/C_i_C++/267735-dll_injection_w_windows_za_pomoca_nieudokumentowanej_funkcji_w_winapi?p=1234215#id1234215
My injector is working when i use him to inject DLL to other process in my user space (i am working as normal user)
but it is not working when
i am injecting to csrss.exe (or other system's process).
I get code of error 5 - Access Denied, when i run injector as Administrator i get code of error 0 (SUCCESS?) but my DLL not aborting process
( abort() - i try do BSoD).
I read about Session Separation and i think it is reason of my problem so i have one question: How i can hacking Windows :)
If it is imposibble can i inject DLL as normal user to proces in Administrator context (or other normal user's process) ?
I need to the the Handle or the PID for all the process that are just being created while I run my program.
So far I have used this code that tell me each time that a process is created. The problem is that I just get the information about a process created but I don't have any information about the process itself. https://msdn.microsoft.com/en-us/library/aa390425(VS.85).aspx
This is the fuction where I get the event but I don't know from where I can get the info for the new process:
HRESULT EventSink::Indicate(long lObjectCount,
IWbemClassObject **apObjArray)
{
HRESULT hres = S_OK;
for (int i = 0; i < lObjectCount; i++)
{
printf("Event occurred\n");
}
return WBEM_S_NO_ERROR;
}
Thank you
Since you are using this WQL sentence SELECT * FROM __InstanceCreationEvent WITHIN 1 WHERE TargetInstance ISA 'Win32_Process', In order to get additional info about the created processes you must access the TargetInstance property which in this case will return a Win32_Process instance.
Try this sample
#include "stdafx.h"
#include <conio.h>
#ifndef EVENTSINK_H
#define EVENTSINK_H
#define _WIN32_DCOM
#include <iostream>
using namespace std;
#include <comdef.h>
#include <Wbemidl.h>
# pragma comment(lib, "wbemuuid.lib")
class EventSink : public IWbemObjectSink
{
LONG m_lRef;
bool bDone;
public:
EventSink() { m_lRef = 0; }
~EventSink() { bDone = true; }
virtual ULONG STDMETHODCALLTYPE AddRef();
virtual ULONG STDMETHODCALLTYPE Release();
virtual HRESULT
STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv);
virtual HRESULT STDMETHODCALLTYPE Indicate(
LONG lObjectCount,
IWbemClassObject __RPC_FAR *__RPC_FAR *apObjArray
);
virtual HRESULT STDMETHODCALLTYPE SetStatus(
/* [in] */ LONG lFlags,
/* [in] */ HRESULT hResult,
/* [in] */ BSTR strParam,
/* [in] */ IWbemClassObject __RPC_FAR *pObjParam
);
};
#endif // end of EventSink.h
ULONG EventSink::AddRef()
{
return InterlockedIncrement(&m_lRef);
}
ULONG EventSink::Release()
{
LONG lRef = InterlockedDecrement(&m_lRef);
if (lRef == 0)
delete this;
return lRef;
}
HRESULT EventSink::QueryInterface(REFIID riid, void** ppv)
{
if (riid == IID_IUnknown || riid == IID_IWbemObjectSink)
{
*ppv = (IWbemObjectSink *) this;
AddRef();
return WBEM_S_NO_ERROR;
}
else return E_NOINTERFACE;
}
HRESULT EventSink::Indicate(long lObjectCount,
IWbemClassObject **apObjArray)
{
HRESULT hr = S_OK;
_variant_t vtProp;
for (int i = 0; i < lObjectCount; i++)
{
hr = apObjArray[i]->Get(_bstr_t(L"TargetInstance"), 0, &vtProp, 0, 0);
if (!FAILED(hr))
{
IUnknown* str = vtProp;
hr = str->QueryInterface(IID_IWbemClassObject, reinterpret_cast< void** >(&apObjArray[i]));
if (SUCCEEDED(hr))
{
_variant_t cn;
hr = apObjArray[i]->Get(L"Caption", 0, &cn, NULL, NULL);
if (SUCCEEDED(hr))
{
if ((cn.vt == VT_NULL) || (cn.vt == VT_EMPTY))
wcout << "Caption : " << ((cn.vt == VT_NULL) ? "NULL" : "EMPTY") << endl;
else
if ((cn.vt & VT_ARRAY))
wcout << "Caption : " << "Array types not supported (yet)" << endl;
else
wcout << "Caption : " << cn.bstrVal << endl;
}
VariantClear(&cn);
hr = apObjArray[i]->Get(L"CommandLine", 0, &cn, NULL, NULL);
if (SUCCEEDED(hr))
{
if ((cn.vt == VT_NULL) || (cn.vt == VT_EMPTY))
wcout << "CommandLine : " << ((cn.vt == VT_NULL) ? "NULL" : "EMPTY") << endl;
else
if ((cn.vt & VT_ARRAY))
wcout << "CommandLine : " << "Array types not supported (yet)" << endl;
else
wcout << "CommandLine : " << cn.bstrVal << endl;
}
VariantClear(&cn);
hr = apObjArray[i]->Get(L"Handle", 0, &cn, NULL, NULL);
if (SUCCEEDED(hr))
{
if ((cn.vt == VT_NULL) || (cn.vt == VT_EMPTY))
wcout << "Handle : " << ((cn.vt == VT_NULL) ? "NULL" : "EMPTY") << endl;
else
if ((cn.vt & VT_ARRAY))
wcout << "Handle : " << "Array types not supported (yet)" << endl;
else
wcout << "Handle : " << cn.bstrVal << endl;
}
VariantClear(&cn);
}
}
VariantClear(&vtProp);
}
return WBEM_S_NO_ERROR;
}
HRESULT EventSink::SetStatus(
/* [in] */ LONG lFlags,
/* [in] */ HRESULT hResult,
/* [in] */ BSTR strParam,
/* [in] */ IWbemClassObject __RPC_FAR *pObjParam
)
{
if (lFlags == WBEM_STATUS_COMPLETE)
{
printf("Call complete. hResult = 0x%X\n", hResult);
}
else if (lFlags == WBEM_STATUS_PROGRESS)
{
printf("Call in progress.\n");
}
return WBEM_S_NO_ERROR;
} // end of EventSink.cpp
int main(int iArgCnt, char ** argv)
{
HRESULT hres;
// Step 1: --------------------------------------------------
// Initialize COM. ------------------------------------------
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres))
{
cout << "Failed to initialize COM library. Error code = 0x"
<< hex << hres << endl;
return 1; // Program has failed.
}
// Step 2: --------------------------------------------------
// Set general COM security levels --------------------------
// Note: If you are using Windows 2000, you need to specify -
// the default authentication credentials for a user by using
// a SOLE_AUTHENTICATION_LIST structure in the pAuthList ----
// parameter of CoInitializeSecurity ------------------------
hres = CoInitializeSecurity(
NULL,
-1, // COM negotiates service
NULL, // Authentication services
NULL, // Reserved
RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication
RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation
NULL, // Authentication info
EOAC_NONE, // Additional capabilities
NULL // Reserved
);
if (FAILED(hres))
{
cout << "Failed to initialize security. Error code = 0x"
<< hex << hres << endl;
CoUninitialize();
return 1; // Program has failed.
}
// Step 3: ---------------------------------------------------
// Obtain the initial locator to WMI -------------------------
IWbemLocator *pLoc = NULL;
hres = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *)&pLoc);
if (FAILED(hres))
{
cout << "Failed to create IWbemLocator object. "
<< "Err code = 0x"
<< hex << hres << endl;
CoUninitialize();
return 1; // Program has failed.
}
// Step 4: ---------------------------------------------------
// Connect to WMI through the IWbemLocator::ConnectServer method
IWbemServices *pSvc = NULL;
// Connect to the local root\cimv2 namespace
// and obtain pointer pSvc to make IWbemServices calls.
hres = pLoc->ConnectServer(
_bstr_t(L"root\\CIMV2"),
NULL,
NULL,
0,
NULL,
0,
0,
&pSvc
);
if (FAILED(hres))
{
cout << "Could not connect. Error code = 0x"
<< hex << hres << endl;
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
cout << "Connected to root\\CIMV2 WMI namespace" << endl;
// Step 5: --------------------------------------------------
// Set security levels on the proxy -------------------------
hres = CoSetProxyBlanket(
pSvc, // Indicates the proxy to set
RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx
RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx
NULL, // Server principal name
RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx
RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
NULL, // client identity
EOAC_NONE // proxy capabilities
);
if (FAILED(hres))
{
cout << "Could not set proxy blanket. Error code = 0x" << hex << hres << endl;
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
// Step 6: -------------------------------------------------
// Receive event notifications -----------------------------
// Use an unsecured apartment for security
IUnsecuredApartment* pUnsecApp = NULL;
hres = CoCreateInstance(CLSID_UnsecuredApartment, NULL, CLSCTX_LOCAL_SERVER, IID_IUnsecuredApartment, (void**)&pUnsecApp);
EventSink* pSink = new EventSink;
pSink->AddRef();
IUnknown* pStubUnk = NULL;
pUnsecApp->CreateObjectStub(pSink, &pStubUnk);
IWbemObjectSink* pStubSink = NULL;
pStubUnk->QueryInterface(IID_IWbemObjectSink, (void **)&pStubSink);
BSTR WQL;
WQL = L"Select * From __InstanceCreationEvent Within 1 "
L"Where TargetInstance ISA 'Win32_Process' "
;
// The ExecNotificationQueryAsync method will call
// The EventQuery::Indicate method when an event occurs
hres = pSvc->ExecNotificationQueryAsync(
_bstr_t("WQL"), _bstr_t(WQL), WBEM_FLAG_SEND_STATUS, NULL, pStubSink);
// Check for errors.
if (FAILED(hres))
{
printf("ExecNotificationQueryAsync failed with = 0x%X\n", hres);
pSvc->Release();
pLoc->Release();
pUnsecApp->Release();
pStubUnk->Release();
pSink->Release();
pStubSink->Release();
CoUninitialize();
return 1;
}
// Wait for the event
cout << "Press any key to terminate" << endl;
while (!_kbhit()) {}
hres = pSvc->CancelAsyncCall(pStubSink);
// Cleanup
// ========
pSvc->Release();
pLoc->Release();
pUnsecApp->Release();
pStubUnk->Release();
pSink->Release();
pStubSink->Release();
CoUninitialize();
return 0; // Program successfully completed.
}
The example above seems to have a memory leak inside EventSink::Indicate.
IUnknown* str = vtProp;
This assignment uses operator IUnknown* of the _variant_t class, which implicitly calls an AddRef() on the object. So str->Release() needs to be called after usage, since
VariantClear(&vtProp);
is not enough to decrement the ref count of the object.
HANDLE Proc;
HMODULE hDLL;
hDLL = LoadLibrary(TEXT("mscoree.dll"));
if(hDLL == NULL)
cout << "No Dll with Specified Name" << endl;
else
{
cout << "DLL Handle" << hDLL << endl<<endl;
cout << "Getting the process address..." << endl;
Proc = GetProcAddress(hDLL,"GetRequestedRuntimeVersion");
if(Proc == NULL)
{
FreeLibrary(hDLL);
cout << "Process load FAILED" << endl;
}
else
{
cout << "Process address found at: " << Proc << endl << endl;
LPWSTR st;DWORD* dwlength; ;DWORD cchBuffer=MAX_PATH;
HRESULT hr=GetCORSystemDirectory(st,cchBuffer,dwlength);
if(hr!=NULL)
{
printf("%s",hr);
}
FreeLibrary(hDLL);
}
}
i did like this to get the .NET installation path but i am getting Linker Errors.
error LNK2019: unresolved external symbol _GetCORSystemDirectory#12 referenced in function _main dot.obj
define the GetCORSystemDirectory signature:
typedef HRESULT ( __stdcall *FNPTR_GET_COR_SYS_DIR) ( LPWSTR pbuffer, DWORD cchBuffer, DWORD* dwlength);
initialise the function pointer:
FNPTR_GET_COR_SYS_DIR GetCORSystemDirectory = NULL;
get a function pointer from mscoree.dll and use:
GetCORSystemDirectory = (FNPTR_GET_COR_SYS_DIR) GetProcAddress (hDLL, "GetCORSystemDirectory");
if( GetCORSystemDirectory!=NULL)
{
...
//use GetCORSystemDirectory
...
}
As requested:
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0600
#endif
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
typedef HRESULT (__stdcall *FNPTR_GET_COR_SYS_DIR) ( LPWSTR pbuffer, DWORD cchBuffer, DWORD* dwlength);
FNPTR_GET_COR_SYS_DIR GetCORSystemDirectory = NULL;
int _tmain(int argc, _TCHAR* argv[])
{
HINSTANCE hDLL = LoadLibrary(TEXT("mscoree.dll"));
GetCORSystemDirectory = (FNPTR_GET_COR_SYS_DIR) GetProcAddress (hDLL, "GetCORSystemDirectory");
if( GetCORSystemDirectory!=NULL)
{
TCHAR buffer[MAX_PATH];
DWORD length;
HRESULT hr = GetCORSystemDirectory(buffer,MAX_PATH,&length);
// buffer should contain the folder name
// use it..
}
return 0;
}
You need to pass "GetCORSystemDirectory" as the second parameter into GetProcAddress() - it will return a pointer to that function implementation. Then you'll cast the pointer appropriately and call the function through it.