Official site anti-cheat Ultra Core Protector

Home Download F.A.Q. Addons Monitor Forum Support Advertise English version site UCP Anti-Cheat  Russian version site UCP Anti-Cheat
Ultra Core Protector - is the client-server anti-cheat freeware, for server protection from unscrupulous players.

Abilities Supported games  
Half-Life
Condition Zero
Counter-Strike 1.6
Day of Defeat
Adrenaline Gamer
Team Fortress Classic
Counter-Strike Source
MU Online
Ragnarok Online
Half-Life 2 Deathmatch
Adrenaline Gamer 2
Team Fortress 2
hSonic Bypass (ASAP Handles! v3)

What is this bypass?

This bypass is the outcome from the common work that @JYam @mistree and myself have done reversing how PcaSvc’s SVCHOST could get its handles on system processes.
I am not going to go into details in this thread since enough information have been given in the others.
In short: We outrun the kernel notification routines set up by anti cheats to modify handle permissions using job objects, therefore obtaining a handle before the callbacks are in place.

Tested working on Windows 10 & Windows 8
Reported working on Windows 7

What’s new in this version?

This version is NOT a proof of concept code, this is a ready to integrate 1 line (only!) bypass.
The bypass is contained in a single .hpp file to include and you can then use it as simply as this:

HANDLE hGame = GetSonicHandle(L"Game.exe", L"Steam.exe");

I made it flexible to be used on any game.
I tested it with several games on my machine, including BE protected games (DayZ), EAC protected games (7 Days to die), and should work on other anti-cheats relying on kernel notification routines as well.

I made it stealthy, limiting the detection vectors to a minimum.
To do so, I read the documentation of every API function called and made sure that:
– It uses only the minimum security access required (e.g. for OpenProcess)
– It closes all unnecessary handles when it finishes and even if something fails
– I encourage the user to also limit the detection vector by providing the possibility to request a handle with minimal rights

Keep in mind that this bypass gives you a handle that could be found, protect or hide your cheat.

User guide: How to use it

This bypass obtains a HANDLE to a program faster than kernel notification routines using job object.
Important: Oppositely to many other bypasses, this one requires to start the cheat before starting the game.

Bypass Syntax (Prototype):

HANDLE GetSonicHandle(
_In_ std::wstring targetProcessName,
_In_Opt_ std::wstring parentProcessName,
_In_Opt_ DWORD dwDesiredAccess,
_In_Opt_ BOOL bInheritHandle
);

Parameters:

targetProcessName [in]
Target process name including “.exe” at the end.
Example of correct parameter: L”DayZ.exe”

targetProcessName [in, optional]
Direct parent process image name.
For games started by Steam, the correct parameter would be L”Steam.exe”.
Games started from Windows directly most of the time have explorer.exe, in that case you can leave the parameter empty or ommit it entirely, the bypass uses explorer.exe as parent by default.
To find the parent process of your game, you can use a software such as Process Hacker or Process Explorer (See the section “How to find my game’s parent process?” for a step by step guide)

dwDesiredAccess [in, optional]
This parameter will be passed to OpenProcess to get the handle on your target and other processes spawned before finding the target.
The access to the process object.
This access right is checked against the security descriptor for the process.
This parameter can be one or more of the process access rights.
If the caller has enabled the SeDebugPrivilege privilege, the requested access is granted regardless of the contents of the security descriptor.

bInheritHandle [in, optional]
This parameter will be passed to OpenProcess to get the handle on your target and other processes spawned before finding the target.
If this value is TRUE, processes created by this process will inherit the handle.
Otherwise, the processes do not inherit this handle.

Bypass Source

This is the source to save as a .hpp or .h file and to include in your cheat.

#include
#include
#include
#include #include
#include

/* GetPIDs creates a snapshot of all processes then processes them one by one to find processes with the given process name */
std::vector GetPIDs(std::wstring targetProcessName) {
std::vector pids;
if (targetProcessName == L"")
return pids; // No process name given
HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); // All processes
PROCESSENTRY32W entry; // Current process
entry.dwSize = sizeof entry;
if (!Process32FirstW(snap, &entry)) // Start with the first in snapshot
return pids;
do {
if (std::wstring(entry.szExeFile) == targetProcessName)
pids.emplace_back(entry.th32ProcessID); // Names match, add to list
} while (Process32NextW(snap, &entry)); // Keep going until end of snapshot
CloseHandle(snap);
return pids;
}

