Skip to content

Commit

Permalink
Thread List Added...
Browse files Browse the repository at this point in the history
I've added support for opening thread, thread context, freezing thread & resuming threads. but something in Cheatengine is relying on OpenThread, not sure yet what. I'll come back to this later once i have some time again.
  • Loading branch information
Metick committed Apr 1, 2024
1 parent 5a49f82 commit ab2d3a7
Show file tree
Hide file tree
Showing 7 changed files with 276 additions and 3 deletions.
2 changes: 1 addition & 1 deletion DMALibrary/Memory/Memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ class Memory
*/
bool Read(uintptr_t address, void* buffer, size_t size) const;
bool Read(uintptr_t address, void* buffer, size_t size, int pid) const;
bool Read(uintptr_t address, void* buffer, size_t size, PDWORD read) const;;
bool Read(uintptr_t address, void* buffer, size_t size, PDWORD read) const;

/**
* brief Reads memory from the process using a template
Expand Down
1 change: 1 addition & 0 deletions plugin/CheatEngine/cepluginsdk.h
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ typedef struct _ExportedFunctions
PVOID Module32Next; // ...
PVOID Heap32ListFirst; // ...
PVOID Heap32ListNext; // ...

//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

//advanced for delphi 7 enterprise dll programmers only
Expand Down
17 changes: 17 additions & 0 deletions plugin/Hooks/hooks.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@

namespace Hooks
{
enum KPROCESSOR_MODE
{
KernelMode,
UserMode,
};

//Mem.cpp
extern SIZE_T hk_virtual_query(HANDLE hProcess, LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength);
extern bool hk_write(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesRead);
Expand All @@ -18,4 +24,15 @@ namespace Hooks
//Modules.cpp
extern BOOL hk_module_32_next(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
extern BOOL hk_module_32_first(HANDLE hSnapshot, LPMODULEENTRY32 lpme);

//Threads.cpp
extern BOOL hk_thread_32_next(HANDLE hSnapshot, LPTHREADENTRY32 lpte);
extern BOOL hk_thread_32_first(HANDLE hSnapshot, LPTHREADENTRY32 lpte);

//Something still relies on OpenThread making this not working properly... gotto figure out what it is and implement it.
extern HANDLE hk_open_thread(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId);
extern BOOL hk_get_thread_context(HANDLE hThread, PCONTEXT pContext);
extern DWORD hk_resume_thread(HANDLE hThread);
extern DWORD hk_suspend_thread(HANDLE hThread);
extern BOOL hk_set_thread_context(HANDLE hThread, PCONTEXT pContext);
}
222 changes: 222 additions & 0 deletions plugin/Hooks/threads.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
#include "hooks.h"
#include "DMALibrary/Memory/Memory.h"

namespace Hooks
{
typedef NTSTATUS (__stdcall*PsLookupThreadByThreadId)(HANDLE ThreadId, /*PETHREAD*/void* Thread);
typedef NTSTATUS (__stdcall*PsGetContextThread)(/*PETHREAD*/void* Thread, PCONTEXT Context, KPROCESSOR_MODE PreviousMode);
typedef NTSTATUS (__stdcall*PsSetContextThread)(/*PETHREAD*/void* Thread, PCONTEXT Context, KPROCESSOR_MODE PreviousMode);
typedef NTSTATUS (__stdcall*PsSuspendThread)(/*PETHREAD*/void* Thread, PULONG PreviousSuspendCount);
typedef NTSTATUS (__stdcall*PsResumeThread)(/*PETHREAD*/void* Thread, PULONG PreviousSuspendCount);

template <typename T, typename... Args>
auto SysCall(uint64_t function, Args&&... args) -> std::enable_if_t<!std::is_void<std::invoke_result_t<T, Args...>>::value, std::invoke_result_t<T, Args...>>
{
uintptr_t ntos_shutdown = mem.GetExportTableAddress("NtShutdownSystem", "csrss.exe", "ntoskrnl.exe");
uint64_t nt_shutdown = (uint64_t)GetProcAddress(LoadLibraryA("ntdll.dll"), "NtShutdownSystem");

if (!function)
{
printf("[!] Failed to get function address\n");
return { };
}

if (ntos_shutdown == 0 || nt_shutdown == 0)
{
printf("[!] Failed to get NtShutdownSystem address\n");
return { };
}

BYTE jmp_bytes[14] = {
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp [RIP+0x00000000]
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // RIP value
};
*reinterpret_cast<uint64_t*>(jmp_bytes + 6) = function;

// Save original bytes
BYTE orig_bytes[sizeof(jmp_bytes)];
if (!mem.Read(ntos_shutdown, (PBYTE)orig_bytes, sizeof(orig_bytes), 4))
return { };

if (!mem.Write(ntos_shutdown, jmp_bytes, sizeof(jmp_bytes), 4))
{
printf("[!] Failed to write memory at 0x%p\n", ntos_shutdown);
return { };
}

using ResultType = decltype(std::invoke(reinterpret_cast<T>(nt_shutdown), std::forward<Args>(args)...));
ResultType buffer { };
buffer = std::invoke(reinterpret_cast<T>(nt_shutdown), std::forward<Args>(args)...);

//Restore function
if (!mem.Write(ntos_shutdown, orig_bytes, sizeof(orig_bytes), 4))
printf("[!] Failed to write memory at 0x%p\n", ntos_shutdown);

return buffer;
}

