delete unused files and start cleaning up code
This commit is contained in:
parent
6b63b91326
commit
38a57eb480
@ -75,9 +75,8 @@ void ProcessWindow::RefreshProcess()
|
||||
void ProcessWindow::AttachProcess()
|
||||
{
|
||||
DWORD pid = GetSelectedPID();
|
||||
if (Host_InjectByPID(pid))
|
||||
if (InjectProcessById(pid))
|
||||
{
|
||||
Host_HijackProcess(pid);
|
||||
RefreshThreadWithPID(pid, true);
|
||||
}
|
||||
}
|
||||
@ -85,7 +84,7 @@ void ProcessWindow::AttachProcess()
|
||||
void ProcessWindow::DetachProcess()
|
||||
{
|
||||
DWORD pid = GetSelectedPID();
|
||||
if (Host_ActiveDetachProcess(pid) == 0)
|
||||
if (DetachProcessById(pid) == 0)
|
||||
RefreshThreadWithPID(pid, false);
|
||||
}
|
||||
|
||||
|
@ -156,7 +156,7 @@ DWORD WINAPI InjectThread(LPVOID lpThreadParameter)
|
||||
Sleep(inject_delay);
|
||||
if (man == NULL)
|
||||
return 0;
|
||||
DWORD status = Host_InjectByPID(pid);
|
||||
DWORD status = InjectProcessById(pid);
|
||||
if (!auto_insert)
|
||||
return status;
|
||||
if (status == -1)
|
||||
|
@ -32,17 +32,10 @@ DWORD ProcessCommand(const std::wstring& cmd, DWORD pid)
|
||||
using std::regex_match;
|
||||
std::match_results<std::wstring::const_iterator> m;
|
||||
|
||||
if (regex_match(cmd, m, wregex(L"/pn(.+)", wregex::icase)))
|
||||
{
|
||||
pid = Host_GetPIDByName(m[1].str().c_str());
|
||||
if (pid == 0)
|
||||
return 0;
|
||||
Host_InjectByPID(pid);
|
||||
}
|
||||
else if (regex_match(cmd, m, wregex(L"/p(\\d+)", wregex::icase)))
|
||||
if (regex_match(cmd, m, wregex(L"/p(\\d+)", wregex::icase)))
|
||||
{
|
||||
pid = std::stoul(m[1].str());
|
||||
Host_InjectByPID(pid);
|
||||
InjectProcessById(pid);
|
||||
}
|
||||
else if (regex_match(cmd, m, wregex(L"/h(.+)", wregex::icase)))
|
||||
{
|
||||
|
@ -246,7 +246,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
if (!IthInitSystemService())
|
||||
TerminateProcess(GetCurrentProcess(), 0);
|
||||
CreateMutex(NULL, TRUE, L"ITH_MAIN_RUNNING");
|
||||
if (Host_Open())
|
||||
if (OpenHost())
|
||||
{
|
||||
SetUnhandledExceptionFilter(UnhandledExcept);
|
||||
Host_GetHookManager(&man);
|
||||
@ -280,7 +280,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
{
|
||||
FindITH();
|
||||
}
|
||||
Host_Close();
|
||||
CloseHost();
|
||||
IthCloseSystemService();
|
||||
TerminateProcess(GetCurrentProcess(), 0);
|
||||
}
|
||||
|
@ -753,7 +753,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
man->RegisterProcessNewHookCallback(RefreshProfileOnNewHook);
|
||||
man->RegisterAddRemoveLinkCallback(AddRemoveLink);
|
||||
man->RegisterConsoleCallback(ConsoleOutput);
|
||||
Host_Start();
|
||||
StartHost();
|
||||
{
|
||||
static const WCHAR program_name[] = L"Interactive Text Hooker";
|
||||
//static const WCHAR program_version[] = L"3.0";
|
||||
|
@ -246,7 +246,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
if (!IthInitSystemService())
|
||||
TerminateProcess(GetCurrentProcess(), 0);
|
||||
CreateMutex(NULL, TRUE, L"ITH_MAIN_RUNNING");
|
||||
if (Host_Open())
|
||||
if (OpenHost())
|
||||
{
|
||||
SetUnhandledExceptionFilter(UnhandledExcept);
|
||||
Host_GetHookManager(&man);
|
||||
@ -280,7 +280,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
{
|
||||
FindITH();
|
||||
}
|
||||
Host_Close();
|
||||
CloseHost();
|
||||
IthCloseSystemService();
|
||||
TerminateProcess(GetCurrentProcess(), 0);
|
||||
}
|
||||
|
@ -4,6 +4,11 @@
|
||||
// ccmacro.h
|
||||
// 12/9/2011 jichi
|
||||
|
||||
#include <string>
|
||||
|
||||
#define CONCAT_STR_NUM(_str, _num) (std::wstring(_str) + std::to_wstring(_num)).c_str()
|
||||
#define CONCAT_STR_STR(_str1, _str2) (std::wstring(_str1) + std::wstring(_str2)).c_str()
|
||||
|
||||
#define CC_UNUSED(_var) (void)(_var)
|
||||
#define CC_NOP CC_UNUSED(0)
|
||||
|
||||
|
@ -19,23 +19,11 @@ set(vnrhost_src
|
||||
host.cc
|
||||
pipe.cc
|
||||
textthread.cc
|
||||
${PROJECT_SOURCE_DIR}/winmaker/winmaker.h
|
||||
${PROJECT_SOURCE_DIR}/winmaker/winmaker.cc
|
||||
${PROJECT_SOURCE_DIR}/winmutex/winmutex.h
|
||||
# ${PROJECT_SOURCE_DIR}/wintimer/wintimer.h
|
||||
# ${PROJECT_SOURCE_DIR}/wintimer/wintimer.cc
|
||||
# ${PROJECT_SOURCE_DIR}/wintimer/wintimerbase.cc
|
||||
# ${PROJECT_SOURCE_DIR}/wintimer/wintimerbase.h
|
||||
${PROJECT_SOURCE_DIR}/windbg/windbg.h
|
||||
${PROJECT_SOURCE_DIR}/windbg/windbg_p.h
|
||||
${PROJECT_SOURCE_DIR}/windbg/inject.h
|
||||
${PROJECT_SOURCE_DIR}/windbg/inject.cc
|
||||
${PROJECT_SOURCE_DIR}/windbg/hijack.h
|
||||
${PROJECT_SOURCE_DIR}/windbg/hijack.cc
|
||||
${PROJECT_SOURCE_DIR}/windbg/util.h
|
||||
# ${PROJECT_SOURCE_DIR}/windbg/util.cc
|
||||
${PROJECT_SOURCE_DIR}/windbg/unload.h
|
||||
${PROJECT_SOURCE_DIR}/windbg/unload.cc
|
||||
${PROJECT_SOURCE_DIR}/sakurakit/skdebug.h
|
||||
)
|
||||
|
||||
|
@ -9,8 +9,6 @@
|
||||
#define IHFAPI __stdcall
|
||||
#ifdef IHF
|
||||
# define IHFSERVICE __declspec(dllexport)
|
||||
#else
|
||||
# define IHFSERVICE __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
// EOF
|
||||
|
@ -16,8 +16,6 @@
|
||||
#include "vnrhook/include/defs.h"
|
||||
#include "vnrhook/include/types.h"
|
||||
#include "ithsys/ithsys.h"
|
||||
#include "windbg/inject.h"
|
||||
#include "winmaker/winmaker.h"
|
||||
#include "ccutil/ccmacro.h"
|
||||
#include <commctrl.h>
|
||||
|
||||
@ -28,446 +26,217 @@
|
||||
#define DEBUG "vnrhost/host.cc"
|
||||
#include "sakurakit/skdebug.h"
|
||||
|
||||
namespace { // unnamed
|
||||
namespace
|
||||
{ // unnamed
|
||||
|
||||
//enum { HOOK_TIMEOUT = -50000000 }; // in nanoseconds = 5 seconds
|
||||
|
||||
CRITICAL_SECTION cs;
|
||||
//WCHAR exist[] = ITH_PIPEEXISTS_EVENT;
|
||||
//WCHAR mutex[] = L"ITH_RUNNING";
|
||||
//WCHAR EngineName[] = ITH_ENGINE_DLL;
|
||||
//WCHAR EngineNameXp[] = ITH_ENGINE_XP_DLL;
|
||||
//WCHAR DllName[] = ITH_CLIENT_DLL;
|
||||
//WCHAR DllNameXp[] = ITH_CLIENT_XP_DLL;
|
||||
HANDLE hServerMutex; // jichi 9/28/2013: used to guard pipe
|
||||
HANDLE hHookMutex; // jichi 9/28/2013: used to guard hook modification
|
||||
CRITICAL_SECTION hostCs;
|
||||
//WCHAR exist[] = ITH_PIPEEXISTS_EVENT;
|
||||
//WCHAR mutex[] = L"ITH_RUNNING";
|
||||
//WCHAR EngineName[] = ITH_ENGINE_DLL;
|
||||
//WCHAR EngineNameXp[] = ITH_ENGINE_XP_DLL;
|
||||
//WCHAR DllName[] = ITH_CLIENT_DLL;
|
||||
//WCHAR DllNameXp[] = ITH_CLIENT_XP_DLL;
|
||||
HANDLE preventDuplicationMutex; // jichi 9/28/2013: used to guard pipe
|
||||
HANDLE hookMutex; // jichi 9/28/2013: used to guard hook modification
|
||||
} // unnamed namespace
|
||||
|
||||
//extern LPWSTR current_dir;
|
||||
extern CRITICAL_SECTION detach_cs;
|
||||
extern CRITICAL_SECTION detachCs;
|
||||
|
||||
Settings *settings;
|
||||
HWND hMainWnd;
|
||||
HANDLE hPipeExist;
|
||||
HWND dummyWindow;
|
||||
HANDLE pipeExistsEvent;
|
||||
BOOL running;
|
||||
|
||||
#define ITH_SYNC_HOOK IthMutexLocker locker(::hHookMutex)
|
||||
#define ITH_SYNC_HOOK IthMutexLocker locker(::hookMutex)
|
||||
|
||||
namespace { // unnamed
|
||||
namespace
|
||||
{ // unnamed
|
||||
|
||||
void GetDebugPriv()
|
||||
{
|
||||
HANDLE hToken;
|
||||
DWORD dwRet;
|
||||
NTSTATUS status;
|
||||
void GetDebugPrivileges()
|
||||
{
|
||||
HANDLE processToken;
|
||||
TOKEN_PRIVILEGES Privileges = { 1, {0x14, 0, SE_PRIVILEGE_ENABLED} };
|
||||
|
||||
TOKEN_PRIVILEGES Privileges = {1,{0x14,0,SE_PRIVILEGE_ENABLED}};
|
||||
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &processToken);
|
||||
AdjustTokenPrivileges(processToken, FALSE, &Privileges, 0, nullptr, nullptr);
|
||||
CloseHandle(processToken);
|
||||
}
|
||||
|
||||
NtOpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
|
||||
|
||||
status = NtAdjustPrivilegesToken(hToken, 0, &Privileges, sizeof(Privileges), 0, &dwRet);
|
||||
//if (STATUS_SUCCESS == status)
|
||||
//{
|
||||
// admin = 1;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// WCHAR buffer[0x10];
|
||||
// swprintf(buffer, L"%.8X",status);
|
||||
// MessageBox(0, NotAdmin, buffer, 0);
|
||||
//}
|
||||
NtClose(hToken);
|
||||
}
|
||||
|
||||
bool sendCommand(HANDLE hCmd, HostCommandType cmd)
|
||||
{
|
||||
IO_STATUS_BLOCK ios;
|
||||
//SendParam sp = {};
|
||||
//sp.type = cmd;
|
||||
DWORD data = cmd;
|
||||
return hCmd && NT_SUCCESS(NtWriteFile(hCmd, 0,0,0, &ios, &data, sizeof(data), 0,0));
|
||||
}
|
||||
|
||||
// jichi 9/22/2013: Change current directory to the same as main module path
|
||||
// Otherwise NtFile* would not work for files with relative paths.
|
||||
//BOOL ChangeCurrentDirectory()
|
||||
//{
|
||||
// if (const wchar_t *path = GetMainModulePath()) // path to VNR's python exe
|
||||
// if (const wchar_t *base = wcsrchr(path, L'\\')) {
|
||||
// size_t len = base - path;
|
||||
// if (len < MAX_PATH) {
|
||||
// wchar_t buf[MAX_PATH];
|
||||
// wcsncpy(buf, path, len);
|
||||
// buf[len] = 0;
|
||||
// return SetCurrentDirectoryW(buf);
|
||||
// }
|
||||
// }
|
||||
// return FALSE;
|
||||
//}
|
||||
|
||||
#if 0
|
||||
bool injectUsingWin32Api(LPCWSTR path, HANDLE hProc)
|
||||
{ return WinDbg::injectDllW(path, 0, hProc); }
|
||||
|
||||
bool ejectUsingWin32Api(HANDLE hModule, HANDLE hProc)
|
||||
{ return WinDbg::ejectDll(hModule, hProc); }
|
||||
|
||||
// The original inject logic in ITH
|
||||
bool injectUsingNTApi(LPCWSTR path, HANDLE hProc)
|
||||
{
|
||||
LPVOID lpvAllocAddr = 0;
|
||||
DWORD dwWrite = 0x1000; //, len = 0;
|
||||
//if (IthIsWine())
|
||||
// lpvAllocAddr = VirtualAllocEx(hProc, nullptr, dwWrite, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
|
||||
//else
|
||||
NtAllocateVirtualMemory(hProc, &lpvAllocAddr, 0, &dwWrite, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
|
||||
if (!lpvAllocAddr)
|
||||
return false;
|
||||
|
||||
CheckThreadStart();
|
||||
|
||||
//Copy module path into address space of target process.
|
||||
//if (IthIsWine())
|
||||
// WriteProcessMemory(hProc, lpvAllocAddr, path, MAX_PATH << 1, &dwWrite);
|
||||
//else
|
||||
NtWriteVirtualMemory(hProc, lpvAllocAddr, (LPVOID)path, MAX_PATH << 1, &dwWrite);
|
||||
HANDLE hTH = IthCreateThread(LoadLibraryW, (DWORD)lpvAllocAddr, hProc);
|
||||
if (hTH == 0 || hTH == INVALID_HANDLE_VALUE) {
|
||||
DOUT("ERROR: failed to create remote cli thread");
|
||||
//ConsoleOutput(ErrorRemoteThread);
|
||||
return false;
|
||||
}
|
||||
// jichi 9/28/2013: no wait as it will not blocked
|
||||
NtWaitForSingleObject(hTH, 0, nullptr);
|
||||
THREAD_BASIC_INFORMATION info;
|
||||
NtQueryInformationThread(hTH, ThreadBasicInformation, &info, sizeof(info), &dwWrite);
|
||||
NtClose(hTH);
|
||||
|
||||
// jichi 10/19/2014: Disable inject the second dll
|
||||
//if (info.ExitStatus) {
|
||||
// //IthCoolDown();
|
||||
// wcscpy(p, engine);
|
||||
// //if (IthIsWine())
|
||||
// // WriteProcessMemory(hProc, lpvAllocAddr, path, MAX_PATH << 1, &dwWrite);
|
||||
// //else
|
||||
// NtWriteVirtualMemory(hProc, lpvAllocAddr, path, MAX_PATH << 1, &dwWrite);
|
||||
// hTH = IthCreateThread(LoadLibraryW, (DWORD)lpvAllocAddr, hProc);
|
||||
// if (hTH == 0 || hTH == INVALID_HANDLE_VALUE) {
|
||||
// //ConsoleOutput(ErrorRemoteThread);
|
||||
// ConsoleOutput("vnrhost:inject: ERROR: failed to create remote eng thread");
|
||||
// return error;
|
||||
// }
|
||||
//
|
||||
// // jichi 9/28/2013: no wait as it will not blocked
|
||||
// NtWaitForSingleObject(hTH, 0, nullptr);
|
||||
// NtClose(hTH);
|
||||
//}
|
||||
|
||||
dwWrite = 0;
|
||||
//if (IthIsWine())
|
||||
// VirtualFreeEx(hProc, lpvAllocAddr, dwWrite, MEM_RELEASE);
|
||||
//else
|
||||
NtFreeVirtualMemory(hProc, &lpvAllocAddr, &dwWrite, MEM_RELEASE);
|
||||
return info.ExitStatus != -1;
|
||||
}
|
||||
|
||||
bool ejectUsingNTApi(HANDLE hModule, HANDLE hProc)
|
||||
{
|
||||
//IthCoolDown();
|
||||
//#ifdef ITH_WINE // Nt series crash on wine
|
||||
// hThread = IthCreateThread(FreeLibrary, engine, hProc);
|
||||
//#else
|
||||
HANDLE hThread = IthCreateThread(LdrUnloadDll, module, hProc);
|
||||
//#endif // ITH_WINE
|
||||
if (hThread == 0 || hThread == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
// jichi 10/22/2013: Timeout might crash vnrsrv
|
||||
//NtWaitForSingleObject(hThread, 0, (PLARGE_INTEGER)&timeout);
|
||||
NtWaitForSingleObject(hThread, 0, nullptr);
|
||||
//man->UnlockHookman();
|
||||
THREAD_BASIC_INFORMATION info;
|
||||
NtQueryInformationThread(hThread, ThreadBasicInformation, &info, sizeof(info), 0);
|
||||
NtClose(hThread);
|
||||
NtSetEvent(hPipeExist, 0);
|
||||
FreeThreadStart(hProc);
|
||||
return info.ExitStatus;
|
||||
}
|
||||
#endif // 0
|
||||
|
||||
bool Inject(HANDLE hProc)
|
||||
{
|
||||
//LPWSTR dllname = (IthIsWindowsXp() && !IthIsWine()) ? DllNameXp : DllName;
|
||||
//LPCWSTR dllname = ITH_USE_XP_DLLS ? ITH_DLL_XP : ITH_DLL;
|
||||
//LPCWSTR dllname = ITH_DLL;
|
||||
//if (!IthCheckFile(dllname))
|
||||
// return error;
|
||||
wchar_t path[MAX_PATH];
|
||||
size_t len = IthGetCurrentModulePath(path, MAX_PATH);
|
||||
if (!len)
|
||||
return false;
|
||||
|
||||
wchar_t *p;
|
||||
for (p = path + len; *p != L'\\'; p--);
|
||||
p++; // ending with L"\\"
|
||||
|
||||
//LPCWSTR mp = GetMainModulePath();
|
||||
//len = wcslen(mp);
|
||||
//memcpy(path, mp, len << 1);
|
||||
//memset(path + len, 0, (MAX_PATH - len) << 1);
|
||||
//LPWSTR p;
|
||||
//for (p = path + len; *p != L'\\'; p--); // Always a \ after drive letter.
|
||||
//p++;
|
||||
::wcscpy(p, ITH_DLL);
|
||||
|
||||
return WinDbg::injectDllW(path, 0, hProc);
|
||||
//if (IthIsWindowsXp()) // && !IthIsWine())
|
||||
// return injectUsingWin32Api(path, hProc);
|
||||
//else
|
||||
// return injectUsingNTApi(path, hProc);
|
||||
}
|
||||
bool sendCommand(HANDLE commandPipe, HostCommandType command)
|
||||
{
|
||||
DWORD unused;
|
||||
return commandPipe && WriteFile(commandPipe, &command, sizeof(command), &unused, nullptr);
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
void CreateNewPipe();
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID unused)
|
||||
{
|
||||
CC_UNUSED(lpvReserved);
|
||||
switch (fdwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
LdrDisableThreadCalloutsForDll(hinstDLL);
|
||||
InitializeCriticalSection(&::cs);
|
||||
IthInitSystemService();
|
||||
GetDebugPriv();
|
||||
// jichi 12/20/2013: Since I already have a GUI, I don't have to InitCommonControls()
|
||||
//Used by timers.
|
||||
InitCommonControls();
|
||||
// jichi 8/24/2013: Create hidden window so that ITH can access timer and events
|
||||
hMainWnd = CreateWindowW(L"Button", L"InternalWindow", 0, 0, 0, 0, 0, 0, 0, hinstDLL, 0);
|
||||
//wm_register_hidden_class("vnrsrv.class");
|
||||
//hMainWnd = (HWND)wm_create_hidden_window("vnrsrv", "Button", hinstDLL);
|
||||
//ChangeCurrentDirectory();
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
if (::running)
|
||||
Host_Close();
|
||||
DeleteCriticalSection(&::cs);
|
||||
IthCloseSystemService();
|
||||
//wm_destroy_window(hMainWnd);
|
||||
DestroyWindow(hMainWnd);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
HANDLE IthOpenPipe(LPWSTR name, ACCESS_MASK direction)
|
||||
{
|
||||
UNICODE_STRING us;
|
||||
RtlInitUnicodeString(&us, name);
|
||||
SECURITY_DESCRIPTOR sd = {1};
|
||||
OBJECT_ATTRIBUTES oa = {sizeof(oa), 0, &us, OBJ_CASE_INSENSITIVE, &sd, 0};
|
||||
HANDLE hFile;
|
||||
IO_STATUS_BLOCK isb;
|
||||
if (NT_SUCCESS(NtCreateFile(&hFile, direction, &oa, &isb, 0, 0, FILE_SHARE_READ, FILE_OPEN, 0, 0, 0)))
|
||||
return hFile;
|
||||
else
|
||||
return INVALID_HANDLE_VALUE;
|
||||
switch (fdwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
DisableThreadLibraryCalls(hinstDLL);
|
||||
InitializeCriticalSection(&::hostCs);
|
||||
IthInitSystemService();
|
||||
GetDebugPrivileges();
|
||||
// jichi 12/20/2013: Since I already have a GUI, I don't have to InitCommonControls()
|
||||
//Used by timers.
|
||||
InitCommonControls();
|
||||
// jichi 8/24/2013: Create hidden window so that ITH can access timer and events
|
||||
dummyWindow = CreateWindowW(L"Button", L"InternalWindow", 0, 0, 0, 0, 0, 0, 0, hinstDLL, 0);
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
if (::running)
|
||||
CloseHost();
|
||||
DeleteCriticalSection(&::hostCs);
|
||||
IthCloseSystemService();
|
||||
DestroyWindow(dummyWindow);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
enum { IHS_SIZE = 0x80 };
|
||||
enum { IHS_BUFF_SIZE = IHS_SIZE - sizeof(HookParam) };
|
||||
enum { IHS_BUFF_SIZE = IHS_SIZE - sizeof(HookParam) };
|
||||
|
||||
struct InsertHookStruct
|
||||
{
|
||||
SendParam sp;
|
||||
BYTE name_buffer[IHS_SIZE];
|
||||
SendParam sp;
|
||||
BYTE name_buffer[IHS_SIZE];
|
||||
};
|
||||
|
||||
IHFSERVICE void IHFAPI Host_Init()
|
||||
IHFSERVICE bool IHFAPI OpenHost()
|
||||
{
|
||||
InitializeCriticalSection(&::cs);
|
||||
GetDebugPriv();
|
||||
bool success;
|
||||
EnterCriticalSection(&::hostCs);
|
||||
|
||||
preventDuplicationMutex = CreateMutexW(nullptr, TRUE, ITH_SERVER_MUTEX);
|
||||
if (GetLastError() == ERROR_ALREADY_EXISTS || ::running)
|
||||
{
|
||||
GROWL_WARN(L"I am sorry that this game is attached by some other VNR ><\nPlease restart the game and try again!");
|
||||
success = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
::running = true;
|
||||
::settings = new Settings;
|
||||
::man = new HookManager;
|
||||
InitializeCriticalSection(&detachCs);
|
||||
::hookMutex = CreateMutexW(nullptr, FALSE, ITH_SERVER_HOOK_MUTEX);
|
||||
success = true;
|
||||
}
|
||||
LeaveCriticalSection(&::hostCs);
|
||||
return success;
|
||||
}
|
||||
|
||||
IHFSERVICE void IHFAPI Host_Destroy()
|
||||
IHFSERVICE void IHFAPI StartHost()
|
||||
{
|
||||
InitializeCriticalSection(&::cs);
|
||||
CreateNewPipe();
|
||||
::pipeExistsEvent = CreateEventW(nullptr, TRUE, TRUE, ITH_PIPEEXISTS_EVENT);
|
||||
}
|
||||
|
||||
IHFSERVICE BOOL IHFAPI Host_Open()
|
||||
IHFSERVICE void IHFAPI CloseHost()
|
||||
{
|
||||
BOOL result = false;
|
||||
EnterCriticalSection(&::cs);
|
||||
DWORD present;
|
||||
hServerMutex = IthCreateMutex(ITH_SERVER_MUTEX, 1, &present);
|
||||
if (present)
|
||||
//MessageBox(0,L"Already running.",0,0);
|
||||
// jichi 8/24/2013
|
||||
GROWL_WARN(L"I am sorry that this game is attached by some other VNR ><\nPlease restart the game and try again!");
|
||||
else if (!::running) {
|
||||
::running = true;
|
||||
::settings = new Settings;
|
||||
::man = new HookManager;
|
||||
//cmdq = new CommandQueue;
|
||||
InitializeCriticalSection(&detach_cs);
|
||||
|
||||
::hHookMutex = IthCreateMutex(ITH_SERVER_HOOK_MUTEX, FALSE);
|
||||
result = true;
|
||||
}
|
||||
LeaveCriticalSection(&::cs);
|
||||
return result;
|
||||
EnterCriticalSection(&::hostCs);
|
||||
if (::running)
|
||||
{
|
||||
::running = FALSE;
|
||||
ResetEvent(::pipeExistsEvent);
|
||||
delete man;
|
||||
delete settings;
|
||||
CloseHandle(::hookMutex);
|
||||
CloseHandle(preventDuplicationMutex);
|
||||
CloseHandle(::pipeExistsEvent);
|
||||
DeleteCriticalSection(&detachCs);
|
||||
}
|
||||
LeaveCriticalSection(&::hostCs);
|
||||
}
|
||||
|
||||
IHFSERVICE DWORD IHFAPI Host_Start()
|
||||
IHFSERVICE bool IHFAPI InjectProcessById(DWORD processId, DWORD timeout)
|
||||
{
|
||||
//IthBreak();
|
||||
CreateNewPipe();
|
||||
::hPipeExist = IthCreateEvent(ITH_PIPEEXISTS_EVENT);
|
||||
NtSetEvent(::hPipeExist, nullptr);
|
||||
return 0;
|
||||
}
|
||||
bool success = true;
|
||||
|
||||
IHFSERVICE DWORD IHFAPI Host_Close()
|
||||
{
|
||||
BOOL result = FALSE;
|
||||
EnterCriticalSection(&::cs);
|
||||
if (::running) {
|
||||
::running = FALSE;
|
||||
HANDLE hRecvPipe = IthOpenPipe(recv_pipe, GENERIC_WRITE);
|
||||
NtClose(hRecvPipe);
|
||||
NtClearEvent(::hPipeExist);
|
||||
//delete cmdq;
|
||||
delete man;
|
||||
delete settings;
|
||||
NtClose(::hHookMutex);
|
||||
NtClose(hServerMutex);
|
||||
NtClose(::hPipeExist);
|
||||
DeleteCriticalSection(&detach_cs);
|
||||
result = TRUE;
|
||||
}
|
||||
LeaveCriticalSection(&::cs);
|
||||
return result;
|
||||
}
|
||||
if (processId == GetCurrentProcessId())
|
||||
{
|
||||
success = false;
|
||||
}
|
||||
|
||||
IHFSERVICE DWORD IHFAPI Host_GetPIDByName(LPCWSTR pwcTarget)
|
||||
{
|
||||
DWORD dwSize = 0x20000,
|
||||
dwExpectSize = 0;
|
||||
LPVOID pBuffer = 0;
|
||||
SYSTEM_PROCESS_INFORMATION *spiProcessInfo;
|
||||
DWORD dwPid = 0;
|
||||
DWORD dwStatus;
|
||||
CloseHandle(CreateMutexW(nullptr, FALSE, CONCAT_STR_NUM(ITH_HOOKMAN_MUTEX_, processId)));
|
||||
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
||||
{
|
||||
man->AddConsoleOutput(L"already locked");
|
||||
success = false;
|
||||
}
|
||||
|
||||
NtAllocateVirtualMemory(NtCurrentProcess(), &pBuffer, 0, &dwSize, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
|
||||
dwStatus = NtQuerySystemInformation(SystemProcessInformation, pBuffer, dwSize, &dwExpectSize);
|
||||
if (!NT_SUCCESS(dwStatus)) {
|
||||
NtFreeVirtualMemory(NtCurrentProcess(),&pBuffer,&dwSize,MEM_RELEASE);
|
||||
if (dwStatus != STATUS_INFO_LENGTH_MISMATCH || dwExpectSize < dwSize)
|
||||
return 0;
|
||||
dwSize = (dwExpectSize | 0xFFF) + 0x4001; //
|
||||
pBuffer = 0;
|
||||
NtAllocateVirtualMemory(NtCurrentProcess(), &pBuffer, 0, &dwSize, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
|
||||
dwStatus = NtQuerySystemInformation(SystemProcessInformation, pBuffer, dwSize, &dwExpectSize);
|
||||
if (!NT_SUCCESS(dwStatus)) goto _end;
|
||||
}
|
||||
HMODULE textHooker = LoadLibraryExW(L"vnrhook", nullptr, DONT_RESOLVE_DLL_REFERENCES);
|
||||
if (textHooker == nullptr)
|
||||
{
|
||||
success = false;
|
||||
}
|
||||
wchar_t textHookerPath[MAX_PATH];
|
||||
unsigned int textHookerPathSize = GetModuleFileNameW(textHooker, textHookerPath, MAX_PATH) * 2 + 2;
|
||||
FreeLibrary(textHooker);
|
||||
|
||||
for (spiProcessInfo = (SYSTEM_PROCESS_INFORMATION *)pBuffer; spiProcessInfo->dNext;) {
|
||||
spiProcessInfo = (SYSTEM_PROCESS_INFORMATION *)
|
||||
((DWORD)spiProcessInfo + spiProcessInfo -> dNext);
|
||||
if (_wcsicmp(pwcTarget, spiProcessInfo -> usName.Buffer) == 0) {
|
||||
dwPid = spiProcessInfo->dUniqueProcessId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!dwPid)
|
||||
DOUT("pid not found");
|
||||
//if (dwPid == 0) ConsoleOutput(ErrorNoProcess);
|
||||
_end:
|
||||
NtFreeVirtualMemory(NtCurrentProcess(),&pBuffer,&dwSize,MEM_RELEASE);
|
||||
return dwPid;
|
||||
}
|
||||
HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId);
|
||||
if (processHandle == INVALID_HANDLE_VALUE || processHandle == nullptr)
|
||||
{
|
||||
success = false;
|
||||
}
|
||||
|
||||
IHFSERVICE bool IHFAPI Host_InjectByPID(DWORD pid)
|
||||
{
|
||||
WCHAR str[0x80];
|
||||
if (!::running)
|
||||
return 0;
|
||||
if (pid == current_process_id) {
|
||||
//ConsoleOutput(SelfAttach);
|
||||
DOUT("refuse to inject myself");
|
||||
return false;
|
||||
}
|
||||
if (man->GetProcessRecord(pid)) {
|
||||
//ConsoleOutput(AlreadyAttach);
|
||||
DOUT("already attached");
|
||||
return false;
|
||||
}
|
||||
swprintf(str, ITH_HOOKMAN_MUTEX_ L"%d", pid);
|
||||
DWORD s;
|
||||
NtClose(IthCreateMutex(str, 0, &s));
|
||||
if (s) {
|
||||
DOUT("already locked");
|
||||
return false;
|
||||
}
|
||||
CLIENT_ID id;
|
||||
OBJECT_ATTRIBUTES oa = {};
|
||||
HANDLE hProc;
|
||||
id.UniqueProcess = pid;
|
||||
id.UniqueThread = 0;
|
||||
oa.uLength = sizeof(oa);
|
||||
if (!NT_SUCCESS(NtOpenProcess(&hProc,
|
||||
PROCESS_QUERY_INFORMATION|
|
||||
PROCESS_CREATE_THREAD|
|
||||
PROCESS_VM_OPERATION|
|
||||
PROCESS_VM_READ|
|
||||
PROCESS_VM_WRITE,
|
||||
&oa, &id))) {
|
||||
//ConsoleOutput(ErrorOpenProcess);
|
||||
DOUT("failed to open process");
|
||||
return false;
|
||||
}
|
||||
void* loadLibraryStartRoutine = GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryW");
|
||||
|
||||
//if (!engine)
|
||||
// engine = ITH_USE_XP_DLLS ? ITH_ENGINE_XP_DLL : ITH_ENGINE_DLL;
|
||||
bool ok = Inject(hProc);
|
||||
//NtClose(hProc); //already closed
|
||||
if (!ok) {
|
||||
DOUT("inject failed");
|
||||
return false;
|
||||
}
|
||||
//swprintf(str, FormatInject, pid, module);
|
||||
//ConsoleOutput(str);
|
||||
DOUT("inject succeed");
|
||||
return true;
|
||||
if (success)
|
||||
{
|
||||
if (LPVOID remoteData = VirtualAllocEx(processHandle, nullptr, textHookerPathSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE))
|
||||
{
|
||||
if (WriteProcessMemory(processHandle, remoteData, textHookerPath, textHookerPathSize, nullptr))
|
||||
{
|
||||
if (HANDLE thread = CreateRemoteThread(processHandle, nullptr, 0, (LPTHREAD_START_ROUTINE)loadLibraryStartRoutine, remoteData, 0, nullptr))
|
||||
{
|
||||
WaitForSingleObject(thread, timeout);
|
||||
CloseHandle(thread);
|
||||
}
|
||||
else
|
||||
{
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
success = false;
|
||||
}
|
||||
VirtualFreeEx(processHandle, remoteData, textHookerPathSize, MEM_RELEASE);
|
||||
}
|
||||
else
|
||||
{
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!success)
|
||||
{
|
||||
man->AddConsoleOutput(L"error: could not inject");
|
||||
}
|
||||
|
||||
CloseHandle(processHandle);
|
||||
return success;
|
||||
}
|
||||
|
||||
// jichi 7/16/2014: Test if process is valid before creating remote threads
|
||||
// See: http://msdn.microsoft.com/en-us/library/ms687032.aspx
|
||||
static bool isProcessTerminated(HANDLE hProc)
|
||||
{ return WAIT_OBJECT_0 == ::WaitForSingleObject(hProc, 0); }
|
||||
//static bool isProcessRunning(HANDLE hProc)
|
||||
//{ return WAIT_TIMEOUT == ::WaitForSingleObject(hProc, 0); }
|
||||
static bool isProcessTerminated(HANDLE processHandle)
|
||||
{
|
||||
return WAIT_OBJECT_0 == ::WaitForSingleObject(processHandle, 0);
|
||||
}
|
||||
|
||||
// jichi 7/16/2014: Test if process is valid before creating remote threads
|
||||
//static bool isProcessRunning(DWORD pid)
|
||||
//{
|
||||
// bool ret = false;
|
||||
// HANDLE hProc = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
|
||||
// if (hProc) {
|
||||
// DWORD status;
|
||||
// if (::GetExitCodeProcess(hProc, &status)) {
|
||||
// ret = status == STILL_ACTIVE;
|
||||
// ::CloseHandle(hProc);
|
||||
// } else
|
||||
// ret = true;
|
||||
// }
|
||||
// return ret;
|
||||
//}
|
||||
|
||||
IHFSERVICE bool IHFAPI Host_ActiveDetachProcess(DWORD pid)
|
||||
IHFSERVICE bool IHFAPI DetachProcessById(DWORD pid) // Todo: clean this up
|
||||
{
|
||||
ITH_SYNC_HOOK;
|
||||
|
||||
@ -543,13 +312,6 @@ IHFSERVICE bool IHFAPI Host_GetSettings(Settings **p)
|
||||
return false;
|
||||
}
|
||||
|
||||
IHFSERVICE bool IHFAPI Host_HijackProcess(DWORD pid)
|
||||
{
|
||||
//ITH_SYNC_HOOK;
|
||||
HANDLE hCmd = man->GetCmdHandleByPID(pid);
|
||||
return hCmd && sendCommand(hCmd, HOST_COMMAND_HIJACK_PROCESS);
|
||||
}
|
||||
|
||||
IHFSERVICE DWORD IHFAPI Host_InsertHook(DWORD pid, HookParam *hp, LPCSTR name)
|
||||
{
|
||||
ITH_SYNC_HOOK;
|
||||
|
@ -14,14 +14,14 @@ struct HookParam;
|
||||
IHFSERVICE void IHFAPI Host_Init();
|
||||
IHFSERVICE void IHFAPI Host_Destroy();
|
||||
|
||||
IHFSERVICE DWORD IHFAPI Host_Start();
|
||||
IHFSERVICE BOOL IHFAPI Host_Open();
|
||||
IHFSERVICE DWORD IHFAPI Host_Close();
|
||||
IHFSERVICE void IHFAPI StartHost();
|
||||
IHFSERVICE bool IHFAPI OpenHost();
|
||||
IHFSERVICE void IHFAPI CloseHost();
|
||||
IHFSERVICE DWORD IHFAPI Host_GetHookManager(HookManager **hookman);
|
||||
IHFSERVICE bool IHFAPI Host_GetSettings(Settings **settings);
|
||||
IHFSERVICE DWORD IHFAPI Host_GetPIDByName(LPCWSTR pwcTarget);
|
||||
IHFSERVICE bool IHFAPI Host_InjectByPID(DWORD pid);
|
||||
IHFSERVICE bool IHFAPI Host_ActiveDetachProcess(DWORD pid);
|
||||
IHFSERVICE bool IHFAPI InjectProcessById(DWORD pid, DWORD timeout = 5000);
|
||||
IHFSERVICE bool IHFAPI DetachProcessById(DWORD pid);
|
||||
IHFSERVICE bool IHFAPI Host_HijackProcess(DWORD pid);
|
||||
IHFSERVICE DWORD IHFAPI Host_InsertHook(DWORD pid, HookParam *hp, LPCSTR name = nullptr);
|
||||
IHFSERVICE DWORD IHFAPI Host_ModifyHook(DWORD pid, HookParam *hp);
|
||||
|
@ -3,6 +3,7 @@
|
||||
// 8/24/2013 jichi
|
||||
// Branch IHF/main.h, rev 111
|
||||
#include <windows.h>
|
||||
#include <tlhelp32.h>
|
||||
|
||||
#define GLOBAL extern
|
||||
#define SHIFT_JIS 0x3A4
|
||||
@ -23,12 +24,12 @@ GLOBAL HookManager *man;
|
||||
GLOBAL SettingManager *setman;
|
||||
GLOBAL WCHAR recv_pipe[];
|
||||
GLOBAL WCHAR command[];
|
||||
GLOBAL HANDLE hPipeExist;
|
||||
GLOBAL HANDLE pipeExistsEvent;
|
||||
GLOBAL DWORD split_time,
|
||||
cyclic_remove,
|
||||
clipboard_flag,
|
||||
global_filter;
|
||||
GLOBAL CRITICAL_SECTION detach_cs;
|
||||
GLOBAL CRITICAL_SECTION detachCs;
|
||||
|
||||
DWORD WINAPI RecvThread(LPVOID lpThreadParameter);
|
||||
DWORD WINAPI CmdThread(LPVOID lpThreadParameter);
|
||||
|
@ -69,9 +69,9 @@ const BYTE *Filter(const BYTE *str, int len)
|
||||
wchar_t recv_pipe[] = ITH_TEXT_PIPE;
|
||||
wchar_t command_pipe[] = ITH_COMMAND_PIPE;
|
||||
|
||||
CRITICAL_SECTION detach_cs; // jichi 9/27/2013: also used in main
|
||||
CRITICAL_SECTION detachCs; // jichi 9/27/2013: also used in main
|
||||
//HANDLE hDetachEvent;
|
||||
extern HANDLE hPipeExist;
|
||||
extern HANDLE pipeExistsEvent;
|
||||
|
||||
void CreateNewPipe()
|
||||
{
|
||||
@ -176,7 +176,7 @@ void DetachFromProcess(DWORD pid)
|
||||
|
||||
//NtSetEvent(hDetachEvent, 0);
|
||||
if (::running)
|
||||
NtSetEvent(hPipeExist, 0);
|
||||
NtSetEvent(pipeExistsEvent, 0);
|
||||
}
|
||||
|
||||
// jichi 9/27/2013: I don't need this
|
||||
@ -291,7 +291,7 @@ DWORD WINAPI RecvThread(LPVOID lpThreadParameter)
|
||||
}
|
||||
}
|
||||
|
||||
EnterCriticalSection(&detach_cs);
|
||||
EnterCriticalSection(&detachCs);
|
||||
|
||||
HANDLE hDisconnect = IthCreateEvent(nullptr);
|
||||
|
||||
@ -310,7 +310,7 @@ DWORD WINAPI RecvThread(LPVOID lpThreadParameter)
|
||||
|
||||
//NtClearEvent(hDetachEvent);
|
||||
|
||||
LeaveCriticalSection(&detach_cs);
|
||||
LeaveCriticalSection(&detachCs);
|
||||
delete[] buff;
|
||||
|
||||
if (::running)
|
||||
|
@ -31,7 +31,7 @@ static DWORD MIN_REDETECT = 0x80;
|
||||
DWORD GetHookName(LPSTR str, DWORD pid, DWORD hook_addr,DWORD max);
|
||||
|
||||
extern Settings *settings;
|
||||
extern HWND hMainWnd;
|
||||
extern HWND dummyWindow;
|
||||
void CALLBACK NewLineBuff(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
|
||||
{
|
||||
KillTimer(hwnd,idEvent);
|
||||
@ -103,7 +103,7 @@ TextThread::TextThread(DWORD id, DWORD hook, DWORD retn, DWORD spl, WORD num) :
|
||||
}
|
||||
TextThread::~TextThread()
|
||||
{
|
||||
//KillTimer(hMainWnd,timer);
|
||||
//KillTimer(dummyWindow,timer);
|
||||
RepeatCountNode *t = head,
|
||||
*tt;
|
||||
while (t) {
|
||||
@ -744,9 +744,9 @@ void TextThread::SetNewLineTimer()
|
||||
{
|
||||
if (thread_number == 0)
|
||||
// jichi 10/27/2013: Not used
|
||||
timer = 0; //SetTimer(hMainWnd,(UINT_PTR)this, settings->splittingInterval, NewLineConsole);
|
||||
timer = 0; //SetTimer(dummyWindow,(UINT_PTR)this, settings->splittingInterval, NewLineConsole);
|
||||
else
|
||||
timer = SetTimer(hMainWnd, (UINT_PTR)this, settings->splittingInterval, NewLineBuff);
|
||||
timer = SetTimer(dummyWindow, (UINT_PTR)this, settings->splittingInterval, NewLineBuff);
|
||||
}
|
||||
|
||||
DWORD TextThread::GetThreadString(LPSTR str, DWORD max)
|
||||
|
@ -59,13 +59,8 @@ set(vnrhook_src
|
||||
${PROJECT_SOURCE_DIR}/memdbg/memsearch.h
|
||||
${PROJECT_SOURCE_DIR}/ntinspect/ntinspect.cc
|
||||
${PROJECT_SOURCE_DIR}/ntinspect/ntinspect.h
|
||||
${PROJECT_SOURCE_DIR}/winkey/winkey.h
|
||||
${PROJECT_SOURCE_DIR}/winversion/winversion.cc
|
||||
${PROJECT_SOURCE_DIR}/winversion/winversion.h
|
||||
${PROJECT_SOURCE_DIR}/winseh/winseh.h
|
||||
${PROJECT_SOURCE_DIR}/winseh/winseh.cc
|
||||
${PROJECT_SOURCE_DIR}/winseh/winseh_safe.cc
|
||||
${PROJECT_SOURCE_DIR}/winseh/safeseh.asm
|
||||
${PROJECT_SOURCE_DIR}/mono/monoobject.h
|
||||
${PROJECT_SOURCE_DIR}/mono/monotype.h
|
||||
)
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include "src/main.h"
|
||||
#include "include/const.h"
|
||||
#include "ithsys/ithsys.h"
|
||||
#include "winkey/winkey.h"
|
||||
#include "disasm/disasm.h"
|
||||
//#include "winseh/winseh.h"
|
||||
|
||||
|
@ -1,89 +0,0 @@
|
||||
// hijack.cc
|
||||
// 1/27/2013 jichi
|
||||
#include "windbg/hijack.h"
|
||||
#include "windbg/windbg_p.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning (disable:4996) // C4996: use POSIX function (stricmp)
|
||||
#endif // _MSC_VER
|
||||
|
||||
//#define DEBUG "winsec"
|
||||
#include "sakurakit/skdebug.h"
|
||||
|
||||
WINDBG_BEGIN_NAMESPACE
|
||||
|
||||
// - Inline Hook -
|
||||
// See: http://asdf.wkeya.com/code/apihook6.html
|
||||
PVOID overrideFunctionA(HMODULE stealFrom, LPCSTR oldFunctionModule, LPCSTR functionName, LPCVOID newFunction)
|
||||
{
|
||||
if (!stealFrom)
|
||||
return nullptr;
|
||||
//HMODULE oldModule = GetModuleHandleA(oldFunctionModule);
|
||||
//if (!oldModule)
|
||||
// return nullptr;
|
||||
//void *originalAddress = GetProcAddress(oldModule, functionName);
|
||||
LPVOID originalAddress = details::getModuleFunctionAddressA(functionName, oldFunctionModule);
|
||||
if (!originalAddress)
|
||||
return nullptr;
|
||||
IMAGE_DOS_HEADER *dosHeader = reinterpret_cast<IMAGE_DOS_HEADER *>(stealFrom);
|
||||
char *base = reinterpret_cast<char *>(stealFrom);
|
||||
if (::IsBadReadPtr(dosHeader, sizeof(IMAGE_DOS_HEADER)) || dosHeader->e_magic != IMAGE_DOS_SIGNATURE)
|
||||
return nullptr;
|
||||
IMAGE_NT_HEADERS *ntHeader =
|
||||
reinterpret_cast<IMAGE_NT_HEADERS* >(base + dosHeader->e_lfanew);
|
||||
if (::IsBadReadPtr(ntHeader, sizeof(IMAGE_NT_HEADERS)) || ntHeader->Signature != IMAGE_NT_SIGNATURE)
|
||||
return nullptr;
|
||||
if (!ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
|
||||
return nullptr;
|
||||
// See: http://msdn.microsoft.com/en-us/magazine/cc301808.aspx
|
||||
IMAGE_IMPORT_DESCRIPTOR *import =
|
||||
reinterpret_cast<IMAGE_IMPORT_DESCRIPTOR *>(base + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
|
||||
|
||||
// scan memory
|
||||
// TODO: add a maximum loop counter here!
|
||||
while (import->Name) {
|
||||
char *name = base + import->Name;
|
||||
if (!::stricmp(name, oldFunctionModule))
|
||||
break;
|
||||
import++;
|
||||
}
|
||||
if (!import->Name)
|
||||
return nullptr;
|
||||
IMAGE_THUNK_DATA *thunk = reinterpret_cast<IMAGE_THUNK_DATA *>(base + import->FirstThunk);
|
||||
while (thunk->u1.Function) {
|
||||
if ((ULONG_PTR)thunk->u1.Function == (ULONG_PTR)originalAddress) {
|
||||
ULONG_PTR *addr = reinterpret_cast<ULONG_PTR *>(&thunk->u1.Function);
|
||||
|
||||
// See: http://asdf.wkeya.com/code/apihook6.html
|
||||
// Inline hook mechanism:
|
||||
//
|
||||
// LPVOID InlineHook3( PUINT8 mem, DWORD dwLen, PUINT8 pfOld, PUINT8 pfNew )
|
||||
// {
|
||||
// DWORD dwOldProtect;
|
||||
// VirtualProtect( ( PUINT8 )( pfOld ), dwLen, PAGE_READWRITE, &dwOldProtect );
|
||||
// // 関数のエントリーから指定したbyte数をメモリの前方にコピー
|
||||
// // メモリの数byte後方からオリジナルへのジャンプを作成
|
||||
// // 指定の関数アドレスから5byteをフックへのjmp命令に書き換え
|
||||
// VirtualProtect( ( PUINT8 )( pfOld ), dwLen, dwOldProtect, &dwOldProtect );
|
||||
// return ( PVOID )mem;
|
||||
// }
|
||||
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
if (::VirtualQuery((LPVOID)addr, &mbi, sizeof(mbi)) == sizeof(mbi)) {
|
||||
DWORD dwOldProtect;
|
||||
if (::VirtualProtect(mbi.BaseAddress, ((ULONG_PTR)addr + 8)-(ULONG_PTR)mbi.BaseAddress, PAGE_EXECUTE_READWRITE, &dwOldProtect)) {
|
||||
*addr = (ULONG_PTR)newFunction;
|
||||
::VirtualProtect(mbi.BaseAddress, ((ULONG_PTR)addr + 8)-(ULONG_PTR)mbi.BaseAddress, dwOldProtect, &dwOldProtect);
|
||||
return originalAddress;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
thunk++;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WINDBG_END_NAMESPACE
|
||||
|
||||
// EOF
|
@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// hijack.h
|
||||
// 1/27/2013 jichi
|
||||
|
||||
#include "windbg/windbg.h"
|
||||
#include <windows.h>
|
||||
|
||||
WINDBG_BEGIN_NAMESPACE
|
||||
|
||||
/**
|
||||
* Replace the named function entry with the new one.
|
||||
* @param stealFrom instance of target module
|
||||
* @param oldFunctionModule TODO
|
||||
* @param functionName name of the target function
|
||||
* @return the orignal address if succeed, else nullptr
|
||||
*
|
||||
* See: http://www.codeproject.com/KB/DLL/DLL_Injection_tutorial.aspx
|
||||
*/
|
||||
PVOID overrideFunctionA(_In_ HMODULE stealFrom, _In_ LPCSTR oldFunctionModule,
|
||||
_In_ LPCSTR functionName, _In_ LPCVOID newFunction);
|
||||
|
||||
WINDBG_END_NAMESPACE
|
||||
|
||||
// EOF
|
@ -1,167 +0,0 @@
|
||||
// inject.cc
|
||||
// 1/27/2013 jichi
|
||||
#include "windbg/inject.h"
|
||||
#include "windbg/windbg_p.h"
|
||||
#include <cwchar> // for wcslen
|
||||
|
||||
//#define DEBUG "windbg::inject"
|
||||
#include "sakurakit/skdebug.h"
|
||||
|
||||
WINDBG_BEGIN_NAMESPACE
|
||||
|
||||
// - Remote Injection -
|
||||
|
||||
BOOL InjectFunction1(LPCVOID addr, LPCVOID data, SIZE_T dataSize, DWORD pid, HANDLE hProcess, INT timeout)
|
||||
{
|
||||
DOUT("enter: pid =" << pid);
|
||||
if (hProcess == INVALID_HANDLE_VALUE && pid) {
|
||||
hProcess = ::OpenProcess(PROCESS_INJECT_ACCESS, FALSE, pid);
|
||||
// TODO: Privilege elevation is not implemented. See: skwinsec.py.
|
||||
//if (!hProcess) {
|
||||
// priv = SkProcessElevator('SeDebugPrivilege')
|
||||
// if not priv.isEmpty():
|
||||
// handle = win32api.OpenProcess(PROCESS_INJECT_ACCESS, 0, pid)
|
||||
//}
|
||||
}
|
||||
if (hProcess == INVALID_HANDLE_VALUE) {
|
||||
DOUT("exit: error: failed to get process handle");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL ret = FALSE;
|
||||
if (LPVOID remoteData = ::VirtualAllocEx(hProcess, nullptr, dataSize, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE)) {
|
||||
if (::WriteProcessMemory(hProcess, remoteData, data, dataSize, nullptr))
|
||||
if (HANDLE hThread = ::CreateRemoteThread(
|
||||
hProcess,
|
||||
nullptr, 0,
|
||||
reinterpret_cast<LPTHREAD_START_ROUTINE>(addr),
|
||||
remoteData,
|
||||
0, nullptr)) {
|
||||
::WaitForSingleObject(hThread, timeout);
|
||||
::CloseHandle(hThread);
|
||||
ret = TRUE;
|
||||
}
|
||||
::VirtualFreeEx(hProcess, remoteData, dataSize, MEM_RELEASE);
|
||||
}
|
||||
::CloseHandle(hProcess);
|
||||
DOUT("exit: ret =" << ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
BOOL injectDllW(LPCWSTR dllPath, DWORD pid, HANDLE hProcess, INT timeout)
|
||||
{
|
||||
DOUT("enter: pid =" << pid);
|
||||
LPCVOID fun = details::getModuleFunctionAddressA("LoadLibraryW", "kernel32.dll");
|
||||
if (!fun) {
|
||||
DOUT("exit error: cannot find function");
|
||||
return FALSE;
|
||||
}
|
||||
LPCVOID data = dllPath;
|
||||
SIZE_T dataSize = ::wcslen(dllPath) * 2 + 2; // L'\0'
|
||||
BOOL ok = InjectFunction1(fun, data, dataSize, pid, hProcess, timeout);
|
||||
DOUT("exit: ret =" << ok);
|
||||
return ok;
|
||||
}
|
||||
|
||||
BOOL ejectDll(HANDLE hDll, DWORD pid, HANDLE hProcess, INT timeout)
|
||||
{
|
||||
DOUT("enter: pid =" << pid);
|
||||
LPCVOID fun = details::getModuleFunctionAddressA("FreeLibrary", "kernel32.dll");
|
||||
if (!fun) {
|
||||
DOUT("exit error: cannot find function");
|
||||
return FALSE;
|
||||
}
|
||||
LPCVOID data = &hDll;
|
||||
SIZE_T dataSize = sizeof(hDll);
|
||||
BOOL ok = InjectFunction1(fun, data, dataSize, pid, hProcess, timeout);
|
||||
DOUT("exit: ret =" << ok);
|
||||
return ok;
|
||||
}
|
||||
|
||||
WINDBG_END_NAMESPACE
|
||||
|
||||
// EOF
|
||||
|
||||
/*
|
||||
enum { CREATE_THREAD_ACCESS = (PROCESS_CREATE_THREAD |
|
||||
PROCESS_QUERY_INFORMATION |
|
||||
PROCESS_VM_OPERATION |
|
||||
PROCESS_VM_WRITE |
|
||||
PROCESS_VM_READ ) };
|
||||
|
||||
|
||||
int InjectDll(HANDLE hProcess, HINSTANCE hInst) {
|
||||
HANDLE hThread;
|
||||
|
||||
wchar_t dllFile[2*MAX_PATH];
|
||||
if (GetModuleFileNameW(hInst, dllFile, sizeof(dllFile)/2) > sizeof(dllFile)/2) return 0;
|
||||
|
||||
void *loadLibraryW = GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "LoadLibraryW");
|
||||
if (!loadLibraryW) return 0;
|
||||
|
||||
wchar_t *name;
|
||||
if (!(name = wcsrchr(dllFile, '\\'))) return 0;
|
||||
name ++;
|
||||
wcscpy(name, DLL_NAME);
|
||||
if (GetFileAttributes(dllFile) == INVALID_FILE_ATTRIBUTES) return 0;
|
||||
|
||||
size_t len = sizeof(wchar_t)*(1+wcslen(dllFile));
|
||||
void *remoteString = (LPVOID)VirtualAllocEx(hProcess,
|
||||
NULL,
|
||||
len,
|
||||
MEM_RESERVE|MEM_COMMIT,
|
||||
PAGE_READWRITE
|
||||
);
|
||||
if (remoteString) {
|
||||
if (WriteProcessMemory(hProcess, (LPVOID)remoteString, dllFile, len, NULL)) {
|
||||
if (hThread = CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE)loadLibraryW, (LPVOID)remoteString, 0,0)) {
|
||||
WaitForSingleObject(hThread, 3000);
|
||||
CloseHandle(hThread);
|
||||
VirtualFreeEx(hProcess, remoteString, len, MEM_FREE);
|
||||
// Make sure it's injected before resuming.
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
VirtualFreeEx(hProcess, remoteString, len, MEM_FREE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getPriv(const char * name) {
|
||||
HANDLE hToken;
|
||||
LUID seValue;
|
||||
TOKEN_PRIVILEGES tkp;
|
||||
|
||||
if (!LookupPrivilegeValueA(NULL, name, &seValue) ||
|
||||
!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
tkp.PrivilegeCount = 1;
|
||||
tkp.Privileges[0].Luid = seValue;
|
||||
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||
|
||||
int res = AdjustTokenPrivileges(hToken, 0, &tkp, sizeof(tkp), NULL, NULL);
|
||||
|
||||
CloseHandle(hToken);
|
||||
return res;
|
||||
}
|
||||
|
||||
inline int getDebugPriv() {
|
||||
return getPriv("SeDebugPrivilege");
|
||||
}
|
||||
|
||||
int InjectIntoProcess(int pid) {
|
||||
HANDLE hProcess = OpenProcess(CREATE_THREAD_ACCESS, 0, pid);
|
||||
if (hProcess == 0) {
|
||||
getDebugPriv();
|
||||
hProcess = OpenProcess(CREATE_THREAD_ACCESS, 0, pid);
|
||||
if (!hProcess) return 0;
|
||||
}
|
||||
|
||||
int out = InjectDll(hProcess);
|
||||
|
||||
CloseHandle(hProcess);
|
||||
return out;
|
||||
}
|
||||
*/
|
@ -1,56 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// inject.h
|
||||
// 1/27/2013 jichi
|
||||
|
||||
#include "windbg/windbg.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
WINDBG_BEGIN_NAMESPACE
|
||||
|
||||
enum { PROCESS_INJECT_ACCESS = PROCESS_CREATE_THREAD|PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ };
|
||||
enum { INJECT_TIMEOUT = 3000 }; // wait at most 3 seconds for creating remote threads
|
||||
|
||||
/**
|
||||
* Inject function with 1 argument
|
||||
* Either pid or the process handle should be specified
|
||||
* @param addr LONG function memory address
|
||||
* @param arg LPVOID arg1 data
|
||||
* @param argSize int arg1 data size
|
||||
* @param pid process id
|
||||
* @param hProcess process handle
|
||||
* @param timeout msec
|
||||
* @return BOOL
|
||||
*/
|
||||
BOOL injectFunction1(_In_ LPCVOID addr, _In_ LPCVOID arg, _In_ SIZE_T argSize,
|
||||
_In_ DWORD pid = 0, _In_ HANDLE hProcess = INVALID_HANDLE_VALUE,
|
||||
_In_ INT timeout = INJECT_TIMEOUT);
|
||||
|
||||
/**
|
||||
* Either pid or the process handle should be specified
|
||||
* @param dllpath ABSOLUTE path to dll
|
||||
* @param pid process id
|
||||
* @param hProcess process handle
|
||||
* @param timeout msec
|
||||
* @return BOOL
|
||||
*/
|
||||
BOOL injectDllW(_In_ LPCWSTR dllPath,
|
||||
_In_ DWORD pid = 0, _In_ HANDLE hProcess = INVALID_HANDLE_VALUE,
|
||||
_In_ INT timeout = INJECT_TIMEOUT);
|
||||
|
||||
/**
|
||||
* Either pid or the process handle should be specified
|
||||
* @param hDll dll module handle
|
||||
* @param pid process id
|
||||
* @param hProcess process handle
|
||||
* @param timeout msec
|
||||
* @return BOOL
|
||||
*/
|
||||
BOOL ejectDll(_In_ HANDLE hDll,
|
||||
_In_ DWORD pid = 0, _In_ HANDLE hProcess = INVALID_HANDLE_VALUE,
|
||||
_In_ INT timeout = INJECT_TIMEOUT);
|
||||
|
||||
WINDBG_END_NAMESPACE
|
||||
|
||||
// EOF
|
@ -1,22 +0,0 @@
|
||||
// unload.cc
|
||||
// 5/2/2014 jichi
|
||||
#include "windbg/unload.h"
|
||||
|
||||
WINDBG_BEGIN_NAMESPACE
|
||||
|
||||
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
|
||||
// See: http://stackoverflow.com/questions/3410130/dll-unloading-itself
|
||||
BOOL unloadCurrentModule()
|
||||
{
|
||||
auto fun = ::FreeLibrary;
|
||||
//auto fun = ::LdrUnloadDll;
|
||||
if (HANDLE h = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)fun, &__ImageBase, 0, NULL)) {
|
||||
::CloseHandle(h);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WINDBG_END_NAMESPACE
|
||||
|
||||
// EOF
|
@ -1,19 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// unload.h
|
||||
// 5/2/2014 jichi
|
||||
|
||||
#include "windbg/windbg.h"
|
||||
#include <windows.h>
|
||||
|
||||
WINDBG_BEGIN_NAMESPACE
|
||||
|
||||
/**
|
||||
* Unload current injected DLL.
|
||||
* @return BOOL
|
||||
*/
|
||||
BOOL unloadCurrentModule();
|
||||
|
||||
WINDBG_END_NAMESPACE
|
||||
|
||||
// EOF
|
@ -1,61 +0,0 @@
|
||||
// windbg/util.cc
|
||||
// 1/27/2013 jichi
|
||||
#include "windbg/util.h"
|
||||
#include <tlhelp32.h>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <list>
|
||||
|
||||
WINDBG_BEGIN_NAMESPACE
|
||||
|
||||
class ThreadsSuspenderPrivate
|
||||
{
|
||||
public:
|
||||
std::list<HANDLE> threads;
|
||||
};
|
||||
|
||||
ThreadsSuspender::ThreadsSuspender(bool autoSuspend)
|
||||
: d_(new D)
|
||||
{ if (autoSuspend) suspend(); }
|
||||
|
||||
ThreadsSuspender::~ThreadsSuspender()
|
||||
{
|
||||
resume();
|
||||
delete d_;
|
||||
}
|
||||
|
||||
void ThreadsSuspender::suspend()
|
||||
{
|
||||
HANDLE hSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
|
||||
if (hSnap == INVALID_HANDLE_VALUE)
|
||||
return;
|
||||
THREADENTRY32 entry;
|
||||
entry.dwSize = sizeof(entry);
|
||||
DWORD pid = ::GetCurrentProcessId();
|
||||
DWORD tid = ::GetCurrentThreadId();
|
||||
if (::Thread32First(hSnap, &entry))
|
||||
do if (entry.dwSize >= 4 * sizeof(DWORD) && entry.th32OwnerProcessID == pid && entry.th32ThreadID != tid) {
|
||||
if (HANDLE hThread = ::OpenThread(THREAD_SUSPEND_RESUME, 0, entry.th32ThreadID)) {
|
||||
if (::SuspendThread(hThread) != DWORD(-1))
|
||||
d_->threads.push_back(hThread);
|
||||
else
|
||||
::CloseHandle(hThread);
|
||||
}
|
||||
entry.dwSize = sizeof(entry);
|
||||
} while (::Thread32Next(hSnap, &entry));
|
||||
::CloseHandle(hSnap);
|
||||
}
|
||||
|
||||
void ThreadsSuspender::resume()
|
||||
{
|
||||
if (!d_->threads.empty()) {
|
||||
BOOST_FOREACH (HANDLE hThread, d_->threads) {
|
||||
::ResumeThread(hThread);
|
||||
::CloseHandle(hThread);
|
||||
}
|
||||
d_->threads.clear();
|
||||
}
|
||||
}
|
||||
|
||||
WINDBG_END_NAMESPACE
|
||||
|
||||
// EOF
|
@ -1,34 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// windbg/util.h
|
||||
// 1/27/2013 jichi
|
||||
|
||||
#include "windbg/windbg.h"
|
||||
#include "sakurakit/skglobal.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
WINDBG_BEGIN_NAMESPACE
|
||||
|
||||
class ThreadsSuspenderPrivate;
|
||||
/**
|
||||
* When created, automatically suspends all threads in the current process.
|
||||
* When destroyed, resume suspended threads.
|
||||
*/
|
||||
class ThreadsSuspender
|
||||
{
|
||||
SK_CLASS(ThreadsSuspender)
|
||||
SK_DISABLE_COPY(ThreadsSuspender)
|
||||
SK_DECLARE_PRIVATE(ThreadsSuspenderPrivate)
|
||||
|
||||
public:
|
||||
explicit ThreadsSuspender(bool autoSuspend = true);
|
||||
~ThreadsSuspender();
|
||||
|
||||
void resume(); ///< Manually resume all threads
|
||||
void suspend(); ///< Manually suspend all threads
|
||||
};
|
||||
|
||||
WINDBG_END_NAMESPACE
|
||||
|
||||
// EOF
|
@ -1,16 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// windbg.h
|
||||
// 1/27/2013 jichi
|
||||
|
||||
#ifndef WINDBG_BEGIN_NAMESPACE
|
||||
# define WINDBG_BEGIN_NAMESPACE namespace WinDbg {
|
||||
#endif
|
||||
#ifndef WINDBG_END_NAMESPACE
|
||||
# define WINDBG_END_NAMESPACE } // namespace WinDbg
|
||||
#endif
|
||||
|
||||
WINDBG_BEGIN_NAMESPACE
|
||||
WINDBG_END_NAMESPACE
|
||||
|
||||
// EOF
|
@ -1,24 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// windbg_p.h
|
||||
// 1/27/2013 jichi
|
||||
|
||||
#include "windbg/windbg.h"
|
||||
#include <windows.h>
|
||||
|
||||
WINDBG_BEGIN_NAMESPACE
|
||||
|
||||
namespace details { // unnamed
|
||||
|
||||
/// Return the address of func in module.
|
||||
inline FARPROC getModuleFunctionAddressA(LPCSTR func, LPCSTR module = nullptr)
|
||||
{ return ::GetProcAddress(::GetModuleHandleA(module), func); }
|
||||
|
||||
inline FARPROC getModuleFunctionAddressW(LPCSTR func, LPCWSTR module = nullptr)
|
||||
{ return ::GetProcAddress(::GetModuleHandleW(module), func); }
|
||||
|
||||
} // unamed namespace details
|
||||
|
||||
WINDBG_END_NAMESPACE
|
||||
|
||||
// EOF
|
@ -1,32 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// winkey.h
|
||||
// 7/21/2011
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#ifndef WINKEY_BEGIN_NAMESPACE
|
||||
# define WINKEY_BEGIN_NAMESPACE namespace WinKey {
|
||||
#endif
|
||||
#ifndef WINKEY_END_NAMESPACE
|
||||
# define WINKEY_END_NAMESPACE } // namespace WinKey
|
||||
#endif
|
||||
|
||||
|
||||
WINKEY_BEGIN_NAMESPACE
|
||||
|
||||
inline bool isKeyPressed(int vk) { return ::GetKeyState(vk) & 0xf0; }
|
||||
inline bool isKeyToggled(int vk) { return ::GetKeyState(vk) & 0x0f; }
|
||||
|
||||
inline bool isKeyReturnPressed() { return isKeyPressed(VK_RETURN); }
|
||||
inline bool isKeyControlPressed() { return isKeyPressed(VK_CONTROL); }
|
||||
inline bool isKeyShiftPressed() { return isKeyPressed(VK_SHIFT); }
|
||||
inline bool isKeyAltPressed() { return isKeyPressed(VK_MENU); }
|
||||
//inline bool sKeyCapslockToggled() { return isKeyToggled(VK_CAPITAL); }
|
||||
inline bool isKeyWinPressed() { return isKeyPressed(VK_LWIN) || isKeyPressed(VK_RWIN); }
|
||||
|
||||
inline bool isMouseLeftButtonPressed() { return isKeyPressed(VK_LBUTTON); }
|
||||
inline bool isMouseMiddleButtonPressed() { return isKeyPressed(VK_MBUTTON); }
|
||||
inline bool isMouseRightButtonPressed() { return isKeyPressed(VK_RBUTTON); }
|
||||
|
||||
WINKEY_END_NAMESPACE
|
@ -1,46 +0,0 @@
|
||||
// winmaker.cc
|
||||
// 2/1/2013 jichi
|
||||
|
||||
#include "winmaker/winmaker.h"
|
||||
#include <windows.h>
|
||||
//#include <commctrl.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning (disable:4800) // C4800: forcing value to bool
|
||||
#endif // _MSC_VER
|
||||
|
||||
// See: http://www.codeguru.com/cpp/w-p/dll/tips/article.php/c3635/Tip-Detecting-a-HMODULEHINSTANCE-Handle-Within-the-Module-Youre-Running-In.htm
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
namespace { // unnamed
|
||||
inline HMODULE _get_module() { return reinterpret_cast<HMODULE>(&__ImageBase); }
|
||||
} // unnamed
|
||||
|
||||
bool wm_register_hidden_class(LPCWSTR className)
|
||||
{
|
||||
WNDCLASSEX wx = {};
|
||||
wx.cbSize = sizeof(wx);
|
||||
wx.lpfnWndProc = ::DefWindowProc;
|
||||
wx.hInstance = ::GetModuleHandle(nullptr);
|
||||
wx.lpszClassName = className;
|
||||
return ::RegisterClassEx(&wx);
|
||||
}
|
||||
|
||||
wm_window_t wm_create_hidden_window(LPCWSTR windowName, LPCWSTR className, wm_module_t dllHandle)
|
||||
{
|
||||
//return ::CreateWindowExA(0, className, windowName, 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, dllHandle, nullptr);
|
||||
HINSTANCE module = reinterpret_cast<HINSTANCE>(dllHandle);
|
||||
if (!module)
|
||||
module = _get_module();
|
||||
return ::CreateWindowEx(0, className, windowName, 0, 0, 0, 0, 0, 0, NULL, module, NULL);
|
||||
}
|
||||
|
||||
bool wm_destroy_window(wm_window_t hwnd)
|
||||
{ return ::DestroyWindow(reinterpret_cast<HWND>(hwnd)); }
|
||||
|
||||
|
||||
// EOF
|
||||
//
|
||||
//void wm_init() { ::InitCommonControls(); }
|
||||
//void wm_destroy() {}
|
||||
//bool wm_destroy_window() { return ::DestroyWindow(hwnd); }
|
||||
|
@ -1,23 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// winmaker.h
|
||||
// 2/1/2013 jichi
|
||||
|
||||
#include <windows.h>
|
||||
typedef void *wm_window_t; // HWMD
|
||||
typedef void *wm_module_t; // HMODULE
|
||||
|
||||
bool wm_register_hidden_class(LPCWSTR className = L"hidden_class");
|
||||
|
||||
wm_window_t wm_create_hidden_window(
|
||||
LPCWSTR windowName = L"hidden_window",
|
||||
LPCWSTR className = L"Button", // bust be one of the common control widgets
|
||||
wm_module_t dllHandle = nullptr);
|
||||
|
||||
bool wm_destroy_window(wm_window_t hwnd);
|
||||
|
||||
// EOF
|
||||
|
||||
//#ifdef QT_CORE_LIB
|
||||
//#include <QtGui/qwindowdefs.h>
|
||||
//WId wm_create_hidden_window(const char *className = "Button", const char *windowName = "hidden_window");
|
@ -1,26 +0,0 @@
|
||||
# Makefile
|
||||
# 12/13/2013 jichi
|
||||
# This file is for Windows only.
|
||||
# Compile SAFESEH table from the ASM file.
|
||||
# See: http://stackoverflow.com/questions/19722308/exception-handler-not-called-in-c
|
||||
# See: http://stackoverflow.com/questions/12019689/custom-seh-handler-with-safeseh
|
||||
# See: http://msdn.microsoft.com/en-us/library/16aexws6.aspx
|
||||
|
||||
BUILDDIR = ../../../build
|
||||
OBJ = $(BUILDDIR)/safeseh.obj
|
||||
|
||||
ML = ml
|
||||
CFLAGS =
|
||||
|
||||
.PHONY: all compile clean
|
||||
|
||||
all: compile
|
||||
|
||||
compile: $(OBJ)
|
||||
|
||||
$(OBJ): safeseh.asm
|
||||
$(ML) $(CFLAGS) -Fo $@ -c -safeseh $^
|
||||
|
||||
clean:
|
||||
|
||||
# EOF
|
@ -1,21 +0,0 @@
|
||||
; safeseh.asm
|
||||
; 12/13/2013 jichi
|
||||
; see: http://stackoverflow.com/questions/12019689/custom-seh-handler-with-safeseh
|
||||
; see: http://code.metager.de/source/xref/WebKit/Source/WebCore/platform/win/makesafeseh.asm
|
||||
; see: http://jpassing.com/2008/05/20/fun-with-low-level-seh/
|
||||
.386
|
||||
.model flat, stdcall
|
||||
option casemap :none
|
||||
|
||||
; The symbol name can be found out using: dumpbin /symbols winseh.obj
|
||||
extern _seh_handler:near ; defined in winseh.cc
|
||||
|
||||
_seh_asm_handler proto
|
||||
.safeseh _seh_asm_handler
|
||||
|
||||
.code
|
||||
_seh_asm_handler proc
|
||||
jmp _seh_handler
|
||||
_seh_asm_handler endp
|
||||
|
||||
end
|
@ -1,52 +0,0 @@
|
||||
// winseh.cc
|
||||
// 12/13/2013 jichi
|
||||
|
||||
#include "winseh/winseh.h"
|
||||
#include "ntdll/ntdll.h"
|
||||
//#include <cstdio>
|
||||
|
||||
// - Define global variables -
|
||||
|
||||
seh_dword_t seh_esp[seh_capacity],
|
||||
seh_eip[seh_capacity],
|
||||
seh_eh[seh_capacity];
|
||||
seh_dword_t seh_count;
|
||||
|
||||
// - Exception handlers -
|
||||
|
||||
// VC 2013: http://msdn.microsoft.com/en-us/library/b6sf5kbd.aspx
|
||||
// typedef EXCEPTION_DISPOSITION (*PEXCEPTION_ROUTINE) (
|
||||
// _In_ PEXCEPTION_RECORD ExceptionRecord,
|
||||
// _In_ ULONG64 EstablisherFrame,
|
||||
// _Inout_ PCONTEXT ContextRecord,
|
||||
// _Inout_ PDISPATCHER_CONTEXT DispatcherContext
|
||||
// );
|
||||
//
|
||||
// winnt.h: http://www.codemachine.com/downloads/win81/ntdef.h
|
||||
// typedef
|
||||
// __drv_sameIRQL
|
||||
// __drv_functionClass(EXCEPTION_ROUTINE)
|
||||
// EXCEPTION_DISPOSITION
|
||||
// NTAPI
|
||||
// EXCEPTION_ROUTINE (
|
||||
// _Inout_ struct _EXCEPTION_RECORD *ExceptionRecord,
|
||||
// _In_ PVOID EstablisherFrame,
|
||||
// _In_ struct _CONTEXT *ContextRecord,
|
||||
// _In_ PVOID DispatcherContext
|
||||
// );
|
||||
extern "C" EXCEPTION_DISPOSITION _seh_handler( // extern C is needed to avoid name hashing in C++
|
||||
_In_ PEXCEPTION_RECORD ExceptionRecord,
|
||||
_In_ PVOID EstablisherFrame, // do not work if I use ULONG64
|
||||
_Inout_ PCONTEXT ContextRecord,
|
||||
_In_ PVOID DispatcherContext) // PDISPATCHER_CONTEXT is not declared in windows.h, use PVOID instead
|
||||
{
|
||||
//assert(::seh_count > 0);
|
||||
ContextRecord->Esp = ::seh_esp[::seh_count - 1];
|
||||
ContextRecord->Eip = ::seh_eip[::seh_count - 1];
|
||||
//printf("seh_handler:%i,%x,%x\n", ::seh_count, ContextRecord->Esp, ContextRecord->Eip);
|
||||
return ::seh_eh[::seh_count - 1] ?
|
||||
reinterpret_cast<PEXCEPTION_ROUTINE>(::seh_eh[::seh_count - 1])(ExceptionRecord, EstablisherFrame, ContextRecord, DispatcherContext) :
|
||||
ExceptionContinueExecution;
|
||||
}
|
||||
|
||||
// EOF
|
@ -1,154 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// winseh.h
|
||||
// 12/13/2013 jichi
|
||||
// See: http://code.metager.de/source/xref/WebKit/Source/WebCore/platform/win/makesafeseh.asm
|
||||
// See: http://jpassing.com/2008/05/20/fun-with-low-level-seh/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning (disable:4733) // C4733: Inline asm assigning to 'FS:0' : handler not registered as safe handler
|
||||
#endif // _MSC_VER
|
||||
|
||||
#define SEH_RAISE (*(int*)0 = 0) // raise C000005, for debugging only
|
||||
|
||||
// Maximum number of nested SEH
|
||||
// Default nested function count is 100, see: http://stackoverflow.com/questions/8656089/solution-for-fatal-error-maximum-function-nesting-level-of-100-reached-abor
|
||||
#ifndef SEH_CAPACITY
|
||||
# define SEH_CAPACITY 100
|
||||
#endif // SEH_CAPACITY
|
||||
|
||||
enum { seh_capacity = SEH_CAPACITY };
|
||||
|
||||
typedef unsigned long seh_dword_t; // DWORD in <windows.h>
|
||||
|
||||
// 12/13/2013 jichi
|
||||
// The list implementation is not thread-safe
|
||||
extern seh_dword_t
|
||||
seh_count // current number of exception handlers
|
||||
, seh_handler // extern PEXCEPTION_ROUTINE seh_handler;
|
||||
, seh_esp[seh_capacity] // LPVOID, current stack
|
||||
, seh_eip[seh_capacity] // LPVOID, current IP address
|
||||
, seh_eh[seh_capacity] // EXCEPTION_ROUTINE, current exception handler function address
|
||||
;
|
||||
|
||||
/**
|
||||
* Push SEH handler
|
||||
* @param _label exception recover label which should be the same as seh_pop_
|
||||
* @param _eh EXCEPTION_ROUTINE or 0
|
||||
* @param _r1 scalar register name, such as eax
|
||||
* @param _r2 counter register name, such as ecx
|
||||
*
|
||||
* Note: __asm prefix is needed to allow inlining macro
|
||||
* I didn't pushad and popad which seems to be not needed
|
||||
*
|
||||
* For SEH, see:
|
||||
* http://www.codeproject.com/Articles/82701/Win32-Exceptions-OS-Level-Point-of-View
|
||||
* http://sploitfun.blogspot.com/2012/08/seh-exploit-part1.html
|
||||
* http://sploitfun.blogspot.com/2012/08/seh-exploit-part2.html
|
||||
*
|
||||
* fs:0x0 on Windows is the pointer to ExceptionList
|
||||
* http://stackoverflow.com/questions/4657661/what-lies-at-fs0x0-on-windows
|
||||
*
|
||||
* EPB and ESP
|
||||
* http://stackoverflow.com/questions/1395591/what-is-exactly-the-base-pointer-and-stack-pointer-to-what-do-they-point
|
||||
*
|
||||
* TODO: get sizeof dword instead of hardcode 4
|
||||
*/
|
||||
#define seh_push_(_label, _eh, _r1, _r2) \
|
||||
{ \
|
||||
__asm mov _r1, _eh /* move new handler address */ \
|
||||
__asm mov _r2, seh_count /* get current seh counter */ \
|
||||
__asm mov dword ptr seh_eh[_r2*4], _r1 /* set recover exception hander */ \
|
||||
__asm mov _r1, _label /* move jump label address */ \
|
||||
__asm mov dword ptr seh_eip[_r2*4], _r1 /* set recover eip as the jump label */ \
|
||||
__asm push seh_handler /* push new safe seh handler */ \
|
||||
__asm push fs:[0] /* push old fs:0 */ \
|
||||
__asm mov dword ptr seh_esp[_r2*4], esp /* safe current stack address */ \
|
||||
__asm mov fs:[0], esp /* change fs:0 to the current stack */ \
|
||||
__asm inc seh_count /* increase number of seh */ \
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore old SEH handler
|
||||
* @param _label exception recover label which should be the same as seh_push_
|
||||
*/
|
||||
#define seh_pop_(_label) \
|
||||
{ \
|
||||
__asm _label: /* the exception recover label */ \
|
||||
__asm pop dword ptr fs:[0] /* restore old fs:0 */ \
|
||||
__asm add esp, 4 /* pop seh_handler */ \
|
||||
__asm dec seh_count /* decrease number of seh */ \
|
||||
}
|
||||
|
||||
// Define seh_exit as the shared exit label
|
||||
#define seh_pop() seh_pop_(seh_exit)
|
||||
#define seh_push() seh_push_(seh_exit, 0, eax, ecx) // use ecx as counter better than ebx
|
||||
|
||||
/**
|
||||
* @param _eh EXCEPTION_ROUTINE or 0
|
||||
*/
|
||||
#define seh_push_eh(_eh) seh_push_(seh_exit, _eh, eax, ecx)
|
||||
|
||||
/**
|
||||
* Wrap the code block with SEH handler
|
||||
* @param* any code block. The colon for the last expression is optional.
|
||||
*/
|
||||
#define seh_with(...) \
|
||||
{ \
|
||||
seh_push() \
|
||||
__VA_ARGS__ \
|
||||
; /* allow __VA_ARGS__ to be an expression */ \
|
||||
seh_pop() \
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the code block with SEH handler
|
||||
* @param _eh EXCEPTION_ROUTINE or 0
|
||||
* @param* any code block. The colon for the last expression is optional.
|
||||
*/
|
||||
#define seh_with_eh(_eh, ...) \
|
||||
{ \
|
||||
seh_push_eh(_eh) \
|
||||
__VA_ARGS__ \
|
||||
; /* allow __VA_ARGS__ to be an expression */ \
|
||||
seh_pop() \
|
||||
}
|
||||
|
||||
// EOF
|
||||
|
||||
//#define seh_push_front() \
|
||||
// { \
|
||||
// __asm mov eax, seh_exit \
|
||||
// __asm mov seh_eip, eax \
|
||||
// __asm push seh_handler \
|
||||
// __asm push fs:[0] \
|
||||
// __asm mov seh_esp, esp \
|
||||
// __asm mov fs:[0], esp \
|
||||
// }
|
||||
//
|
||||
//#define seh_pop_front() \
|
||||
// { \
|
||||
// __asm seh_exit: \
|
||||
// __asm mov eax, [esp] \
|
||||
// __asm mov fs:[0], eax \
|
||||
// __asm add esp, 8 \
|
||||
// }
|
||||
//
|
||||
//#define seh_push_back() \
|
||||
// { \
|
||||
// __asm mov eax, seh_exit \
|
||||
// __asm mov ecx, seh_capacity - 1 \
|
||||
// __asm mov DWORD PTR seh_eip[ecx*4], eax \
|
||||
// __asm push seh_handler \
|
||||
// __asm push fs:[0] \
|
||||
// __asm mov DWORD PTR seh_esp[ecx*4], esp \
|
||||
// __asm mov fs:[0], esp \
|
||||
// }
|
||||
//
|
||||
//#define seh_pop_back() \
|
||||
// { \
|
||||
// __asm seh_exit: \
|
||||
// __asm mov eax, [esp] \
|
||||
// __asm mov fs:[0], eax \
|
||||
// __asm add esp, 8 \
|
||||
// }
|
@ -1,10 +0,0 @@
|
||||
// winseh_safe.cc
|
||||
// 12/13/2013 jichi
|
||||
// See: http://stackoverflow.com/questions/12019689/custom-seh-handler-with-safeseh
|
||||
|
||||
#include "winseh/winseh.h"
|
||||
|
||||
extern "C" int __stdcall _seh_asm_handler();
|
||||
seh_dword_t seh_handler = reinterpret_cast<seh_dword_t>(_seh_asm_handler);
|
||||
|
||||
// EOF
|
@ -1,11 +0,0 @@
|
||||
// winseh_unsafe.cc
|
||||
// 12/13/2013 jichi
|
||||
// See: http://stackoverflow.com/questions/19722308/exception-handler-not-called-in-c
|
||||
|
||||
#include "winseh/winseh.h"
|
||||
#include <windows.h>
|
||||
|
||||
extern "C" EXCEPTION_DISPOSITION _seh_handler(PEXCEPTION_RECORD, PVOID, PCONTEXT, PVOID);
|
||||
seh_dword_t seh_handler = reinterpret_cast<seh_dword_t>(_seh_handler);
|
||||
|
||||
// EOF
|
@ -1,49 +0,0 @@
|
||||
// wintimer.cc
|
||||
// 6/6/2012 jichi
|
||||
|
||||
#include "wintimer/wintimer.h"
|
||||
|
||||
//#define DEBUG "wintimer.cc"
|
||||
#include "sakurakit/skdebug.h"
|
||||
#include <windows.h>
|
||||
WINTIMER_BEGIN_NAMESPACE
|
||||
|
||||
void WinTimer::singleShot(int msecs, const function_type &f, WId parent)
|
||||
{
|
||||
Self *t = new Self(parent);
|
||||
t->setInterval(msecs);
|
||||
t->setSingleShot(true);
|
||||
t->setFunction([=] { // Copy function f instead of pass by reference.
|
||||
f();
|
||||
delete t;
|
||||
});
|
||||
t->start();
|
||||
}
|
||||
|
||||
WINTIMER_END_NAMESPACE
|
||||
|
||||
// EOF
|
||||
|
||||
/*
|
||||
// - Single shot -
|
||||
|
||||
namespace { // unnamed
|
||||
|
||||
class apply_delete
|
||||
{
|
||||
typedef WinTimer::function_type function_type;
|
||||
function_type f_;
|
||||
WinTimer *t_;
|
||||
public:
|
||||
apply_delete(const function_type &f, WinTimer *t)
|
||||
: f_(f), t_(t) { Q_ASSERT(t); }
|
||||
|
||||
void operator()()
|
||||
{
|
||||
f_();
|
||||
delete t_;
|
||||
}
|
||||
};
|
||||
|
||||
} // unnamed namespace
|
||||
*/
|
@ -1,93 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// wintimer.h
|
||||
// 6/6/2012 jichi
|
||||
//
|
||||
// A light-weighted native windows timer as a replacement of QTimer from Qt.
|
||||
// Implementation is based on Windows Messaging. A visible parent hwnd is required.
|
||||
//
|
||||
// This timer is critical where QTimer or event loop are not available, or need to
|
||||
// warp to different event loop. Some usage cases follow:
|
||||
// - Used by texthook as a replacement of QTimer in non-QThread
|
||||
// - Used by qapplicationloader to implement pseudo event loop
|
||||
// - Used by winhook to synchronize with window event loop across threads
|
||||
|
||||
#include "wintimer/wintimerbase.h"
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
/**
|
||||
* @brief A light-weighted native windows timer as a replacement of QTimer.
|
||||
*
|
||||
* Needed when in a thread where event loop is not accessible.
|
||||
* Implemented using extensive inlining over pimp, so that the entire class
|
||||
* could be put on the stack without heap.
|
||||
*
|
||||
* Each timer requires an valid visible window's handle to synchronize with.
|
||||
* Either specify the window handle with the parent window or a global window.
|
||||
*/
|
||||
class WinTimer : protected WinTimerBase
|
||||
{
|
||||
SK_EXTEND_CLASS(WinTimer, WinTimerBase)
|
||||
SK_DISABLE_COPY(WinTimer)
|
||||
|
||||
// - Construction -
|
||||
public:
|
||||
//typedef std::function<void ()> function_type;
|
||||
using Base::function_type; ///< std::function<void ()>
|
||||
|
||||
/// Default parent window of all timers.
|
||||
static WId globalWindow() { return Base::globalWindow; }
|
||||
static void setGlobalWindow(WId winId) { Base::globalWindow = winId; }
|
||||
|
||||
//static WId createHiddenWindow();
|
||||
|
||||
public:
|
||||
/// Construct a timer with the parent window handle.
|
||||
explicit WinTimer(WId parentWindow = 0) { setParentWindow(parentWindow); }
|
||||
|
||||
static void singleShot(int msecs, const function_type &f, WId parent = 0);
|
||||
|
||||
// - Properties -
|
||||
public:
|
||||
using Base::isActive;
|
||||
using Base::isSingleShot;
|
||||
|
||||
void setSingleShot(bool t) { Base::singleShot = t; }
|
||||
|
||||
//bool isEmpty() const { return Base::function.empty(); }
|
||||
|
||||
WId parentWindow() const { return Base::parentWindow; }
|
||||
void setParentWindow(WId winId) { Base::parentWindow = winId ? winId : Base::globalWindow; }
|
||||
|
||||
int interval() const { return Base::interval; }
|
||||
void setInterval(int msecs) { Base::interval = msecs; }
|
||||
|
||||
/// Timeout callback when trigger.
|
||||
void setFunction(const function_type &f) { Base::function = f; }
|
||||
|
||||
/// @overload Set callback to a class method
|
||||
template <typename Class, typename Member>
|
||||
void setMethod(Class *obj, Member mfunc)
|
||||
{ setFunction(boost::bind(mfunc, obj)); }
|
||||
|
||||
/// @overload Set callback to a const class method
|
||||
template <typename Class, typename Member>
|
||||
void setMethod(const Class *obj, Member mfunc)
|
||||
{ setFunction(boost::bind(mfunc, obj)); }
|
||||
|
||||
// - Actions -
|
||||
public:
|
||||
/// Start TimerProc
|
||||
using Base::start;
|
||||
|
||||
/// Stop TimerProc
|
||||
using Base::stop;
|
||||
|
||||
/// Reset interval and start TimerProc
|
||||
void start(int interval) { setInterval(interval); start(); }
|
||||
|
||||
/// Invoke the callback. This function is the callback of the underlying TimerProc
|
||||
using Base::trigger;
|
||||
};
|
||||
|
||||
WINTIMER_END_NAMESPACE
|
@ -1,73 +0,0 @@
|
||||
// wintimerbase.cc
|
||||
// 6/6/2012 jichi
|
||||
|
||||
#include "wintimer/wintimerbase.h"
|
||||
#ifdef QT_CORE_LIB
|
||||
# include <qt_windows.h>
|
||||
#else
|
||||
# include <windows.h>
|
||||
#endif // QT_CORE_LIB
|
||||
#include "ccutil/ccmacro.h"
|
||||
|
||||
//#define DEBUG "wintimerbase.cc"
|
||||
#include "sakurakit/skdebug.h"
|
||||
|
||||
static VOID CALLBACK WinTimerProc(
|
||||
HWND hwnd, // ウィンドウのハンドル
|
||||
UINT uMsg, // WM_TIMER メッセージ
|
||||
UINT_PTR idEvent, // Timer ID
|
||||
DWORD dwTime // 現在のシステム時刻
|
||||
)
|
||||
{
|
||||
Q_UNUSED(hwnd)
|
||||
Q_UNUSED(dwTime)
|
||||
Q_UNUSED(uMsg)
|
||||
Q_ASSERT(idEvent);
|
||||
if (CC_UNLIKELY(!idEvent))
|
||||
return;
|
||||
DOUT("enter");
|
||||
WinTimerBase *t = reinterpret_cast<WinTimerBase *>(idEvent);
|
||||
|
||||
if (t->isSingleShot() && t->isActive())
|
||||
t->stop();
|
||||
t->trigger();
|
||||
DOUT("leave");
|
||||
}
|
||||
|
||||
WINTIMER_BEGIN_NAMESPACE
|
||||
|
||||
// - Construction -
|
||||
|
||||
WId WinTimerBase::globalWindow;
|
||||
|
||||
//WId WinTimer::createHiddenWindow()
|
||||
//{
|
||||
// DOUT("enter: warning: hidden window used");
|
||||
// QWidget *w = new QWidget;
|
||||
// w->resize(QSize());
|
||||
// w->show();
|
||||
// DOUT("leave");
|
||||
// return w->winId();
|
||||
//}
|
||||
|
||||
// - Timer -
|
||||
|
||||
void WinTimerBase::start()
|
||||
{
|
||||
DOUT("enter: active =" << active << ", interval =" << interval);
|
||||
active = true;
|
||||
::SetTimer(parentWindow, reinterpret_cast<UINT_PTR>(this), interval, WinTimerProc);
|
||||
DOUT("leave");
|
||||
}
|
||||
|
||||
void WinTimerBase::stop()
|
||||
{
|
||||
DOUT("enter: active =" << active);
|
||||
active = false;
|
||||
::KillTimer(parentWindow, reinterpret_cast<UINT_PTR>(this));
|
||||
DOUT("leave");
|
||||
}
|
||||
|
||||
WINTIMER_END_NAMESPACE
|
||||
|
||||
// EOF
|
@ -1,68 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// wintimerbase.h
|
||||
// 6/6/2012 jichi
|
||||
//
|
||||
// Internal header for wintimer base class.
|
||||
|
||||
#include "sakurakit/skglobal.h"
|
||||
#include <functional>
|
||||
|
||||
#ifdef QT_CORE_LIB
|
||||
# include <QtGui/qwindowdefs.h>
|
||||
#else
|
||||
# include <windows.h>
|
||||
#endif // QT_CORE_LIB
|
||||
|
||||
#ifndef WINTIMER_BEGIN_NAMESPACE
|
||||
# define WINTIMER_BEGIN_NAMESPACE
|
||||
#endif
|
||||
#ifndef WINTIMER_END_NAMESPACE
|
||||
# define WINTIMER_END_NAMESPACE
|
||||
#endif
|
||||
|
||||
WINTIMER_BEGIN_NAMESPACE
|
||||
|
||||
/// Internal base class for WinTimer
|
||||
class WinTimerBase
|
||||
{
|
||||
SK_CLASS(WinTimerBase)
|
||||
SK_DISABLE_COPY(WinTimerBase)
|
||||
|
||||
// - Types -
|
||||
public:
|
||||
typedef std::function<void ()> function_type;
|
||||
#ifndef QT_CORE_LIB
|
||||
typedef HWND WId;
|
||||
#endif // QT_CORE_LIB
|
||||
|
||||
// - Methods -
|
||||
public:
|
||||
/// Construct a timer with the parent window handle.
|
||||
WinTimerBase()
|
||||
: parentWindow(0), // use 0 instead of nullptr to be consistent with Qt5
|
||||
interval(0), singleShot(false), active(false) {}
|
||||
|
||||
bool isSingleShot() const { return singleShot; }
|
||||
bool isActive() const { return active; }
|
||||
|
||||
/// Start TimerProc
|
||||
void start();
|
||||
/// Stop TimerProc
|
||||
void stop();
|
||||
/// Invoke the callback. This function is the callback of the underlying TimerProc
|
||||
void trigger() { function(); }
|
||||
|
||||
// - Fields -
|
||||
protected:
|
||||
static WId globalWindow;
|
||||
|
||||
WId parentWindow;
|
||||
int interval;
|
||||
bool singleShot;
|
||||
bool active;
|
||||
function_type function;
|
||||
|
||||
};
|
||||
|
||||
WINTIMER_END_NAMESPACE
|
Loading…
Reference in New Issue
Block a user