mireado

update to 3.5640.1

update to ITHVNR 3.5640.1
and translation
Showing 140 changed files with 3558 additions and 705 deletions
# common.pri
# DEFINES += _CRT_NON_CONFORMING_SWPRINTFS
# config.pri
# win32 {
# DEFINES += _SECURE_SCL=0 _SCL_SECURE_NO_WARNINGS
# DEFINES += _CRT_SECURE_NO_WARNINGS
# QMAKE_CXXFLAGS += -wd4819
# }
# config.pri
# win32 {
# CONFIG(nocrt) {
# message(CONFIG nocrt)
# QMAKE_CFLAGS -= /MD /MDd
# QMAKE_CFLAGS_DEBUG -= /MD /MDd
# QMAKE_CFLAGS_RELEASE -= /MD /MDd
# QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO -= /MD /MDd
# QMAKE_CXXFLAGS -= /MD /MDd
# QMAKE_CXXFLAGS_DEBUG -= /MD /MDd
# QMAKE_CXXFLAGS_RELEASE -= /MD /MDd
# QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO -= /MD /MDd
# }
# CONFIG(eha) {
# message(CONFIG eha)
# QMAKE_CXXFLAGS_STL_ON -= /EHsc
# QMAKE_CXXFLAGS_EXCEPTIONS_ON -= /EHsc
# QMAKE_CXXFLAGS_STL_ON += /EHa
# QMAKE_CXXFLAGS_EXCEPTIONS_ON += /EHa
# }
# CONFIG(noeh) {
# message(CONFIG noeh)
# QMAKE_CXXFLAGS += /GR-
# QMAKE_CXXFLAGS_RTTI_ON -= /GR
# QMAKE_CXXFLAGS_STL_ON -= /EHsc
# QMAKE_CXXFLAGS_EXCEPTIONS_ON -= /EHsc
# CONFIG(dll) {
# QMAKE_LFLAGS += /ENTRY:"DllMain"
# }
# }
# CONFIG(nosafeseh) {
# message(CONFIG nosafeseh)
# QMAKE_LFLAGS += -safeseh:no
# }
# }
# dllconfig.pri
# win32 {
# CONFIG(eh): DEFINES += ITH_HAS_SEH
# CONFIG(noeh): DEFINES -= ITH_HAS_SEH
# }
cmake_minimum_required(VERSION 2.8)
set(CMAKE_CONFIGURATION_TYPES Debug Release)
......@@ -66,10 +14,11 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/Release")
set(CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION ON)
set(CPACK_GENERATOR "ZIP")
set(CPACK_PACKAGE_VERSION_MAJOR 3)
set(CPACK_PACKAGE_VERSION_MINOR 4152)
set(CPACK_PACKAGE_VERSION_PATCH 0)
set(CPACK_PACKAGE_VERSION_MINOR 5640)
set(CPACK_PACKAGE_VERSION_PATCH 1)
set(CPACK_SOURCE_GENERATOR "ZIP")
set(CPACK_SOURCE_IGNORE_FILES "/CVS/;/\\\\.svn/;/\\\\.bzr/;/\\\\.hg/;/\\\\.git/;\\\\.swp$;\\\\.#;/#" ".*\\\\.user$" "\\\\.gitignore$" "\\\\.gitmodules$" "\\\\.git$")
include(CPack)
......@@ -84,24 +33,20 @@ add_compile_options(
)
add_definitions(
-D_SECURE_SCL=0 # config.pri
-D_SCL_SECURE_NO_WARNINGS # config.pri
-D_CRT_SECURE_NO_WARNINGS # config.pri
-DUNICODE # config.pri
-D_UNICODE
-D_CRT_NON_CONFORMING_SWPRINTFS # common.pri
-DITH_HAS_CRT
/D_SECURE_SCL=0 # config.pri
/D_SCL_SECURE_NO_WARNINGS # config.pri
/D_CRT_SECURE_NO_WARNINGS # config.pri
/DUNICODE # config.pri
/D_UNICODE
/D_CRT_NON_CONFORMING_SWPRINTFS # common.pri
/DITH_HAS_CRT
)
include_directories(${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/vnr ${CMAKE_BINARY_DIR}/gui)
set(common_src
vnr/ith/common/const.h
vnr/ith/common/defs.h
vnr/ith/common/except.h
vnr/ith/common/growl.h
vnr/ith/common/memory.h
vnr/ith/common/types.h
include_directories(
.
vnr
vnr/texthook
${CMAKE_BINARY_DIR}/gui
)
set(resource_src
......@@ -119,13 +64,8 @@ set(ithvnr_src
gui/main.cpp
gui/ProcessWindow.cpp
gui/ProcessWindow.h
gui/Profile.cpp
gui/Profile.h
gui/ProfileManager.cpp
gui/ProfileManager.h
gui/pugiconfig.hpp
gui/pugixml.cpp
gui/pugixml.hpp
gui/resource.h
gui/utility.cpp
gui/utility.h
......@@ -135,17 +75,15 @@ set(ithvnr_src
gui/window.h
gui/TextBuffer.cpp
gui/TextBuffer.h
${common_src}
${resource_src}
)
source_group("common" FILES ${common_src})
source_group("Resource Files" FILES ${resource_src})
add_executable(${PROJECT_NAME} ${ithvnr_src})
add_subdirectory(vnr)
# add_subdirectory(profile)
set_target_properties(${PROJECT_NAME} PROPERTIES
LINK_FLAGS "/SUBSYSTEM:WINDOWS /MANIFESTDEPENDENCY:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\""
......@@ -158,8 +96,9 @@ target_compile_definitions(${PROJECT_NAME}
)
target_link_libraries(${PROJECT_NAME}
profile
vnrhost
vnrsys
ithsys
${WDK_HOME}/lib/wxp/i386/ntdll.lib
comctl32.lib
psapi.lib
......
......@@ -16,6 +16,7 @@
*/
#pragma once
#include "ITH.h"
typedef void (*CustomFilterCallBack) (WORD, PVOID);
......
......@@ -15,7 +15,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <windows.h>
#include <Windows.h>
#include <string>
#include <sstream>
#include <ios>
......@@ -29,9 +30,8 @@
#include <map>
#include <CommCtrl.h>
#include <intrin.h>
#include <WindowsX.h>
#include <sstream>
#include <regex>
#include <set>
#include "pugixml.hpp"
#include "profile/pugixml.hpp"
#pragma warning(disable: 4146)
......
// Generated by ResEdit 1.6.3
// Copyright (C) 2006-2014
// Generated by ResEdit 1.6.5
// Copyright (C) 2006-2015
// http://www.resedit.net
#include <windows.h>
......@@ -7,9 +7,6 @@
#include <richedit.h>
#include "resource.h"
#define WC_LISTVIEW L"SysListView32"
......@@ -22,14 +19,14 @@ STYLE DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYS
CAPTION "Process Explorer"
FONT 8, "MS Shell Dlg", 400, 0, 1
{
DEFPUSHBUTTON "확인", IDOK, 281, 189, 53, 14, 0, WS_EX_LEFT
PUSHBUTTON "프로필 제거", IDC_BUTTON6, 226, 189, 53, 14, 0, WS_EX_LEFT
CONTROL "", IDC_LIST1, WC_LISTVIEW, WS_TABSTOP | WS_BORDER | LVS_ALIGNLEFT | LVS_SHOWSELALWAYS | LVS_SINGLESEL | LVS_REPORT, 7, 20, 327, 164, WS_EX_LEFT
LTEXT "프로세스", IDC_STATIC, 7, 7, 65, 13, SS_LEFT | SS_CENTERIMAGE, WS_EX_LEFT
PUSHBUTTON "부착", IDC_BUTTON2, 61, 189, 53, 14, 0, WS_EX_LEFT
PUSHBUTTON "탈착", IDC_BUTTON3, 116, 189, 53, 14, 0, WS_EX_LEFT
PUSHBUTTON "프로필 추가", IDC_BUTTON5, 171, 189, 53, 14, 0, WS_EX_LEFT
PUSHBUTTON "새로고침", IDC_BUTTON1, 7, 189, 53, 14, 0, WS_EX_LEFT
DEFPUSHBUTTON "확인", IDOK, 281, 189, 53, 14, 0, WS_EX_LEFT
PUSHBUTTON "프로필 제거", IDC_BUTTON6, 226, 189, 53, 14, 0, WS_EX_LEFT
CONTROL "", IDC_LIST1, WC_LISTVIEW, WS_TABSTOP | WS_BORDER | LVS_ALIGNLEFT | LVS_SHOWSELALWAYS | LVS_SINGLESEL | LVS_REPORT, 7, 20, 327, 164, WS_EX_LEFT
LTEXT "프로세스", IDC_STATIC, 7, 7, 65, 13, SS_LEFT | SS_CENTERIMAGE, WS_EX_LEFT
PUSHBUTTON "부착", IDC_BUTTON2, 61, 189, 53, 14, 0, WS_EX_LEFT
PUSHBUTTON "탈착", IDC_BUTTON3, 116, 189, 53, 14, 0, WS_EX_LEFT
PUSHBUTTON "프로필 추가", IDC_BUTTON5, 171, 189, 53, 14, 0, WS_EX_LEFT
PUSHBUTTON "새로고침", IDC_BUTTON1, 7, 189, 53, 14, 0, WS_EX_LEFT
}
......@@ -40,22 +37,22 @@ STYLE DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYS
CAPTION "Option"
FONT 8, "MS Shell Dlg", 400, 0, 1
{
DEFPUSHBUTTON "확인", IDOK, 8, 164, 50, 14, 0, WS_EX_LEFT
PUSHBUTTON "취소", IDCANCEL, 65, 164, 50, 14, 0, WS_EX_LEFT
EDITTEXT IDC_EDIT1, 60, 7, 55, 14, ES_AUTOHSCROLL, WS_EX_LEFT
LTEXT "문단나누기", IDC_STATIC, 7, 7, 47, 13, SS_LEFT | SS_CENTERIMAGE, WS_EX_LEFT
EDITTEXT IDC_EDIT2, 60, 25, 55, 14, ES_AUTOHSCROLL, WS_EX_LEFT
LTEXT "프로세스 대기", IDC_STATIC, 7, 26, 47, 13, SS_LEFT | SS_CENTERIMAGE, WS_EX_LEFT
EDITTEXT IDC_EDIT3, 60, 45, 55, 14, ES_AUTOHSCROLL, WS_EX_LEFT
LTEXT "인젝션 대기", IDC_STATIC, 7, 45, 47, 13, SS_LEFT | SS_CENTERIMAGE, WS_EX_LEFT
EDITTEXT IDC_EDIT4, 60, 65, 55, 14, ES_AUTOHSCROLL, WS_EX_LEFT
LTEXT "삽입 대기", IDC_STATIC, 7, 65, 47, 13, SS_LEFT | SS_CENTERIMAGE, WS_EX_LEFT
AUTOCHECKBOX "자동 부착", IDC_CHECK1, 7, 87, 54, 10, 0, WS_EX_LEFT
AUTOCHECKBOX "자동 삽입", IDC_CHECK2, 62, 87, 50, 10, 0, WS_EX_LEFT
AUTOCHECKBOX "클립보드로 자동 복사", IDC_CHECK3, 7, 103, 88, 10, 0, WS_EX_LEFT
AUTOCHECKBOX "자동 반복문 제거", IDC_CHECK4, 7, 119, 95, 10, 0, WS_EX_LEFT
AUTOCHECKBOX "문자필터 초기화", IDC_CHECK6, 7, 149, 81, 8, 0, WS_EX_LEFT
AUTOCHECKBOX "글로벌 필터 활성화", IDC_CHECK5, 7, 134, 75, 10, 0, WS_EX_LEFT
DEFPUSHBUTTON "확인", IDOK, 8, 164, 50, 14, 0, WS_EX_LEFT
PUSHBUTTON "취소", IDCANCEL, 65, 164, 50, 14, 0, WS_EX_LEFT
EDITTEXT IDC_EDIT1, 60, 7, 55, 14, ES_AUTOHSCROLL, WS_EX_LEFT
LTEXT "문단나누기", IDC_STATIC, 7, 7, 47, 13, SS_LEFT | SS_CENTERIMAGE, WS_EX_LEFT
EDITTEXT IDC_EDIT2, 60, 25, 55, 14, ES_AUTOHSCROLL, WS_EX_LEFT
LTEXT "프로세스 대기", IDC_STATIC, 7, 26, 47, 13, SS_LEFT | SS_CENTERIMAGE, WS_EX_LEFT
EDITTEXT IDC_EDIT3, 60, 45, 55, 14, ES_AUTOHSCROLL, WS_EX_LEFT
LTEXT "인젝션 대기", IDC_STATIC, 7, 45, 47, 13, SS_LEFT | SS_CENTERIMAGE, WS_EX_LEFT
EDITTEXT IDC_EDIT4, 60, 65, 55, 14, ES_AUTOHSCROLL, WS_EX_LEFT
LTEXT "삽입 대기", IDC_STATIC, 7, 65, 47, 13, SS_LEFT | SS_CENTERIMAGE, WS_EX_LEFT
AUTOCHECKBOX "자동 부착", IDC_CHECK1, 7, 87, 54, 10, 0, WS_EX_LEFT
AUTOCHECKBOX "자동 삽입", IDC_CHECK2, 62, 87, 50, 10, 0, WS_EX_LEFT
AUTOCHECKBOX "클립보드로 자동 복사", IDC_CHECK3, 7, 103, 88, 10, 0, WS_EX_LEFT
AUTOCHECKBOX "자동 반복문 제거", IDC_CHECK4, 7, 119, 95, 10, 0, WS_EX_LEFT
AUTOCHECKBOX "문자필터 초기화", IDC_CHECK6, 7, 149, 81, 8, 0, WS_EX_LEFT
AUTOCHECKBOX "글로벌 필터 활성화", IDC_CHECK5, 7, 134, 75, 10, 0, WS_EX_LEFT
}
......@@ -65,3 +62,21 @@ FONT 8, "MS Shell Dlg", 400, 0, 1
//
LANGUAGE LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN
IDI_ICON1 ICON "icon1.ico"
//
// Version Information resources
//
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
1 VERSIONINFO
FILEVERSION 0,0,0,0
PRODUCTVERSION 0,0,0,0
FILEOS VOS_UNKNOWN
FILETYPE VFT_UNKNOWN
FILESUBTYPE VFT2_UNKNOWN
FILEFLAGSMASK 0
FILEFLAGS 0
{
}
......
#include "ProcessWindow.h"
#include "resource.h"
#include "ith/host/srv.h"
#include "ith/host/hookman.h"
#include "host/host.h"
#include "host/hookman.h"
#include "ProfileManager.h"
#include "Profile.h"
#include "profile/Profile.h"
extern HookManager* man; // main.cpp
extern ProfileManager* pfman; // ProfileManager.cpp
......@@ -22,6 +22,8 @@ ProcessWindow::ProcessWindow(HWND hDialog) : hDlg(hDialog)
ListView_SetExtendedListViewStyleEx(hlProcess, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
InitProcessDlg();
RefreshProcess();
EnableWindow(hbDetach, FALSE);
EnableWindow(hbAttach, FALSE);
}
void ProcessWindow::InitProcessDlg()
......@@ -73,30 +75,33 @@ void ProcessWindow::RefreshProcess()
void ProcessWindow::AttachProcess()
{
DWORD pid = GetSelectedPID();
if (IHF_InjectByPID(pid) != -1)
if (Host_InjectByPID(pid))
{
Host_HijackProcess(pid);
RefreshThreadWithPID(pid, true);
}
}
void ProcessWindow::DetachProcess()
{
DWORD pid = GetSelectedPID();
if (IHF_ActiveDetachProcess(pid) == 0)
if (Host_ActiveDetachProcess(pid) == 0)
RefreshThreadWithPID(pid, false);
}
void ProcessWindow::AddCurrentToProfile()
void ProcessWindow::CreateProfileForSelectedProcess()
{
DWORD pid = GetSelectedPID();
auto path = GetProcessPath(pid);
if (!path.empty())
{
Profile* pf = pfman->AddProfile(path, pid);
pfman->FindProfileAndUpdateHookAddresses(pid, path);
Profile* pf = pfman->CreateProfile(pid);
pfman->SaveProfiles();
RefreshThread(ListView_GetSelectionMark(hlProcess));
}
}
void ProcessWindow::RemoveCurrentFromProfile()
void ProcessWindow::DeleteProfileForSelectedProcess()
{
DWORD pid = GetSelectedPID();
auto path = GetProcessPath(pid);
......@@ -132,7 +137,7 @@ void ProcessWindow::RefreshThreadWithPID(DWORD pid, bool isAttached)
DWORD ProcessWindow::GetSelectedPID()
{
LVITEM item={};
LVITEM item = {};
item.mask = LVIF_PARAM;
item.iItem = ListView_GetSelectionMark(hlProcess);
ListView_GetItem(hlProcess, &item);
......
#pragma once
#include "ITH.h"
class ProcessWindow
......@@ -9,8 +10,8 @@ public:
void RefreshProcess();
void AttachProcess();
void DetachProcess();
void AddCurrentToProfile();
void RemoveCurrentFromProfile();
void CreateProfileForSelectedProcess();
void DeleteProfileForSelectedProcess();
void RefreshThread(int index);
private:
void RefreshThreadWithPID(DWORD pid, bool isAttached);
......
#include "ProfileManager.h"
#include "Profile.h"
#include "ith/host/srv.h"
#include "ith/host/hookman.h"
#include "ith/common/types.h"
#include "ith/common/const.h"
#include "profile/Profile.h"
#include "host/host.h"
#include "host/hookman.h"
#include "vnrhook/include/types.h"
#include "vnrhook/include/const.h"
#include "utility.h"
#include "profile/misc.h"
extern HookManager* man; // main.cpp
extern LONG auto_inject, auto_insert, inject_delay; // main.cpp
......@@ -12,21 +14,16 @@ bool MonitorFlag;
ProfileManager* pfman;
DWORD WINAPI MonitorThread(LPVOID lpThreadParameter);
void AddHooksToProfile(Profile& pf, const ProcessRecord& pr);
void AddThreadsToProfile(Profile& pf, const ProcessRecord& pr, DWORD pid);
DWORD AddThreadToProfile(Profile& pf, const ProcessRecord& pr, TextThread& thread);
void MakeHookRelative(const ProcessRecord& pr, HookParam& hp);
std::wstring GetHookNameByAddress(const ProcessRecord& pr, DWORD hook_address);
void GetHookNameToAddressMap(const ProcessRecord& pr, std::map<std::wstring, DWORD>& hookNameToAddress);
ProfileManager::ProfileManager():
ProfileManager::ProfileManager() :
hMonitorThread(IthCreateThread(MonitorThread, 0))
{
LoadProfile();
LoadProfiles();
}
ProfileManager::~ProfileManager()
{
SaveProfile();
SaveProfiles();
WaitForSingleObject(hMonitorThread.get(), 0);
}
......@@ -42,7 +39,7 @@ Profile* ProfileManager::GetProfile(DWORD pid)
return NULL;
}
bool ProfileManager::AddProfile(pugi::xml_node game)
bool ProfileManager::CreateProfile(pugi::xml_node game)
{
auto file = game.child(L"File");
auto profile = game.child(L"Profile");
......@@ -56,13 +53,17 @@ bool ProfileManager::AddProfile(pugi::xml_node game)
auto pf = new Profile(title);
if (!pf->XmlReadProfile(profile))
return false;
AddProfile(path.value(), profile_ptr(pf));
return true;
CSLock lock(cs);
auto& oldProfile = profile_tree[path.value()];
if (!oldProfile)
oldProfile.swap(profile_ptr(pf));
return true;
}
Profile* ProfileManager::AddProfile(const std::wstring& path, DWORD pid)
Profile* ProfileManager::CreateProfile(DWORD pid)
{
CSLock lock(cs);
auto path = GetProcessPath(pid);
auto& pf = profile_tree[path];
if (!pf)
{
......@@ -72,15 +73,6 @@ Profile* ProfileManager::AddProfile(const std::wstring& path, DWORD pid)
return pf.get();
}
Profile* ProfileManager::AddProfile(const std::wstring& path, profile_ptr new_profile)
{
CSLock lock(cs);
auto& pf = profile_tree[path];
if (!pf)
pf.swap(new_profile);
return pf.get();
}
void ProfileManager::WriteProfileXml(const std::wstring& path, Profile& pf, pugi::xml_node root)
{
auto game = root.append_child(L"Game");
......@@ -96,7 +88,7 @@ void ProfileManager::WriteProfileXml(const std::wstring& path, Profile& pf, pugi
}
}
void ProfileManager::LoadProfile()
void ProfileManager::LoadProfiles()
{
pugi::xml_document doc;
UniqueHandle hFile(IthCreateFile(L"ITH_Profile.xml", GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING));
......@@ -112,10 +104,10 @@ void ProfileManager::LoadProfile()
if (!root)
return;
for (auto game = root.begin(); game != root.end(); ++game)
AddProfile(*game);
CreateProfile(*game);
}
void ProfileManager::SaveProfile()
void ProfileManager::SaveProfiles()
{
pugi::xml_document doc;
auto root = doc.append_child(L"ITH_Profile");
......@@ -138,44 +130,14 @@ void ProfileManager::DeleteProfile(const std::wstring& path)
profile_tree.erase(profile_tree.find(path));
}
void ProfileManager::FindProfileAndUpdateHookAddresses(DWORD pid, const std::wstring& path)
Profile* ProfileManager::GetProfile(const std::wstring& path)
{
if (path.empty())
return;
return nullptr;
auto it = profile_tree.find(path);
if (it == profile_tree.end())
return;
auto& pf = it->second;
const ProcessRecord* pr = man->GetProcessRecord(pid);
if (pr == NULL)
return;
// hook name -> hook address
std::map<std::wstring, DWORD> hookNameToAddress;
GetHookNameToAddressMap(*pr, hookNameToAddress);
for (auto thread_profile = pf->Threads().begin(); thread_profile != pf->Threads().end();
++thread_profile)
{
auto it = hookNameToAddress.find((*thread_profile)->HookName());
if (it != hookNameToAddress.end())
(*thread_profile)->HookAddress() = it->second;
}
}
void GetHookNameToAddressMap(const ProcessRecord& pr,
std::map<std::wstring, DWORD>& hookNameToAddress)
{
WaitForSingleObject(pr.hookman_mutex, 0);
auto hooks = (const Hook*)pr.hookman_map;
for (DWORD i = 0; i < MAX_HOOK; ++i)
{
if (hooks[i].Address() == 0)
continue;
auto& hook = hooks[i];
std::unique_ptr<WCHAR[]> name(new WCHAR[hook.NameLength() * 2]);
if (ReadProcessMemory(pr.process_handle, hook.Name(), name.get(), hook.NameLength() * 2, NULL))
hookNameToAddress[name.get()] = hook.Address();
}
ReleaseMutex(pr.hookman_mutex);
return nullptr;
return it->second.get();
}
bool ProfileManager::HasProfile(const std::wstring& path)
......@@ -183,7 +145,7 @@ bool ProfileManager::HasProfile(const std::wstring& path)
return profile_tree.find(path) != profile_tree.end();
}
DWORD ProfileManager::ProfileCount()
DWORD ProfileManager::CountProfiles()
{
return profile_tree.size();
}
......@@ -194,7 +156,7 @@ DWORD WINAPI InjectThread(LPVOID lpThreadParameter)
Sleep(inject_delay);
if (man == NULL)
return 0;
DWORD status = IHF_InjectByPID(pid);
DWORD status = Host_InjectByPID(pid);
if (!auto_insert)
return status;
if (status == -1)
......@@ -206,7 +168,10 @@ DWORD WINAPI InjectThread(LPVOID lpThreadParameter)
SendParam sp;
sp.type = 0;
for (auto hp = pf->Hooks().begin(); hp != pf->Hooks().end(); ++hp)
IHF_InsertHook(pid, const_cast<HookParam*>(&(*hp)->HP()), (*hp)->Name().c_str());
{
std::string name = toMultiByteString((*hp)->Name());
Host_InsertHook(pid, const_cast<HookParam*>(&(*hp)->HP()), name.c_str());
}
}
return status;
}
......@@ -215,7 +180,7 @@ DWORD WINAPI MonitorThread(LPVOID lpThreadParameter)
{
while (MonitorFlag)
{
DWORD aProcesses[1024], cbNeeded, cProcesses;
DWORD aProcesses[1024], cbNeeded, cProcesses;
if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
break;
cProcesses = cbNeeded / sizeof(DWORD);
......@@ -237,116 +202,17 @@ DWORD WINAPI MonitorThread(LPVOID lpThreadParameter)
DWORD SaveProcessProfile(DWORD pid)
{
const ProcessRecord* pr = man->GetProcessRecord(pid);
if (pr == NULL)
return 0;
std::wstring path = GetProcessPath(pid);
if (path.empty())
return 0;
pugi::xml_document doc;
pugi::xml_node profile_node = doc.append_child(L"Profile");
man->GetProfile(pid, profile_node);
Profile* pf = pfman->GetProfile(pid);
if (pf != NULL)
pf->Clear();
else
pf = pfman->AddProfile(path, pid);
AddHooksToProfile(*pf, *pr);
AddThreadsToProfile(*pf, *pr, pid);
pf = pfman->CreateProfile(pid);
pf->XmlReadProfile(profile_node);
return 0;
}
void AddHooksToProfile(Profile& pf, const ProcessRecord& pr)
{
WaitForSingleObject(pr.hookman_mutex, 0);
auto hooks = (const Hook*)pr.hookman_map;
for (DWORD i = 0; i < MAX_HOOK; ++i)
{
if (hooks[i].Address() == 0)
continue;
auto& hook = hooks[i];
DWORD type = hook.Type();
if ((type & HOOK_ADDITIONAL) && (type & HOOK_ENGINE) == 0)
{
std::unique_ptr<WCHAR[]> name(new WCHAR[hook.NameLength() * 2]);
if (ReadProcessMemory(pr.process_handle, hook.Name(), name.get(), hook.NameLength() * 2, NULL))
{
if (hook.hp.module)
{
HookParam hp = hook.hp;
MakeHookRelative(pr, hp);
pf.AddHook(hp, name.get());
}
else
pf.AddHook(hook.hp, name.get());
}
}
}
ReleaseMutex(pr.hookman_mutex);
}
void MakeHookRelative(const ProcessRecord& pr, HookParam& hp)
{
MEMORY_BASIC_INFORMATION info;
VirtualQueryEx(pr.process_handle, (LPCVOID)hp.addr, &info, sizeof(info));
hp.addr -= (DWORD)info.AllocationBase;
hp.function = 0;
}
void AddThreadsToProfile(Profile& pf, const ProcessRecord& pr, DWORD pid)
{
man->LockHookman();
ThreadTable* table = man->Table();
for (int i = 0; i < table->Used(); ++i)
{
TextThread* tt = table->FindThread(i);
if (tt == NULL || tt->GetThreadParameter()->pid != pid)
continue;
//if (tt->Status() & CURRENT_SELECT || tt->Link() || tt->GetComment())
if (tt->Status() & CURRENT_SELECT || tt->Link())
AddThreadToProfile(pf, pr, *tt);
}
man->UnlockHookman();
}
DWORD AddThreadToProfile(Profile& pf, const ProcessRecord& pr, TextThread& thread)
{
const ThreadParameter* tp = thread.GetThreadParameter();
std::wstring hook_name = GetHookNameByAddress(pr, tp->hook);
if (hook_name.empty())
return -1;
auto thread_profile = new ThreadProfile(hook_name, tp->retn, tp->spl, 0, 0,
THREAD_MASK_RETN | THREAD_MASK_SPLIT, L"");
DWORD threads_size = pf.Threads().size();
int thread_profile_index = pf.AddThread(thread_ptr(thread_profile));
if (thread_profile_index == threads_size) // new thread
{
WORD iw = thread_profile_index & 0xFFFF;
if (thread.Status() & CURRENT_SELECT)
pf.SelectedIndex() = iw;
if (thread.Link())
{
WORD to_index = AddThreadToProfile(pf, pr, *(thread.Link())) & 0xFFFF;
if (iw >= 0)
pf.AddLink(link_ptr(new LinkProfile(iw, to_index)));
}
}
return thread_profile_index; // in case more than one thread links to the same thread.
}
std::wstring GetHookNameByAddress(const ProcessRecord& pr, DWORD hook_address)
{
std::wstring hook_name;
WaitForSingleObject(pr.hookman_mutex, 0);
auto hooks = (const Hook*)pr.hookman_map;
for (int i = 0; i < MAX_HOOK; ++i)
{
auto& hook = hooks[i];
if (hook.Address() == hook_address)
{
std::unique_ptr<WCHAR[]> name(new WCHAR[hook.NameLength() * 2]);
if (ReadProcessMemory(pr.process_handle, hooks[i].Name(), name.get(), hook.NameLength() * 2, NULL))
hook_name = name.get();
break;
}
}
ReleaseMutex(pr.hookman_mutex);
return hook_name;
}
......
#pragma once
#include "ITH.h"
#include "utility.h" // UniqueHandle, CriticalSection
......@@ -9,14 +10,14 @@ class ProfileManager
public:
ProfileManager();
~ProfileManager();
Profile* AddProfile(const std::wstring& path, DWORD pid);
void DeleteProfile(const std::wstring& path);
void LoadProfile();
void SaveProfile();
void FindProfileAndUpdateHookAddresses(DWORD pid, const std::wstring& path);
Profile* CreateProfile(DWORD pid);
Profile* GetProfile(DWORD pid);
Profile* GetProfile(const std::wstring& path);
void LoadProfiles();
void SaveProfiles();
void DeleteProfile(const std::wstring& path);
void UpdateHookAddresses(DWORD pid);
bool HasProfile(const std::wstring& path);
Profile* GetProfile(DWORD pid);
DWORD ProfileCount();
private:
typedef std::unique_ptr<Profile> profile_ptr;
typedef std::map<std::wstring, profile_ptr> profile_map;
......@@ -24,8 +25,8 @@ private:
ProfileManager(const ProfileManager&);
ProfileManager operator=(const ProfileManager&);
bool AddProfile(pugi::xml_node game);
Profile* AddProfile(const std::wstring& path, profile_ptr new_profile);
DWORD CountProfiles();
bool CreateProfile(pugi::xml_node game);
void WriteProfileXml(const std::wstring& path, Profile& pf, pugi::xml_node doc);
// locate profile with executable path
profile_map profile_tree;
......
......@@ -3,8 +3,8 @@
DWORD WINAPI FlushThread(LPVOID lParam); // window.cpp
TextBuffer::TextBuffer(HWND edit) : hThread(IthCreateThread(FlushThread, (DWORD)this)),
hEdit(edit),
running(true)
hEdit(edit),
running(true)
{
}
......
#pragma once
#include "ITH.h"
#include "utility.h" // UniqueHandle, CriticalSection
......
......@@ -16,157 +16,16 @@
*/
#include "ITH.h"
#include "ith/host/srv.h"
#include "ith/common/const.h"
#include "ith/common/types.h"
#include "host/host.h"
#include "vnrhook/include/const.h"
#include "vnrhook/include/types.h"
#include "language.h"
#include "utility.h"
#include "profile/misc.h"
extern HookManager* man;
extern HWND hwndProcessComboBox;
bool Parse(const std::wstring& cmd, HookParam& hp)
{
using std::wregex;
using std::regex_search;
// /H[X]{A|B|W|S|Q}[N][data_offset[*drdo]][:sub_offset[*drso]]@addr[:[module[:{name|#ordinal}]]]
wregex rx(L"^X?([ABWSQ])(N)?", wregex::icase);
std::match_results<std::wstring::const_iterator> m;
auto start = cmd.begin();
auto end = cmd.end();
bool result = regex_search(start, end, m, rx);
if (!result)
return result;
start = m[0].second;
if (m[2].matched)
hp.type |= NO_CONTEXT;
switch (m[1].first[0])
{
case L's':
case L'S':
hp.type |= USING_STRING;
break;
case L'e':
case L'E':
hp.type |= STRING_LAST_CHAR;
case L'a':
case L'A':
hp.type |= BIG_ENDIAN;
hp.length_offset = 1;
break;
case L'b':
case L'B':
hp.length_offset = 1;
break;
case L'h':
case L'H':
hp.type |= PRINT_DWORD;
case L'q':
case L'Q':
hp.type |= USING_STRING | USING_UNICODE;
break;
case L'l':
case L'L':
hp.type |= STRING_LAST_CHAR;
case L'w':
case L'W':
hp.type |= USING_UNICODE;
hp.length_offset = 1;
break;
default:
break;
}
// [data_offset[*drdo]]
std::wstring data_offset(L"(-?[[:xdigit:]]+)"), drdo(L"(\\*-?[[:xdigit:]]+)?");
rx = wregex(L"^"+ data_offset + drdo, wregex::icase);
result = regex_search(start, end, m, rx);
if (result)
{
start = m[0].second;
hp.off = std::stoul(m[1].str(), NULL, 16);
if (m[2].matched)
{
hp.type |= DATA_INDIRECT;
hp.ind = std::stoul(m[2].str().substr(1), NULL, 16);
}
}
// [:sub_offset[*drso]]
std::wstring sub_offset(L"(-?[[:xdigit:]]+)"), drso(L"(\\*-?[[:xdigit:]]+)?");
rx = wregex(L"^:" + sub_offset + drso, wregex::icase);
result = regex_search(start, end, m, rx);
if (result)
{
start = m[0].second;
hp.type |= USING_SPLIT;
hp.split = std::stoul(m[1].str(), NULL, 16);
if (m[2].matched)
{
hp.type |= SPLIT_INDIRECT;
hp.split_ind = std::stoul(m[2].str().substr(1), NULL, 16);
}
}
// @addr
rx = wregex(L"^@[[:xdigit:]]+", wregex::icase);
result = regex_search(start, end, m, rx);
if (!result)
return false;
start = m[0].second;
hp.addr = std::stoul(m[0].str().substr(1), NULL, 16);
if (hp.off & 0x80000000)
hp.off -= 4;
if (hp.split & 0x80000000)
hp.split -= 4;
// [:[module[:{name|#ordinal}]]]
// ":" ->
// "" -> MODULE_OFFSET && module == NULL && function == addr
// ":GDI.dll" -> MODULE_OFFSET && module != NULL
// ":GDI.dll:strlen" -> MODULE_OFFSET | FUNCTION_OFFSET && module != NULL && function != NULL
// ":GDI.dll:#123" -> MODULE_OFFSET | FUNCTION_OFFSET && module != NULL && function != NULL
std::wstring module(L"([[:graph:]]+)"), name(L"[[:graph:]]+"), ordinal(L"\\d+");
rx = wregex(L"^:(" + module + L"(:" + name + L"|#" + ordinal + L")?)?$", wregex::icase);
result = regex_search(start, end, m, rx);
if (result) // :[module[:{name|#ordinal}]]
{
if (m[1].matched) // module
{
hp.type |= MODULE_OFFSET;
std::wstring module = m[2];
std::transform(module.begin(), module.end(), module.begin(), ::towlower);
hp.module = Hash(module);
if (m[3].matched) // :name|#ordinal
{
hp.type |= FUNCTION_OFFSET;
hp.function = Hash(m[3].str().substr(1));
}
}
}
else
{
rx = wregex(L"^!([[:xdigit:]]+)(!([[:xdigit:]]+))?$", wregex::icase);
result = regex_search(start, end, m, rx);
if (result)
{
hp.type |= MODULE_OFFSET;
hp.module = std::stoul(m[1].str(), NULL, 16);
if (m[2].matched)
{
hp.type |= FUNCTION_OFFSET;
hp.function = std::stoul(m[2].str().substr(1), NULL, 16);
}
}
else
{
hp.type |= MODULE_OFFSET;
hp.function = hp.addr;
}
}
return true;
}
DWORD ProcessCommand(const std::wstring& cmd, DWORD pid)
{
using std::wregex;
......@@ -175,40 +34,40 @@ DWORD ProcessCommand(const std::wstring& cmd, DWORD pid)
if (regex_match(cmd, m, wregex(L"/pn(.+)", wregex::icase)))
{
pid = IHF_GetPIDByName(m[1].str().c_str());
pid = Host_GetPIDByName(m[1].str().c_str());
if (pid == 0)
return 0;
IHF_InjectByPID(pid);
Host_InjectByPID(pid);
}
else if (regex_match(cmd, m, wregex(L"/p(\\d+)", wregex::icase)))
{
pid = std::stoul(m[1].str());
IHF_InjectByPID(pid);
Host_InjectByPID(pid);
}
else if (regex_match(cmd, m, wregex (L"/h(.+)", wregex::icase)))
else if (regex_match(cmd, m, wregex(L"/h(.+)", wregex::icase)))
{
HookParam hp = {};
if (Parse(m[1].str(), hp))
IHF_InsertHook(pid, &hp);
Host_InsertHook(pid, &hp);
}
else if (regex_match(cmd, m, wregex(L"(?::|)(?:ㅇ|연|l|)([[:xdigit:]]+)(?:-| )([[:xdigit:]]+)", wregex::icase)))
else if (regex_match(cmd, m, wregex(L"(?::|)(?:|연|l|)([[:xdigit:]]+)(?:-| )([[:xdigit:]]+)", wregex::icase)))
{
DWORD from = std::stoul(m[1].str(), NULL, 16);
DWORD to = std::stoul(m[2].str(), NULL, 16);
IHF_AddLink(from, to);
Host_AddLink(from, to);
}
else if (regex_match(cmd, m, wregex(L"(?::|)(?:ㅎ|해|해제|u)([[:xdigit:]]+)", wregex::icase)))
else if (regex_match(cmd, m, wregex(L"(?::|)(?:ㅎ|해|해제|u)([[:xdigit:]]+)", wregex::icase)))
{
DWORD from = std::stoul(m[1].str(), NULL, 16);
IHF_UnLink(from);
Host_UnLink(from);
}
else if (regex_match(cmd, m, wregex(L"(?::|)(?:ㄷ|도|도움|도움말|h|help)", wregex::icase)))
else if (regex_match(cmd, m, wregex(L"(?::|)(?:ㄷ|도|도움|도움말|h|help)", wregex::icase)))
{
ConsoleOutput(Usage);
}
else
{
ConsoleOutput(L"알 수 없는 명령어. 도움말을 보시려면, :h 나 :help를 입력하세요.");
ConsoleOutput(L"알 수 없는 명령어. 도움말을 보시려면, :h 나 :help를 입력하세요.");
}
return 0;
}
......
......@@ -14,44 +14,44 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
const wchar_t* Warning=L"경고!";
const wchar_t* Warning = L"경고!";
//command.cpp
const wchar_t* ErrorSyntax=L"명령어 오류";
const wchar_t* Usage = L"명령어:\r\n\
const wchar_t* ErrorSyntax = L"명령어 오류";
const wchar_t* Usage = L"령어:\r\n\
\r\n\
도움말 //도움말을 출력합니다\r\n\
출발 도착 // '출발'스레드에서 '도착'스레드로 연결합니다\r\n\
ㅎ출발 // '출발'스레드에 연결된 링크를 해제합니다\r\n\
도움말 //도움말을 출력합니다\r\n\
출발 도착 // '출발'스레드에서 '도착'스레드로 연결합니다\r\n\
ㅎ출발 // '출발'스레드에 연결된 링크를 해제합니다\r\n\
\r\n\
'출발'과 '도착'에는 16진법(헥사코드) 스레드번호를 입력합니다. 스레드 번호는 맨 앞에 있는 첫 번째 숫자열입니다.\r\n\
'출발'과 '도착'에는 16진법(헥사코드) 스레드번호를 입력합니다. 스레드 번호는 맨 앞에 있는 첫 번째 숫자열입니다.\r\n\
\r\n\
로더 옵션:\r\n\
/P[{process_id|Nprocess_name}] //프로세스에 부착\r\n\
로더 옵션:\r\n\
/P[{process_id|Nprocess_name}] //프로세스에 부착\r\n\
\r\n\
H코드 후킹 옵션:\r\n\
H코드 후킹 옵션:\r\n\
/H[X]{A|B|W|S|Q}[N][data_offset[*drdo]][:sub_offset[*drso]]@addr[:module[:{name|#ordinal}]]\r\n\
\r\n\
(서수를 제외한) /H코드의 모든 숫자는 아무것도 처리되지 않은 16진법(헥사코드)입니다";
(서수를 제외한) /H코드의 모든 숫자는 아무것도 처리되지 않은 16진법(헥사코드)입니다";
const wchar_t* ExtendedUsage = L"/H[X]{A|B|W|S|Q}[N][data_offset[*drdo]][:sub_offset[*drso]]@addr[:[module[:{name|#ordinal}]]]\r\n\
\r\n\
추가 사용자정의 후킹설정\r\n\
추가 사용자정의 후킹설정\r\n\
\r\n\
후킹 종류 :\r\n\
A - DBCS 문자\r\n\
B - DBCS 문자(big-endian)\r\n\
W - UCS2 문자\r\n\
S - MBCS 문자열\r\n\
Q - UTF-16 문자열\r\n\
후킹 종류 :\r\n\
A - DBCS 문자\r\n\
B - DBCS 문자(big-endian)\r\n\
W - UCS2 문자\r\n\
S - MBCS 자열\r\n\
Q - UTF-16 자열\r\n\
\r\n\
매개변수:\r\n\
X - 하드웨어 구획점 사용\r\n\
N - 문법을 사용하지 않음\r\n\
개변수:\r\n\
X - 하드웨어 구획점 사용\r\n\
N - 문법을 사용하지 않음\r\n\
data_offset - stack offset to char / string pointer\r\n\
drdo - add a level of indirection to data_offset\r\n\
sub_offset - stack offset to subcontext\r\n\
drso - add a level of indirection to sub_offset\r\n\
addr - 후킹할 주소\r\n\
addr - 후킹할 주소\r\n\
module - name of the module to use as base for 'addr'\r\n\
name - name of the 'module' export to use as base for 'addr'\r\n\
ordinal - number of the 'module' export ordinal to use as base for 'addr'\r\n\
......@@ -64,70 +64,70 @@ Negative values of 'data_offset' and 'sub_offset' refer to registers: \r\n\
All numbers except ordinal are hexadecimal without any prefixes";
//inject.cpp
const wchar_t* ErrorRemoteThread=L"원격 스레드를 생성할 수 없음.";
const wchar_t* ErrorOpenProcess=L"프로세스를 열 수 없음.";
const wchar_t* ErrorNoProcess=L"프로세스를 찾을 수 없음";
const wchar_t* SelfAttach=L"ITH.exe에 부착하지 말아 주세요";
const wchar_t* AlreadyAttach=L"프로세스가 이미 부착됨.";
const wchar_t* FormatInject=L"프로세스 %d에 인젝션. 모듈 기반 %.8X";
const wchar_t* ErrorRemoteThread = L"원격 스레드를 생성할 수 없음.";
const wchar_t* ErrorOpenProcess = L"프로세스를 열 수 없음.";
const wchar_t* ErrorNoProcess = L"프로세스를 찾을 수 없음";
const wchar_t* SelfAttach = L"ITH.exe에 부착하지 말아 주세요";
const wchar_t* AlreadyAttach = L"프로세스가 이미 부착됨.";
const wchar_t* FormatInject = L"프로세스 %d에 인젝션. 모듈 기반 %.8X";
//main.cpp
const wchar_t* NotAdmin=L"SeDebugPrevilege을 활성화 할 수 없습니다. ITH가 제대로 작동하지 못합니다.\r\n\
관리자 계정으로 실행하시거나 UAC를 끄시고 ITH를 실행해 주세요.";
const wchar_t* NotAdmin = L"SeDebugPrevilege을 활성화 할 수 없습니다. ITH가 제대로 작동하지 못합니다.\r\n\
관리자 계정으로 실행하시거나 UAC를 끄시고 ITH를 실행해 주세요.";
//pipe.cpp
const wchar_t* ErrorCreatePipe=L"텍스트 파이프를 생성할 수 없거나, 요청이 너무 많습니다.";
const wchar_t* FormatDetach=L"프로세스 %d가 탈착됨.";
const wchar_t* ErrorCmdQueueFull=L"명령어 대기열이 가득참.";
const wchar_t* ErrorNoAttach=L"프로세스가 부착되지 않음.";
const wchar_t* ErrorCreatePipe = L"텍스트 파이프를 생성할 수 없거나, 요청이 너무 많습니다.";
const wchar_t* FormatDetach = L"프로세스 %d가 탈착됨.";
const wchar_t* ErrorCmdQueueFull = L"명령어 대기열이 가득참.";
const wchar_t* ErrorNoAttach = L"프로세스가 부착되지 않음.";
//profile.cpp
const wchar_t* ErrorMonitor=L"프로세스를 감시할 수 없음.";
const wchar_t* ErrorMonitor = L"프로세스를 감시할 수 없음.";
//utility.cpp
const wchar_t* InitMessage=L"Copyright (C) 2010-2012 kaosu <qiupf2000@gmail.com>\r\n\
const wchar_t* InitMessage = L"Copyright (C) 2010-2012 kaosu <qiupf2000@gmail.com>\r\n\
Copyright (C) 2015 zorkzero <zorkzero@hotmail.com>\r\n\
소스코드 <https://code.google.com/p/interactive-text-hooker/>\r\n\
일반토론 <https://groups.google.com/forum/?fromgroups#!forum/interactive-text-hooker>\r\n\
한글화 @mireado<https://twitter.com/mireado>";
const wchar_t* BackgroundMsg=L"도움말을 보시려면, \"help\", \"도움말\"이나 \"도움\"을 입력하세요.";
const wchar_t* ErrorLinkExist=L"연결이 존재함.";
const wchar_t* ErrorCylicLink=L"연결실패. 순환연결은 허용되지 않습니다.";
const wchar_t* FormatLink=L"출발스레드%.4x에서 도착스레드%.4x로 연결.";
const wchar_t* ErrorLink=L"연결실패. 출발/도착 스레드를 찾을 수 없음.";
const wchar_t* ErrorDeleteCombo=L"글상자에서 지우기 실패.";
소스코드 <https://code.google.com/p/interactive-text-hooker/>\r\n\
반토론 <https://groups.google.com/forum/?fromgroups#!forum/interactive-text-hooker>\r\n\
한글화 @mireado<https://twitter.com/mireado>";
const wchar_t* BackgroundMsg = L"도움말을 보시려면, \"help\", \"도움말\"이나 \"도움\"을 입력하세요.";
const wchar_t* ErrorLinkExist = L"연결이 존재함.";
const wchar_t* ErrorCylicLink = L"연결실패. 순환연결은 허용되지 않습니다.";
const wchar_t* FormatLink = L"출발스레드%.4x에서 도착스레드%.4x로 연결.";
const wchar_t* ErrorLink = L"연결실패. 출발/도착 스레드를 찾을 수 없음.";
const wchar_t* ErrorDeleteCombo = L"글상자에서 지우기 실패.";
//window.cpp
const wchar_t* ClassName=L"ITH";
const wchar_t* ClassNameAdmin=L"ITH (관리자)";
const wchar_t* ErrorNotSplit=L"먼저 문단 나누기를 활성화해주세요!";
const wchar_t* ErrorNotModule=L"먼저 모듈을 활성화해주세요!";
const wchar_t* ClassName = L"ITH";
const wchar_t* ClassNameAdmin = L"ITH (관리자)";
const wchar_t* ErrorNotSplit = L"먼저 문단 나누기를 활성화해주세요!";
const wchar_t* ErrorNotModule = L"먼저 모듈을 활성화해주세요!";
//Main window buttons
const wchar_t* ButtonTitleProcess=L"프로세스";
const wchar_t* ButtonTitleThread=L"스레드";
const wchar_t* ButtonTitleHook=L"후킹";
const wchar_t* ButtonTitleProfile=L"프로필";
const wchar_t* ButtonTitleOption=L"옵션";
const wchar_t* ButtonTitleClear=L"지우기";
const wchar_t* ButtonTitleSave=L"저장";
const wchar_t* ButtonTitleTop=L"항상위";
const wchar_t* ButtonTitleProcess = L"프로세스";
const wchar_t* ButtonTitleThread = L"스레드";
const wchar_t* ButtonTitleHook = L"후킹";
const wchar_t* ButtonTitleProfile = L"프로필";
const wchar_t* ButtonTitleOption = L"옵션";
const wchar_t* ButtonTitleClear = L"지우기";
const wchar_t* ButtonTitleSave = L"저장";
const wchar_t* ButtonTitleTop = L"항상위";
//Hook window
const wchar_t* SpecialHook=L"H코드 후킹, AGTH 코드는 지원하지 않습니다.";
const wchar_t* SpecialHook = L"H코드 후킹, AGTH 코드는 지원하지 않습니다.";
//Process window
const wchar_t* TabTitlePID=L"PID";
const wchar_t* TabTitleMemory=L"메모리";
const wchar_t* TabTitleName=L"이름";
const wchar_t* TabTitleTID=L"TID";
const wchar_t* TabTitleStart=L"시작";
const wchar_t* TabTitleModule=L"모듈";
const wchar_t* TabTitleState=L"상태";
const wchar_t* SuccessAttach=L"프로세스에 ITH 부착성공.";
const wchar_t* FailAttach=L"프로세스에 ITH 부착실패.";
const wchar_t* SuccessDetach=L"프로세스에서 ITH 탈착성공.";
const wchar_t* FailDetach=L"ITH 탈착실패.";
const wchar_t* TabTitlePID = L"PID";
const wchar_t* TabTitleMemory = L"메모리";
const wchar_t* TabTitleName = L"이름";
const wchar_t* TabTitleTID = L"TID";
const wchar_t* TabTitleStart = L"시작";
const wchar_t* TabTitleModule = L"모듈";
const wchar_t* TabTitleState = L"상태";
const wchar_t* SuccessAttach = L"프로세스에 ITH 부착성공.";
const wchar_t* FailAttach = L"프로세스에 ITH 부착실패.";
const wchar_t* SuccessDetach = L"프로세스에서 ITH 탈착성공.";
const wchar_t* FailDetach = L"ITH 탈착실패.";
//Profile window
const wchar_t* ProfileExist=L"프로필이 이미 존재함.";
const wchar_t* SuccessAddProfile=L"프로필 추가됨.";
const wchar_t* FailAddProfile=L"프로필 추가실패";
const wchar_t* TabTitleNumber=L"No.";
const wchar_t* NoFile=L"파일을 찾을 수 없음.";
const wchar_t* PathDismatch=L"프로세스 이름이 일치하지 않습니다, 계속하시겠습니까?";
const wchar_t* SuccessImportProfile=L"프로필 가져오기 성공";
//const wchar_t* SuccessAddProfile=L"Profile added.";
const wchar_t* ProfileExist = L"프로필이 이미 존재함.";
const wchar_t* SuccessAddProfile = L"프로필 추가됨.";
const wchar_t* FailAddProfile = L"프로필 추가실패";
const wchar_t* TabTitleNumber = L"No.";
const wchar_t* NoFile = L"파일을 찾을 수 없음.";
const wchar_t* PathDismatch = L"프로세스 이름이 일치하지 않습니다, 계속하시겠습니까?";
const wchar_t* SuccessImportProfile = L"프로필 가져오기 성공";
//const wchar_t* SuccessAddProfile=L"Profile added.";
\ No newline at end of file
......
......@@ -16,11 +16,11 @@
*/
#include "ITH.h"
#include "ith/host/srv.h"
#include "ith/host/hookman.h"
#include "ith/host/SettingManager.h"
#include "host/host.h"
#include "host/hookman.h"
#include "host/settings.h"
#include "CustomFilter.h"
#include "profile.h"
#include "profile/Profile.h"
#include "ProfileManager.h"
HINSTANCE hIns;
......@@ -39,10 +39,10 @@ extern "C" {
CustomFilter* uni_filter;
CustomFilter* mb_filter;
HookManager* man;
SettingManager* setman;
Settings* setman;
LONG split_time, cyclic_remove, global_filter;
LONG process_time, inject_delay, insert_delay,
auto_inject, auto_insert, clipboard_flag;
auto_inject, auto_insert, clipboard_flag;
std::map<std::wstring, long> setting;
......@@ -69,11 +69,13 @@ void RecordUniChar(WORD uni, PVOID f)
void SaveSettings()
{
GetWindowRect(hMainWnd, &window);
setting[L"window_left"] = window.left;
setting[L"window_right"] = window.right;
setting[L"window_top"] = window.top;
setting[L"window_bottom"] = window.bottom;
WINDOWPLACEMENT wndpl;
wndpl.length = sizeof(WINDOWPLACEMENT);
GetWindowPlacement(hMainWnd, &wndpl);
setting[L"window_left"] = wndpl.rcNormalPosition.left;
setting[L"window_right"] = wndpl.rcNormalPosition.right;
setting[L"window_top"] = wndpl.rcNormalPosition.top;
setting[L"window_bottom"] = wndpl.rcNormalPosition.bottom;
setting[L"split_time"] = split_time;
setting[L"process_time"] = process_time;
setting[L"inject_delay"] = inject_delay;
......@@ -238,17 +240,18 @@ LONG WINAPI UnhandledExcept(_EXCEPTION_POINTERS *ExceptionInfo)
return 0;
}
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
InitCommonControls();
if (!IthInitSystemService())
TerminateProcess(GetCurrentProcess(), 0);
CreateMutex(NULL, TRUE, L"ITH_MAIN_RUNNING");
if (IHF_Init())
if (Host_Open())
{
SetUnhandledExceptionFilter(UnhandledExcept);
IHF_GetHookManager(&man);
IHF_GetSettingManager(&setman);
setman->SetValue(SETTING_SPLIT_TIME, 200);
Host_GetHookManager(&man);
Host_GetSettings(&setman);
setman->splittingInterval = 200;
MonitorFlag = true;
pfman = new ProfileManager();
mb_filter = new CustomFilter();
......@@ -256,11 +259,11 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
DefaultSettings();
LoadSettings();
InitializeSettings();
setman->SetValue(SETTING_SPLIT_TIME, split_time);
setman->SetValue(SETTING_CLIPFLAG, clipboard_flag);
setman->splittingInterval = split_time;
setman->clipboardFlag = clipboard_flag > 0;
hIns = hInstance;
MyRegisterClass(hIns);
InitInstance(hIns, IHF_IsAdmin(), &window);
InitInstance(hIns, FALSE, &window);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
......@@ -277,7 +280,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
{
FindITH();
}
IHF_Cleanup();
Host_Close();
IthCloseSystemService();
TerminateProcess(GetCurrentProcess(), 0);
}
......
......@@ -16,10 +16,11 @@
*/
#include "utility.h"
#include "ith/host/srv.h"
#include "ith/host/hookman.h"
#include "ith/common/types.h"
#include "ith/common/const.h"
#include "host/host.h"
#include "host/hookman.h"
#include "vnrhook/include/types.h"
#include "vnrhook/include/const.h"
#include "profile/misc.h"
extern HookManager* man; // main.cpp
......@@ -65,11 +66,11 @@ std::wstring GetWindowsPath(const std::wstring& path)
// path is in device form
// \Device\HarddiskVolume2\Windows\System32\taskhost.exe
auto pathOffset = path.find(L'\\', 1) + 1;
pathOffset = path.find(L'\\', pathOffset);
pathOffset = path.find(L'\\', pathOffset);
std::wstring devicePath = path.substr(0, pathOffset); // \Device\HarddiskVolume2
std::wstring dosDrive = GetDriveLetter(devicePath); // C:
if (dosDrive.empty())
return L"";
return path;
std::wstring dosPath = dosDrive; // C:
dosPath += path.substr(pathOffset); // C:\Windows\System32\taskhost.exe
return dosPath;
......@@ -117,16 +118,16 @@ std::wstring GetCode(const HookParam& hp, DWORD pid)
code += c;
if (hp.type & NO_CONTEXT)
code += L'N';
if (hp.off >> 31)
code += L"-" + ToHexString(-(hp.off + 4));
if (hp.offset >> 31)
code += L"-" + ToHexString(-(hp.offset + 4));
else
code += ToHexString(hp.off);
code += ToHexString(hp.offset);
if (hp.type & DATA_INDIRECT)
{
if (hp.ind >> 31)
code += L"*-" + ToHexString(-hp.ind);
if (hp.index >> 31)
code += L"*-" + ToHexString(-hp.index);
else
code += L"*" + ToHexString(hp.ind);
code += L"*" + ToHexString(hp.index);
}
if (hp.type & USING_SPLIT)
{
......@@ -137,21 +138,21 @@ std::wstring GetCode(const HookParam& hp, DWORD pid)
}
if (hp.type & SPLIT_INDIRECT)
{
if (hp.split_ind >> 31)
code += L"*-" + ToHexString(-hp.split_ind);
if (hp.split_index >> 31)
code += L"*-" + ToHexString(-hp.split_index);
else
code += L"*" + ToHexString(hp.split_ind);
code += L"*" + ToHexString(hp.split_index);
}
if (pid)
{
PVOID allocationBase = GetAllocationBase(pid, (LPCVOID)hp.addr);
PVOID allocationBase = GetAllocationBase(pid, (LPCVOID)hp.address);
if (allocationBase)
{
std::wstring path = GetModuleFileNameAsString(pid, allocationBase);
if (!path.empty())
{
auto fileName = path.substr(path.rfind(L'\\') + 1);
DWORD relativeHookAddress = hp.addr - (DWORD)allocationBase;
DWORD relativeHookAddress = hp.address - (DWORD)allocationBase;
code += L"@" + ToHexString(relativeHookAddress) + L":" + fileName;
return code;
}
......@@ -159,20 +160,20 @@ std::wstring GetCode(const HookParam& hp, DWORD pid)
}
if (hp.module)
{
code += L"@" + ToHexString(hp.addr) + L"!" + ToHexString(hp.module);
code += L"@" + ToHexString(hp.address) + L"!" + ToHexString(hp.module);
if (hp.function)
code += L"!" + ToHexString(hp.function);
}
else
{
// hack, the original address is stored in the function field
// if (module == NULL && function != NULL)
// in TextHook::UnsafeInsertHookCode() MODULE_OFFSET and FUNCTION_OFFSET are removed from
// HookParam.type
// Hack. The original address is stored in the function field
// if (module == NULL && function != NULL).
// MODULE_OFFSET and FUNCTION_OFFSET are removed from HookParam.type in
// TextHook::UnsafeInsertHookCode() and can not be used here.
if (hp.function)
code += L"@" + ToHexString(hp.function);
else
code += L"@" + ToHexString(hp.addr) + L":";
code += L"@" + ToHexString(hp.address) + L":";
}
return code;
}
......@@ -282,13 +283,13 @@ HANDLE IthCreateFile(LPCWSTR name, DWORD option, DWORD share, DWORD disposition)
return CreateFile(path.c_str(), option, share, NULL, disposition, FILE_ATTRIBUTE_NORMAL, NULL);
}
//SJIS->Unicode. 'mb' must be null-terminated. 'wc_length' is the length of 'wc' in characters.
//SJIS->Unicode. mb must be null-terminated. wc_length is the length of wc in characters.
int MB_WC(const char* mb, wchar_t* wc, int wc_length)
{
return MultiByteToWideChar(932, 0, mb, -1, wc, wc_length);
}
// Count characters in wide string. 'mb_length' is the number of bytes from 'mb' to convert or
// Count characters in wide string. mb_length is the number of bytes from mb to convert or
// -1 if the string is null terminated.
int MB_WC_count(const char* mb, int mb_length)
{
......@@ -300,12 +301,3 @@ int WC_MB(const wchar_t *wc, char* mb, int mb_length)
{
return WideCharToMultiByte(932, 0, wc, -1, mb, mb_length, NULL, NULL);
}
DWORD Hash(const std::wstring& module, int length)
{
DWORD hash = 0;
auto end = length < 0 || static_cast<std::size_t>(length) > module.length() ? module.end() : module.begin() + length;
for (auto it = module.begin(); it != end; ++it)
hash = _rotr(hash, 7) + *it;
return hash;
}
......
#pragma once
#include "ITH.h"
struct HookParam;
struct ProcessRecord;
DWORD Hash(const std::wstring& module, int length = -1);
DWORD ProcessCommand(const std::wstring& cmd, DWORD pid);
std::wstring GetProcessPath(DWORD pid);
void ConsoleOutput(LPCWSTR);
......@@ -58,13 +58,6 @@ int MB_WC_count(const char* mb, int mb_length);
int WC_MB(const wchar_t *wc, char* mb, int mb_length);
bool Parse(const std::wstring& cmd, HookParam& hp);
template <typename T>
std::wstring ToHexString(T i) {
std::wstringstream ss;
ss << std::uppercase << std::hex << i;
return ss.str();
}
// http://jrdodds.blogs.com/blog/2004/08/raii_in_c.html
class CriticalSection
{
......
This diff is collapsed. Click to expand it.
......@@ -16,4 +16,5 @@
*/
#pragma once
#include "ITH.h"
......
# config.pri
# DEFINES += _SECURE_SCL=0 _SCL_SECURE_NO_WARNINGS
# DEFINES += _CRT_SECURE_NO_WARNINGS
cmake_minimum_required(VERSION 2.8)
set(CMAKE_CONFIGURATION_TYPES Debug Release)
project(vnr)
set(WDK_HOME "C:\\WinDDK\\7600.16385.1" CACHE FILEPATH "path to the Windows DDK directory")
set(WDK_HOME "C:\\WinDDK\\7600.16385.1" CACHE FILEPATH "Windows Driver Kit path")
add_definitions(
-DUNICODE
-D_UNICODE
/DUNICODE
/D_UNICODE
/D_SECURE_SCL=0
/D_SCL_SECURE_NO_WARNINGS
/D_CRT_SECURE_NO_WARNINGS
)
include_directories(${PROJECT_SOURCE_DIR})
set(common_src
${PROJECT_SOURCE_DIR}/ith/common/const.h
${PROJECT_SOURCE_DIR}/ith/common/defs.h
${PROJECT_SOURCE_DIR}/ith/common/except.h
${PROJECT_SOURCE_DIR}/ith/common/growl.h
${PROJECT_SOURCE_DIR}/ith/common/memory.h
${PROJECT_SOURCE_DIR}/ith/common/types.h
)
set(import_src
${PROJECT_SOURCE_DIR}/ith/import/mono/funcinfo.h
${PROJECT_SOURCE_DIR}/ith/import/mono/types.h
${PROJECT_SOURCE_DIR}/ith/import/ppsspp/funcinfo.h
include_directories(
${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/texthook
)
add_subdirectory(ith/hook)
add_subdirectory(ith/host)
add_subdirectory(ith/sys)
add_subdirectory(vnrhook)
add_subdirectory(texthook/host)
add_subdirectory(ithsys)
add_subdirectory(profile)
......
......@@ -72,8 +72,8 @@ win32 {
## External Libraries
win32 {
D3D_HOME = "$$PROGRAMFILES/Microsoft DirectX SDK"
DETOURS_HOME = "$$PROGRAMFILES/Microsoft Research/Detours Express 3.0"
D3D_HOME = "C:/Program Files/Microsoft DirectX SDK"
DETOURS_HOME = "C:/Program Files/Microsoft Research/Detours Express 3.0"
#DEV_HOME = c:/dev
DEV_HOME = z:/local/windows/developer
BOOST_HOME = $$DEV_HOME/boost/build
......@@ -81,8 +81,8 @@ win32 {
MSIME_HOME = $$DEV_HOME/msime
#PYTHON_HOME = $$ROOTDIR/../Python
#PYTHON_HOME = C:/Python
PYTHON_HOME = Z:/Local/Windows/Developer/Python
PYSIDE_HOME = $$PYTHON_HOME/Lib/site-packages/PySide
PYTHON_HOME = $$DEV_HOME/python
PYSIDE_HOME = $$PYTHON_HOME/lib/site-packages/PySide
QT_HOME = c:/qt/4
QT_SRC = c:/qt
SAPI_HOME = "$$PROGRAMFILES/Microsoft Speech SDK 5.1"
......@@ -161,7 +161,7 @@ win32 {
QMAKE_CXXFLAGS_EXCEPTIONS_ON += -EHa
}
CONFIG(noeh) { # No Exception handler
CONFIG(noeh) { # No exception handler
message(CONFIG noeh)
#CONFIG -= rtti #-exceptions -stl
QMAKE_CXXFLAGS += /GR-
......@@ -175,7 +175,7 @@ win32 {
}
}
CONFIG(nosafeseh) { # No Exception handler
CONFIG(nosafeseh) { # No safe exception handler
message(CONFIG nosafeseh)
# Disable SafeSEH table
......
@echo off
setlocal
if [%1] == [] (
echo usage: copy_vnr <path-to-Sakura-directory>
echo usage: copy_vnr path_to_Sakura
goto :EOF
)
xcopy %1\config.pri . /S /Y /I
xcopy %1\cpp\libs\ccutil ccutil /S /Y /I
xcopy %1\cpp\libs\cpputil cpputil /S /Y /I
xcopy %1\cpp\libs\disasm disasm /S /Y /I /EXCLUDE:exclude.txt
xcopy %1\cpp\plugins\ith ith /S /Y /I
xcopy %1\cpp\libs\hashutil hashutil /S /Y /I
xcopy %1\cpp\plugins\ithsys ithsys /S /Y /I
xcopy %1\cpp\plugins\vnrhook vnrhook /S /Y /I
xcopy %1\cpp\plugins\texthook texthook /S /Y /I /EXCLUDE:exclude.txt
xcopy %1\cpp\libs\memdbg memdbg /S /Y /I
xcopy %1\cpp\libs\ntdll ntdll /S /Y /I
xcopy %1\cpp\libs\ntinspect ntinspect /S /Y /I
xcopy %1\cpp\libs\winkey winkey /S /Y /I
xcopy %1\cpp\libs\winmaker winmaker /S /Y /I
xcopy %1\cpp\libs\winmutex winmutex /S /Y /I
xcopy %1\cpp\libs\winversion winversion /S /Y /I
xcopy %1\cpp\libs\winseh winseh /S /Y /I
xcopy %1\cpp\libs\wintimer wintimer /S /Y /I
xcopy %1\cpp\libs\windbg windbg /S /Y /I
xcopy %1\cpp\libs\sakurakit sakurakit /S /Y /I
xcopy %1\cpp\libs\mono mono /S /Y /I
endlocal
......
......@@ -19,8 +19,8 @@ inline size_t cpp_basic_strlen(const charT *s)
return p - s;
}
inline size_t cpp_strlen(const char *s) { return cpp_basic_strlen(s); }
inline size_t cpp_wstrlen(const wchar_t *s) { return cpp_basic_strlen(s); }
inline size_t cpp_strlen(const char *s) { return cpp_basic_strlen<char>(s); }
inline size_t cpp_wstrlen(const wchar_t *s) { return cpp_basic_strlen<wchar_t>(s); }
template <typename charT>
inline size_t cpp_basic_strnlen(const charT *s, size_t n)
......@@ -30,8 +30,8 @@ inline size_t cpp_basic_strnlen(const charT *s, size_t n)
return p - s;
}
inline size_t cpp_strnlen(const char *s, size_t n) { return cpp_basic_strnlen(s, n); }
inline size_t cpp_wstrnlen(const wchar_t *s, size_t n) { return cpp_basic_strnlen(s, n); }
inline size_t cpp_strnlen(const char *s, size_t n) { return cpp_basic_strnlen<char>(s, n); }
inline size_t cpp_wstrnlen(const wchar_t *s, size_t n) { return cpp_basic_strnlen<wchar_t>(s, n); }
// strnchr
......@@ -45,19 +45,15 @@ inline size_t cpp_wstrnlen(const wchar_t *s, size_t n) { return cpp_basic_strnle
return nullptr; \
}
template <typename charT>
inline charT *cpp_basic_strnchr(charT *s, int c, size_t n)
cpp_basic_strnchr_(s, c, n)
inline charT *cpp_basic_strnchr(charT *s, charT c, size_t n) cpp_basic_strnchr_(s, c, n)
template <typename charT>
inline const charT *cpp_basic_strnchr(const charT *s, int c, size_t n)
cpp_basic_strnchr_(s, c, n)
inline const charT *cpp_basic_strnchr(const charT *s, charT c, size_t n) cpp_basic_strnchr_(s, c, n)
// The same as memchr
inline char *cpp_strnchr(char *s, int c, size_t n) { return cpp_basic_strnchr(s, c, n); }
inline const char *cpp_strnchr(const char *s, int c, size_t n) { return cpp_basic_strnchr(s, c, n); }
inline wchar_t *cpp_wcsnchr(wchar_t *s, int c, size_t n) { return cpp_basic_strnchr(s, c, n); }
inline const wchar_t *cpp_wcsnchr(const wchar_t *s, int c, size_t n) { return cpp_basic_strnchr(s, c, n); }
inline char *cpp_strnchr(char *s, char c, size_t n) { return cpp_basic_strnchr<char>(s, c, n); }
inline const char *cpp_strnchr(const char *s, char c, size_t n) { return cpp_basic_strnchr<char>(s, c, n); }
inline wchar_t *cpp_wcsnchr(wchar_t *s, wchar_t c, size_t n) { return cpp_basic_strnchr<wchar_t>(s, c, n); }
inline const wchar_t *cpp_wcsnchr(const wchar_t *s, wchar_t c, size_t n) { return cpp_basic_strnchr<wchar_t>(s, c, n); }
// strnstr
......@@ -72,25 +68,19 @@ inline const wchar_t *cpp_wcsnchr(const wchar_t *s, int c, size_t n) { return cp
}
template <typename charT>
inline charT *cpp_basic_strnstr(charT *s, const charT *r, size_t n)
cpp_basic_strnstr_(s, n, r, ::strlen(r), ::strncmp)
inline charT *cpp_basic_strnstr(charT *s, const charT *r, size_t n) cpp_basic_strnstr_(s, n, r, ::strlen(r), ::strncmp)
template <typename charT>
inline const charT *cpp_basic_strnstr(const charT *s, const charT *r, size_t n)
cpp_basic_strnstr_(s, n, r, ::strlen(r), ::strncmp)
inline const charT *cpp_basic_strnstr(const charT *s, const charT *r, size_t n) cpp_basic_strnstr_(s, n, r, ::strlen(r), ::strncmp)
template <>
inline wchar_t *cpp_basic_strnstr<wchar_t>(wchar_t *s, const wchar_t *r, size_t n)
cpp_basic_strnstr_(s, n, r, ::wcslen(r), ::wcsncmp)
inline wchar_t *cpp_basic_strnstr<wchar_t>(wchar_t *s, const wchar_t *r, size_t n) cpp_basic_strnstr_(s, n, r, ::wcslen(r), ::wcsncmp)
template <>
inline const wchar_t *cpp_basic_strnstr<wchar_t>(const wchar_t *s, const wchar_t *r, size_t n)
cpp_basic_strnstr_(s, n, r, ::wcslen(r), ::wcsncmp)
inline const wchar_t *cpp_basic_strnstr<wchar_t>(const wchar_t *s, const wchar_t *r, size_t n) cpp_basic_strnstr_(s, n, r, ::wcslen(r), ::wcsncmp)
inline char *cpp_strnstr(char *s, const char *r, size_t n) { return cpp_basic_strnstr(s, r, n); }
inline const char *cpp_strnstr(const char *s, const char *r, size_t n) { return cpp_basic_strnstr(s, r, n); }
inline wchar_t *cpp_wcsnstr(wchar_t *s, const wchar_t *r, size_t n) { return cpp_basic_strnstr(s, r, n); }
inline const wchar_t *cpp_wcsnstr(const wchar_t *s, const wchar_t *r, size_t n) { return cpp_basic_strnstr(s, r, n); }
inline char *cpp_strnstr(char *s, const char *r, size_t n) { return cpp_basic_strnstr<char>(s, r, n); }
inline const char *cpp_strnstr(const char *s, const char *r, size_t n) { return cpp_basic_strnstr<char>(s, r, n); }
inline wchar_t *cpp_wcsnstr(wchar_t *s, const wchar_t *r, size_t n) { return cpp_basic_strnstr<wchar_t>(s, r, n); }
inline const wchar_t *cpp_wcsnstr(const wchar_t *s, const wchar_t *r, size_t n) { return cpp_basic_strnstr<wchar_t>(s, r, n); }
// strnpbrk
......
......@@ -4,9 +4,23 @@
// cpplocale.h
// 9/26/2014 jichi
#include <codecvt>
#include <locale>
#ifdef WITHOUT_CXX_CODECVT
// http://www.boost.org/doc/libs/1_48_0/libs/serialization/doc/codecvt.html
# define BOOST_UTF8_BEGIN_NAMESPACE
# define BOOST_UTF8_END_NAMESPACE
# define BOOST_UTF8_DECL
# include <boost/detail/utf8_codecvt_facet.hpp>
# include <boost/detail/utf8_codecvt_facet.ipp> // WARNING: This implementation should only be included ONCE
# define CPPLOCALE_NEW_FACET_UTF8(charT) (new utf8_codecvt_facet) // charT is ignored and assumed to be wchar_t
//# include <boost/detail/serialization/utf8_codecvt_facet.hpp>
//# define CPPLOCALE_NEW_FACET_UTF8(charT) (new utf8_codecvt_facet<charT>)
#else
# include <codecvt>
# define CPPLOCALE_NEW_FACET_UTF8(charT) (new std::codecvt_utf8<charT, 0x10ffff, std::consume_header>)
#endif // WITHOUT_CXX_CODECVT
//#include <boost/locale.hpp>
// See: http://stackoverflow.com/questions/20195262/how-to-read-an-utf-8-encoded-file-containing-chinese-characters-and-output-them
......@@ -15,7 +29,7 @@
// - 0x10ffff is the default maximum value.
// - std::consume_header will skip the leading encoding byte from the input.
template <class charT>
inline std::locale cpp_utf8_locale(std::locale init = std::locale())
{ return std::locale(init, new std::codecvt_utf8<charT, 0x10ffff, std::consume_header>()); }
inline std::locale cpp_utf8_locale(std::locale init = std::locale()) //::empty())
{ return std::locale(init, CPPLOCALE_NEW_FACET_UTF8(charT)); }
#endif // CPPLOCALE_H
......
......@@ -4,33 +4,15 @@
// cppstring.h
// 10/12/2014 jichi
#include <cstring>
#include <string>
/#include <string>
// Initializers
template <typename charT, typename stringT>
inline std::basic_string<charT> cpp_basic_string_of(const stringT &s)
{ return std::basic_string<charT>(s.cbegin(), s.cend()); }
template <typename charT>
inline std::basic_string<charT> cpp_basic_string_of(const std::string &s)
{ return std::basic_string<charT>(s.begin(), s.end()); }
template <typename stringT>
inline std::string cpp_string_of(const stringT &s)
{ return std::string(s.cbegin(), s.cend()); }
inline std::string cpp_string_of(const char *s)
{ return s; }
inline std::string cpp_string_of(const wchar_t *s)
{ return std::string(s, s + ::wcslen(s)); }
template <typename stringT>
inline std::wstring cpp_wstring_of(const stringT &s)
{ return std::wstring(s.cbegin(), s.cend()); }
inline std::wstring cpp_wstring_of(const wchar_t *s)
{ return s; }
inline std::wstring cpp_wstring_of(const char *s)
{ return std::wstring(s, s + ::strlen(s)); }
inline std::wstring cpp_wstring_of(const std::string &s)
{ return std::wstring(s.begin(), s.end()); }
#endif // CPPSTRING_H
......
......@@ -9,6 +9,7 @@
// 3024b815 0f1302 movlps qword ptr ds:[edx],xmm0
#include "disasm.h"
#include <windows.h>
// disasm_flag values:
enum : unsigned {
......@@ -29,21 +30,22 @@ DISASM_BEGIN_NAMESPACE
// But the are currently unused and could make disasm thread-unsafe
namespace { // unnamed
BYTE disasm_seg, // CS DS ES SS FS GS
disasm_rep, // REPZ/REPNZ
disasm_opcode, // opcode
disasm_opcode2, // used when opcode==0f
disasm_modrm, // modxxxrm
disasm_sib, // scale-index-base
disasm_mem[8], // mem addr value
disasm_data[8]; // data value
BYTE disasm_seg // CS DS ES SS FS GS
, disasm_rep // REPZ/REPNZ
, disasm_opcode // opcode
, disasm_opcode2 // used when opcode==0f
, disasm_modrm // modxxxrm
, disasm_sib // scale-index-base
, disasm_mem[8] // mem addr value
, disasm_data[8] // data value
;
} // unnamed namespace
// return: length if success, 0 if error
int disasm(const BYTE *opcode0)
size_t disasm(const void *opcode0)
{
const BYTE *opcode = opcode0;
const BYTE *opcode = (const BYTE *)opcode0;
DWORD disasm_len = 0, // 0 if error
disasm_flag = 0, // C_xxx
......@@ -253,7 +255,7 @@ retry:
for (DWORD i = 0; i < disasm_datasize; i++)
disasm_data[i] = *opcode++;
disasm_len = opcode - opcode0;
disasm_len = opcode - (const BYTE *)opcode0;
return disasm_len;
} // disasm
......
......@@ -4,7 +4,7 @@
// Include typedef of BYTE
//#include <windef.h>
#include <windows.h>
//#include <windows.h>
//#ifdef QT_CORE_LIB
//# include <qt_windows.h>
......@@ -20,7 +20,13 @@
#endif
DISASM_BEGIN_NAMESPACE
int disasm(const BYTE *opcode0); // return: op length if success, 0 if error
/**
* This function can do more, but currently only used to estimate the length of an instruction.
* Warning: The current implementation is stateful and hence not thread-safe.
* @param address of the instruction to look at
* @return length of the instruction at the address or 0 if failed
*/
size_t disasm(const void *address);
DISASM_END_NAMESPACE
// EOF
......
#ifndef HASHSTR_H
#define HASHSTR_H
// hashstr.h
// 8/1/2011
// See: http://www.cse.yorku.ca/~oz/hash.html
#include "hashutil/hashutil.h"
#include <cstdint>
HASHUTIL_BEGIN_NAMESPACE
enum : uint64_t { djb2_hash0 = 5381 };
/// djb2: h = h*33 + c
template <typename charT>
inline uint64_t djb2(const charT *str, uint64_t hash = djb2_hash0)
{
charT c;
while ((c = *str++))
hash = ((hash << 5) + hash) + c; // hash * 33 + c
return hash;
}
/// n: length
template <typename charT>
inline uint64_t djb2_n(const charT *str, size_t len, uint64_t hash = djb2_hash0)
{
while (len--)
hash = ((hash << 5) + hash) + (*str++); // hash * 33 + c
return hash;
}
/// sdbm: hash(i) = hash(i - 1) * 65599 + str[i];
template <typename charT>
inline uint64_t sdbm(const charT *str, uint64_t hash = 0)
{
charT c;
while ((c = *str++))
hash = c + (hash << 6) + (hash << 16) - hash;
return hash;
}
template <typename charT>
inline uint64_t loselose(const charT *str, uint64_t hash = 0)
{
charT c;
while ((c = *str++))
hash += c;
return hash;
}
HASHUTIL_END_NAMESPACE
#endif // HASHSTR_H
#ifndef HASHUTIL_H
#define HASHUTIL_H
// hashutil.h
// 6/16/2015 jichi
// Redefine HASHUTIL_BEGIN_NAMESPACE/HASHUTIL_END_NAMESPACE if need custom namespace
#ifndef HASHUTIL_BEGIN_NAMESPACE
# define HASHUTIL_BEGIN_NAMESPACE namespace hashutil {
#endif
#ifndef HASHUTIL_END_NAMESPACE
# define HASHUTIL_END_NAMESPACE } // namespace hashutil
#endif
#endif // HASHUTIL_H
# hashutil.pri
# 6/28/2011 jichi
DEFINES += WITH_LIB_HASHUTIL
DEPENDPATH += $$PWD
HEADERS += \
$$PWD/hashstr.h \
$$PWD/hashutil.h
# EOF
# # ithsys.pro
# CONFIG += noqt staticlib
# include(../../../config.pri)
# # jichi 7/12/2015: Always enable SEH
# DEFINES += ITH_HAS_SEH
# DEFINES += _CRT_NON_CONFORMING_SWPRINTFS
set(ithsys_src
ithsys.h
ithsys.cc
)
add_library(ithsys STATIC ${ithsys_src})
target_compile_options(ithsys PRIVATE
$<$<CONFIG:Release>:>
$<$<CONFIG:Debug>:>
)
target_link_libraries(ithsys comctl32.lib)
target_compile_definitions(ithsys
PRIVATE
ITH_HAS_SEH
_CRT_NON_CONFORMING_SWPRINTFS
)
This diff is collapsed. Click to expand it.
#pragma once
// ithsys.h
// 8/23/2013 jichi
// Branch: ITH/IHF_SYS.h, rev 111
#ifdef _MSC_VER
# pragma warning(disable:4800) // C4800: forcing value to bool
#endif // _MSC_VER
#include "ntdll/ntdll.h"
// jichi 8/24/2013: Why extern "C"? Any specific reason to use C instead of C++ naming?
extern "C" {
//int disasm(BYTE *opcode0); // jichi 8/15/2013: move disasm to separate file
extern WORD *NlsAnsiCodePage;
int FillRange(LPCWSTR name,DWORD *lower, DWORD *upper);
int MB_WC(char *mb, wchar_t *wc);
//int MB_WC_count(char *mb, int mb_length);
int WC_MB(wchar_t *wc, char *mb);
// jichi 10/1/2013: Return 0 if failed. So, it is ambiguous if the search pattern starts at 0
DWORD SearchPattern(DWORD base, DWORD base_length, LPCVOID search, DWORD search_length); // KMP
// jichi 2/5/2014: The same as SearchPattern except it uses 0xff to match everything
// According to @Andys, 0xff seldom appear in the source code: http://sakuradite.com/topic/124
enum : BYTE { SP_ANY = 0xff };
#define SP_ANY_2 SP_ANY,SP_ANY
#define SP_ANY_3 SP_ANY,SP_ANY,SP_ANY
#define SP_ANY_4 SP_ANY,SP_ANY,SP_ANY,SP_ANY
DWORD SearchPatternEx(DWORD base, DWORD base_length, LPCVOID search, DWORD search_length, BYTE wildcard=SP_ANY);
BOOL IthInitSystemService();
void IthCloseSystemService();
DWORD IthGetMemoryRange(LPCVOID mem, DWORD *base, DWORD *size);
BOOL IthCheckFile(LPCWSTR file);
BOOL IthFindFile(LPCWSTR file);
BOOL IthGetFileInfo(LPCWSTR file, LPVOID info, DWORD size = 0x1000);
BOOL IthCheckFileFullPath(LPCWSTR file);
HANDLE IthCreateFile(LPCWSTR name, DWORD option, DWORD share, DWORD disposition);
HANDLE IthCreateFileInDirectory(LPCWSTR name, HANDLE dir, DWORD option, DWORD share, DWORD disposition);
HANDLE IthCreateDirectory(LPCWSTR name);
HANDLE IthCreateFileFullPath(LPCWSTR fullpath, DWORD option, DWORD share, DWORD disposition);
HANDLE IthPromptCreateFile(DWORD option, DWORD share, DWORD disposition);
HANDLE IthCreateSection(LPCWSTR name, DWORD size, DWORD right);
HANDLE IthCreateEvent(LPCWSTR name, DWORD auto_reset=0, DWORD init_state=0);
HANDLE IthOpenEvent(LPCWSTR name);
void IthSetEvent(HANDLE hEvent);
void IthResetEvent(HANDLE hEvent);
HANDLE IthCreateMutex(LPCWSTR name, BOOL InitialOwner, DWORD *exist=0);
HANDLE IthOpenMutex(LPCWSTR name);
BOOL IthReleaseMutex(HANDLE hMutex);
//DWORD IthWaitForSingleObject(HANDLE hObject, DWORD dwTime);
HANDLE IthCreateThread(LPCVOID start_addr, DWORD param, HANDLE hProc=(HANDLE)-1);
DWORD GetExportAddress(DWORD hModule,DWORD hash);
void IthSleep(int time); // jichi 9/28/2013: in ms
void IthSystemTimeToLocalTime(LARGE_INTEGER *ptime);
void FreeThreadStart(HANDLE hProc);
void CheckThreadStart();
} // extern "C"
#ifdef ITH_HAS_HEAP
extern HANDLE hHeap; // used in ith/common/memory.h
#endif // ITH_HAS_HEAP
extern DWORD current_process_id;
extern DWORD debug;
extern BYTE LeadByteTable[];
extern LPVOID page;
extern BYTE launch_time[];
inline DWORD GetHash(LPSTR str)
{
DWORD hash = 0;
//for (; *str; str++)
while (*str)
hash = ((hash>>7) | (hash<<25)) + *str++;
return hash;
}
inline DWORD GetHash(LPCWSTR str)
{
DWORD hash = 0;
//for (; *str; str++)
while (*str)
hash = ((hash>>7) | (hash<<25)) + *str++;
return hash;
}
inline void IthBreak()
{ if (debug) __debugbreak(); }
inline LPCWSTR GetMainModulePath()
{
__asm
{
mov eax, fs:[0x30]
mov eax, [eax + 0xC]
mov eax, [eax + 0xC]
mov eax, [eax + 0x28]
}
}
// jichi 9/28/2013: Add this to lock NtWriteFile in wine
class IthMutexLocker
{
HANDLE m;
public:
explicit IthMutexLocker(HANDLE mutex) : m(mutex)
{ NtWaitForSingleObject(m, 0, 0); }
~IthMutexLocker() { if (m != INVALID_HANDLE_VALUE) IthReleaseMutex(m); }
bool locked() const { return m != INVALID_HANDLE_VALUE; }
void unlock() { if (m != INVALID_HANDLE_VALUE) { IthReleaseMutex(m); m = INVALID_HANDLE_VALUE; } }
};
void IthCoolDown();
BOOL IthIsWine();
BOOL IthIsWindowsXp();
//BOOL IthIsWindows8OrGreater(); // not public
/** Get current dll path.
* @param buf
* @param len
* @return length of the path excluding \0
*/
size_t IthGetCurrentModulePath(wchar_t *buf, size_t len);
// EOF
# ithsys.pri
# 8/21/2013 jichi
DEFINES += WITH_LIB_ITHSYS
LIBS += -lithsys
DEPENDPATH += $$PWD
HEADERS += $$PWD/ithsys.h
#SOURCES += $$PWD/ithsys.cc
#include($$LIBDIR/winddk/winddk.pri)
#LIBS += -L$$WDK/lib/wxp/i386
# EOF
# ithsys.pro
# 8/21/2013 jichi
# Build ithsys.lib
#CONFIG += noqt noeh staticlib
CONFIG += noqt staticlib
include(../../../config.pri)
include($$LIBDIR/ntdll/ntdll.pri)
#LIBS += -L$$WDK7_HOME/lib/wxp/i386 -lntdll
#include($$LIBDIR/winddk/winddk.pri)
#LIBS += -L$$WDK/lib/wxp/i386
# jichi 9/22/2013: When ITH is on wine, certain NT functions are replaced
#DEFINES += ITH_WINE
# jichi 7/12/2015: Always enable SEH
DEFINES += ITH_HAS_SEH
# jichi 11/24/2013: Disable manual heap
DEFINES -= ITH_HAS_HEAP
## Libraries
#INCLUDEPATH += $$ITH_HOME/include
#INCLUDEPATH += $$WDK7_HOME/inc/ddk
#LIBS += -lgdi32 -luser32 -lkernel32
#LIBS += -L$$WDK7_HOME/lib/wxp/i386 -lntdll
#LIBS += $$WDK7_HOME/lib/crt/i386/msvcrt.lib # Override msvcrt10
#DEFINES += ITH_HAS_CXX
#LIBS += -lith_sys -lntdll
#LIBS += -lith_tls -lntdll
#LIBS += -lntoskrnl
DEFINES += _CRT_NON_CONFORMING_SWPRINTFS
## Sources
TEMPLATE = lib
TARGET = ithsys
HEADERS += ithsys.h
SOURCES += ithsys.cc
OTHER_FILES += ithsys.pri
# EOF
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
# mono.pri
# 9/26/2012 jichi
DEFINES += WITH_LIB_MONO
DEPENDPATH += $$PWD
HEADERS += \
$$PWD/monoobject.h \
$$PWD/monotype.h
# EOF
#ifndef MONOOBJECT_H
#define MONOOBJECT_H
// monoobject.h
// 12/26/2014 jichi
// https://github.com/mono/mono/blob/master/mono/metadata/object.h
// https://github.com/mono/mono/blob/master/mono/metadata/object-internals.h
// https://github.com/mono/mono/blob/master/mono/util/mono-publib.h
#include <cstdint>
#define MONO_ZERO_LEN_ARRAY 1
// mono/io-layer/uglify.h
//typedef int8_t gint8;
//typedef int32_t gint32;
//typedef wchar_t gunichar2; // either char or wchar_t, depending on how mono is compiled
typedef int32_t mono_bool;
typedef uint8_t mono_byte;
typedef uint16_t mono_unichar2;
typedef uint32_t mono_unichar4;
// mono/metadata/object.h
typedef mono_bool MonoBoolean;
struct MonoArray;
struct MonoDelegate;
struct MonoDomain;
struct MonoException;
struct MonoString;
struct MonoThreadsSync;
struct MonoThread;
struct MonoVTable;
struct MonoObject {
MonoVTable *vtable;
MonoThreadsSync *synchronisation;
};
struct MonoString {
MonoObject object;
int32_t length;
mono_unichar2 chars[MONO_ZERO_LEN_ARRAY];
};
#endif // MONOOBJECT_H
#ifndef MONOTYPE_H
#define MONOTYPE_H
// monotype.h
// 12/26/2014 jichi
// https://github.com/mono/mono/blob/master/mono/metadata/object.h
#include "mono/monoobject.h"
// Function typedefs
typedef MonoDomain *(* mono_object_get_domain_fun_t)(MonoObject *obj);
typedef MonoString *(* mono_string_new_utf16_fun_t)(MonoDomain *domain, const mono_unichar2 *text, int32_t len);
typedef char * (* mono_string_to_utf8_fun_t)(MonoString *string_obj);
#endif // MONOTYPE_H
......@@ -3,11 +3,15 @@
#include "ntdll/ntdll.h"
#include "ntinspect/ntinspect.h"
// https://social.msdn.microsoft.com/Forums/vstudio/en-US/4cb11cd3-8ce0-49d7-9dda-d62e9ae0180b/how-to-get-current-module-handle?forum=vcgeneral
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
//#ifdef _MSC_VER
//# pragma warning(disable:4018) // C4018: signed/unsigned mismatch
//#endif // _MSC_VER
namespace { // unnamed
// Replacement of wcscpy_s which is not available on Windows XP's msvcrt
// http://sakuradite.com/topic/247
errno_t wcscpy_safe(wchar_t *buffer, size_t bufferSize, const wchar_t *source)
......@@ -22,7 +26,12 @@ errno_t wcscpy_safe(wchar_t *buffer, size_t bufferSize, const wchar_t *source)
NTINSPECT_BEGIN_NAMESPACE
BOOL getCurrentProcessName(LPWSTR buffer, int bufferSize)
// https://social.msdn.microsoft.com/Forums/vstudio/en-US/4cb11cd3-8ce0-49d7-9dda-d62e9ae0180b/how-to-get-current-module-handle?forum=vcgeneral
HMODULE getCurrentModuleHandle() { return (HMODULE)&__ImageBase; }
/** Memory range */
BOOL getProcessName(LPWSTR buffer, int bufferSize)
{
//assert(name);
PLDR_DATA_TABLE_ENTRY it;
......@@ -38,6 +47,7 @@ BOOL getCurrentProcessName(LPWSTR buffer, int bufferSize)
return 0 == wcscpy_safe(buffer, bufferSize, it->BaseDllName.Buffer);
}
// See: ITH FillRange
BOOL getModuleMemoryRange(LPCWSTR moduleName, DWORD *lowerBound, DWORD *upperBound)
{
//assert(lower);
......@@ -86,15 +96,114 @@ BOOL getModuleMemoryRange(LPCWSTR moduleName, DWORD *lowerBound, DWORD *upperBou
return FALSE;
}
BOOL getCurrentMemoryRange(DWORD *lowerBound, DWORD *upperBound)
BOOL getProcessMemoryRange(DWORD *lowerBound, DWORD *upperBound)
{
WCHAR procName[MAX_PATH]; // cached
*lowerBound = 0;
*upperBound = 0;
return getCurrentProcessName(procName, MAX_PATH)
return getProcessName(procName, MAX_PATH)
&& getModuleMemoryRange(procName, lowerBound, upperBound);
}
/** Module header */
// See: ITH AddAllModules
bool iterModule(const iter_module_fun_t &fun)
{
// Iterate loaded modules
PPEB ppeb;
__asm {
mov eax, fs:[0x30]
mov ppeb, eax
}
const DWORD start = *(DWORD *)&ppeb->Ldr->InLoadOrderModuleList;
for (auto it = (PLDR_DATA_TABLE_ENTRY)start;
it->SizeOfImage && *(DWORD *)it != start;
it = (PLDR_DATA_TABLE_ENTRY)it->InLoadOrderModuleList.Flink)
if (!fun((HMODULE)it->DllBase, it->BaseDllName.Buffer))
return false;
return true;
}
// See: ITH AddAllModules
DWORD getExportFunction(LPCSTR funcName)
{
// Iterate loaded modules
PPEB ppeb;
__asm {
mov eax, fs:[0x30]
mov ppeb, eax
}
const DWORD start = *(DWORD *)&ppeb->Ldr->InLoadOrderModuleList;
for (auto it = (PLDR_DATA_TABLE_ENTRY)start;
it->SizeOfImage && *(DWORD *)it != start;
it = (PLDR_DATA_TABLE_ENTRY)it->InLoadOrderModuleList.Flink) {
//if (moduleName && ::wcscmp(moduleName, it->BaseDllName.Buffer)) // BaseDllName.Buffer == moduleName
// continue;
if (DWORD addr = getModuleExportFunction((HMODULE)it->DllBase, funcName))
return addr;
}
return 0;
}
// See: ITH AddModule
DWORD getModuleExportFunction(HMODULE hModule, LPCSTR funcName)
{
if (!hModule)
return 0;
DWORD startAddress = (DWORD)hModule;
IMAGE_DOS_HEADER *DosHdr = (IMAGE_DOS_HEADER *)hModule;
if (IMAGE_DOS_SIGNATURE == DosHdr->e_magic) {
DWORD dwReadAddr = startAddress + DosHdr->e_lfanew;
IMAGE_NT_HEADERS *NtHdr = (IMAGE_NT_HEADERS *)dwReadAddr;
if (IMAGE_NT_SIGNATURE == NtHdr->Signature) {
DWORD dwExportAddr = NtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
if (dwExportAddr == 0)
return 0;
dwExportAddr += startAddress;
IMAGE_EXPORT_DIRECTORY *ExtDir = (IMAGE_EXPORT_DIRECTORY *)dwExportAddr;
dwExportAddr = startAddress + ExtDir->AddressOfNames;
for (UINT uj = 0; uj < ExtDir->NumberOfNames; uj++) {
DWORD dwFuncName = *(DWORD *)dwExportAddr;
LPCSTR pcFuncName = (LPCSTR)(startAddress + dwFuncName);
if (::strcmp(funcName, pcFuncName) == 0) {
char *pcFuncPtr = (char *)(startAddress + (DWORD)ExtDir->AddressOfNameOrdinals+(uj * sizeof(WORD)));
WORD word = *(WORD *)pcFuncPtr;
pcFuncPtr = (char *)(startAddress + (DWORD)ExtDir->AddressOfFunctions+(word * sizeof(DWORD)));
return startAddress + *(DWORD *)pcFuncPtr; // absolute address
}
dwExportAddr += sizeof(DWORD);
}
}
}
return 0;
}
// See: ITH FindImportEntry
DWORD getModuleImportAddress(HMODULE hModule, DWORD exportAddress)
{
if (!hModule)
return 0;
DWORD startAddress = (DWORD)hModule;
IMAGE_DOS_HEADER *DosHdr = (IMAGE_DOS_HEADER *)hModule;
if (IMAGE_DOS_SIGNATURE == DosHdr->e_magic) {
IMAGE_NT_HEADERS *NtHdr = (IMAGE_NT_HEADERS *)(startAddress + DosHdr->e_lfanew);
if (IMAGE_NT_SIGNATURE == NtHdr->Signature) {
DWORD IAT = NtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress;
DWORD end = NtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size;
IAT += startAddress;
end += IAT;
for (DWORD pt = IAT; pt < end; pt += 4) {
DWORD addr = *(DWORD *)pt;
if (addr == (DWORD)exportAddress)
return pt;
}
}
}
return 0;
}
NTINSPECT_END_NAMESPACE
// EOF
......
......@@ -4,6 +4,9 @@
// 4/20/2014 jichi
#include <windows.h>
#ifndef MEMDBG_NO_STL
# include <functional>
#endif // MEMDBG_NO_STL
#ifndef NTINSPECT_BEGIN_NAMESPACE
# define NTINSPECT_BEGIN_NAMESPACE namespace NtInspect {
......@@ -14,17 +17,73 @@
NTINSPECT_BEGIN_NAMESPACE
// Get the module handle of the current module (not the current process that is GetModuleHandleA(0))
HMODULE getCurrentModuleHandle();
/// Get current module name in fs:0x30
BOOL getCurrentProcessName(_Out_ LPWSTR buffer, _In_ int bufferSize);
BOOL getProcessName(_Out_ LPWSTR buffer, _In_ int bufferSize);
/**
* Get the memory range of the module if succeed
* See: ITH FillRange
* @param moduleName
* @param[out[ lowerBound
* @param[out] upperBound
* @return if succeed
*/
BOOL getModuleMemoryRange(_In_ LPCWSTR moduleName, _Out_ DWORD *lowerBound, _Out_ DWORD *upperBound);
/// Get memory of the current process
BOOL getCurrentMemoryRange(_Out_ DWORD *lowerBound, _Out_ DWORD *upperBound);
/// Get memory of the current process module
BOOL getProcessMemoryRange(_Out_ DWORD *lowerBound, _Out_ DWORD *upperBound);
#ifndef NTINSPECT_NO_STL
/// Iterate module information and return false if abort iteration.
typedef std::function<bool (HMODULE hModule, LPCWSTR moduleName)> iter_module_fun_t;
#else
typedef bool (* iter_module_fun_t)(HMODULE hModule, LPCWSTR moduleName);
#endif // NTINSPECT_NO_STL
/**
* Iterate all modules
* @param fun the first parameter is the address of the caller, and the second parameter is the address of the call itself
* @return false if return early, and true if iterate all elements
*/
bool iterModule(const iter_module_fun_t &fun);
/**
* Return the absolute address of the function imported from the given module
* @param functionName
* @param* hModule find from any module when null
* @return function address or 0
*/
DWORD getModuleExportFunction(HMODULE hModule, LPCSTR functionName);
inline DWORD getModuleExportFunctionA(LPCSTR moduleName, LPCSTR functionName)
{ return getModuleExportFunction(::GetModuleHandleA(moduleName), functionName); }
inline DWORD getModuleExportFunctionW(LPCWSTR moduleName, LPCSTR functionName)
{ return getModuleExportFunction(::GetModuleHandleW(moduleName), functionName); }
/// Get the function address exported from any module
DWORD getExportFunction(LPCSTR functionName);
/**
* Get the import address in the specified module
* @param hModule
* @param exportAddress absolute address of the function exported from other modules
* @return function address or 0
*/
DWORD getModuleImportAddress(HMODULE hModule, DWORD exportAddress);
inline DWORD getModuleImportAddressA(LPCSTR moduleName, DWORD exportAddress)
{ return getModuleImportAddress(::GetModuleHandleA(moduleName), exportAddress); }
inline DWORD getModuleImportAddressW(LPCWSTR moduleName, DWORD exportAddress)
{ return getModuleImportAddress(::GetModuleHandleW(moduleName), exportAddress); }
/// Get the import address in the current executable
inline DWORD getProcessImportAddress(DWORD exportAddress)
{ return getModuleImportAddress(::GetModuleHandleA(nullptr), exportAddress); }
NTINSPECT_END_NAMESPACE
......
set(profile_src
Profile.h
Profile.cpp
pugiconfig.hpp
pugixml.cpp
pugixml.hpp
misc.h
misc.cpp
)
add_library(profile STATIC ${profile_src})
target_compile_options(profile PRIVATE
$<$<CONFIG:Release>:>
$<$<CONFIG:Debug>:>
)
#target_link_libraries(profile comctl32.lib)
#target_compile_definitions(profile
# PRIVATE
# _CRT_NON_CONFORMING_SWPRINTFS
#)
/* Copyright (C) 2010-2012 kaosu (qiupf2000@gmail.com)
* This file is part of the Interactive Text Hooker.
* Interactive Text Hooker is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "host/host.h"
#include "host/hookman.h"
#include "vnrhook/include/types.h"
#include "vnrhook/include/const.h"
#include "Profile.h"
#include "misc.h"
#include <algorithm>
#include "pugixml.hpp"
extern HookManager* man;
Profile::Profile(const std::wstring& title) :
select_index(-1),
title(title)
{}
const std::unordered_set<hook_ptr>& Profile::Hooks() const
{
return hooks;
}
const std::vector<thread_ptr>& Profile::Threads() const
{
return threads;
}
const std::unordered_set<link_ptr>& Profile::Links() const
{
return links;
}
bool Profile::XmlReadProfile(pugi::xml_node profile)
{
auto hooks_node = profile.child(L"Hooks");
auto threads_node = profile.child(L"Threads");
auto links_node = profile.child(L"Links");
if (hooks_node && !XmlReadProfileHook(hooks_node))
return false;
if (threads_node && !XmlReadProfileThread(threads_node))
return false;
if (links_node && !XmlReadProfileLink(links_node))
return false;
auto select_node = profile.child(L"Select");
if (select_node)
{
auto thread_index = select_node.attribute(L"ThreadIndex");
if (!thread_index)
return false;
DWORD tmp_select = std::stoul(thread_index.value(), NULL, 16);
select_index = tmp_select & 0xFFFF;
}
return true;
}
bool Profile::XmlReadProfileHook(pugi::xml_node hooks_node)
{
for (auto hook = hooks_node.begin(); hook != hooks_node.end(); ++hook)
{
std::wstring name = hook->name();
if (name.empty() || name.compare(L"Hook") != 0)
return false;
auto type = hook->attribute(L"Type");
if (!type || type.empty())
return false;
auto code = hook->attribute(L"Code");
if (!code)
return false;
std::wstring code_value = code.value();
HookParam hp = {};
switch (type.value()[0])
{
case L'H':
if (code_value[0] != L'/')
return false;
if (code_value[1] != L'H' && code_value[1] != L'h')
return false;
if (Parse(code_value.substr(2), hp))
{
auto name = hook->attribute(L"Name");
if (!name || name.empty())
AddHook(hook_ptr(new HookProfile(hp, L"")));
else
AddHook(hook_ptr(new HookProfile(hp, name.value())));
}
break;
default:
return false;
}
}
return true;
}
bool Profile::XmlReadProfileThread(pugi::xml_node threads_node)
{
std::wstring hook_name_buffer;
for (auto thread = threads_node.begin(); thread != threads_node.end(); ++thread)
{
std::wstring name = thread->name();
if (name.empty() || name.compare(L"Thread") != 0)
return false;
auto hook_name = thread->attribute(L"HookName");
if (!hook_name)
return false;
auto context = thread->attribute(L"Context");
if (!context)
return false;
auto sub_context = thread->attribute(L"SubContext");
if (!sub_context)
return false;
auto mask = thread->attribute(L"Mask");
if (!mask)
return false;
DWORD mask_tmp = std::stoul(mask.value(), NULL, 16);
auto comment = thread->attribute(L"Comment");
auto retn = std::stoul(context.value(), NULL, 16);
auto split = std::stoul(sub_context.value(), NULL, 16);
WORD flags = mask_tmp & 0xFFFF;
auto tp = new ThreadProfile(hook_name.value(), retn, split, 0, 0, flags,
comment.value());
AddThread(thread_ptr(tp));
}
return true;
}
bool Profile::XmlReadProfileLink(pugi::xml_node links_node)
{
for (auto link = links_node.begin(); link != links_node.end(); ++link)
{
std::wstring name = link->name();
if (name.empty() || name.compare(L"Link") != 0)
return false;
auto from = link->attribute(L"From");
if (!from)
return false;
DWORD link_from = std::stoul(from.value(), NULL, 16);
auto to = link->attribute(L"To");
if (!to)
return false;
DWORD link_to = std::stoul(to.value(), NULL, 16);
auto lp = new LinkProfile(link_from & 0xFFFF, link_to & 0xFFFF);
AddLink(link_ptr(lp));
}
return true;
}
bool Profile::XmlWriteProfile(pugi::xml_node profile_node)
{
if (!hooks.empty())
{
auto node = profile_node.append_child(L"Hooks");
XmlWriteProfileHook(node);
}
if (!threads.empty())
{
auto node = profile_node.append_child(L"Threads");
XmlWriteProfileThread(node);
}
if (!links.empty())
{
auto node = profile_node.append_child(L"Links");
XmlWriteProfileLink(node);
}
if (select_index != 0xFFFF)
{
auto node = profile_node.append_child(L"Select");
node.append_attribute(L"ThreadIndex") = select_index;
}
return true;
}
bool Profile::XmlWriteProfileHook(pugi::xml_node hooks_node)
{
for (auto hook = hooks.begin(); hook != hooks.end(); ++hook)
{
auto hook_node = hooks_node.append_child(L"Hook");
hook_node.append_attribute(L"Type") = L"H";
hook_node.append_attribute(L"Code") = ParseCode((*hook)->HP()).c_str();
if (!(*hook)->Name().empty())
hook_node.append_attribute(L"Name") = (*hook)->Name().c_str();
}
return true;
}
bool Profile::XmlWriteProfileThread(pugi::xml_node threads_node)
{
for (auto thread = threads.begin(); thread != threads.end(); ++thread)
{
const std::wstring& name = (*thread)->HookName();
if (name.empty())
return false;
auto node = threads_node.append_child(L"Thread");
node.append_attribute(L"HookName") = name.c_str();
std::wstring hex = ToHexString((*thread)->Flags() & (THREAD_MASK_RETN | THREAD_MASK_SPLIT));
node.append_attribute(L"Mask") = hex.c_str();
hex = ToHexString((*thread)->Split());
node.append_attribute(L"SubContext") = hex.c_str();
hex = ToHexString((*thread)->Return());
node.append_attribute(L"Context") = hex.c_str();
if (!(*thread)->Comment().empty())
node.append_attribute(L"Comment") = (*thread)->Comment().c_str();
}
return true;
}
bool Profile::XmlWriteProfileLink(pugi::xml_node links_node)
{
for (auto link = links.begin(); link != links.end(); ++link)
{
auto node = links_node.append_child(L"Link");
node.append_attribute(L"From") = ToHexString((*link)->FromIndex()).c_str();
node.append_attribute(L"To") = ToHexString((*link)->ToIndex()).c_str();
}
return true;
}
void Profile::Clear()
{
title = L"";
select_index = -1;
hooks.clear();
threads.clear();
links.clear();
}
void Profile::AddHook(hook_ptr hook)
{
hooks.insert(std::move(hook));
}
// add the thread profile and return its index
int Profile::AddThread(thread_ptr tp)
{
auto it = std::find_if(threads.begin(), threads.end(), [&tp](thread_ptr& thread)
{
return thread->HookName().compare(tp->HookName()) == 0 &&
thread->Return() == tp->Return() &&
thread->Split() == tp->Split();
});
if (it != threads.end())
return it - threads.begin();
threads.push_back(std::move(tp));
return threads.size() - 1;
}
void Profile::AddLink(link_ptr link)
{
links.insert(std::move(link));
}
const std::wstring& Profile::Title() const
{
return title;
}
bool Profile::IsThreadSelected(thread_ptr_iter thread_profile)
{
if (thread_profile != threads.end())
{
auto thread_index = thread_profile - threads.begin();
return select_index == thread_index;
}
return false;
}
thread_ptr_iter Profile::FindThread(const ThreadParameter* tp, const std::wstring& hook_name) const
{
auto thread_profile = std::find_if(threads.begin(), threads.end(),
[&tp, &hook_name](const thread_ptr& thread_profile) -> bool
{
return thread_profile->HookName().compare(hook_name) == 0
&& thread_profile->Return() == tp->retn
&& thread_profile->Split() == tp->spl;
});
return thread_profile;
}
/* Copyright (C) 2010-2012 kaosu (qiupf2000@gmail.com)
* This file is part of the Interactive Text Hooker.
* Interactive Text Hooker is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "vnrhook/include/types.h" // HookParam
#include <string>
#include <memory>
#include <vector>
#include <unordered_set>
struct ThreadParameter;
class TextThread;
class HookProfile;
class ThreadProfile;
class LinkProfile;
typedef std::unique_ptr<HookProfile> hook_ptr;
typedef std::unique_ptr<ThreadProfile> thread_ptr;
typedef std::unique_ptr<LinkProfile> link_ptr;
typedef std::vector<thread_ptr>::const_iterator thread_ptr_iter;
namespace pugi {
class xml_node;
}
#define THREAD_MASK_RETN 1
#define THREAD_MASK_SPLIT 2
class HookProfile
{
HookParam hp;
std::wstring name;
public:
HookProfile(const HookParam& hp, const std::wstring& name) :
hp(hp),
name(name)
{}
const HookParam& HP() const { return hp; };
const std::wstring& Name() const { return name; };
};
class ThreadProfile
{
std::wstring hook_name;
DWORD retn;
DWORD split;
DWORD hook_addr;
WORD hm_index, flags;
std::wstring comment;
public:
ThreadProfile(const std::wstring& hook_name,
DWORD retn,
DWORD split,
DWORD hook_addr,
WORD hm_index,
WORD flags,
const std::wstring& comment) :
hook_name(hook_name),
retn(retn),
split(split),
hook_addr(hook_addr),
hm_index(hm_index),
flags(flags),
comment(comment)
{
}
const std::wstring& HookName() const { return hook_name; }
const std::wstring& Comment() const { return comment; }
DWORD Return() const { return retn; }
DWORD Split() const { return split; }
DWORD& HookAddress() { return hook_addr; }
WORD& HookManagerIndex() { return hm_index; }
WORD Flags() const { return flags; }
};
class LinkProfile
{
WORD from_index, to_index;
public:
LinkProfile(WORD from_index, WORD to_index) :
from_index(from_index),
to_index(to_index)
{}
WORD FromIndex() const { return from_index; }
WORD ToIndex() const { return to_index; }
};
namespace std {
template<>
struct hash<hook_ptr> {
size_t operator()(const hook_ptr &r) const
{
return hash<DWORD>{}(r->HP().address)
^ hash<DWORD>{}(r->HP().module)
^ hash<DWORD>{}(r->HP().function);
}
};
template<>
struct equal_to<hook_ptr> {
bool operator()(const hook_ptr& r, const hook_ptr& r2) const
{
return r->HP().address == r2->HP().address
&& r->HP().module == r2->HP().module
&& r->HP().function == r2->HP().function;
}
};
template<>
struct hash<link_ptr> {
size_t operator()(const link_ptr &r) const
{
return hash<WORD>{}(r->FromIndex())
^ hash<WORD>{}(r->ToIndex());
}
};
template<>
struct equal_to<link_ptr> {
bool operator()(const link_ptr& r, const link_ptr& r2) const
{
return r->FromIndex() == r2->FromIndex()
&& r->ToIndex() == r2->ToIndex();
}
};
}
class Profile
{
public:
Profile(const std::wstring& title);
bool XmlReadProfile(pugi::xml_node profile_node);
bool XmlWriteProfile(pugi::xml_node profile_node);
void AddHook(hook_ptr hook);
int AddThread(thread_ptr tp);
void AddLink(link_ptr lp);
void Clear();
const std::unordered_set<hook_ptr>& Hooks() const;
const std::vector<thread_ptr>& Threads() const;
const std::unordered_set<link_ptr>& Links() const;
const std::wstring& Title() const;
thread_ptr_iter FindThread(const ThreadParameter* tp, const std::wstring& hook_name) const;
WORD& SelectedIndex() { return select_index; }
bool IsThreadSelected(thread_ptr_iter thread_profile);
private:
bool XmlReadProfileHook(pugi::xml_node hooks_node);
bool XmlReadProfileThread(pugi::xml_node threads_node);
bool XmlReadProfileLink(pugi::xml_node links_node);
bool XmlWriteProfileHook(pugi::xml_node hooks_node);
bool XmlWriteProfileThread(pugi::xml_node threads_node);
bool XmlWriteProfileLink(pugi::xml_node links_node);
std::wstring title;
std::unordered_set<hook_ptr> hooks;
std::vector<thread_ptr> threads;
std::unordered_set<link_ptr> links;
WORD select_index;
};
#include "misc.h"
#include <regex>
#include <memory>
#include "host/host.h"
#include "vnrhook/include/const.h"
#include "vnrhook/include/types.h"
DWORD Hash(const std::wstring& module, int length)
{
DWORD hash = 0;
auto end = (length < 0 || static_cast<size_t>(length) > module.length()) ?
module.end() :
module.begin() + length;
for (auto it = module.begin(); it != end; ++it)
hash = _rotr(hash, 7) + *it;
return hash;
}
bool Parse(const std::wstring& cmd, HookParam& hp)
{
using std::wregex;
using std::regex_search;
// /H[X]{A|B|W|S|Q}[N][data_offset[*drdo]][:sub_offset[*drso]]@addr[:[module[:{name|#ordinal}]]]
wregex rx(L"^X?([ABWSQ])(N)?", wregex::icase);
std::match_results<std::wstring::const_iterator> m;
auto start = cmd.begin();
auto end = cmd.end();
bool result = regex_search(start, end, m, rx);
if (!result)
return result;
start = m[0].second;
if (m[2].matched)
hp.type |= NO_CONTEXT;
switch (m[1].first[0])
{
case L's':
case L'S':
hp.type |= USING_STRING;
break;
case L'e':
case L'E':
hp.type |= STRING_LAST_CHAR;
case L'a':
case L'A':
hp.type |= BIG_ENDIAN;
hp.length_offset = 1;
break;
case L'b':
case L'B':
hp.length_offset = 1;
break;
case L'h':
case L'H':
hp.type |= PRINT_DWORD;
case L'q':
case L'Q':
hp.type |= USING_STRING | USING_UNICODE;
break;
case L'l':
case L'L':
hp.type |= STRING_LAST_CHAR;
case L'w':
case L'W':
hp.type |= USING_UNICODE;
hp.length_offset = 1;
break;
default:
break;
}
// [data_offset[*drdo]]
std::wstring data_offset(L"(-?[[:xdigit:]]+)"), drdo(L"(\\*-?[[:xdigit:]]+)?");
rx = wregex(L"^" + data_offset + drdo, wregex::icase);
result = regex_search(start, end, m, rx);
if (result)
{
start = m[0].second;
hp.offset = std::stoul(m[1].str(), NULL, 16);
if (m[2].matched)
{
hp.type |= DATA_INDIRECT;
hp.index = std::stoul(m[2].str().substr(1), NULL, 16);
}
}
// [:sub_offset[*drso]]
std::wstring sub_offset(L"(-?[[:xdigit:]]+)"), drso(L"(\\*-?[[:xdigit:]]+)?");
rx = wregex(L"^:" + sub_offset + drso, wregex::icase);
result = regex_search(start, end, m, rx);
if (result)
{
start = m[0].second;
hp.type |= USING_SPLIT;
hp.split = std::stoul(m[1].str(), NULL, 16);
if (m[2].matched)
{
hp.type |= SPLIT_INDIRECT;
hp.split_index = std::stoul(m[2].str().substr(1), NULL, 16);
}
}
// @addr
rx = wregex(L"^@[[:xdigit:]]+", wregex::icase);
result = regex_search(start, end, m, rx);
if (!result)
return false;
start = m[0].second;
hp.address = std::stoul(m[0].str().substr(1), NULL, 16);
if (hp.offset & 0x80000000)
hp.offset -= 4;
if (hp.split & 0x80000000)
hp.split -= 4;
// [:[module[:{name|#ordinal}]]]
// ":" -> module == NULL &% function == NULL
// "" -> MODULE_OFFSET && module == NULL && function == addr
// ":GDI.dll" -> MODULE_OFFSET && module != NULL
// ":GDI.dll:strlen" -> MODULE_OFFSET | FUNCTION_OFFSET && module != NULL && function != NULL
// ":GDI.dll:#123" -> MODULE_OFFSET | FUNCTION_OFFSET && module != NULL && function != NULL
std::wstring module(L"([[:graph:]]+)"), name(L"[[:graph:]]+"), ordinal(L"\\d+");
rx = wregex(L"^:(" + module + L"(:" + name + L"|#" + ordinal + L")?)?$", wregex::icase);
result = regex_search(start, end, m, rx);
if (result) // :[module[:{name|#ordinal}]]
{
if (m[1].matched) // module
{
hp.type |= MODULE_OFFSET;
std::wstring module = m[2];
std::transform(module.begin(), module.end(), module.begin(), ::towlower);
hp.module = Hash(module);
if (m[3].matched) // :name|#ordinal
{
hp.type |= FUNCTION_OFFSET;
hp.function = Hash(m[3].str().substr(1));
}
}
}
else
{
rx = wregex(L"^!([[:xdigit:]]+)(!([[:xdigit:]]+))?$", wregex::icase);
result = regex_search(start, end, m, rx);
if (result)
{
hp.type |= MODULE_OFFSET;
hp.module = std::stoul(m[1].str(), NULL, 16);
if (m[2].matched)
{
hp.type |= FUNCTION_OFFSET;
hp.function = std::stoul(m[2].str().substr(1), NULL, 16);
}
}
else
{
// Hack. Hook is relative to the executable. Store the original address in function.
// hp.module == NULL && hp.function != NULL
hp.type |= MODULE_OFFSET;
hp.function = hp.address;
}
}
return true;
}
std::wstring ParseCode(const HookParam& hp)
{
std::wstring code(L"/H");
WCHAR c;
if (hp.type & PRINT_DWORD)
c = L'H';
else if (hp.type & USING_UNICODE)
{
if (hp.type & USING_STRING)
c = L'Q';
else if (hp.type & STRING_LAST_CHAR)
c = L'L';
else
c = L'W';
}
else
{
if (hp.type & USING_STRING)
c = L'S';
else if (hp.type & BIG_ENDIAN)
c = L'A';
else if (hp.type & STRING_LAST_CHAR)
c = L'E';
else
c = L'B';
}
code += c;
if (hp.type & NO_CONTEXT)
code += L'N';
if (hp.offset >> 31)
code += L'-' + ToHexString(-(hp.offset + 4));
else
code += ToHexString(hp.offset);
if (hp.type & DATA_INDIRECT)
{
if (hp.index >> 31)
code += L'*-' + ToHexString(-hp.index);
else
code += L'*' + ToHexString(hp.index);
}
if (hp.type & USING_SPLIT)
{
if (hp.split >> 31)
code += L":-" + ToHexString(-(4 + hp.split));
else
code += L":" + ToHexString(hp.split);
}
if (hp.type & SPLIT_INDIRECT)
{
if (hp.split_index >> 31)
code += L"*-" + ToHexString(-hp.split_index);
else
code += L"*" + ToHexString(hp.split_index);
}
if (hp.module)
{
code += L"@" + ToHexString(hp.address) + L"!" + ToHexString(hp.module);
if (hp.function)
code += L"!" + ToHexString(hp.function);
}
else
{
// Hack. The original address is stored in the function field
// if (module == NULL && function != NULL).
// MODULE_OFFSET and FUNCTION_OFFSET are removed from HookParam.type in
// TextHook::UnsafeInsertHookCode() and can not be used here.
if (hp.function)
code += L"@" + ToHexString(hp.function);
else
code += L"@" + ToHexString(hp.address) + L":";
}
return code;
}
std::string toMultiByteString(const std::wstring& unicodeString)
{
int cbMultiByte = WideCharToMultiByte(932, 0, unicodeString.c_str(), unicodeString.length(),
NULL, 0, NULL, NULL);
auto lpMultiByteStr = std::make_unique<CHAR[]>(cbMultiByte);
WideCharToMultiByte(932, 0, unicodeString.c_str(), unicodeString.length(),
lpMultiByteStr.get(), cbMultiByte, NULL, NULL);
return std::string(lpMultiByteStr.get(), cbMultiByte);
}
std::wstring toUnicodeString(const std::string& mbString)
{
int cchWideChar = MultiByteToWideChar(932, 0, mbString.c_str(), mbString.length(), NULL, 0);
auto lpWideCharStr = std::make_unique<WCHAR[]>(cchWideChar);
MultiByteToWideChar(932, 0, mbString.c_str(), mbString.length(), lpWideCharStr.get(), cchWideChar);
return std::wstring(lpWideCharStr.get(), cchWideChar);
}
std::wstring GetHookNameByAddress(const ProcessRecord& pr, DWORD hook_address)
{
std::wstring hook_name;
WaitForSingleObject(pr.hookman_mutex, 0);
auto hooks = (const Hook*)pr.hookman_map;
for (int i = 0; i < MAX_HOOK; ++i)
{
auto& hook = hooks[i];
if (hook.Address() == hook_address)
{
std::unique_ptr<CHAR[]> name(new CHAR[hook.NameLength()]);
// name is zero terminated
if (ReadProcessMemory(pr.process_handle, hooks[i].Name(), name.get(), hook.NameLength(), NULL))
hook_name = toUnicodeString(name.get());
break;
}
}
ReleaseMutex(pr.hookman_mutex);
return hook_name;
}
#pragma once
#include <Windows.h>
#include <string>
#include <sstream>
struct HookParam;
struct ProcessRecord;
bool Parse(const std::wstring& cmd, HookParam& hp);
DWORD Hash(const std::wstring& module, int length = -1);
std::wstring ParseCode(const HookParam& hp);
std::string toMultiByteString(const std::wstring& unicodeString);
std::wstring toUnicodeString(const std::string& mbString);
std::wstring GetHookNameByAddress(const ProcessRecord& pr, DWORD hook_address);
template <typename T>
std::wstring ToHexString(T i) {
std::wstringstream ss;
ss << std::uppercase << std::hex << i;
return ss.str();
}
/**
* pugixml parser - version 1.6
* --------------------------------------------------------
* Copyright (C) 2006-2015, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
* Report bugs and download new versions at http://pugixml.org/
*
* This library is distributed under the MIT License. See notice at the end
* of this file.
*
* This work is based on the pugxml parser, which is:
* Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
*/
#ifndef HEADER_PUGICONFIG_HPP
#define HEADER_PUGICONFIG_HPP
// Uncomment this to enable wchar_t mode
#define PUGIXML_WCHAR_MODE
// Uncomment this to disable XPath
// #define PUGIXML_NO_XPATH
// Uncomment this to disable STL
// #define PUGIXML_NO_STL
// Uncomment this to disable exceptions
// #define PUGIXML_NO_EXCEPTIONS
// Set this to control attributes for public classes/functions, i.e.:
// #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL
// #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL
// #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall
// In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead
// Tune these constants to adjust memory-related behavior
// #define PUGIXML_MEMORY_PAGE_SIZE 32768
// #define PUGIXML_MEMORY_OUTPUT_STACK 10240
// #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096
// Uncomment this to switch to header-only version
// #define PUGIXML_HEADER_ONLY
// Uncomment this to enable long long support
// #define PUGIXML_HAS_LONG_LONG
#endif
/**
* Copyright (c) 2006-2015 Arseny Kapoulkine
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
# sakurakit.pri
# 6/28/2011 jichi
#
# config:
# - sakurakit_qml
# - sakurakit_gui
# - sakurakit_widgets
DEFINES += WITH_LIB_SAKURAKIT
DEPENDPATH += $$PWD
#QT += core
HEADERS += \
$$PWD/skautorun.h \
$$PWD/skdebug.h \
$$PWD/skglobal.h \
$$PWD/skhash.h
#CONFIG(sakurakit_gui) {
# DEFINES += SK_ENABLE_GUI
# QT += gui
# HEADERS += \
# $$PWD/skuiutil.h
#
# CONFIG(sakurakit_qml) {
# DEFINES += SK_ENABLE_QML
# QT += qml quick
# HEADERS += \
# $$PWD/skdraggablequickview.h
# SOURCES += \
# $$PWD/skdraggablequickview.cc
# }
#
# CONFIG(sakurakit_widgets) {
# DEFINES += SK_ENABLE_WIDGETS
# QT += widgets
# HEADERS += \
# $$PWD/skdraggabledialog.h \
# $$PWD/skdraggablemainwindow.h \
# $$PWD/skdraggablewidget.h \
# $$PWD/skpushbutton.h \
# $$PWD/sksystemtrayicon.h \
# $$PWD/sktoolbutton.h \
# $$PWD/skwindowcontainer.h
# SOURCES += \
# $$PWD/skdraggablewidget.cc \
# $$PWD/skpushbutton.cc \
# $$PWD/sktoolbutton.cc \
# $$PWD/skwindowcontainer.cc \
# $$PWD/skdraggabledialog.cc \
# $$PWD/skdraggablemainwindow.cc
#
# CONFIG(sakurakit_qml) {
# HEADERS += \
# $$PWD/skquickwidget.h
# SOURCES += \
# $$PWD/skquickwidget.cc
# }
# }
#}
# EOF
#ifndef SKAUTORUN_H
#define SKAUTORUN_H
// skautorun.h
// 9/30/2012 jichi
#include "sakurakit/skglobal.h"
#include <functional>
SK_BEGIN_NAMESPACE
class SkAutoRun
{
public:
typedef std::function<void ()> function_type;
SkAutoRun(const function_type &start, const function_type &exit)
: exit_(exit) { start(); }
~SkAutoRun() { exit_(); }
private:
function_type exit_;
};
class SkAutoRunAtStartup
{
public:
typedef SkAutoRun::function_type function_type;
explicit SkAutoRunAtStartup(const function_type &start) { start(); }
};
class SkAutoRunAtExit
{
public:
typedef SkAutoRun::function_type function_type;
explicit SkAutoRunAtExit(const function_type &exit) : exit_(exit) {}
~SkAutoRunAtExit() { exit_(); }
private:
function_type exit_;
};
SK_END_NAMESPACE
#endif // SkAUTORUN_H
#ifndef SKDEBUG_H
#define SKDEBUG_H
// skdebug.h
// 10/16/2011 jichi
// Macros for debug.
// Debug I/O
// - DPRINT: similar to fprintf, or KDPrint. Print to qDebug
// - DOUT: similar to std::cout. Print to qDebug
// - DERR: similar to std::cerr. Print to qWarning
#if defined(DEBUG) && !defined(SK_NO_DEBUG)
# if defined(QT_CORE_LIB) && !defined(SK_NO_QT)
# include <QtCore/QDebug>
# define DPRINT(...) qDebug(QString("%1:%2:").arg((DEBUG), (__FUNCTION__)).toLocal8Bit().constData(), __VA_ARGS__)
# define DOUT(_msg) qDebug() << QString("%1:%2:").arg((DEBUG), (__FUNCTION__)).toLocal8Bit().constData() << _msg
# define DERR(_msg) qWarning() << QString("%1:%2:").arg((DEBUG), (__FUNCTION__)).toLocal8Bit().constData() << _msg
# else
# include <iostream>
# include <cstdio>
# define DPRINT(...) fprintf(stderr, DEBUG ":" __FUNCTION__ ": " __VA_ARGS__)
# define DWPRINT(...) fwprintf(stderr, DEBUG ":" __FUNCTION__ ": " __VA_ARGS__)
# define DOUT(_msg) std::cout << DEBUG << ":" << __FUNCTION__ << ": " << _msg << std::endl
# define DWOUT(_msg) std::wcout << DEBUG << ":" << __FUNCTION__ << ": " << _msg << std::endl
# define DERR(_msg) std::cerr << DEBUG << ":" << __FUNCTION__ << ": " << _msg << std::endl
# define DWERR(_msg) std::wcerr << DEBUG << ":" << __FUNCTION__ << ": " << _msg << std::endl
# endif // QT_CORE_LIB
#else // DEBUG
# define DPRINT(_dummy) (void)0
# define DOUT(_dummy) (void)0
# define DERR(_dummy) (void)0
//#ifdef _MSC_VER
//# pragma warning (disable:4390) // C4390: empty controlled statement found: is this the intent?
//#endif // _MSC_VER
//#ifdef __GNUC__
//# pragma GCC diagnostic ignored "-Wempty-body" // empty body in an if or else statement
//#endif // __GNUC__
#endif // DEBUG
#endif // SKDEBUG_H
#ifndef SKGLOBAL_H
#define SKGLOBAL_H
// skglobal.h
// 9/15/2012 jichi
// Similar to QtGlobal from Qt.
//
// Conventions:
// - All classes in sakurakit will be wrapped with SK_BEGIN_NAMESPACE and SK_END_NAMESPACE
// - All classes from sakurakit begin with Sk, such as SkClassA.
// All functions from sakurakit begin with sk, such as skFuncA.
// Redefine SK_BEGIN_NAMESPACE/SK_END_NAMESPACE if need custom namespace
#ifndef SK_BEGIN_NAMESPACE
# define SK_BEGIN_NAMESPACE namespace Sk {
#endif
#ifndef SK_END_NAMESPACE
# define SK_END_NAMESPACE } // namespace Sk
#endif
#define SK_FORWARD_DECLARE_CLASS(_name) SK_BEGIN_NAMESPACE class _name; SK_END_NAMESPACE
#define SK_FORWARD_DECLARE_STRUCT(_name) SK_BEGIN_NAMESPACE struct _name; SK_END_NAMESPACE
SK_BEGIN_NAMESPACE
namespace Sk {}
SK_END_NAMESPACE
// In case Qt is not avaliable
//inline void sk_noop(void) {}
//
//template <typename T>
//inline void skUnused(T &x) { (void)x; }
#define SK_UNUSED(_var) (void)(_var)
#define SK_NOP SK_UNUSED(0)
// same as Q_DISABLE_COPY and boost::noncopyable
// Disable when BOOST_PYTHON is enabled
#ifdef BOOST_PYTHON
# define SK_DISABLE_COPY(_class)
#else
# define SK_DISABLE_COPY(_class) \
_class(const _class &); \
_class &operator=(const _class &);
#endif // BOOST_PYTHON
// - Qt-like Pimp -
// Similar to QT_DECLARE_PRIVATE
#define SK_DECLARE_PRIVATE(_class) \
friend class _class; \
typedef _class D; \
D *const d_;
// Similar to QT_DECLARE_PUBLIC
#define SK_DECLARE_PUBLIC(_class) \
friend class _class; \
typedef _class Q; \
Q *const q_;
// - Self and Base -
#define SK_CLASS(_self) \
typedef _self Self; \
Self *self() const { return const_cast<Self *>(this); }
#define SK_EXTEND_CLASS(_self, _base) \
SK_CLASS(_self) \
typedef _base Base;
#define SK_UNDEF_POS QPoint(-1, -1)
#define SK_UNDEF_POSF QPointF(-1, -1)
// - QWidget Style Class for QSS -
// Read-only property
#define SK_STYLE_CLASS(_class) \
Q_PROPERTY(QString class READ styleClass) \
public: \
QString styleClass() const { return #_class; } \
private:
// Read-write property
#define SK_SYNTHESIZE_STYLE_CLASS \
Q_PROPERTY(QString class READ styleClass WRITE setStyleClass) \
QString styleClass_; \
public: \
QString styleClass() const { return styleClass_; } \
public slots: \
void seStyleClass(const QString &value) { styleClass_ = value; } \
private:
#endif // SKGLOBAL_H
#ifndef SKHASH_H
#define SKHASH_H
// skhash.h
// 8/1/2011
#include "sakurakit/skglobal.h"
#include <QtGlobal>
SK_BEGIN_NAMESPACE
enum : quint64 { djb2_hash0 = 5381 };
/// djb2: h = h*33 + c
inline quint64 djb2(const quint8 *str, quint64 hash = djb2_hash0)
{
quint8 c;
while ((c = *str++))
hash = ((hash << 5) + hash) + c; // hash * 33 + c
return hash;
}
/// s: signed char
inline quint64 djb2_s(const char *str, quint64 hash = djb2_hash0)
{
char c;
while ((c = *str++))
hash = ((hash << 5) + hash) + c; // hash * 33 + c
return hash;
}
/// n: length
inline quint64 djb2_n(const quint8 *str, size_t len, quint64 hash = djb2_hash0)
{
while (len--)
hash = ((hash << 5) + hash) + (*str++); // hash * 33 + c
return hash;
}
/// sdbm: hash(i) = hash(i - 1) * 65599 + str[i];
inline quint64 sdbm(const quint8 *str, quint64 hash = 0)
{
quint8 c;
while ((c = *str++))
hash = c + (hash << 6) + (hash << 16) - hash;
return hash;
}
inline quint64 loselose(const quint8 *str, quint64 hash = 0)
{
quint8 c;
while ((c = *str++))
hash += c;
return hash;
}
SK_END_NAMESPACE
#endif // SKHASH_H
#pragma once
// growl.h
// 9/17/2013 jichi
//#ifdef GROWL_HAS_GROWL
#include <windows.h>
#include <cstdio>
#define GROWL_MSG_A(_msg) MessageBoxA(nullptr, _msg, "VNR Message", MB_OK)
#define GROWL_MSG(_msg) MessageBoxW(nullptr, _msg, L"VNR Message", MB_OK)
#define GROWL_WARN(_msg) MessageBoxW(nullptr, _msg, L"VNR Warning", MB_OK)
#define GROWL_ERROR(_msg) MessageBoxW(nullptr, _msg, L"VNR Error", MB_OK)
inline void GROWL_DWORD(DWORD value)
{
WCHAR buf[100];
swprintf(buf, L"DWORD: %x", value);
GROWL_MSG(buf);
}
inline void GROWL_DWORD2(DWORD v, DWORD v2)
{
WCHAR buf[100];
swprintf(buf, L"DWORD2: %x,%x", v, v2);
GROWL_MSG(buf);
}
inline void GROWL_DWORD3(DWORD v, DWORD v2, DWORD v3)
{
WCHAR buf[100];
swprintf(buf, L"DWORD3: %x,%x,%x", v, v2, v3);
GROWL_MSG(buf);
}
inline void GROWL_DWORD4(DWORD v, DWORD v2, DWORD v3, DWORD v4)
{
WCHAR buf[100];
swprintf(buf, L"DWORD4: %x,%x,%x,%x", v, v2, v3, v4);
GROWL_MSG(buf);
}
inline void GROWL_DWORD5(DWORD v, DWORD v2, DWORD v3, DWORD v4, DWORD v5)
{
WCHAR buf[100];
swprintf(buf, L"DWORD5: %x,%x,%x,%x,%x", v, v2, v3, v4, v5);
GROWL_MSG(buf);
}
inline void GROWL_DWORD6(DWORD v, DWORD v2, DWORD v3, DWORD v4, DWORD v5, DWORD v6)
{
WCHAR buf[100];
swprintf(buf, L"DWORD6: %x,%x,%x,%x,%x,%x", v, v2, v3, v4, v5, v6);
GROWL_MSG(buf);
}
inline void GROWL_DWORD7(DWORD v, DWORD v2, DWORD v3, DWORD v4, DWORD v5, DWORD v6, DWORD v7)
{
WCHAR buf[100];
swprintf(buf, L"DWORD7: %x,%x,%x,%x,%x,%x,%x", v, v2, v3, v4, v5, v6, v7);
GROWL_MSG(buf);
}
inline void GROWL_DWORD8(DWORD v, DWORD v2, DWORD v3, DWORD v4, DWORD v5, DWORD v6, DWORD v7, DWORD v8)
{
WCHAR buf[100];
swprintf(buf, L"DWORD8: %x,%x,%x,%x,%x,%x,%x,%x", v, v2, v3, v4, v5, v6, v7, v8);
GROWL_MSG(buf);
}
inline void GROWL_DWORD9(DWORD v, DWORD v2, DWORD v3, DWORD v4, DWORD v5, DWORD v6, DWORD v7, DWORD v8, DWORD v9)
{
WCHAR buf[100];
swprintf(buf, L"DWORD9: %x,%x,%x,%x,%x,%x,%x,%x,%x", v, v2, v3, v4, v5, v6, v7, v8, v9);
GROWL_MSG(buf);
}
inline void GROWL(DWORD v) { GROWL_DWORD(v); }
inline void GROWL(LPCWSTR v) { GROWL_MSG(v); }
inline void GROWL(LPCSTR v) { GROWL_MSG_A(v); }
//#endif // GROWL_HAS_GROWL
// EOF
# texthook.pro
# CONFIG += noqtgui dll #eha # eha will catch all exceptions, but does not work on Windows XP
# DEFINES += ITH_HAS_CRT # Use native CRT
# # TODO: Get rid of dependence on msvc's swprintf
# DEFINES += _CRT_NON_CONFORMING_SWPRINTFS
set(vnrhost_src
avl_p.h
config.h
hookman.h
host.h
host_p.h
settings.h
textthread.h
textthread_p.h
hookman.cc
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
)
add_library(vnrhost SHARED ${vnrhost_src})
set_target_properties(vnrhost PROPERTIES LINK_FLAGS /SUBSYSTEM:WINDOWS)
target_compile_options(vnrhost PRIVATE
# /GR-
$<$<CONFIG:Release>:>
$<$<CONFIG:Debug>:>
)
#STRING(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
target_link_libraries(vnrhost
ithsys
profile
${WDK_HOME}/lib/wxp/i386/ntdll.lib
)
target_compile_definitions(vnrhost
PRIVATE
ITH_HAS_CRT
_CRT_NON_CONFORMING_SWPRINTFS
)
install(TARGETS vnrhost RUNTIME
DESTINATION .
CONFIGURATIONS Release
)
This diff is collapsed. Click to expand it.
#pragma once
// config.h
// 8/23/2013 jichi
// The first header file that are included by all source files.
#define IHF // for dll import
//#include "ith/dllconfig.h"
#define IHFAPI __stdcall
#ifdef IHF
# define IHFSERVICE __declspec(dllexport)
#else
# define IHFSERVICE __declspec(dllimport)
#endif
// EOF
This diff is collapsed. Click to expand it.
#pragma once
// hookman.h
// 8/23/2013 jichi
// Branch: ITH/HookManager.h, rev 133
#include "host/avl_p.h"
#include "host/textthread.h"
#include "winmutex/winmutex.h"
namespace pugi {
class xml_node;
}
class Profile;
enum { MAX_REGISTER = 0xf };
enum { MAX_PREV_REPEAT_LENGTH = 0x20 };
struct ProcessRecord {
DWORD pid_register;
DWORD hookman_register;
DWORD module_register;
//DWORD engine_register; // jichi 10/19/2014: removed
HANDLE process_handle;
HANDLE hookman_mutex;
HANDLE hookman_section;
LPVOID hookman_map;
};
class ThreadTable : public MyVector<TextThread *, 0x40>
{
public:
virtual void SetThread(DWORD number, TextThread *ptr);
virtual TextThread *FindThread(DWORD number);
};
struct IHFSERVICE TCmp { char operator()(const ThreadParameter *t1, const ThreadParameter *t2); };
struct IHFSERVICE TCpy { void operator()(ThreadParameter *t1, const ThreadParameter *t2); };
struct IHFSERVICE TLen { int operator()(const ThreadParameter *t); };
typedef DWORD (*ProcessEventCallback)(DWORD pid);
class IHFSERVICE HookManager : public AVLTree<ThreadParameter, DWORD, TCmp, TCpy, TLen>
{
public:
HookManager();
~HookManager();
// jichi 12/26/2013: remove virtual modifiers
TextThread *FindSingle(DWORD pid, DWORD hook, DWORD retn, DWORD split);
TextThread *FindSingle(DWORD number);
ProcessRecord *GetProcessRecord(DWORD pid);
DWORD GetProcessIDByPath(LPCWSTR str); // private
void RemoveSingleThread(DWORD number);
//void LockHookman();
//void UnlockHookman();
void ResetRepeatStatus();
void ClearCurrent();
void AddLink(WORD from, WORD to);
void UnLink(WORD from);
void UnLinkAll(WORD from);
void SelectCurrent(DWORD num);
void DetachProcess(DWORD pid);
void SetCurrent(TextThread *it);
void AddConsoleOutput(LPCWSTR text);
// jichi 10/27/2013: Add const; add space.
void DispatchText(DWORD pid, const BYTE *text, DWORD hook, DWORD retn, DWORD split, int len, bool space);
void ClearText(DWORD pid, DWORD hook, DWORD retn, DWORD split); // private
void RemoveProcessContext(DWORD pid); // private
void RemoveSingleHook(DWORD pid, DWORD addr);
void RegisterThread(TextThread*, DWORD); // private
void RegisterPipe(HANDLE text, HANDLE cmd, HANDLE thread);
void RegisterProcess(DWORD pid, DWORD hookman, DWORD module);
void UnRegisterProcess(DWORD pid);
//void SetName(DWORD);
DWORD GetCurrentPID(); // private
HANDLE GetCmdHandleByPID(DWORD pid);
ConsoleCallback RegisterConsoleCallback(ConsoleCallback cf)
{ return (ConsoleCallback)_InterlockedExchange((long*)&console,(long)cf); }
ConsoleWCallback RegisterConsoleWCallback(ConsoleWCallback cf)
{ return (ConsoleWCallback)_InterlockedExchange((long*)&wconsole,(long)cf); }
ThreadEventCallback RegisterThreadCreateCallback(ThreadEventCallback cf)
{ return (ThreadEventCallback)_InterlockedExchange((long*)&create,(long)cf); }
ThreadEventCallback RegisterThreadRemoveCallback(ThreadEventCallback cf)
{ return (ThreadEventCallback)_InterlockedExchange((long*)&remove,(long)cf); }
ThreadEventCallback RegisterThreadResetCallback(ThreadEventCallback cf)
{ return (ThreadEventCallback)_InterlockedExchange((long*)&reset,(long)cf); }
ThreadEventCallback RegisterAddRemoveLinkCallback(ThreadEventCallback cf)
{ return (ThreadEventCallback)_InterlockedExchange((long*)&addRemoveLink, (long)cf); }
ProcessEventCallback RegisterProcessAttachCallback(ProcessEventCallback cf)
{ return (ProcessEventCallback)_InterlockedExchange((long*)&attach,(long)cf); }
ProcessEventCallback RegisterProcessDetachCallback(ProcessEventCallback cf)
{ return (ProcessEventCallback)_InterlockedExchange((long*)&detach,(long)cf); }
ProcessEventCallback RegisterProcessNewHookCallback(ProcessEventCallback cf)
{ return (ProcessEventCallback)_InterlockedExchange((long*)&hook,(long)cf); }
ProcessEventCallback ProcessNewHook() { return hook; }
TextThread *GetCurrentThread() { return current; } // private
ProcessRecord *Records() { return record; } // private
ThreadTable *Table() { return thread_table; } // private
//DWORD& SplitTime() { return split_time; }
//DWORD& RepeatCount() { return repeat_count; }
//DWORD& CyclicRemove() { return cyclic_remove; }
//DWORD& GlobalFilter() { return global_filter; }
void ConsoleOutput(LPCSTR text) { if (console) console(text); } // not thread safe
void ConsoleOutputW(LPCWSTR text) { if (wconsole) wconsole(text); } // not thread safe
void OnThreadCreate(pugi::xml_node profile_node, TextThread* thread);
void GetProfile(DWORD pid, pugi::xml_node profile_node);
private:
typedef win_mutex<CRITICAL_SECTION> mutex_type;
mutex_type hmcs;
TextThread *current;
ConsoleCallback console; // jichi 12/25/2013: add console output callback
ConsoleWCallback wconsole;
ThreadEventCallback create,
remove,
reset,
addRemoveLink;
ProcessEventCallback attach,
detach,
hook;
DWORD current_pid;
ThreadTable *thread_table;
HANDLE destroy_event;
ProcessRecord record[MAX_REGISTER + 1];
HANDLE text_pipes[MAX_REGISTER + 1],
cmd_pipes[MAX_REGISTER + 1],
recv_threads[MAX_REGISTER + 1];
WORD register_count,
new_thread_number;
// jichi 1/16/2014: Stop adding new threads when full
bool IsFull() const; // { return new_thread_number >= MAX_HOOK; }
bool IsEmpty() const { return !new_thread_number; }
void HookManager::AddThreadsToProfile(Profile& pf, const ProcessRecord& pr, DWORD pid);
};
// EOF
This diff is collapsed. Click to expand it.
#pragma once
// host.h
// 8/23/2013 jichi
// Branch: ITH/IHF.h, rev 105
//#include "host/settings.h"
#include "config.h"
#include "host/hookman.h"
struct Settings;
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 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 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);
IHFSERVICE DWORD IHFAPI Host_RemoveHook(DWORD pid, DWORD addr);
IHFSERVICE DWORD IHFAPI Host_AddLink(DWORD from, DWORD to);
IHFSERVICE DWORD IHFAPI Host_UnLink(DWORD from);
IHFSERVICE DWORD IHFAPI Host_UnLinkAll(DWORD from);
// EOF
# host.pri
# 8/9/2011 jichi
DEFINES += WITH_LIB_VNRHOST
DEPENDPATH += $$PWD
HEADERS += \
$$PWD/avl_p.h \
$$PWD/hookman.h \
$$PWD/settings.h \
$$PWD/host.h \
$$PWD/host_p.h \
$$PWD/textthread.h \
$$PWD/textthread_p.h
SOURCES += \
$$PWD/hookman.cc \
$$PWD/host.cc \
$$PWD/pipe.cc \
$$PWD/textthread.cc
# EOF
#pragma once
// host_p.h
// 8/24/2013 jichi
// Branch IHF/main.h, rev 111
#include <windows.h>
#define GLOBAL extern
#define SHIFT_JIS 0x3A4
class HookManager;
//class CommandQueue;
class SettingManager;
class TextHook;
//class BitMap;
//class CustomFilterMultiByte;
//class CustomFilterUnicode;
//#define TextHook Hook
GLOBAL BOOL running;
//GLOBAL BitMap *pid_map;
//GLOBAL CustomFilterMultiByte *mb_filter;
//GLOBAL CustomFilterUnicode *uni_filter;
GLOBAL HookManager *man;
//GLOBAL CommandQueue *cmdq;
GLOBAL SettingManager *setman;
GLOBAL WCHAR recv_pipe[];
GLOBAL WCHAR command[];
GLOBAL HANDLE hPipeExist;
GLOBAL DWORD split_time,
cyclic_remove,
clipboard_flag,
global_filter;
GLOBAL CRITICAL_SECTION detach_cs;
DWORD WINAPI RecvThread(LPVOID lpThreadParameter);
DWORD WINAPI CmdThread(LPVOID lpThreadParameter);
DWORD GetCurrentPID();
//DWORD GetProcessIDByPath(LPWSTR str);
HANDLE GetCmdHandleByPID(DWORD pid);
//DWORD Inject(HANDLE hProc);
//DWORD InjectByPID(DWORD pid);
//DWORD PIDByName(LPWSTR target);
//DWORD Hash(LPCWSTR module, int length=-1);
// EOF
// pipe.cc
// 8/24/2013 jichi
// Branch IHF/pipe.cpp, rev 93
// 8/24/2013 TODO: Clean up this file
#include "host_p.h"
#include "hookman.h"
#include "vnrhook/include/defs.h"
#include "vnrhook/include/const.h"
#include "ithsys/ithsys.h"
#include <stdio.h>
//#include "CommandQueue.h"
//#include <QtCore/QDebug>
#define DEBUG "vnrhost/pipe.cc"
#include "sakurakit/skdebug.h"
//DWORD WINAPI UpdateWindows(LPVOID lpThreadParameter);
namespace { // unnamed
enum NamedPipeCommand {
NAMED_PIPE_DISCONNECT = 1
, NAMED_PIPE_CONNECT = 2
};
bool newline = false;
bool detach = false;
// jichi 10/27/2013
// Check if text has leading space
enum { _filter_limit = 0x20 }; // The same as the orignal ITH filter. So, I don't have to check \u3000
//enum { _filter_limit = 0x19 };
inline bool has_leading_space(const BYTE *text, int len)
{
return len == 1 ? *text <= _filter_limit : // 1 byte
*reinterpret_cast<const WORD *>(text) <= _filter_limit; // 2 bytes
}
// jichi 9/28/2013: Skip leading garbage
// Note:
// - Modifying limit will break manual translation. The orignal one is 0x20
// - Eliminating 0x20 will break English-translated games
const BYTE *Filter(const BYTE *str, int len)
{
#ifdef ITH_DISABLE_FILTER // jichi 9/28/2013: only for debugging purpose
return str;
#endif // ITH_DISABLE_FILTER
// if (len && *str == 0x10) // jichi 9/28/2013: garbage on wine, data link escape, or ^P
// return nullptr;
//enum { limit = 0x19 };
while (true)
if (len >= 2) {
if (*(const WORD *)str <= _filter_limit) { // jichi 10/27/2013: two bytes
str += 2;
len -= 2;
} else
break;
} else if (*str <= _filter_limit) { // jichi 10/27/2013: 1 byte
str++;
len--;
} else
break;
return str;
}
} // unnamed namespace
//WCHAR recv_pipe[] = L"\\??\\pipe\\ITH_PIPE";
//WCHAR command_pipe[] = L"\\??\\pipe\\ITH_COMMAND";
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
//HANDLE hDetachEvent;
extern HANDLE hPipeExist;
void CreateNewPipe()
{
static DWORD acl[7] = {
0x1C0002,
1,
0x140000,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
0x101,
0x1000000,
0};
static SECURITY_DESCRIPTOR sd = {1, 0, 4, 0, 0, 0, (PACL)acl};
HANDLE hTextPipe, hCmdPipe, hThread;
IO_STATUS_BLOCK ios;
UNICODE_STRING us;
OBJECT_ATTRIBUTES oa = {sizeof(oa), 0, &us, OBJ_CASE_INSENSITIVE, &sd, 0};
LARGE_INTEGER time = {-500000, -1};
RtlInitUnicodeString(&us, recv_pipe);
if (!NT_SUCCESS(NtCreateNamedPipeFile(
&hTextPipe,
GENERIC_READ | SYNCHRONIZE,
&oa,
&ios,
FILE_SHARE_WRITE,
FILE_OPEN_IF,
FILE_SYNCHRONOUS_IO_NONALERT,
1, 1, 0, -1,
0x1000,
0x1000,
&time))) {
//ConsoleOutput(ErrorCreatePipe);
DOUT("failed to create recv pipe");
return;
}
RtlInitUnicodeString(&us, command_pipe);
if (!NT_SUCCESS(NtCreateNamedPipeFile(
&hCmdPipe,
GENERIC_WRITE | SYNCHRONIZE,
&oa,
&ios,
FILE_SHARE_READ,
FILE_OPEN_IF,
FILE_SYNCHRONOUS_IO_NONALERT,
1, 1, 0, -1,
0x1000,
0x1000,
&time))) {
//ConsoleOutput(ErrorCreatePipe);
DOUT("failed to create cmd pipe");
return;
}
hThread = IthCreateThread(RecvThread, (DWORD)hTextPipe);
man->RegisterPipe(hTextPipe, hCmdPipe, hThread);
}
void DetachFromProcess(DWORD pid)
{
HANDLE hMutex = INVALID_HANDLE_VALUE,
hEvent = INVALID_HANDLE_VALUE;
//try {
IO_STATUS_BLOCK ios;
ProcessRecord *pr = man->GetProcessRecord(pid);
if (!pr)
return;
//IthBreak();
hEvent = IthCreateEvent(nullptr);
if (STATUS_PENDING == NtFsControlFile(
man->GetCmdHandleByPID(pid),
hEvent,
0,0,
&ios,
CTL_CODE(FILE_DEVICE_NAMED_PIPE, NAMED_PIPE_DISCONNECT, 0, 0),
0,0,0,0))
NtWaitForSingleObject(hEvent, 0, 0);
NtClose(hEvent);
//hEvent = INVALID_HANDLE_VALUE;
WCHAR mutex[0x20];
swprintf(mutex, ITH_DETACH_MUTEX_ L"%d", pid);
hMutex = IthOpenMutex(mutex);
if (hMutex != INVALID_HANDLE_VALUE) {
NtWaitForSingleObject(hMutex, 0, 0);
NtReleaseMutant(hMutex, 0);
NtClose(hMutex);
//hMutex = INVALID_HANDLE_VALUE;
}
//} catch (...) {
// if (hEvent != INVALID_HANDLE_VALUE)
// NtClose(hEvent);
// else if (hMutex != INVALID_HANDLE_VALUE) {
// NtWaitForSingleObject(hMutex, 0, 0);
// NtReleaseMutant(hMutex, 0);
// NtClose(hMutex);
// }
//}
//NtSetEvent(hDetachEvent, 0);
if (::running)
NtSetEvent(hPipeExist, 0);
}
// jichi 9/27/2013: I don't need this
//void OutputDWORD(DWORD d)
//{
// WCHAR str[0x20];
// swprintf(str, L"%.8X", d);
// ConsoleOutput(str);
//}
DWORD WINAPI RecvThread(LPVOID lpThreadParameter)
{
HANDLE hTextPipe = (HANDLE)lpThreadParameter;
IO_STATUS_BLOCK ios;
NtFsControlFile(hTextPipe,
0, 0, 0,
&ios,
CTL_CODE(FILE_DEVICE_NAMED_PIPE, NAMED_PIPE_CONNECT, 0, 0),
0, 0, 0, 0);
if (!::running) {
NtClose(hTextPipe);
return 0;
}
BYTE *buff;
enum { PipeBufferSize = 0x1000 };
buff = new BYTE[PipeBufferSize];
::memset(buff, 0, PipeBufferSize); // jichi 8/27/2013: zero memory, or it will crash wine on start up
// 10/19/2014 jichi: there are totally three words received
// See: hook/rpc/pipe.cc
// struct {
// DWORD pid;
// TextHook *man;
// DWORD module;
// //DWORD engine;
// } u;
enum { module_struct_size = 12 };
NtReadFile(hTextPipe, 0, 0, 0, &ios, buff, module_struct_size, 0, 0);
// jichi 7/2/2015: This must be consistent with the struct declared in vnrhook/pipe.cc
DWORD pid = *(DWORD *)buff,
module = *(DWORD *)(buff + 0x8),
hookman = *(DWORD *)(buff + 0x4);
//engine = *(DWORD *)(buff + 0xc);
man->RegisterProcess(pid, hookman, module);
// jichi 9/27/2013: why recursion?
CreateNewPipe();
//NtClose(IthCreateThread(UpdateWindows,0));
while (::running) {
if (!NT_SUCCESS(NtReadFile(hTextPipe,
0, 0, 0,
&ios,
buff,
0xf80,
0, 0)))
break;
enum { data_offset = 0xc }; // jichi 10/27/2013: Seem to be the data offset in the pipe
DWORD RecvLen = ios.uInformation;
if (RecvLen < data_offset)
break;
DWORD hook = *(DWORD *)buff;
union { DWORD retn; DWORD cmd_type; };
union { DWORD split; DWORD new_engine_type; };
retn = *(DWORD *)(buff + 4);
split = *(DWORD *)(buff + 8);
buff[RecvLen] = 0;
buff[RecvLen + 1] = 0;
if (hook == HOST_NOTIFICATION) {
switch (cmd_type) {
case HOST_NOTIFICATION_NEWHOOK:
{
static long lock;
while (InterlockedExchange(&lock, 1) == 1);
ProcessEventCallback new_hook = man->ProcessNewHook();
if (new_hook)
new_hook(pid);
lock = 0;
} break;
case HOST_NOTIFICATION_TEXT:
//qDebug() << ((LPCSTR)(buff + 8));
break;
}
} else {
// jichi 9/28/2013: Debug raw data
//ITH_DEBUG_DWORD9(RecvLen - 0xc,
// buff[0xc], buff[0xd], buff[0xe], buff[0xf],
// buff[0x10], buff[0x11], buff[0x12], buff[0x13]);
const BYTE *data = buff + data_offset; // th
int len = RecvLen - data_offset;
bool space = ::has_leading_space(data, len);
if (space) {
const BYTE *it = ::Filter(data, len);
len -= it - data;
data = it;
}
if (len >> 31) // jichi 10/27/2013: len is too large, which seldom happens
len = 0;
//man->DispatchText(pid, len ? data : nullptr, hook, retn, split, len, space);
man->DispatchText(pid, data, hook, retn, split, len, space);
}
}
EnterCriticalSection(&detach_cs);
HANDLE hDisconnect = IthCreateEvent(nullptr);
if (STATUS_PENDING == NtFsControlFile(
hTextPipe,
hDisconnect,
0, 0,
&ios,
CTL_CODE(FILE_DEVICE_NAMED_PIPE, NAMED_PIPE_DISCONNECT, 0, 0),
0, 0, 0, 0))
NtWaitForSingleObject(hDisconnect, 0, 0);
NtClose(hDisconnect);
DetachFromProcess(pid);
man->UnRegisterProcess(pid);
//NtClearEvent(hDetachEvent);
LeaveCriticalSection(&detach_cs);
delete[] buff;
if (::running)
DOUT("detached");
//if (::running) {
// swprintf((LPWSTR)buff, FormatDetach, pid);
// ConsoleOutput((LPWSTR)buff);
// NtClose(IthCreateThread(UpdateWindows, 0));
//}
return 0;
}
// EOF
#pragma once
// settings.h
// 8/24/2013 jichi
struct Settings {
//bool debug; // whether output debug messages using pipes
int splittingInterval;// time to split text into sentences
bool clipboardFlag;
Settings() : splittingInterval(200),
clipboardFlag(false)
{}
};
// EOF
This diff is collapsed. Click to expand it.
#pragma once
// textthread.h
// 8/23/2013 jichi
// Branch: ITH/TextThread.h, rev 120
#include "host/textthread_p.h"
#include <intrin.h> // require _InterlockedExchange
struct RepeatCountNode {
short repeat;
short count;
RepeatCountNode *next;
//RepeatCountNode() : repeat(0), count(0), next(nullptr) {}
};
struct ThreadParameter {
DWORD pid; // jichi: 5/11/2014: The process ID
DWORD hook;
DWORD retn; // jichi 5/11/2014: The return address of the hook
DWORD spl; // jichi 5/11/2014: the processed split value of the hook parameter
};
#define CURRENT_SELECT 0x1000
#define REPEAT_NUMBER_DECIDED 0x2000
#define BUFF_NEWLINE 0x4000
#define CYCLIC_REPEAT 0x8000
#define COUNT_PER_FOWARD 0x200
#define REPEAT_DETECT 0x10000
#define REPEAT_SUPPRESS 0x20000
#define REPEAT_NEWLINE 0x40000
class TextThread;
typedef void (* ConsoleCallback)(LPCSTR text);
typedef void (* ConsoleWCallback)(LPCWSTR text);
typedef DWORD (* ThreadOutputFilterCallback)(TextThread *, BYTE *, DWORD, DWORD, PVOID, bool space); // jichi 10/27/2013: Add space
typedef DWORD (* ThreadEventCallback)(TextThread *);
//extern DWORD split_time,repeat_count,global_filter,cyclic_remove;
class TextThread : public MyVector<BYTE, 0x200>
{
public:
TextThread(DWORD pid, DWORD hook, DWORD retn, DWORD spl, WORD num);
~TextThread();
//virtual void CopyLastSentence(LPWSTR str);
//virtual void SetComment(LPWSTR);
//virtual void ExportTextToFile(LPWSTR filename);
virtual bool CheckCycle(TextThread *start);
virtual DWORD GetThreadString(LPSTR str, DWORD max);
virtual DWORD GetEntryString(LPSTR str, DWORD max = 0x200);
void Reset();
void AddText(const BYTE *con,int len, bool new_line, bool space); // jichi 10/27/2013: add const; remove console; add space
void RemoveSingleRepeatAuto(const BYTE *con, int &len); // jichi 10/27/2013: add const
void RemoveSingleRepeatForce(BYTE *con, int &len);
void RemoveCyclicRepeat(BYTE *&con, int &len);
void ResetRepeatStatus();
void AddLineBreak();
//void ResetEditText();
void ComboSelectCurrent();
void UnLinkAll();
void CopyLastToClipboard();
//void AdjustPrevRepeat(DWORD len);
//void PrevRepeatLength(DWORD &len);
//bool AddToCombo();
bool RemoveFromCombo();
void SetNewLineFlag();
void SetNewLineTimer();
BYTE *GetStore(DWORD *len) { if (len) *len = used; return storage; }
DWORD LastSentenceLen() { return used - last_sentence; }
DWORD PID() const { return tp.pid; }
DWORD Addr() const {return tp.hook; }
DWORD &Status() { return status; }
WORD Number() const { return thread_number; }
WORD &Last() { return last; }
WORD &LinkNumber() { return link_number; }
UINT_PTR &Timer() { return timer; }
ThreadParameter *GetThreadParameter() { return &tp; }
TextThread *&Link() { return link; }
//LPCWSTR GetComment() { return comment; }
ThreadOutputFilterCallback RegisterOutputCallBack(ThreadOutputFilterCallback cb, PVOID data)
{
app_data = data;
return (ThreadOutputFilterCallback)_InterlockedExchange((long*)&output,(long)cb);
}
ThreadOutputFilterCallback RegisterFilterCallBack(ThreadOutputFilterCallback cb, PVOID data)
{
app_data = data;
return (ThreadOutputFilterCallback)_InterlockedExchange((long*)&filter,(long)cb);
}
void SetRepeatFlag() { status |= CYCLIC_REPEAT; }
void ClearNewLineFlag() { status &= ~BUFF_NEWLINE; }
void ClearRepeatFlag() { status &= ~CYCLIC_REPEAT; }
protected:
void AddTextDirect(const BYTE *con, int len, bool space); // jichi 10/27/2013: add const; add space; change to protected
private:
ThreadParameter tp;
WORD thread_number,
link_number;
WORD last,
align_space;
WORD repeat_single;
WORD repeat_single_current;
WORD repeat_single_count;
WORD repeat_detect_count;
RepeatCountNode *head;
TextThread *link;
ThreadOutputFilterCallback filter; // jichi 10/27/2013: Remove filter
ThreadOutputFilterCallback output;
PVOID app_data;
LPSTR thread_string;
UINT_PTR timer;
DWORD status,repeat_detect_limit;
DWORD last_sentence,
prev_sentence,
sentence_length,
repeat_index,
last_time;
};
// EOF
#pragma once
// textthread_p.h
// 8/14/2013 jichi
// Branch: ITH/main_template.h, rev 66
#include <windows.h>
template <typename T>
void Release(const T &p) { delete p; }
// Prevent memory release.
// Used when T is basic types and will be automatically released (on stack).
#define MK_BASIC_TYPE(T) \
template<> \
void Release<T>(const T &p) {}
template<class T>
struct BinaryEqual {
bool operator ()(const T &a, const T &b, DWORD) { return a == b; }
};
template<class T, int default_size, class fComp=BinaryEqual<T> >
class MyVector
{
public:
MyVector() : size(default_size), used(0)
{
InitializeCriticalSection(&cs_store);
storage = new T[size];
// jichi 9/21/2013: zero memory
// This would cause trouble if T is not an atomic type
::memset(storage, 0, sizeof(T) * size);
}
virtual ~MyVector()
{
if (storage)
delete[] storage;
DeleteCriticalSection(&cs_store);
storage = 0;
}
void Reset()
{
EnterCriticalSection(&cs_store);
for (int i = 0; i < used; i++) {
Release<T>(storage[i]);
storage[i] = T();
}
used = 0;
LeaveCriticalSection(&cs_store);
}
void Remove(int index)
{
if (index>=used)
return;
Release<T>(storage[index]);
for (int i = index; i < used; i++)
storage[i] = storage[i+1];
used--;
}
void ClearMemory(int offset, int clear_size)
{
if (clear_size < 0)
return;
EnterCriticalSection(&cs_store);
if (offset+clear_size <= size)
::memset(storage+offset, 0, clear_size * sizeof(T)); // jichi 11/30/2013: This is the original code of ITH
LeaveCriticalSection(&cs_store);
//else __asm int 3
}
int AddToStore(T *con,int amount)
{
if (amount <= 0 || con == 0)
return 0;
int status = 0;
EnterCriticalSection(&cs_store);
if (amount + used + 2 >= size) {
while (amount + used + 2 >= size)
size<<=1;
T *temp;
if (size * sizeof(T) < 0x1000000) {
temp = new T[size];
if (size > used)
::memset(temp, 0, (size - used) * sizeof(T)); // jichi 9/25/2013: zero memory
memcpy(temp, storage, used * sizeof(T));
} else {
size = default_size;
temp = new T[size];
::memset(temp, 0, sizeof(T) * size); // jichi 9/25/2013: zero memory
used = 0;
status = 1;
}
delete[] storage;
storage = temp;
}
memcpy(storage+used, con, amount * sizeof(T));
used += amount;
LeaveCriticalSection(&cs_store);
return status;
}
int Find(const T &item, int start = 0, DWORD control = 0)
{
int c = -1;
for (int i=start; i < used; i++)
if (fCmp(storage[i],item,control)) {
c=i;
break;
}
//if (storage[i]==item) {c=i;break;}
return c;
}
int Used() const { return used; }
T *Storage() const { return storage; }
void LockVector() { EnterCriticalSection(&cs_store); }
void UnlockVector() { LeaveCriticalSection(&cs_store); }
protected:
CRITICAL_SECTION cs_store;
int size,
used;
T *storage;
fComp fCmp;
};
// EOF
/*
#ifndef ITH_STACK
#define ITH_STACK
template<class T, int default_size>
class MyStack
{
public:
MyStack(): index(0) {}
void push_back(const T& e)
{
if (index<default_size)
s[index++]=e;
}
void pop_back()
{
index--;
}
T& back()
{
return s[index-1];
}
T& operator[](int i) {return s[i];}
int size() {return index;}
private:
int index;
T s[default_size];
};
#endif
*/
# 6/6/2012
# IHF.dll
# Skip swprintf and MessageBox statements in GetDebugPriv
#
# SVN checkout: 2012/6/6
# - IHF/main.cpp: 2012/4/8
# - IHF.{dll,lib}: 2012/6/5
6F753055 CALL DWORD PTR DS:ntdll.ZwAdjustPrivilegesTOken
6F75305B TEST EAX,EAX
6F75305B JNE SHORT 6F753077 => JNE SHORT 6F75309F
...
6F753077 PUSH EAX
...
6F75309F MOVE EAX,DWORD PTR SS:[ESP]
6F7530A2 PUSH EAX
6F7530A3 CALL DWORD PTR DS:ntdll.NtClose
...
# EOF
This diff is collapsed. Click to expand it.
#pragma once
// ihf_p.h
// 10/15/2011 jichi
// Internal header.
// Wrapper of IHF functions.
#include <QtCore/QHash>
#include <QtCore/QList>
#include <QtCore/QString>
#include <QtGui/qwindowdefs.h> // for WId
//struct Settings; // opaque in ith/host/settings.h
class HookManager; // opaque in ith/host/hookman.h
class TextThread; // opaque in ith/host/textthread.h
class TextThreadDelegate;
enum { ITH_THREAD_NAME_CAPACITY = 0x200 }; // used internally by ITH
class Ihf
{
Ihf() {} // Singleton
static bool enabled_;
//static Settings *settings_;
static HookManager *hookManager_;
static qint64 messageInterval_;
static WId parentWindow_;
static QHash<TextThread *, TextThreadDelegate *> threadDelegates_;
//static QHash<TextThreadDelegate *, TextThreadDelegate *> linkedDelegates_;
static QHash<QString, ulong> hookAddresses_;
enum { WhitelistSize = 0x20 + 1 }; // ITH capacity is 0x20
static qint32 whitelist_[WhitelistSize]; // List of signatures. The last element is zero. I.e., at most BlackSize-1 threads.
static bool whitelistEnabled_;
static char keptThreadName_[ITH_THREAD_NAME_CAPACITY];
//static QString userDefinedThreadName_;
public:
// - Initialization -
static void init();
static void destroy();
static bool load();
static bool isLoaded() { return hookManager_; }
static void unload();
// - Properties -
static bool isEnabled() { return enabled_; }
static void setEnabled(bool t) { enabled_ = t; }
/// A valid window handle is required to make ITH work
static WId parentWindow() { return parentWindow_; }
static void setParentWindow(WId hwnd) { parentWindow_ = hwnd; }
/// Timeout (msecs) for a text message
static qint64 messageInterval() { return messageInterval_; }
static void setMessageInterval(qint64 msecs) { messageInterval_ = msecs; }
// - Injection -
static bool attachProcess(ulong pid);
static bool detachProcess(ulong pid);
static bool hijackProcess(ulong pid);
/// Add hook code
static bool addHook(ulong pid, const QString &code, const QString &name = QString(), bool verbose = true);
static bool updateHook(ulong pid, const QString &code); // not used
static bool removeHook(ulong pid, const QString &code);
static bool verifyHookCode(const QString &code);
// - Whitelist -
static bool isWhitelistEnabled() { return whitelistEnabled_; }
static void setWhitelistEnabled(bool t) { whitelistEnabled_ = t; }
static QList<qint32> whitelist();
static void setWhitelist(const QList<qint32> &l);
static void clearWhitelist();
//static QString userDefinedThreadName() { return userDefinedThreadName_; }
//static void setUserDefinedThreadName(const QString &val) { userDefinedThreadName_ = val; }
static const char *keptThreadName() { return keptThreadName_; }
static void setKeptThreadName(const QString &v)
{
if (v.size() < ITH_THREAD_NAME_CAPACITY)
::strcpy(keptThreadName_, v.toAscii());
else
setKeptThreadName(v.left(ITH_THREAD_NAME_CAPACITY - 1));
}
private:
static bool whitelistContains(qint32 signature);
// - Callbacks -
//static ulong processAttach(ulong pid);
//static ulong processDetach(ulong pid);
//static ulong processNewHook(ulong pid);
static ulong threadCreate(_In_ TextThread *t);
static ulong threadRemove(_In_ TextThread *t);
static ulong threadOutput(_In_ TextThread *t, _In_ uchar *data, _In_ ulong dataLength, _In_ ulong bNewLine, _In_ void *pUserData, _In_ bool space);
//static ulong threadFilter(_In_ TextThread *t, _Out_ uchar *data, _In_ ulong dataLength, _In_ ulong bNewLine, _In_ void *pUserData);
//static ulong threadReset(TextThread *t);
//static void consoleOutput(const char *text);
//static void consoleOutputW(const wchar_t *text);
// - Linked threasds -
private:
//static TextThreadDelegate *findLinkedDelegate(TextThreadDelegate *d);
static void updateLinkedDelegate(TextThreadDelegate *d);
};
// EOF
// ith_p.cc
// 10/15/2011 jichi
#include "texthook/ith_p.h"
#include "vnrhook/include/const.h"
#include "vnrhook/include/types.h"
#include <string>
#define DEBUG "ith_p.cc"
#include "sakurakit/skdebug.h"
// HookParam copied from ITH/common.h:
// struct HookParam // size = 40 (0x24)
// {
// typedef void (*DataFun)(DWORD, HookParam*, DWORD*, DWORD*, DWORD*);
//
// DWORD addr; // 4
// DWORD off, // 8
// ind, // 12
// split, // 16
// split_ind; // 20
// DWORD module, // 24
// function; // 28
// DataFun text_fun; // 32, jichi: is this the same in x86 and x86_64?
// DWORD type; // 36
// WORD length_offset; // 38
// BYTE hook_len, // 39
// recover_len; // 40
// };
// - Implementation Details -
namespace { namespace detail { // unnamed
// ITH ORIGINAL CODE BEGIN
// See: ITH/ITH.h
// Revision: 133
inline DWORD Hash(_In_ LPWSTR module, int length = -1)
{
bool flag = length == -1;
DWORD hash = 0;
for (; *module && (flag || length--); module++)
hash = _rotr(hash,7) + *module; //hash=((hash>>7)|(hash<<25))+(*module);
return hash;
}
// See: ITH/command.cpp
// Revision: 133
//
// jichi note: str[0xF] will be modified and restored.
// So, the buffer of str must be larger than 0xF.
int Convert(_In_ LPWSTR str, _Out_ DWORD *num, _In_ LPWSTR delim)
{
if (!num)
return -1;
WCHAR t = *str,
tc = *(str + 0xF);
WCHAR temp[0x10] = {};
LPWSTR it = temp,
istr = str,
id = temp;
if (delim) {
id = wcschr(delim, t);
str[0xF] = delim[0]; // reset str[0xF] in case of out-of-bound iteration
}
else
str[0xF] = 0; // reset str[0xF] in case of out-of-bound iteration
while (!id && t) {
*it = t;
it++; istr++;
t = *istr;
if (delim)
id = wcschr(delim, t);
}
swscanf(temp, L"%x", num);
str[0xF] = tc; // restore the str[0xF]
if (!id || istr - str == 0xF)
return -1;
if (!t)
return istr - str; // >= 0
else
return id - delim; // >= 0
}
// See: ITH/command.cpp
// Revision: 133
//
// jichi note: str[0xF] will be modified and restored.
// So, the buffer of cmd must be larger than 0xF*2 = 0x1F.
bool Parse(_In_ LPWSTR cmd, _Out_ HookParam &hp)
{
::memset(&hp, 0, sizeof(hp));
int t;
bool accept = false;
DWORD *data = &hp.offset; //
LPWSTR offset = cmd + 1;
LPWSTR delim_str = L":*@!";
LPWSTR delim = delim_str;
if (*offset == L'n' || *offset == 'N') {
offset++;
hp.type |= NO_CONTEXT;
}
// jichi 4/25/2015: Add support for fixing hook
if (*offset == L'f' || *offset == 'F') {
offset++;
hp.type |= FIXING_SPLIT;
}
if (*offset == L'j' || *offset == 'J') { // 11/22/2015: J stands for Japanese only
offset++;
hp.type |= NO_ASCII;
}
while (!accept) {
t = Convert(offset, data, delim);
if (t < 0)
return false; //ConsoleOutput(L"Syntax error.");
offset = ::wcschr(offset , delim[t]);
if (offset)
offset++; // skip the current delim
else //goto _error;
return false; //ConsoleOutput(L"Syntax error.");
switch (delim[t]) {
case L':':
data = &hp.split;
delim = delim_str + 1;
hp.type |= USING_SPLIT;
break;
case L'*':
if (hp.split) {
data = &hp.split_index;
delim = delim_str + 2;
hp.type |= SPLIT_INDIRECT;
}
else {
hp.type |= DATA_INDIRECT;
data = &hp.index;
}
break;
case L'@':
accept = true;
break;
}
}
t = Convert(offset, &hp.address, delim_str);
if (t < 0)
return false;
if (hp.offset & 0x80000000)
hp.offset -= 4;
if (hp.split & 0x80000000)
hp.split -= 4;
LPWSTR temp = offset;
offset = ::wcschr(offset, L':');
if (offset) {
hp.type |= MODULE_OFFSET;
offset++;
delim = ::wcschr(offset, L':');
if (delim) {
*delim = 0;
delim++;
_wcslwr(offset);
hp.function = Hash(delim);
hp.module = Hash(offset, delim - offset - 1);
hp.type |= FUNCTION_OFFSET;
}
else
hp.module = Hash(_wcslwr(offset));
} else {
offset = ::wcschr(temp, L'!');
if (offset) {
hp.type |= MODULE_OFFSET;
swscanf(offset + 1, L"%x", &hp.module);
offset = ::wcschr(offset + 1, L'!');
if (offset) {
hp.type |= FUNCTION_OFFSET;
swscanf(offset + 1, L"%x", &hp.function);
}
}
}
switch (*cmd) {
case L's':
case L'S':
hp.type |= USING_STRING;
break;
case L'e':
case L'E':
hp.type |= STRING_LAST_CHAR;
case L'a':
case L'A':
hp.type |= BIG_ENDIAN;
hp.length_offset = 1;
break;
case L'b':
case L'B':
hp.length_offset = 1;
break;
// jichi 12/7/2014: Disabled
//case L'h':
//case L'H':
// hp.type |= PRINT_DWORD;
case L'q':
case L'Q':
hp.type |= USING_STRING | USING_UNICODE;
break;
case L'l':
case L'L':
hp.type |= STRING_LAST_CHAR;
case L'w':
case L'W':
hp.type |= USING_UNICODE;
hp.length_offset = 1;
break;
default: ;
}
//ConsoleOutput(L"Try to insert additional hook.");
return true;
}
// ITH ORIGINAL CODE END
}} // unnamed detail
// - ITH API -
// Sample code: L"/HS-4:-14@4383C0" (WHITE ALBUM 2)
bool Ith::parseHookCode(const QString &code, HookParam *hp, bool verbose)
{
#define HCODE_PREFIX "/H"
enum { HCODE_PREFIX_LEN = sizeof(HCODE_PREFIX) -1 }; // 2
if (!hp || !code.startsWith(HCODE_PREFIX))
return false;
if (verbose)
DOUT("enter: code =" << code);
else
DOUT("enter");
size_t bufsize = qMax(0xFF, code.size() + 1); // in case detail::Convert modify the buffer
auto buf = new wchar_t[bufsize];
code.toWCharArray(buf);
buf[code.size()] = 0;
bool ret = detail::Parse(buf + HCODE_PREFIX_LEN, *hp);
delete[] buf;
#ifdef DEBUG
if (ret && verbose)
qDebug()
<< "addr:" << hp->address
<< ", text_fun:" << hp->text_fun
<< ", function:"<< hp->function
<< ", hook_len:" << hp->hook_len
<< ", ind:" << hp->index
<< ", length_offset:" << hp->length_offset
<< ", module:" << hp->module
<< ", off:" <<hp->offset
<< ", recover_len:" << hp->recover_len
<< ", split:" << hp->split
<< ", split_ind:" << hp->split_index
<< ", type:" << hp->type;
#endif // DEBUG
DOUT("leave: ret =" << ret);
return ret;
#undef HOOK_CODE_PREFIX
}
bool Ith::verifyHookCode(const QString &code)
{
HookParam hp = {};
return parseHookCode(code, &hp);
}
// EOF
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.