/* Close all HANDLEs in a std::vector (for cleanup) */
bool CloseVectorHandles(std::vector vHandles) {
bool allSuccess = true;
for (int i(0); i < vHandles.size(); ++i) { if (!CloseHandle(vHandles[i])) allSuccess = false; } return allSuccess; } HANDLE GetSonicHandle(std::wstring targetProcessName, std::wstring parentProcessName = L"", DWORD dwDesiredAccess = PROCESS_ALL_ACCESS, BOOL bInheritHandle = FALSE) { if (targetProcessName == L"") return NULL; // No target process specified, exit HANDLE hTarget = NULL; // Handle to return /* Getting process handle(s) on parent(s) */ std::vector vhParentProcesses;
if (parentProcessName != L"") { // Parent process name specified, using that parent
std::vector pids = GetPIDs(parentProcessName); // Getting PID of parent process(es) (might be several processes with same image name, trying on all)
if (pids.empty())
return NULL;
for (int i(0); i < pids.size(); ++i) { HANDLE hParentProcess = OpenProcess(PROCESS_SET_QUOTA | PROCESS_TERMINATE, TRUE, pids[i]); if (hParentProcess == NULL) continue; vhParentProcesses.push_back(hParentProcess); } } else { // Parent process name NOT specified, using explorer.exe by default DWORD explorerPID = NULL; HWND hDesktopWindow = GetShellWindow(); // Getting handle on desktop window GetWindowThreadProcessId(hDesktopWindow, &explorerPID); // Using desktop window handle to get handle on explorer.exe HANDLE hExplorerProcess = OpenProcess(PROCESS_SET_QUOTA | PROCESS_TERMINATE, TRUE, explorerPID); if (hExplorerProcess != NULL) vhParentProcesses.push_back(hExplorerProcess); } if (vhParentProcesses.empty()) // Couldn't open any parent process return NULL; /* Creating job to get instant notification of new child processes */ HANDLE ioPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, NULL); HANDLE jobObject = CreateJobObject(NULL, NULL); if (jobObject == NULL || ioPort == NULL) { // Error, cleanup CloseVectorHandles(vhParentProcesses); CloseHandle(ioPort); CloseHandle(jobObject); return NULL; } JOBOBJECT_ASSOCIATE_COMPLETION_PORT jobIOport; jobIOport.CompletionKey = NULL; jobIOport.CompletionPort = ioPort; BOOL setInfoJobObjStatus = SetInformationJobObject(jobObject, JobObjectAssociateCompletionPortInformation, &jobIOport, sizeof(jobIOport)); if (!setInfoJobObjStatus) { // Error, cleanup CloseVectorHandles(vhParentProcesses); CloseHandle(ioPort); CloseHandle(jobObject); return NULL; } bool procInJob = false; for (int j(0); j < vhParentProcesses.size(); ++j) { if (AssignProcessToJobObject(jobObject, vhParentProcesses[j]) && !procInJob) procInJob = true; } if (!procInJob) { // Couldn't add any process to the job, cleanup CloseVectorHandles(vhParentProcesses); CloseHandle(ioPort); CloseHandle(jobObject); return NULL; } /* Preparing synchronisation between threads */ HANDLE hsNewHandle = CreateSemaphore(NULL, 0, 9999, NULL); if (!hsNewHandle) { // Couldn't create semaphore, cleanup CloseVectorHandles(vhParentProcesses); CloseHandle(ioPort); CloseHandle(jobObject); return NULL; } /* Handle-receiver thread */ bool gotFirstHandle = false; bool stopReceiving = false; std::vector vhSonicProcesses;
std::thread handleReceiver = std::thread([&]() {
DWORD numberOfBytesTransferred;
ULONG_PTR completionKey;
LPOVERLAPPED overlapped;
while (GetQueuedCompletionStatus(ioPort, &numberOfBytesTransferred, &completionKey, &overlapped, INFINITE)) {
if (stopReceiving)
break; // Termination of the handle-receiving thread received
HANDLE hSonicProcess = OpenProcess(dwDesiredAccess, bInheritHandle, reinterpret_cast(overlapped));
if (hSonicProcess == NULL)
continue;
vhSonicProcesses.push_back(hSonicProcess);
ReleaseSemaphore(hsNewHandle, 1, NULL);
}
return EXIT_SUCCESS;
});

/* Handle-checker thread */
std::thread handleChecker = std::thread([&]() {
int handlesChecked = 0, handleChecking = 0;
while (true) {
WaitForSingleObject(hsNewHandle, INFINITE); // Waiting for receiver thread to signal new handle gathered
handleChecking = handlesChecked; // Using the number of handle checked to process the right handle in the vector
++handlesChecked; // Whatever happens, we will consider this handle checked
TCHAR processImageFileName[MAX_PATH];
DWORD maxLength = MAX_PATH;
if (!QueryFullProcessImageName(vhSonicProcesses[handleChecking], NULL, processImageFileName, &maxLength)) { // Couldn't retrieve full process name image
CloseHandle(vhSonicProcesses[handleChecking]);
continue;
}
std::wstring strProcessImageFileName = processImageFileName;
size_t posLastDir = strProcessImageFileName.find_last_of(L"\\");
if (posLastDir == std::string::npos) { // Error, couldn't find the last "\" in the process image file name
CloseHandle(vhSonicProcesses[handleChecking]);
continue;
}
std::wstring strProcessName = strProcessImageFileName.substr(posLastDir + 1); // Extracting process name only (e.g. C:\Windows\explorer.exe -> explorer.exe)
if (strProcessName != targetProcessName) { // *Jedi voice* This is not the handle you are looking for
CloseHandle(vhSonicProcesses[handleChecking]);
continue;
}
/* Handle to target acquired, stopping receiving thread */
hTarget = vhSonicProcesses[handleChecking];
stopReceiving = true;
PostQueuedCompletionStatus(ioPort, NULL, NULL, NULL);
handleReceiver.join();
/* Check if other handles have been created by receiving thread while we were processing in this thread */
if (handlesChecked < vhSonicProcesses.size()) for (handlesChecked; handlesChecked < vhSonicProcesses.size(); ++handlesChecked) CloseHandle(vhSonicProcesses[handlesChecked]); return EXIT_SUCCESS; } }); /* Awaiting end of threads (the checker thread terminates the receiver) */ handleChecker.join(); /* Cleanup before returning handle */ CloseVectorHandles(vhParentProcesses); CloseHandle(ioPort); CloseHandle(jobObject); CloseHandle(hsNewHandle); return hTarget; }

Proof of concept program & demo

To test the bypass and verify that your game and its anti-cheat are vulnerable.

Source of the PoC:

#include
#include
#include
#include "hSonicBypass.hpp"

using namespace std;

wstring str2wstr(string in) { wstring out; out.assign(in.begin(), in.end()); return out; }
string wstr2str(wstring in) { string out; out.assign(in.begin(), in.end()); return out; }

int main() {
cout << "[ ## ] hSonic Bypass demo - By harakirinox, JYam, and mistree @ UnknownCheats.me" << endl; cout << "[ ?? ] Internals: Outruns kernel notification routines with job objects (using method from PcaSvc)" << endl; cout << endl; cout << "[ !! ] Requires to know the parent of target process (e.g. Steam.exe for steam games, explorer for some others ...)" << endl; cout << "[ !! ] Use Process Hacker or Process Explorer to find parent processes easily" << endl; cout << endl; /* Prompts user for the process name to get a handle on and its parent */ string processName = ""; cout << "[ -- ] Process name to get a handle on (e.g. Game.exe):" << endl; cout << "[ >> ] ";
getline(cin, processName);
string parentName = "";
cout << "[ -- ] Enter parent name (e.g. Steam.exe, leave blank to use explorer.exe):" << endl; cout << "[ >> ] ";
getline(cin, parentName);
cout << "[ !! ] Ready to get handle, please start target program." << endl; wstring wProcessName = str2wstr(processName); wstring wParentName = str2wstr(parentName); HANDLE hGame = GetSonicHandle(wProcessName, wParentName); //HANDLE hGame = GetSonicHandle(L"Game.exe", L"Steam.exe"); // Only use this in your cheat cout << "[ :) ] Got Handle ID: 0x" << hex << hGame << endl; cout << "[ .. ] Press ENTER to exit when you are done verifying handle (e.g. with Process Hacker or Process Explorer)" << endl; getchar(); return EXIT_SUCCESS; }