NTSTATUS fnPsLookupThreadByThreadId(HANDLE threadId, void* thread)
{
auto ptr = mem.GetExportTableAddress("PsLookupThreadByThreadId", "csrss.exe", "ntoskrnl.exe");
if (ptr > 0)
return SysCall<PsLookupThreadByThreadId>(ptr, threadId, thread);
return 1;
}

NTSTATUS fnPsGetContextThread(void* thread, PCONTEXT context, KPROCESSOR_MODE previousMode)
{
auto ptr = mem.GetExportTableAddress("PsGetContextThread", "csrss.exe", "ntoskrnl.exe");
if (ptr > 0)
return SysCall<PsGetContextThread>(ptr, thread, context, previousMode);
return 1;
}

NTSTATUS fnPsSetContextThread(void* thread, PCONTEXT context, KPROCESSOR_MODE previousMode)
{
auto ptr = mem.GetExportTableAddress("PsSetContextThread", "csrss.exe", "ntoskrnl.exe");
if (ptr > 0)
return SysCall<PsSetContextThread>(ptr, thread, context, previousMode);
return 1;
}

NTSTATUS fnPsSuspendThread(void* thread, PULONG previousSuspendCount)
{
static uintptr_t ptr = 0;
if (!ptr)
{
PVMMDLL_MAP_MODULEENTRY module_info;
auto result = VMMDLL_Map_GetModuleFromNameW(mem.vHandle, 4, (LPWSTR)L"ntoskrnl.exe", &module_info, VMMDLL_MODULE_FLAG_NORMAL);
if (result)
{
char str[32];
ZeroMemory(str, 32);
if (!VMMDLL_PdbLoad(mem.vHandle, 4, module_info->vaBase, str))
{
printf("failed to load pdb\n");
return 1;
}

if (!VMMDLL_PdbSymbolAddress(mem.vHandle, str, (LPSTR)"PsSuspendThread", &ptr))
{
printf("failed to find PsSuspendThread\n");
return 1;
}
if (ptr > 0)
return SysCall<PsSuspendThread>(ptr, thread, previousSuspendCount);
}
}
if (ptr > 0)
return SysCall<PsSuspendThread>(ptr, thread, previousSuspendCount);
return 1;
}

NTSTATUS fnPsResumeThread(void* thread, PULONG previousSuspendCount)
{
static uintptr_t ptr = 0;
if (!ptr)
{
PVMMDLL_MAP_MODULEENTRY module_info;
auto result = VMMDLL_Map_GetModuleFromNameW(mem.vHandle, 4, (LPWSTR)L"ntoskrnl.exe", &module_info, VMMDLL_MODULE_FLAG_NORMAL);
if (result)
{
char str[32];
ZeroMemory(str, 32);
if (!VMMDLL_PdbLoad(mem.vHandle, 4, module_info->vaBase, str))
{
printf("failed to load pdb\n");
return 1;
}

if (!VMMDLL_PdbSymbolAddress(mem.vHandle, str, (LPSTR)"PsResumeThread", &ptr))
{
printf("failed to find PsResumeThread\n");
return 1;
}
if (ptr > 0)
return SysCall<PsResumeThread>(ptr, thread, previousSuspendCount);
}
}
if (ptr > 0)
return SysCall<PsResumeThread>(ptr, thread, previousSuspendCount);
return 1;
}

HANDLE hk_open_thread(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId)
{
HANDLE hThread = 0;
printf("dwThreadId: %d\n", dwThreadId);
NTSTATUS status = fnPsLookupThreadByThreadId((HANDLE)dwThreadId, &hThread);
printf("Created Thread: %p\n", hThread);
if (status == 0)
return hThread;
return nullptr;
}

BOOL hk_get_thread_context(HANDLE hThread, PCONTEXT pContext)
{
return (fnPsGetContextThread(hThread, pContext, UserMode) == 0);
}

BOOL hk_set_thread_context(HANDLE hThread, PCONTEXT pContext)
{
printf("set_thread_context\n");
printf("hThread: %p\n", hThread);
NTSTATUS status = fnPsSetContextThread(hThread, pContext, UserMode);
printf("status: %d\n", status);
return (status == 0);
}

DWORD hk_suspend_thread(HANDLE hThread)
{
ULONG suspendCount = 0;
NTSTATUS status = fnPsSuspendThread(hThread, &suspendCount);
if (status == 0)
return suspendCount;
return -1;
}

DWORD hk_resume_thread(HANDLE hThread)
{
ULONG suspendCount = 0;
NTSTATUS status = fnPsResumeThread(hThread, &suspendCount);
if (status == 0)
return suspendCount;

return -1;
}

PVMMDLL_MAP_THREAD thread_info = NULL;
DWORD current_thread = 0;

BOOL hk_thread_32_first(HANDLE hSnapshot, LPTHREADENTRY32 lpte)
{
thread_info = NULL;
current_thread = 0;
if (!VMMDLL_Map_GetThread(mem.vHandle, mem.current_process.PID, &thread_info))
return false;

lpte->dwSize = sizeof(LPTHREADENTRY32);
lpte->th32ThreadID = thread_info->pMap[current_thread].dwTID;
lpte->th32OwnerProcessID = thread_info->pMap[current_thread].dwPID;
lpte->tpBasePri = thread_info->pMap[current_thread].bBasePriority;
lpte->tpDeltaPri = thread_info->pMap[current_thread].bPriority;
return true;
}

BOOL hk_thread_32_next(HANDLE hSnapshot, LPTHREADENTRY32 lpte)
{
if (current_thread >= thread_info->cMap)
{
current_thread = 0;
return false;
}

lpte->dwSize = sizeof(LPTHREADENTRY32);
lpte->th32ThreadID = thread_info->pMap[current_thread].dwTID;
lpte->th32OwnerProcessID = thread_info->pMap[current_thread].dwPID;
lpte->tpBasePri = thread_info->pMap[current_thread].bBasePriority;
lpte->tpDeltaPri = thread_info->pMap[current_thread].bPriority;
current_thread++;
return true;
}
}
35 changes: 33 additions & 2 deletions plugin/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,17 @@ BOOL __stdcall CEPlugin_InitializePlugin(PExportedFunctions ef, int pluginid)
auto process_32_next = ef->Process32Next;
auto module_32_first = ef->Module32First;
auto module_32_next = ef->Module32Next;
auto thread_32_first = ef->Thread32First;
auto thread_32_next = ef->Thread32Next;

/*auto open_thread = ef->OpenThread;
auto get_thread_context = ef->GetThreadContext;
auto set_thread_context = ef->SetThreadContext;
auto suspend_thread = ef->SuspendThread;
auto resume_thread = ef->ResumeThread;*/

printf("Initialize DMA in advance (Required for Set Thread Context)\n");
mem.Init("", true);

printf("Hooking Open Process 0x%p\n", open_process);
*(uintptr_t*)(open_process) = (uintptr_t)&Hooks::hk_open_process;
Expand Down Expand Up @@ -114,8 +125,28 @@ BOOL __stdcall CEPlugin_InitializePlugin(PExportedFunctions ef, int pluginid)
printf("Hooking Module32Next 0x%p\n", module_32_next);
*(uintptr_t*)(module_32_next) = (uintptr_t)&Hooks::hk_module_32_next;

printf("Initialize DMA in advance\n");
mem.Init("", true);
printf("Hooking Thread32First 0x%p\n", thread_32_first);
*(uintptr_t*)(thread_32_first) = (uintptr_t)&Hooks::hk_thread_32_first;

printf("Hooking Thread32Next 0x%p\n", thread_32_next);
*(uintptr_t*)(thread_32_next) = (uintptr_t)&Hooks::hk_thread_32_next;

//Check comment in Hooks.h for why this is commented out.
/*
printf("Hooking OpenThread 0x%p\n", open_thread);
*(uintptr_t*)(open_thread) = (uintptr_t)&Hooks::hk_open_thread;
printf("Hooking GetThreadContext 0x%p\n", get_thread_context);
*(uintptr_t*)(get_thread_context) = (uintptr_t)&Hooks::hk_get_thread_context;
printf("Hooking SetThreadContext 0x%p\n", set_thread_context);
*(uintptr_t*)(set_thread_context) = (uintptr_t)&Hooks::hk_set_thread_context;
printf("Hooking SuspendThread 0x%p\n", suspend_thread);
*(uintptr_t*)(suspend_thread) = (uintptr_t)&Hooks::hk_suspend_thread;
printf("Hooking ResumeThread 0x%p\n", resume_thread);
*(uintptr_t*)(resume_thread) = (uintptr_t)&Hooks::hk_resume_thread;*/

//TODO: fix this, this doesn't seem to work for me, i don't know why.
/*init4.callbackroutine = PointersReassigned;
Expand Down
1 change: 1 addition & 0 deletions plugin/plugin.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@
<ClCompile Include="Hooks\mem.cpp" />
<ClCompile Include="Hooks\module.cpp" />
<ClCompile Include="Hooks\process.cpp" />
<ClCompile Include="Hooks\threads.cpp" />
<ClCompile Include="main.c" />
</ItemGroup>
<ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions plugin/plugin.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<ClCompile Include="Hooks\mem.cpp" />
<ClCompile Include="Hooks\process.cpp" />
<ClCompile Include="Hooks\module.cpp" />
<ClCompile Include="Hooks\threads.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Memory\memmy.h" />
Expand Down

0 comments on commit ab2d3a7

Please sign in to comment.