update basic GUI
This commit is contained in:
parent
a01fe75881
commit
fc2d14fdcf
@ -19,14 +19,14 @@ STYLE DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYS
|
|||||||
CAPTION "Process Explorer"
|
CAPTION "Process Explorer"
|
||||||
FONT 8, "MS Shell Dlg", 400, 0, 1
|
FONT 8, "MS Shell Dlg", 400, 0, 1
|
||||||
{
|
{
|
||||||
DEFPUSHBUTTON "확인", IDOK, 281, 189, 53, 14, 0, WS_EX_LEFT
|
DEFPUSHBUTTON "OK", IDOK, 281, 189, 53, 14, 0, WS_EX_LEFT
|
||||||
PUSHBUTTON "프로필 제거", IDC_BUTTON6, 226, 189, 53, 14, 0, WS_EX_LEFT
|
PUSHBUTTON "Remove Profile", 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
|
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
|
LTEXT "Process", 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 "Attach", IDC_BUTTON2, 61, 189, 53, 14, 0, WS_EX_LEFT
|
||||||
PUSHBUTTON "탈착", IDC_BUTTON3, 116, 189, 53, 14, 0, WS_EX_LEFT
|
PUSHBUTTON "Detach", IDC_BUTTON3, 116, 189, 53, 14, 0, WS_EX_LEFT
|
||||||
PUSHBUTTON "프로필 추가", IDC_BUTTON5, 171, 189, 53, 14, 0, WS_EX_LEFT
|
PUSHBUTTON "Add Profile", IDC_BUTTON5, 171, 189, 53, 14, 0, WS_EX_LEFT
|
||||||
PUSHBUTTON "새로고침", IDC_BUTTON1, 7, 189, 53, 14, 0, WS_EX_LEFT
|
PUSHBUTTON "Refresh", IDC_BUTTON1, 7, 189, 53, 14, 0, WS_EX_LEFT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -37,22 +37,22 @@ STYLE DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYS
|
|||||||
CAPTION "Option"
|
CAPTION "Option"
|
||||||
FONT 8, "MS Shell Dlg", 400, 0, 1
|
FONT 8, "MS Shell Dlg", 400, 0, 1
|
||||||
{
|
{
|
||||||
DEFPUSHBUTTON "확인", IDOK, 8, 164, 50, 14, 0, WS_EX_LEFT
|
DEFPUSHBUTTON "OK", IDOK, 8, 164, 50, 14, 0, WS_EX_LEFT
|
||||||
PUSHBUTTON "취소", IDCANCEL, 65, 164, 50, 14, 0, WS_EX_LEFT
|
PUSHBUTTON "Cancel", IDCANCEL, 65, 164, 50, 14, 0, WS_EX_LEFT
|
||||||
EDITTEXT IDC_EDIT1, 60, 7, 55, 14, ES_AUTOHSCROLL, 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
|
LTEXT "Split time", 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
|
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
|
LTEXT "Process delay", 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
|
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
|
LTEXT "Inject delay", 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
|
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
|
LTEXT "Insert delay", 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 "Auto attach", IDC_CHECK1, 7, 87, 54, 10, 0, WS_EX_LEFT
|
||||||
AUTOCHECKBOX "자동 삽입", IDC_CHECK2, 62, 87, 50, 10, 0, WS_EX_LEFT
|
AUTOCHECKBOX "Auto insert", IDC_CHECK2, 62, 87, 50, 10, 0, WS_EX_LEFT
|
||||||
AUTOCHECKBOX "클립보드로 자동 복사", IDC_CHECK3, 7, 103, 88, 10, 0, WS_EX_LEFT
|
AUTOCHECKBOX "Auto copy to clipboard", IDC_CHECK3, 7, 103, 88, 10, 0, WS_EX_LEFT
|
||||||
AUTOCHECKBOX "자동 반복문 제거", IDC_CHECK4, 7, 119, 95, 10, 0, WS_EX_LEFT
|
AUTOCHECKBOX "Auto suppress repetition", IDC_CHECK4, 7, 119, 95, 10, 0, WS_EX_LEFT
|
||||||
AUTOCHECKBOX "문자필터 초기화", IDC_CHECK6, 7, 149, 81, 8, 0, WS_EX_LEFT
|
AUTOCHECKBOX "Reset character filter", IDC_CHECK6, 7, 149, 81, 8, 0, WS_EX_LEFT
|
||||||
AUTOCHECKBOX "글로벌 필터 활성화", IDC_CHECK5, 7, 134, 75, 10, 0, WS_EX_LEFT
|
AUTOCHECKBOX "Enable global filter", IDC_CHECK5, 7, 134, 75, 10, 0, WS_EX_LEFT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -50,24 +50,24 @@ DWORD ProcessCommand(const std::wstring& cmd, DWORD pid)
|
|||||||
if (Parse(m[1].str(), hp))
|
if (Parse(m[1].str(), hp))
|
||||||
Host_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 from = std::stoul(m[1].str(), NULL, 16);
|
||||||
DWORD to = std::stoul(m[2].str(), NULL, 16);
|
DWORD to = std::stoul(m[2].str(), NULL, 16);
|
||||||
Host_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);
|
DWORD from = std::stoul(m[1].str(), NULL, 16);
|
||||||
Host_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);
|
ConsoleOutput(Usage);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ConsoleOutput(L"알 수 없는 명령어. 도움말을 보시려면, :h 나 :help를 입력하세요.");
|
ConsoleOutput(L"Unknown command. Type :h or :help for help.");
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
141
gui/language.cpp
141
gui/language.cpp
@ -14,44 +14,44 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
const wchar_t* Warning = L"경고!";
|
const wchar_t* Warning=L"Warning!";
|
||||||
//command.cpp
|
//command.cpp
|
||||||
const wchar_t* ErrorSyntax = L"명령어 오류";
|
const wchar_t* ErrorSyntax=L"Syntax error";
|
||||||
const wchar_t* Usage = L"명령어:\r\n\
|
const wchar_t* Usage = L"Syntax:\r\n\
|
||||||
\r\n\
|
\r\n\
|
||||||
도움말 //도움말을 출력합니다\r\n\
|
:H[ELP] - print help\r\n\
|
||||||
출발 도착 // '출발'스레드에서 '도착'스레드로 연결합니다\r\n\
|
:Lfrom-to - link from thread 'from' to thread 'to'\r\n\
|
||||||
ㅎ출발 // '출발'스레드에 연결된 링크를 해제합니다\r\n\
|
:Ufrom - unlink link from thread 'from'\r\n\
|
||||||
\r\n\
|
\r\n\
|
||||||
'출발'과 '도착'에는 16진법(헥사코드) 스레드번호를 입력합니다. 스레드 번호는 맨 앞에 있는 첫 번째 숫자열입니다.\r\n\
|
'from' and 'to' and hexadecimal thread numbers. The thread number is the first number in the combo box.\r\n\
|
||||||
\r\n\
|
\r\n\
|
||||||
로더 옵션:\r\n\
|
Loader options:\r\n\
|
||||||
/P[{process_id|Nprocess_name}] //프로세스에 부착\r\n\
|
/P[{process_id|Nprocess_name}] - attach to process\r\n\
|
||||||
\r\n\
|
\r\n\
|
||||||
H코드 후킹 옵션:\r\n\
|
Hook options:\r\n\
|
||||||
/H[X]{A|B|W|S|Q}[N][data_offset[*drdo]][:sub_offset[*drso]]@addr[:module[:{name|#ordinal}]]\r\n\
|
/H[X]{A|B|W|S|Q}[N][data_offset[*drdo]][:sub_offset[*drso]]@addr[:module[:{name|#ordinal}]]\r\n\
|
||||||
\r\n\
|
\r\n\
|
||||||
(서수를 제외한) /H코드의 모든 숫자는 아무것도 처리되지 않은 16진법(헥사코드)입니다";
|
All numbers in /H (except ordinal) are hexadecimal without any prefixes";
|
||||||
|
|
||||||
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\
|
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\
|
Set additional custom hook\r\n\
|
||||||
\r\n\
|
\r\n\
|
||||||
후킹 종류 :\r\n\
|
Hook types :\r\n\
|
||||||
A - DBCS 문자\r\n\
|
A - DBCS char\r\n\
|
||||||
B - DBCS 문자(big-endian)\r\n\
|
B - DBCS char(big-endian)\r\n\
|
||||||
W - UCS2 문자\r\n\
|
W - UCS2 char\r\n\
|
||||||
S - MBCS 문자열\r\n\
|
S - MBCS string\r\n\
|
||||||
Q - UTF-16 문자열\r\n\
|
Q - UTF-16 string\r\n\
|
||||||
\r\n\
|
\r\n\
|
||||||
매개변수:\r\n\
|
Parameters:\r\n\
|
||||||
X - 하드웨어 구획점 사용\r\n\
|
X - use hardware breakpoints\r\n\
|
||||||
N - 문법을 사용하지 않음\r\n\
|
N - don't use contexts\r\n\
|
||||||
data_offset - stack offset to char / string pointer\r\n\
|
data_offset - stack offset to char / string pointer\r\n\
|
||||||
drdo - add a level of indirection to data_offset\r\n\
|
drdo - add a level of indirection to data_offset\r\n\
|
||||||
sub_offset - stack offset to subcontext\r\n\
|
sub_offset - stack offset to subcontext\r\n\
|
||||||
drso - add a level of indirection to sub_offset\r\n\
|
drso - add a level of indirection to sub_offset\r\n\
|
||||||
addr - 후킹할 주소\r\n\
|
addr - address of the hook\r\n\
|
||||||
module - name of the module to use as base for '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\
|
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\
|
ordinal - number of the 'module' export ordinal to use as base for 'addr'\r\n\
|
||||||
@ -64,70 +64,69 @@ Negative values of 'data_offset' and 'sub_offset' refer to registers: \r\n\
|
|||||||
All numbers except ordinal are hexadecimal without any prefixes";
|
All numbers except ordinal are hexadecimal without any prefixes";
|
||||||
|
|
||||||
//inject.cpp
|
//inject.cpp
|
||||||
const wchar_t* ErrorRemoteThread = L"원격 스레드를 생성할 수 없음.";
|
const wchar_t* ErrorRemoteThread=L"Can't create remote thread.";
|
||||||
const wchar_t* ErrorOpenProcess = L"프로세스를 열 수 없음.";
|
const wchar_t* ErrorOpenProcess=L"Can't open process.";
|
||||||
const wchar_t* ErrorNoProcess = L"프로세스를 찾을 수 없음";
|
const wchar_t* ErrorNoProcess=L"Process not found";
|
||||||
const wchar_t* SelfAttach = L"ITH.exe에 부착하지 말아 주세요";
|
const wchar_t* SelfAttach=L"Please do not attach to ITH.exe";
|
||||||
const wchar_t* AlreadyAttach = L"프로세스가 이미 부착됨.";
|
const wchar_t* AlreadyAttach=L"Process already attached.";
|
||||||
const wchar_t* FormatInject = L"프로세스 %d에 인젝션. 모듈 기반 %.8X";
|
const wchar_t* FormatInject=L"Inject process %d. Module base %.8X";
|
||||||
//main.cpp
|
//main.cpp
|
||||||
const wchar_t* NotAdmin = L"SeDebugPrevilege을 활성화 할 수 없습니다. ITH가 제대로 작동하지 못합니다.\r\n\
|
const wchar_t* NotAdmin=L"Can't enable SeDebugPrevilege. ITH might malfunction.\r\n\
|
||||||
관리자 계정으로 실행하시거나 UAC를 끄시고 ITH를 실행해 주세요.";
|
Please run ITH as administrator or turn off UAC.";
|
||||||
//pipe.cpp
|
//pipe.cpp
|
||||||
const wchar_t* ErrorCreatePipe = L"텍스트 파이프를 생성할 수 없거나, 요청이 너무 많습니다.";
|
const wchar_t* ErrorCreatePipe=L"Can't create text pipe or too many instance.";
|
||||||
const wchar_t* FormatDetach = L"프로세스 %d가 탈착됨.";
|
const wchar_t* FormatDetach=L"Process %d detached.";
|
||||||
const wchar_t* ErrorCmdQueueFull = L"명령어 대기열이 가득참.";
|
const wchar_t* ErrorCmdQueueFull=L"Command queue full.";
|
||||||
const wchar_t* ErrorNoAttach = L"프로세스가 부착되지 않음.";
|
const wchar_t* ErrorNoAttach=L"No process attached.";
|
||||||
|
|
||||||
//profile.cpp
|
//profile.cpp
|
||||||
const wchar_t* ErrorMonitor = L"프로세스를 감시할 수 없음.";
|
const wchar_t* ErrorMonitor=L"Can't monitor process.";
|
||||||
//utility.cpp
|
//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\
|
Copyright (C) 2015 zorkzero <zorkzero@hotmail.com>\r\n\
|
||||||
소스코드 <https://code.google.com/p/interactive-text-hooker/>\r\n\
|
Source code <https://code.google.com/p/interactive-text-hooker/>\r\n\
|
||||||
일반토론 <https://groups.google.com/forum/?fromgroups#!forum/interactive-text-hooker>\r\n\
|
General discussion <https://groups.google.com/forum/?fromgroups#!forum/interactive-text-hooker>";
|
||||||
한글화 @mireado<https://twitter.com/mireado>";
|
const wchar_t* BackgroundMsg=L"Type \":h\" or \":help\" for help.";
|
||||||
const wchar_t* BackgroundMsg = L"도움말을 보시려면, \"help\", \"도움말\"이나 \"도움\"을 입력하세요.";
|
const wchar_t* ErrorLinkExist=L"Link exist.";
|
||||||
const wchar_t* ErrorLinkExist = L"연결이 존재함.";
|
const wchar_t* ErrorCylicLink=L"Link failed. No cyclic link allowed.";
|
||||||
const wchar_t* ErrorCylicLink = L"연결실패. 순환연결은 허용되지 않습니다.";
|
const wchar_t* FormatLink=L"Link from thread%.4x to thread%.4x.";
|
||||||
const wchar_t* FormatLink = L"출발스레드%.4x에서 도착스레드%.4x로 연결.";
|
const wchar_t* ErrorLink=L"Link failed. Source or/and destination thread not found.";
|
||||||
const wchar_t* ErrorLink = L"연결실패. 출발/도착 스레드를 찾을 수 없음.";
|
const wchar_t* ErrorDeleteCombo=L"Error delete from combo.";
|
||||||
const wchar_t* ErrorDeleteCombo = L"글상자에서 지우기 실패.";
|
|
||||||
|
|
||||||
//window.cpp
|
//window.cpp
|
||||||
const wchar_t* ClassName=L"ITH";
|
const wchar_t* ClassName=L"ITH";
|
||||||
const wchar_t* ClassNameAdmin = L"ITH (관리자)";
|
const wchar_t* ClassNameAdmin=L"ITH (Administrator)";
|
||||||
const wchar_t* ErrorNotSplit = L"먼저 문단 나누기를 활성화해주세요!";
|
const wchar_t* ErrorNotSplit=L"Need to enable split first!";
|
||||||
const wchar_t* ErrorNotModule = L"먼저 모듈을 활성화해주세요!";
|
const wchar_t* ErrorNotModule=L"Need to enable module first!";
|
||||||
//Main window buttons
|
//Main window buttons
|
||||||
const wchar_t* ButtonTitleProcess = L"프로세스";
|
const wchar_t* ButtonTitleProcess=L"Process";
|
||||||
const wchar_t* ButtonTitleThread = L"스레드";
|
const wchar_t* ButtonTitleThread=L"Thread";
|
||||||
const wchar_t* ButtonTitleHook = L"후킹";
|
const wchar_t* ButtonTitleHook=L"Hook";
|
||||||
const wchar_t* ButtonTitleProfile = L"프로필";
|
const wchar_t* ButtonTitleProfile=L"Profile";
|
||||||
const wchar_t* ButtonTitleOption = L"옵션";
|
const wchar_t* ButtonTitleOption=L"Option";
|
||||||
const wchar_t* ButtonTitleClear = L"지우기";
|
const wchar_t* ButtonTitleClear=L"Clear";
|
||||||
const wchar_t* ButtonTitleSave = L"저장";
|
const wchar_t* ButtonTitleSave=L"Save";
|
||||||
const wchar_t* ButtonTitleTop = L"항상위";
|
const wchar_t* ButtonTitleTop=L"Top";
|
||||||
//Hook window
|
//Hook window
|
||||||
const wchar_t* SpecialHook = L"H코드 후킹, AGTH 코드는 지원하지 않습니다.";
|
const wchar_t* SpecialHook=L"Special hook, no AGTH equivalent.";
|
||||||
//Process window
|
//Process window
|
||||||
const wchar_t* TabTitlePID=L"PID";
|
const wchar_t* TabTitlePID=L"PID";
|
||||||
const wchar_t* TabTitleMemory = L"메모리";
|
const wchar_t* TabTitleMemory=L"Memory";
|
||||||
const wchar_t* TabTitleName = L"이름";
|
const wchar_t* TabTitleName=L"Name";
|
||||||
const wchar_t* TabTitleTID=L"TID";
|
const wchar_t* TabTitleTID=L"TID";
|
||||||
const wchar_t* TabTitleStart = L"시작";
|
const wchar_t* TabTitleStart=L"Start";
|
||||||
const wchar_t* TabTitleModule = L"모듈";
|
const wchar_t* TabTitleModule=L"Module";
|
||||||
const wchar_t* TabTitleState = L"상태";
|
const wchar_t* TabTitleState=L"State";
|
||||||
const wchar_t* SuccessAttach = L"프로세스에 ITH 부착성공.";
|
const wchar_t* SuccessAttach=L"Attach ITH to process successfully.";
|
||||||
const wchar_t* FailAttach = L"프로세스에 ITH 부착실패.";
|
const wchar_t* FailAttach=L"Failed to attach ITH to process.";
|
||||||
const wchar_t* SuccessDetach = L"프로세스에서 ITH 탈착성공.";
|
const wchar_t* SuccessDetach=L"ITH detach from process.";
|
||||||
const wchar_t* FailDetach = L"ITH 탈착실패.";
|
const wchar_t* FailDetach=L"Detach failed.";
|
||||||
//Profile window
|
//Profile window
|
||||||
const wchar_t* ProfileExist = L"프로필이 이미 존재함.";
|
const wchar_t* ProfileExist=L"Profile already exists.";
|
||||||
const wchar_t* SuccessAddProfile = L"프로필 추가됨.";
|
const wchar_t* SuccessAddProfile=L"Profile added.";
|
||||||
const wchar_t* FailAddProfile = L"프로필 추가실패";
|
const wchar_t* FailAddProfile=L"Fail to add profile";
|
||||||
const wchar_t* TabTitleNumber=L"No.";
|
const wchar_t* TabTitleNumber=L"No.";
|
||||||
const wchar_t* NoFile = L"파일을 찾을 수 없음.";
|
const wchar_t* NoFile=L"Can't find file.";
|
||||||
const wchar_t* PathDismatch = L"프로세스 이름이 일치하지 않습니다, 계속하시겠습니까?";
|
const wchar_t* PathDismatch=L"Process name dismatch, continue?";
|
||||||
const wchar_t* SuccessImportProfile = L"프로필 가져오기 성공";
|
const wchar_t* SuccessImportProfile=L"Import profile success";
|
||||||
//const wchar_t* SuccessAddProfile=L"Profile added.";
|
//const wchar_t* SuccessAddProfile=L"Profile added.";
|
@ -280,19 +280,19 @@ LRESULT CALLBACK EditCmdProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPar
|
|||||||
|
|
||||||
void CreateButtons(HWND hWnd)
|
void CreateButtons(HWND hWnd)
|
||||||
{
|
{
|
||||||
hwndProcess = CreateWindow(L"Button", L"프로세스", WS_CHILD | WS_VISIBLE,
|
hwndProcess = CreateWindow(L"Button", L"Process", WS_CHILD | WS_VISIBLE,
|
||||||
0, 0, 0, 0, hWnd, 0, hIns, NULL);
|
0, 0, 0, 0, hWnd, 0, hIns, NULL);
|
||||||
hwndOption = CreateWindow(L"Button", L"옵션", WS_CHILD | WS_VISIBLE,
|
hwndOption = CreateWindow(L"Button", L"Option", WS_CHILD | WS_VISIBLE,
|
||||||
0, 0, 0, 0, hWnd, 0, hIns, NULL);
|
0, 0, 0, 0, hWnd, 0, hIns, NULL);
|
||||||
hwndClear = CreateWindow(L"Button", L"지우기", WS_CHILD | WS_VISIBLE,
|
hwndClear = CreateWindow(L"Button", L"Clear", WS_CHILD | WS_VISIBLE,
|
||||||
0, 0, 0, 0, hWnd, 0, hIns, NULL);
|
0, 0, 0, 0, hWnd, 0, hIns, NULL);
|
||||||
hwndSave = CreateWindow(L"Button", L"저장", WS_CHILD | WS_VISIBLE,
|
hwndSave = CreateWindow(L"Button", L"Save", WS_CHILD | WS_VISIBLE,
|
||||||
0, 0, 0, 0, hWnd, 0, hIns, NULL);
|
0, 0, 0, 0, hWnd, 0, hIns, NULL);
|
||||||
hwndRemoveLink = CreateWindow(L"Button", L"링크해제", WS_CHILD | WS_VISIBLE,
|
hwndRemoveLink = CreateWindow(L"Button", L"Unlink", WS_CHILD | WS_VISIBLE,
|
||||||
0, 0, 0, 0, hWnd, 0, hIns, NULL);
|
0, 0, 0, 0, hWnd, 0, hIns, NULL);
|
||||||
hwndRemoveHook = CreateWindow(L"Button", L"후킹해제", WS_CHILD | WS_VISIBLE,
|
hwndRemoveHook = CreateWindow(L"Button", L"Unhook", WS_CHILD | WS_VISIBLE,
|
||||||
0, 0, 0, 0, hWnd, 0, hIns, NULL);
|
0, 0, 0, 0, hWnd, 0, hIns, NULL);
|
||||||
hwndTop = CreateWindow(L"Button", L"항상위", WS_CHILD | WS_VISIBLE | BS_PUSHLIKE | BS_CHECKBOX,
|
hwndTop = CreateWindow(L"Button", L"Top", WS_CHILD | WS_VISIBLE | BS_PUSHLIKE | BS_CHECKBOX,
|
||||||
0, 0, 0, 0, hWnd, 0, hIns, NULL);
|
0, 0, 0, 0, hWnd, 0, hIns, NULL);
|
||||||
hwndProcessComboBox = CreateWindow(L"ComboBox", NULL,
|
hwndProcessComboBox = CreateWindow(L"ComboBox", NULL,
|
||||||
WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST |
|
WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST |
|
||||||
|
44
i18n/gui_korean/CustomFilter.cpp
Normal file
44
i18n/gui_korean/CustomFilter.cpp
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/* 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 "CustomFilter.h"
|
||||||
|
|
||||||
|
void CustomFilter::Insert(WORD number)
|
||||||
|
{
|
||||||
|
set.insert(number);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomFilter::Erase(WORD number)
|
||||||
|
{
|
||||||
|
set.erase(number);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CustomFilter::Find(WORD number) const
|
||||||
|
{
|
||||||
|
return set.find(number) != set.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomFilter::Clear()
|
||||||
|
{
|
||||||
|
set.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomFilter::Traverse(CustomFilterCallBack callback, PVOID param)
|
||||||
|
{
|
||||||
|
for (auto ch = set.begin(); ch != set.end(); ++ch)
|
||||||
|
callback(*ch, param);
|
||||||
|
}
|
34
i18n/gui_korean/CustomFilter.h
Normal file
34
i18n/gui_korean/CustomFilter.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/* 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 "ITH.h"
|
||||||
|
|
||||||
|
typedef void (*CustomFilterCallBack) (WORD, PVOID);
|
||||||
|
|
||||||
|
class CustomFilter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool Find(WORD number) const;
|
||||||
|
void Insert(WORD number);
|
||||||
|
void Erase(WORD number);
|
||||||
|
void Clear();
|
||||||
|
void Traverse(CustomFilterCallBack callback, PVOID param);
|
||||||
|
private:
|
||||||
|
std::set<WORD> set;
|
||||||
|
};
|
37
i18n/gui_korean/ITH.h
Normal file
37
i18n/gui_korean/ITH.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/* 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 <Windows.h>
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <ios>
|
||||||
|
#include <memory>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <WindowsX.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <Psapi.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <CommCtrl.h>
|
||||||
|
#include <intrin.h>
|
||||||
|
#include <sstream>
|
||||||
|
#include <regex>
|
||||||
|
#include <set>
|
||||||
|
#include "profile/pugixml.hpp"
|
||||||
|
#pragma warning(disable: 4146)
|
82
i18n/gui_korean/ITHVNR.rc
Normal file
82
i18n/gui_korean/ITHVNR.rc
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
// Generated by ResEdit 1.6.5
|
||||||
|
// Copyright (C) 2006-2015
|
||||||
|
// http://www.resedit.net
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <commctrl.h>
|
||||||
|
#include <richedit.h>
|
||||||
|
#include "resource.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Dialog resources
|
||||||
|
//
|
||||||
|
LANGUAGE LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN
|
||||||
|
IDD_DIALOG2 DIALOGEX 100, 100, 341, 210
|
||||||
|
STYLE DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYSMENU
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
LANGUAGE LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN
|
||||||
|
IDD_DIALOG4 DIALOGEX 150, 100, 123, 185
|
||||||
|
STYLE DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYSMENU
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Icon resources
|
||||||
|
//
|
||||||
|
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
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
145
i18n/gui_korean/ProcessWindow.cpp
Normal file
145
i18n/gui_korean/ProcessWindow.cpp
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
#include "ProcessWindow.h"
|
||||||
|
#include "resource.h"
|
||||||
|
#include "host/host.h"
|
||||||
|
#include "host/hookman.h"
|
||||||
|
#include "ProfileManager.h"
|
||||||
|
#include "profile/Profile.h"
|
||||||
|
|
||||||
|
extern HookManager* man; // main.cpp
|
||||||
|
extern ProfileManager* pfman; // ProfileManager.cpp
|
||||||
|
|
||||||
|
ProcessWindow::ProcessWindow(HWND hDialog) : hDlg(hDialog)
|
||||||
|
{
|
||||||
|
hbRefresh = GetDlgItem(hDlg, IDC_BUTTON1);
|
||||||
|
hbAttach = GetDlgItem(hDlg, IDC_BUTTON2);
|
||||||
|
hbDetach = GetDlgItem(hDlg, IDC_BUTTON3);
|
||||||
|
hbAddProfile = GetDlgItem(hDlg, IDC_BUTTON5);
|
||||||
|
hbRemoveProfile = GetDlgItem(hDlg, IDC_BUTTON6);
|
||||||
|
EnableWindow(hbAddProfile, FALSE);
|
||||||
|
EnableWindow(hbRemoveProfile, FALSE);
|
||||||
|
hlProcess = GetDlgItem(hDlg, IDC_LIST1);
|
||||||
|
heOutput = GetDlgItem(hDlg, IDC_EDIT1);
|
||||||
|
ListView_SetExtendedListViewStyleEx(hlProcess, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
|
||||||
|
InitProcessDlg();
|
||||||
|
RefreshProcess();
|
||||||
|
EnableWindow(hbDetach, FALSE);
|
||||||
|
EnableWindow(hbAttach, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessWindow::InitProcessDlg()
|
||||||
|
{
|
||||||
|
LVCOLUMN lvc = {};
|
||||||
|
lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
|
||||||
|
lvc.fmt = LVCFMT_RIGHT; // left-aligned column
|
||||||
|
lvc.cx = 40;
|
||||||
|
lvc.pszText = L"PID";
|
||||||
|
ListView_InsertColumn(hlProcess, 0, &lvc);
|
||||||
|
lvc.cx = 100;
|
||||||
|
lvc.fmt = LVCFMT_LEFT; // left-aligned column
|
||||||
|
lvc.pszText = L"Name";
|
||||||
|
ListView_InsertColumn(hlProcess, 1, &lvc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessWindow::RefreshProcess()
|
||||||
|
{
|
||||||
|
ListView_DeleteAllItems(hlProcess);
|
||||||
|
LVITEM item = {};
|
||||||
|
item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;
|
||||||
|
DWORD idProcess[1024], cbNeeded;
|
||||||
|
WCHAR path[MAX_PATH];
|
||||||
|
|
||||||
|
if (EnumProcesses(idProcess, sizeof(idProcess), &cbNeeded))
|
||||||
|
{
|
||||||
|
DWORD len = cbNeeded / sizeof(DWORD);
|
||||||
|
for (DWORD i = 0; i < len; ++i)
|
||||||
|
{
|
||||||
|
DWORD pid = idProcess[i];
|
||||||
|
UniqueHandle hProcess(OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid));
|
||||||
|
if (hProcess)
|
||||||
|
{
|
||||||
|
if (GetProcessImageFileName(hProcess.get(), path, MAX_PATH))
|
||||||
|
{
|
||||||
|
WCHAR buffer[256];
|
||||||
|
std::swprintf(buffer, L"%d", pid);
|
||||||
|
PWCHAR name = wcsrchr(path, L'\\') + 1;
|
||||||
|
item.pszText = buffer;
|
||||||
|
item.lParam = pid;
|
||||||
|
ListView_InsertItem(hlProcess, &item);
|
||||||
|
ListView_SetItemText(hlProcess, item.iItem, 1, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessWindow::AttachProcess()
|
||||||
|
{
|
||||||
|
DWORD pid = GetSelectedPID();
|
||||||
|
if (Host_InjectByPID(pid))
|
||||||
|
{
|
||||||
|
Host_HijackProcess(pid);
|
||||||
|
RefreshThreadWithPID(pid, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessWindow::DetachProcess()
|
||||||
|
{
|
||||||
|
DWORD pid = GetSelectedPID();
|
||||||
|
if (Host_ActiveDetachProcess(pid) == 0)
|
||||||
|
RefreshThreadWithPID(pid, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessWindow::CreateProfileForSelectedProcess()
|
||||||
|
{
|
||||||
|
DWORD pid = GetSelectedPID();
|
||||||
|
auto path = GetProcessPath(pid);
|
||||||
|
if (!path.empty())
|
||||||
|
{
|
||||||
|
Profile* pf = pfman->CreateProfile(pid);
|
||||||
|
pfman->SaveProfiles();
|
||||||
|
RefreshThread(ListView_GetSelectionMark(hlProcess));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessWindow::DeleteProfileForSelectedProcess()
|
||||||
|
{
|
||||||
|
DWORD pid = GetSelectedPID();
|
||||||
|
auto path = GetProcessPath(pid);
|
||||||
|
if (!path.empty())
|
||||||
|
{
|
||||||
|
pfman->DeleteProfile(path);
|
||||||
|
RefreshThread(ListView_GetSelectionMark(hlProcess));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessWindow::RefreshThread(int index)
|
||||||
|
{
|
||||||
|
LVITEM item = {};
|
||||||
|
item.mask = LVIF_PARAM;
|
||||||
|
item.iItem = index;
|
||||||
|
ListView_GetItem(hlProcess, &item);
|
||||||
|
DWORD pid = item.lParam;
|
||||||
|
bool isAttached = man->GetProcessRecord(pid) != NULL;
|
||||||
|
RefreshThreadWithPID(pid, isAttached);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessWindow::RefreshThreadWithPID(DWORD pid, bool isAttached)
|
||||||
|
{
|
||||||
|
EnableWindow(hbDetach, isAttached);
|
||||||
|
EnableWindow(hbAttach, !isAttached);
|
||||||
|
auto path = GetProcessPath(pid);
|
||||||
|
bool hasProfile = !path.empty() && pfman->HasProfile(path);
|
||||||
|
EnableWindow(hbAddProfile, isAttached && !hasProfile);
|
||||||
|
EnableWindow(hbRemoveProfile, hasProfile);
|
||||||
|
if (pid == GetCurrentProcessId())
|
||||||
|
EnableWindow(hbAttach, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD ProcessWindow::GetSelectedPID()
|
||||||
|
{
|
||||||
|
LVITEM item = {};
|
||||||
|
item.mask = LVIF_PARAM;
|
||||||
|
item.iItem = ListView_GetSelectionMark(hlProcess);
|
||||||
|
ListView_GetItem(hlProcess, &item);
|
||||||
|
return item.lParam;
|
||||||
|
}
|
23
i18n/gui_korean/ProcessWindow.h
Normal file
23
i18n/gui_korean/ProcessWindow.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ITH.h"
|
||||||
|
|
||||||
|
class ProcessWindow
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ProcessWindow(HWND hDialog);
|
||||||
|
void InitProcessDlg();
|
||||||
|
void RefreshProcess();
|
||||||
|
void AttachProcess();
|
||||||
|
void DetachProcess();
|
||||||
|
void CreateProfileForSelectedProcess();
|
||||||
|
void DeleteProfileForSelectedProcess();
|
||||||
|
void RefreshThread(int index);
|
||||||
|
private:
|
||||||
|
void RefreshThreadWithPID(DWORD pid, bool isAttached);
|
||||||
|
DWORD GetSelectedPID();
|
||||||
|
HWND hDlg;
|
||||||
|
HWND hlProcess;
|
||||||
|
HWND hbRefresh,hbAttach,hbDetach,hbAddProfile,hbRemoveProfile;
|
||||||
|
HWND heOutput;
|
||||||
|
};
|
218
i18n/gui_korean/ProfileManager.cpp
Normal file
218
i18n/gui_korean/ProfileManager.cpp
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
#include "ProfileManager.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
|
||||||
|
extern LONG insert_delay, process_time; // main.cpp
|
||||||
|
bool MonitorFlag;
|
||||||
|
ProfileManager* pfman;
|
||||||
|
|
||||||
|
DWORD WINAPI MonitorThread(LPVOID lpThreadParameter);
|
||||||
|
|
||||||
|
ProfileManager::ProfileManager() :
|
||||||
|
hMonitorThread(IthCreateThread(MonitorThread, 0))
|
||||||
|
{
|
||||||
|
LoadProfiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
ProfileManager::~ProfileManager()
|
||||||
|
{
|
||||||
|
SaveProfiles();
|
||||||
|
WaitForSingleObject(hMonitorThread.get(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Profile* ProfileManager::GetProfile(DWORD pid)
|
||||||
|
{
|
||||||
|
std::wstring path = GetProcessPath(pid);
|
||||||
|
if (!path.empty())
|
||||||
|
{
|
||||||
|
auto node = profile_tree.find(path);
|
||||||
|
if (node != profile_tree.end())
|
||||||
|
return node->second.get();
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProfileManager::CreateProfile(pugi::xml_node game)
|
||||||
|
{
|
||||||
|
auto file = game.child(L"File");
|
||||||
|
auto profile = game.child(L"Profile");
|
||||||
|
if (!file || !profile)
|
||||||
|
return false;
|
||||||
|
auto path = file.attribute(L"Path");
|
||||||
|
if (!path)
|
||||||
|
return false;
|
||||||
|
auto profile_title = game.attribute(L"Title");
|
||||||
|
auto title = profile_title ? profile_title.value() : L"";
|
||||||
|
auto pf = new Profile(title);
|
||||||
|
if (!pf->XmlReadProfile(profile))
|
||||||
|
return false;
|
||||||
|
CSLock lock(cs);
|
||||||
|
auto& oldProfile = profile_tree[path.value()];
|
||||||
|
if (!oldProfile)
|
||||||
|
oldProfile.swap(profile_ptr(pf));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Profile* ProfileManager::CreateProfile(DWORD pid)
|
||||||
|
{
|
||||||
|
CSLock lock(cs);
|
||||||
|
auto path = GetProcessPath(pid);
|
||||||
|
auto& pf = profile_tree[path];
|
||||||
|
if (!pf)
|
||||||
|
{
|
||||||
|
std::wstring title = GetProcessTitle(pid);
|
||||||
|
pf.reset(new Profile(title));
|
||||||
|
}
|
||||||
|
return pf.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProfileManager::WriteProfileXml(const std::wstring& path, Profile& pf, pugi::xml_node root)
|
||||||
|
{
|
||||||
|
auto game = root.append_child(L"Game");
|
||||||
|
auto file_node = game.append_child(L"File");
|
||||||
|
file_node.append_attribute(L"Path") = path.c_str();
|
||||||
|
auto profile_node = game.append_child(L"Profile");
|
||||||
|
pf.XmlWriteProfile(profile_node);
|
||||||
|
if (!pf.Title().empty())
|
||||||
|
{
|
||||||
|
if (!game.attribute(L"Title"))
|
||||||
|
game.append_attribute(L"Title");
|
||||||
|
game.attribute(L"Title") = pf.Title().c_str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProfileManager::LoadProfiles()
|
||||||
|
{
|
||||||
|
pugi::xml_document doc;
|
||||||
|
UniqueHandle hFile(IthCreateFile(L"ITH_Profile.xml", GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING));
|
||||||
|
if (hFile.get() == INVALID_HANDLE_VALUE)
|
||||||
|
return;
|
||||||
|
DWORD size = GetFileSize(hFile.get(), NULL);
|
||||||
|
std::unique_ptr<char[]> buffer(new char[size]);
|
||||||
|
ReadFile(hFile.get(), buffer.get(), size, &size, NULL);
|
||||||
|
auto result = doc.load_buffer(buffer.get(), size);
|
||||||
|
if (!result)
|
||||||
|
return;
|
||||||
|
auto root = doc.root().child(L"ITH_Profile");
|
||||||
|
if (!root)
|
||||||
|
return;
|
||||||
|
for (auto game = root.begin(); game != root.end(); ++game)
|
||||||
|
CreateProfile(*game);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProfileManager::SaveProfiles()
|
||||||
|
{
|
||||||
|
pugi::xml_document doc;
|
||||||
|
auto root = doc.append_child(L"ITH_Profile");
|
||||||
|
for (auto it = profile_tree.begin(); it != profile_tree.end(); ++it) {
|
||||||
|
auto& path = it->first;
|
||||||
|
auto& profile = it->second;
|
||||||
|
WriteProfileXml(path, *profile, root);
|
||||||
|
}
|
||||||
|
UniqueHandle hFile(IthCreateFile(L"ITH_Profile.xml", GENERIC_WRITE, 0, CREATE_ALWAYS));
|
||||||
|
if (hFile.get() != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
FileWriter fw(hFile.get());
|
||||||
|
doc.save(fw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProfileManager::DeleteProfile(const std::wstring& path)
|
||||||
|
{
|
||||||
|
CSLock lock(cs);
|
||||||
|
profile_tree.erase(profile_tree.find(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
Profile* ProfileManager::GetProfile(const std::wstring& path)
|
||||||
|
{
|
||||||
|
if (path.empty())
|
||||||
|
return nullptr;
|
||||||
|
auto it = profile_tree.find(path);
|
||||||
|
if (it == profile_tree.end())
|
||||||
|
return nullptr;
|
||||||
|
return it->second.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProfileManager::HasProfile(const std::wstring& path)
|
||||||
|
{
|
||||||
|
return profile_tree.find(path) != profile_tree.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD ProfileManager::CountProfiles()
|
||||||
|
{
|
||||||
|
return profile_tree.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD WINAPI InjectThread(LPVOID lpThreadParameter)
|
||||||
|
{
|
||||||
|
DWORD pid = (DWORD)lpThreadParameter;
|
||||||
|
Sleep(inject_delay);
|
||||||
|
if (man == NULL)
|
||||||
|
return 0;
|
||||||
|
DWORD status = Host_InjectByPID(pid);
|
||||||
|
if (!auto_insert)
|
||||||
|
return status;
|
||||||
|
if (status == -1)
|
||||||
|
return status;
|
||||||
|
Sleep(insert_delay);
|
||||||
|
const Profile* pf = pfman->GetProfile(pid);
|
||||||
|
if (pf)
|
||||||
|
{
|
||||||
|
SendParam sp;
|
||||||
|
sp.type = 0;
|
||||||
|
for (auto hp = pf->Hooks().begin(); hp != pf->Hooks().end(); ++hp)
|
||||||
|
{
|
||||||
|
std::string name = toMultiByteString((*hp)->Name());
|
||||||
|
Host_InsertHook(pid, const_cast<HookParam*>(&(*hp)->HP()), name.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD WINAPI MonitorThread(LPVOID lpThreadParameter)
|
||||||
|
{
|
||||||
|
while (MonitorFlag)
|
||||||
|
{
|
||||||
|
DWORD aProcesses[1024], cbNeeded, cProcesses;
|
||||||
|
if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
|
||||||
|
break;
|
||||||
|
cProcesses = cbNeeded / sizeof(DWORD);
|
||||||
|
for (size_t i = 0; i < cProcesses; ++i)
|
||||||
|
{
|
||||||
|
Sleep(process_time);
|
||||||
|
if (!auto_inject || man == NULL || man->GetProcessRecord(aProcesses[i]))
|
||||||
|
continue;
|
||||||
|
std::wstring process_path = GetProcessPath(aProcesses[i]);
|
||||||
|
if (!process_path.empty() && pfman->HasProfile(process_path))
|
||||||
|
{
|
||||||
|
UniqueHandle hThread(IthCreateThread(InjectThread, aProcesses[i]));
|
||||||
|
WaitForSingleObject(hThread.get(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD SaveProcessProfile(DWORD pid)
|
||||||
|
{
|
||||||
|
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->CreateProfile(pid);
|
||||||
|
pf->XmlReadProfile(profile_node);
|
||||||
|
return 0;
|
||||||
|
}
|
35
i18n/gui_korean/ProfileManager.h
Normal file
35
i18n/gui_korean/ProfileManager.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ITH.h"
|
||||||
|
#include "utility.h" // UniqueHandle, CriticalSection
|
||||||
|
|
||||||
|
class Profile;
|
||||||
|
|
||||||
|
class ProfileManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ProfileManager();
|
||||||
|
~ProfileManager();
|
||||||
|
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);
|
||||||
|
private:
|
||||||
|
typedef std::unique_ptr<Profile> profile_ptr;
|
||||||
|
typedef std::map<std::wstring, profile_ptr> profile_map;
|
||||||
|
|
||||||
|
ProfileManager(const ProfileManager&);
|
||||||
|
ProfileManager operator=(const ProfileManager&);
|
||||||
|
|
||||||
|
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;
|
||||||
|
CriticalSection cs;
|
||||||
|
UniqueHandle hMonitorThread;
|
||||||
|
};
|
41
i18n/gui_korean/TextBuffer.cpp
Normal file
41
i18n/gui_korean/TextBuffer.cpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#include "TextBuffer.h"
|
||||||
|
|
||||||
|
DWORD WINAPI FlushThread(LPVOID lParam); // window.cpp
|
||||||
|
|
||||||
|
TextBuffer::TextBuffer(HWND edit) : hThread(IthCreateThread(FlushThread, (DWORD)this)),
|
||||||
|
hEdit(edit),
|
||||||
|
running(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TextBuffer::~TextBuffer()
|
||||||
|
{
|
||||||
|
running = false;
|
||||||
|
WaitForSingleObject(hThread.get(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextBuffer::AddText(LPCWSTR str, int len, bool line)
|
||||||
|
{
|
||||||
|
CSLock lock(cs);
|
||||||
|
if (len > 0)
|
||||||
|
this->str.append(str, len);
|
||||||
|
line_break = line;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextBuffer::Flush()
|
||||||
|
{
|
||||||
|
CSLock lock(cs);
|
||||||
|
if (line_break || str.empty())
|
||||||
|
return;
|
||||||
|
DWORD t = Edit_GetTextLength(hEdit);
|
||||||
|
Edit_SetSel(hEdit, t, -1);
|
||||||
|
Edit_ReplaceSel(hEdit, str.c_str());
|
||||||
|
str.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextBuffer::ClearBuffer()
|
||||||
|
{
|
||||||
|
CSLock lock(cs);
|
||||||
|
str.clear();
|
||||||
|
line_break = false;
|
||||||
|
}
|
21
i18n/gui_korean/TextBuffer.h
Normal file
21
i18n/gui_korean/TextBuffer.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ITH.h"
|
||||||
|
#include "utility.h" // UniqueHandle, CriticalSection
|
||||||
|
|
||||||
|
class TextBuffer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TextBuffer(HWND edit);
|
||||||
|
~TextBuffer();
|
||||||
|
void Flush();
|
||||||
|
void AddText(LPCWSTR str, int len, bool line);
|
||||||
|
void ClearBuffer();
|
||||||
|
bool Running() { return running; }
|
||||||
|
private:
|
||||||
|
CriticalSection cs;
|
||||||
|
bool line_break, running;
|
||||||
|
UniqueHandle hThread;
|
||||||
|
HWND hEdit;
|
||||||
|
std::wstring str;
|
||||||
|
};
|
73
i18n/gui_korean/command.cpp
Normal file
73
i18n/gui_korean/command.cpp
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/* 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 "ITH.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;
|
||||||
|
|
||||||
|
DWORD ProcessCommand(const std::wstring& cmd, DWORD pid)
|
||||||
|
{
|
||||||
|
using std::wregex;
|
||||||
|
using std::regex_match;
|
||||||
|
std::match_results<std::wstring::const_iterator> m;
|
||||||
|
|
||||||
|
if (regex_match(cmd, m, wregex(L"/pn(.+)", wregex::icase)))
|
||||||
|
{
|
||||||
|
pid = Host_GetPIDByName(m[1].str().c_str());
|
||||||
|
if (pid == 0)
|
||||||
|
return 0;
|
||||||
|
Host_InjectByPID(pid);
|
||||||
|
}
|
||||||
|
else if (regex_match(cmd, m, wregex(L"/p(\\d+)", wregex::icase)))
|
||||||
|
{
|
||||||
|
pid = std::stoul(m[1].str());
|
||||||
|
Host_InjectByPID(pid);
|
||||||
|
}
|
||||||
|
else if (regex_match(cmd, m, wregex(L"/h(.+)", wregex::icase)))
|
||||||
|
{
|
||||||
|
HookParam hp = {};
|
||||||
|
if (Parse(m[1].str(), hp))
|
||||||
|
Host_InsertHook(pid, &hp);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
Host_AddLink(from, to);
|
||||||
|
}
|
||||||
|
else if (regex_match(cmd, m, wregex(L"(?::|)(?:ㅎ|해|해제|u)([[:xdigit:]]+)", wregex::icase)))
|
||||||
|
{
|
||||||
|
DWORD from = std::stoul(m[1].str(), NULL, 16);
|
||||||
|
Host_UnLink(from);
|
||||||
|
}
|
||||||
|
else if (regex_match(cmd, m, wregex(L"(?::|)(?:ㄷ|도|도움|도움말|h|help)", wregex::icase)))
|
||||||
|
{
|
||||||
|
ConsoleOutput(Usage);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ConsoleOutput(L"알 수 없는 명령어. 도움말을 보시려면, :h 나 :help를 입력하세요.");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
BIN
i18n/gui_korean/icon1.ico
Normal file
BIN
i18n/gui_korean/icon1.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
133
i18n/gui_korean/language.cpp
Normal file
133
i18n/gui_korean/language.cpp
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
/* 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/>.
|
||||||
|
*/
|
||||||
|
const wchar_t* Warning = L"경고!";
|
||||||
|
//command.cpp
|
||||||
|
const wchar_t* ErrorSyntax = L"명령어 오류";
|
||||||
|
const wchar_t* Usage = L"명령어:\r\n\
|
||||||
|
\r\n\
|
||||||
|
도움말 //도움말을 출력합니다\r\n\
|
||||||
|
출발 도착 // '출발'스레드에서 '도착'스레드로 연결합니다\r\n\
|
||||||
|
ㅎ출발 // '출발'스레드에 연결된 링크를 해제합니다\r\n\
|
||||||
|
\r\n\
|
||||||
|
'출발'과 '도착'에는 16진법(헥사코드) 스레드번호를 입력합니다. 스레드 번호는 맨 앞에 있는 첫 번째 숫자열입니다.\r\n\
|
||||||
|
\r\n\
|
||||||
|
로더 옵션:\r\n\
|
||||||
|
/P[{process_id|Nprocess_name}] //프로세스에 부착\r\n\
|
||||||
|
\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진법(헥사코드)입니다";
|
||||||
|
|
||||||
|
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\
|
||||||
|
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\
|
||||||
|
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\
|
||||||
|
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\
|
||||||
|
\r\n\
|
||||||
|
Negative values of 'data_offset' and 'sub_offset' refer to registers: \r\n\
|
||||||
|
- 4 for EAX, -8 for ECX, -C for EDX, -10 for EBX, -14 for ESP, -18 for EBP, -1C for ESI, -20 for EDI\r\n\
|
||||||
|
\r\n\
|
||||||
|
\"Add a level of indirection\" means in C/C++ style: (*(ESP+data_offset)+drdo) instead of (ESP+data_offset)\r\n\
|
||||||
|
\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";
|
||||||
|
//main.cpp
|
||||||
|
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"프로세스가 부착되지 않음.";
|
||||||
|
|
||||||
|
//profile.cpp
|
||||||
|
const wchar_t* ErrorMonitor = L"프로세스를 감시할 수 없음.";
|
||||||
|
//utility.cpp
|
||||||
|
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"글상자에서 지우기 실패.";
|
||||||
|
|
||||||
|
//window.cpp
|
||||||
|
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"항상위";
|
||||||
|
//Hook window
|
||||||
|
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 탈착실패.";
|
||||||
|
//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.";
|
86
i18n/gui_korean/language.h
Normal file
86
i18n/gui_korean/language.h
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/* 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
|
||||||
|
|
||||||
|
extern const wchar_t* Warning;
|
||||||
|
//command.cpp
|
||||||
|
extern const wchar_t* ErrorSyntax;
|
||||||
|
extern const wchar_t* Usage;
|
||||||
|
extern const wchar_t* ExtendedUsage;
|
||||||
|
//inject.cpp
|
||||||
|
extern const wchar_t* ErrorRemoteThread;
|
||||||
|
extern const wchar_t* ErrorOpenProcess;
|
||||||
|
extern const wchar_t* ErrorNoProcess;
|
||||||
|
extern const wchar_t* SelfAttach;
|
||||||
|
extern const wchar_t* AlreadyAttach;
|
||||||
|
extern const wchar_t* FormatInject;
|
||||||
|
//main.cpp
|
||||||
|
extern const wchar_t* NotAdmin;
|
||||||
|
//pipe.cpp
|
||||||
|
extern const wchar_t* ErrorCreatePipe;
|
||||||
|
extern const wchar_t* FormatDetach;
|
||||||
|
extern const wchar_t* ErrorCmdQueueFull;
|
||||||
|
extern const wchar_t* ErrorNoAttach;
|
||||||
|
|
||||||
|
//profile.cpp
|
||||||
|
extern const wchar_t* ErrorMonitor;
|
||||||
|
|
||||||
|
//utility.cpp
|
||||||
|
extern const wchar_t* InitMessage;
|
||||||
|
extern const wchar_t* BackgroundMsg;
|
||||||
|
extern const wchar_t* ErrorLinkExist;
|
||||||
|
extern const wchar_t* ErrorCylicLink;
|
||||||
|
extern const wchar_t* FormatLink;
|
||||||
|
extern const wchar_t* ErrorLink;
|
||||||
|
extern const wchar_t* ErrorDeleteCombo;
|
||||||
|
|
||||||
|
//window.cpp
|
||||||
|
extern const wchar_t* ClassName;
|
||||||
|
extern const wchar_t* ClassNameAdmin;
|
||||||
|
extern const wchar_t* ErrorNotSplit;
|
||||||
|
extern const wchar_t* ErrorNotModule;
|
||||||
|
//Main window buttons
|
||||||
|
extern const wchar_t* ButtonTitleProcess;
|
||||||
|
extern const wchar_t* ButtonTitleThread;
|
||||||
|
extern const wchar_t* ButtonTitleHook;
|
||||||
|
extern const wchar_t* ButtonTitleProfile;
|
||||||
|
extern const wchar_t* ButtonTitleOption;
|
||||||
|
extern const wchar_t* ButtonTitleClear;
|
||||||
|
extern const wchar_t* ButtonTitleSave;
|
||||||
|
extern const wchar_t* ButtonTitleTop;
|
||||||
|
//Hook window
|
||||||
|
extern const wchar_t* SpecialHook;
|
||||||
|
//Process window
|
||||||
|
extern const wchar_t* TabTitlePID;
|
||||||
|
extern const wchar_t* TabTitleMemory;
|
||||||
|
extern const wchar_t* TabTitleName;
|
||||||
|
extern const wchar_t* TabTitleTID;
|
||||||
|
extern const wchar_t* TabTitleStart;
|
||||||
|
extern const wchar_t* TabTitleModule;
|
||||||
|
extern const wchar_t* TabTitleState;
|
||||||
|
extern const wchar_t* SuccessAttach;
|
||||||
|
extern const wchar_t* FailAttach;
|
||||||
|
extern const wchar_t* SuccessDetach;
|
||||||
|
extern const wchar_t* FailDetach;
|
||||||
|
//Profile window
|
||||||
|
extern const wchar_t* ProfileExist;
|
||||||
|
extern const wchar_t* SuccessAddProfile;
|
||||||
|
extern const wchar_t* FailAddProfile;
|
||||||
|
extern const wchar_t* TabTitleNumber;
|
||||||
|
extern const wchar_t* NoFile;
|
||||||
|
extern const wchar_t* PathDismatch;
|
||||||
|
extern const wchar_t* SuccessImportProfile;
|
286
i18n/gui_korean/main.cpp
Normal file
286
i18n/gui_korean/main.cpp
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
/* 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 "ITH.h"
|
||||||
|
#include "host/host.h"
|
||||||
|
#include "host/hookman.h"
|
||||||
|
#include "host/settings.h"
|
||||||
|
#include "CustomFilter.h"
|
||||||
|
#include "profile/Profile.h"
|
||||||
|
#include "ProfileManager.h"
|
||||||
|
|
||||||
|
HINSTANCE hIns;
|
||||||
|
ATOM MyRegisterClass(HINSTANCE hInstance);
|
||||||
|
BOOL InitInstance(HINSTANCE hInstance, DWORD nCmdShow, RECT *rc);
|
||||||
|
RECT window;
|
||||||
|
extern HWND hMainWnd; // windows.cpp
|
||||||
|
extern bool MonitorFlag; // ProfileManager.cpp
|
||||||
|
extern ProfileManager* pfman; // ProfileManager.cpp
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
BOOL IthInitSystemService();
|
||||||
|
void IthCloseSystemService();
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomFilter* uni_filter;
|
||||||
|
CustomFilter* mb_filter;
|
||||||
|
HookManager* man;
|
||||||
|
Settings* setman;
|
||||||
|
LONG split_time, cyclic_remove, global_filter;
|
||||||
|
LONG process_time, inject_delay, insert_delay,
|
||||||
|
auto_inject, auto_insert, clipboard_flag;
|
||||||
|
|
||||||
|
std::map<std::wstring, long> setting;
|
||||||
|
|
||||||
|
void RecordMBChar(WORD mb, PVOID f)
|
||||||
|
{
|
||||||
|
auto filter = (pugi::xml_node*)f;
|
||||||
|
DWORD m = mb;
|
||||||
|
WCHAR buffer[16];
|
||||||
|
std::swprintf(buffer, L"m%04X", m);
|
||||||
|
filter->append_attribute(buffer) = L"0";
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecordUniChar(WORD uni, PVOID f)
|
||||||
|
{
|
||||||
|
auto filter = (pugi::xml_node*)f;
|
||||||
|
DWORD m = uni;
|
||||||
|
WCHAR buffer[16];
|
||||||
|
std::swprintf(buffer, L"u%04X", m);
|
||||||
|
filter->append_attribute(buffer) = L"0";
|
||||||
|
std::wstring text = filter->text().get();
|
||||||
|
text += (wchar_t)m;
|
||||||
|
filter->text().set(text.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveSettings()
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
setting[L"insert_delay"] = insert_delay;
|
||||||
|
setting[L"auto_inject"] = auto_inject;
|
||||||
|
setting[L"auto_insert"] = auto_insert;
|
||||||
|
setting[L"auto_copy"] = clipboard_flag;
|
||||||
|
setting[L"auto_suppress"] = cyclic_remove;
|
||||||
|
setting[L"global_filter"] = global_filter;
|
||||||
|
|
||||||
|
UniqueHandle hFile(IthCreateFile(L"ITH.xml", GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS));
|
||||||
|
if (hFile.get() != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
FileWriter fw(hFile.get());
|
||||||
|
pugi::xml_document doc;
|
||||||
|
auto root = doc.root().append_child(L"ITH_Setting");
|
||||||
|
for (auto it = setting.begin(); it != setting.end(); ++it)
|
||||||
|
root.append_attribute(it->first.c_str()).set_value(it->second);
|
||||||
|
auto filter = root.append_child(L"SingleCharFilter");
|
||||||
|
filter.append_child(pugi::xml_node_type::node_pcdata);
|
||||||
|
mb_filter->Traverse(RecordMBChar, &filter);
|
||||||
|
uni_filter->Traverse(RecordUniChar, &filter);
|
||||||
|
doc.save(fw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefaultSettings()
|
||||||
|
{
|
||||||
|
setting[L"split_time"] = 200;
|
||||||
|
setting[L"process_time"] = 50;
|
||||||
|
setting[L"inject_delay"] = 3000;
|
||||||
|
setting[L"insert_delay"] = 500;
|
||||||
|
setting[L"auto_inject"] = 1;
|
||||||
|
setting[L"auto_insert"] = 1;
|
||||||
|
setting[L"auto_copy"] = 0;
|
||||||
|
setting[L"auto_suppress"] = 0;
|
||||||
|
setting[L"global_filter"] = 0;
|
||||||
|
setting[L"window_left"] = 100;
|
||||||
|
setting[L"window_right"] = 800;
|
||||||
|
setting[L"window_top"] = 100;
|
||||||
|
setting[L"window_bottom"] = 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeSettings()
|
||||||
|
{
|
||||||
|
split_time = setting[L"split_time"];
|
||||||
|
process_time = setting[L"process_time"];
|
||||||
|
inject_delay = setting[L"inject_delay"];
|
||||||
|
insert_delay = setting[L"insert_delay"];
|
||||||
|
auto_inject = setting[L"auto_inject"];
|
||||||
|
auto_insert = setting[L"auto_insert"];
|
||||||
|
clipboard_flag = setting[L"auto_copy"];
|
||||||
|
cyclic_remove = setting[L"auto_suppress"];
|
||||||
|
global_filter = setting[L"global_filter"];
|
||||||
|
window.left = setting[L"window_left"];
|
||||||
|
window.right = setting[L"window_right"];
|
||||||
|
window.top = setting[L"window_top"];
|
||||||
|
window.bottom = setting[L"window_bottom"];
|
||||||
|
|
||||||
|
if (auto_inject > 1)
|
||||||
|
auto_inject = 1;
|
||||||
|
if (auto_insert > 1)
|
||||||
|
auto_insert = 1;
|
||||||
|
if (clipboard_flag > 1)
|
||||||
|
clipboard_flag = 1;
|
||||||
|
if (cyclic_remove > 1)
|
||||||
|
cyclic_remove = 1;
|
||||||
|
|
||||||
|
if (window.right < window.left || window.right - window.left < 600)
|
||||||
|
window.right = window.left + 600;
|
||||||
|
if (window.bottom < window.top || window.bottom - window.top < 200)
|
||||||
|
window.bottom = window.top + 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadSettings()
|
||||||
|
{
|
||||||
|
UniqueHandle hFile(IthCreateFile(L"ITH.xml", GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING));
|
||||||
|
if (hFile.get() != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
DWORD size = GetFileSize(hFile.get(), NULL);
|
||||||
|
std::unique_ptr<char[]> buffer(new char[size]);
|
||||||
|
ReadFile(hFile.get(), buffer.get(), size, &size, NULL);
|
||||||
|
pugi::xml_document doc;
|
||||||
|
auto result = doc.load_buffer_inplace(buffer.get(), size);
|
||||||
|
if (!result)
|
||||||
|
return;
|
||||||
|
auto root = doc.root().child(L"ITH_Setting");
|
||||||
|
for (auto attr = root.attributes_begin(); attr != root.attributes_end(); ++attr)
|
||||||
|
{
|
||||||
|
auto it = setting.find(attr->name());
|
||||||
|
if (it != setting.end())
|
||||||
|
it->second = std::stoul(attr->value());
|
||||||
|
}
|
||||||
|
auto filter = root.child(L"SingleCharFilter");
|
||||||
|
if (filter)
|
||||||
|
{
|
||||||
|
for (auto attr = filter.attributes_begin(); attr != filter.attributes_end(); ++attr)
|
||||||
|
{
|
||||||
|
if (attr->name()[0] == L'm')
|
||||||
|
{
|
||||||
|
DWORD c = std::stoul(attr->name() + 1, NULL, 16);
|
||||||
|
mb_filter->Insert(c & 0xFFFF);
|
||||||
|
}
|
||||||
|
else if (attr->name()[0] == L'u')
|
||||||
|
{
|
||||||
|
DWORD c = std::stoul(attr->name() + 1, NULL, 16);
|
||||||
|
uni_filter->Insert(c & 0xFFFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::wstring filter_value = filter.text().get();
|
||||||
|
for (auto it = filter_value.begin(); it != filter_value.end(); ++it)
|
||||||
|
{
|
||||||
|
WCHAR filter_unichar[2] = { *it, L'\0' };
|
||||||
|
char filter_mbchar[4];
|
||||||
|
WC_MB(filter_unichar, filter_mbchar, 4);
|
||||||
|
mb_filter->Insert(*(WORD*)filter_mbchar);
|
||||||
|
uni_filter->Insert(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern LPCWSTR ClassName, ClassNameAdmin;
|
||||||
|
static WCHAR mutex[] = L"ITH_RUNNING";
|
||||||
|
DWORD FindITH()
|
||||||
|
{
|
||||||
|
HWND hwnd = FindWindow(ClassName, ClassName);
|
||||||
|
if (hwnd == NULL)
|
||||||
|
hwnd = FindWindow(ClassName, ClassNameAdmin);
|
||||||
|
if (hwnd)
|
||||||
|
{
|
||||||
|
ShowWindow(hwnd, SW_SHOWNORMAL);
|
||||||
|
SetForegroundWindow(hwnd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
LONG WINAPI UnhandledExcept(_EXCEPTION_POINTERS *ExceptionInfo)
|
||||||
|
{
|
||||||
|
wchar_t path_name[512]; // fully qualified path name
|
||||||
|
WCHAR code[16];
|
||||||
|
EXCEPTION_RECORD* rec = ExceptionInfo->ExceptionRecord;
|
||||||
|
std::swprintf(code, L"%08X", rec->ExceptionCode);
|
||||||
|
MEMORY_BASIC_INFORMATION info;
|
||||||
|
if (VirtualQuery(rec->ExceptionAddress, &info, sizeof(info)))
|
||||||
|
{
|
||||||
|
if (GetModuleFileName((HMODULE)info.AllocationBase, path_name, 512))
|
||||||
|
{
|
||||||
|
LPWSTR name = wcsrchr(path_name, L'\\');
|
||||||
|
if (name)
|
||||||
|
{
|
||||||
|
DWORD addr = (DWORD)rec->ExceptionAddress;
|
||||||
|
std::swprintf(name, L"%s:%08X", name + 1, addr - (DWORD)info.AllocationBase);
|
||||||
|
MessageBox(NULL, name, code, MB_OK);
|
||||||
|
TerminateProcess(GetCurrentProcess(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::swprintf(path_name, L"%08X", rec->ExceptionAddress);
|
||||||
|
MessageBox(NULL, path_name, code, MB_OK);
|
||||||
|
TerminateProcess(GetCurrentProcess(), 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (Host_Open())
|
||||||
|
{
|
||||||
|
SetUnhandledExceptionFilter(UnhandledExcept);
|
||||||
|
Host_GetHookManager(&man);
|
||||||
|
Host_GetSettings(&setman);
|
||||||
|
setman->splittingInterval = 200;
|
||||||
|
MonitorFlag = true;
|
||||||
|
pfman = new ProfileManager();
|
||||||
|
mb_filter = new CustomFilter();
|
||||||
|
uni_filter = new CustomFilter();
|
||||||
|
DefaultSettings();
|
||||||
|
LoadSettings();
|
||||||
|
InitializeSettings();
|
||||||
|
setman->splittingInterval = split_time;
|
||||||
|
setman->clipboardFlag = clipboard_flag > 0;
|
||||||
|
hIns = hInstance;
|
||||||
|
MyRegisterClass(hIns);
|
||||||
|
InitInstance(hIns, FALSE, &window);
|
||||||
|
MSG msg;
|
||||||
|
while (GetMessage(&msg, NULL, 0, 0))
|
||||||
|
{
|
||||||
|
TranslateMessage(&msg);
|
||||||
|
DispatchMessage(&msg);
|
||||||
|
}
|
||||||
|
//delete mb_filter;
|
||||||
|
//delete uni_filter;
|
||||||
|
delete pfman;
|
||||||
|
MonitorFlag = false;
|
||||||
|
man = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FindITH();
|
||||||
|
}
|
||||||
|
Host_Close();
|
||||||
|
IthCloseSystemService();
|
||||||
|
TerminateProcess(GetCurrentProcess(), 0);
|
||||||
|
}
|
23
i18n/gui_korean/resource.h
Normal file
23
i18n/gui_korean/resource.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#ifndef IDC_STATIC
|
||||||
|
#define IDC_STATIC (-1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define IDD_DIALOG2 102
|
||||||
|
#define IDD_DIALOG4 104
|
||||||
|
#define IDI_ICON1 110
|
||||||
|
#define IDC_CHECK1 1000
|
||||||
|
#define IDC_CHECK2 1001
|
||||||
|
#define IDC_CHECK3 1002
|
||||||
|
#define IDC_CHECK4 1003
|
||||||
|
#define IDC_CHECK5 1004
|
||||||
|
#define IDC_EDIT1 1011
|
||||||
|
#define IDC_EDIT2 1012
|
||||||
|
#define IDC_EDIT3 1013
|
||||||
|
#define IDC_EDIT4 1014
|
||||||
|
#define IDC_BUTTON1 1020
|
||||||
|
#define IDC_BUTTON2 1021
|
||||||
|
#define IDC_BUTTON3 1022
|
||||||
|
#define IDC_BUTTON5 1024
|
||||||
|
#define IDC_LIST1 1028
|
||||||
|
#define IDC_BUTTON6 40000
|
||||||
|
#define IDC_CHECK6 40001
|
303
i18n/gui_korean/utility.cpp
Normal file
303
i18n/gui_korean/utility.cpp
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
/* 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 "utility.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
|
||||||
|
|
||||||
|
std::wstring GetDriveLetter(const std::wstring& devicePath);
|
||||||
|
std::wstring GetWindowsPath(const std::wstring& fileObjectPath);
|
||||||
|
PVOID GetAllocationBase(DWORD pid, LPCVOID);
|
||||||
|
std::wstring GetModuleFileNameAsString(DWORD pid, PVOID allocationBase);
|
||||||
|
std::wstring GetModuleFileNameAsString();
|
||||||
|
std::wstring GetProcessPath(HANDLE hProc);
|
||||||
|
|
||||||
|
void ConsoleOutput(LPCWSTR text)
|
||||||
|
{
|
||||||
|
man->AddConsoleOutput(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsoleOutput(LPCSTR text)
|
||||||
|
{
|
||||||
|
int wc_length = MB_WC_count(text, -1);
|
||||||
|
LPWSTR wc = new WCHAR[wc_length];
|
||||||
|
MB_WC(text, wc, wc_length);
|
||||||
|
man->AddConsoleOutput(wc);
|
||||||
|
delete wc;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring GetProcessPath(DWORD pid)
|
||||||
|
{
|
||||||
|
UniqueHandle hProc(OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid));
|
||||||
|
if (hProc)
|
||||||
|
return GetProcessPath(hProc.get());
|
||||||
|
else
|
||||||
|
return L"";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring GetProcessPath(HANDLE hProc)
|
||||||
|
{
|
||||||
|
wchar_t path[MAX_PATH];
|
||||||
|
GetProcessImageFileName(hProc, path, MAX_PATH);
|
||||||
|
return GetWindowsPath(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
std::wstring devicePath = path.substr(0, pathOffset); // \Device\HarddiskVolume2
|
||||||
|
std::wstring dosDrive = GetDriveLetter(devicePath); // C:
|
||||||
|
if (dosDrive.empty())
|
||||||
|
return path;
|
||||||
|
std::wstring dosPath = dosDrive; // C:
|
||||||
|
dosPath += path.substr(pathOffset); // C:\Windows\System32\taskhost.exe
|
||||||
|
return dosPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring GetDriveLetter(const std::wstring& devicePath)
|
||||||
|
{
|
||||||
|
for (wchar_t drive = L'A'; drive <= L'Z'; drive++)
|
||||||
|
{
|
||||||
|
wchar_t szDriveName[3] = { drive, L':', L'\0' };
|
||||||
|
wchar_t szTarget[512];
|
||||||
|
if (QueryDosDevice(szDriveName, szTarget, 512))
|
||||||
|
if (devicePath.compare(szTarget) == 0)
|
||||||
|
return szDriveName;
|
||||||
|
}
|
||||||
|
return L"";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring GetCode(const HookParam& hp, DWORD pid)
|
||||||
|
{
|
||||||
|
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 (pid)
|
||||||
|
{
|
||||||
|
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.address - (DWORD)allocationBase;
|
||||||
|
code += L"@" + ToHexString(relativeHookAddress) + L":" + fileName;
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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::wstring GetModuleFileNameAsString(DWORD pid, PVOID allocationBase)
|
||||||
|
{
|
||||||
|
const ProcessRecord* pr = man->GetProcessRecord(pid);
|
||||||
|
if (pr)
|
||||||
|
{
|
||||||
|
HANDLE hProc = pr->process_handle;
|
||||||
|
WCHAR path[MAX_PATH];
|
||||||
|
if (GetModuleFileNameEx(hProc, (HMODULE)allocationBase, path, MAX_PATH))
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
return L"";
|
||||||
|
}
|
||||||
|
|
||||||
|
PVOID GetAllocationBase(DWORD pid, LPCVOID addr)
|
||||||
|
{
|
||||||
|
const ProcessRecord *pr = man->GetProcessRecord(pid);
|
||||||
|
if (pr)
|
||||||
|
{
|
||||||
|
MEMORY_BASIC_INFORMATION info;
|
||||||
|
HANDLE hProc = pr->process_handle;
|
||||||
|
if (VirtualQueryEx(hProc, addr, &info, sizeof(info)))
|
||||||
|
{
|
||||||
|
if (info.Type & MEM_IMAGE)
|
||||||
|
return info.AllocationBase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TitleParam
|
||||||
|
{
|
||||||
|
DWORD pid, buffer_len, retn_len;
|
||||||
|
std::wstring buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOL CALLBACK EnumProc(HWND hwnd, LPARAM lParam)
|
||||||
|
{
|
||||||
|
TitleParam* p = (TitleParam*)lParam;
|
||||||
|
DWORD pid;
|
||||||
|
GetWindowThreadProcessId(hwnd, &pid);
|
||||||
|
if (pid == p->pid)
|
||||||
|
{
|
||||||
|
if (GetWindowLong(hwnd, GWL_STYLE) & WS_VISIBLE)
|
||||||
|
{
|
||||||
|
int len = GetWindowTextLength(hwnd);
|
||||||
|
std::unique_ptr<wchar_t[]> result(new wchar_t[len + 1]);
|
||||||
|
GetWindowText(hwnd, result.get(), len + 1);
|
||||||
|
p->buffer = result.get();
|
||||||
|
p->retn_len = p->buffer.size();
|
||||||
|
if (!p->buffer.empty())
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring GetProcessTitle(DWORD pid)
|
||||||
|
{
|
||||||
|
TitleParam p;
|
||||||
|
p.pid = pid;
|
||||||
|
p.buffer_len = 0;
|
||||||
|
p.retn_len = 0;
|
||||||
|
EnumWindows(EnumProc, (LPARAM)&p);
|
||||||
|
return p.buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowsError::WindowsError(DWORD error_code) : error_code(error_code), msg("")
|
||||||
|
{
|
||||||
|
CHAR str[512];
|
||||||
|
std::sprintf(str, "error code 0x%8x", error_code);
|
||||||
|
msg = str;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *WindowsError::what() const
|
||||||
|
{
|
||||||
|
return msg.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE IthCreateThread(LPVOID start_addr, DWORD param)
|
||||||
|
{
|
||||||
|
return CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)start_addr, (LPVOID)param, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring GetModuleFileNameAsString()
|
||||||
|
{
|
||||||
|
WCHAR path[MAX_PATH];
|
||||||
|
GetModuleFileName(NULL, path, MAX_PATH);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IthCreateDirectory(LPCWSTR name)
|
||||||
|
{
|
||||||
|
std::wstring path = GetModuleFileNameAsString();
|
||||||
|
path = path.substr(0, path.rfind(L'\\') + 1) + name;
|
||||||
|
BOOL error_code = CreateDirectory(path.c_str(), NULL);
|
||||||
|
return error_code != 0 || GetLastError() == ERROR_ALREADY_EXISTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE IthCreateFile(LPCWSTR name, DWORD option, DWORD share, DWORD disposition)
|
||||||
|
{
|
||||||
|
std::wstring path = GetModuleFileNameAsString();
|
||||||
|
path = path.substr(0, path.rfind(L'\\') + 1) + name;
|
||||||
|
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.
|
||||||
|
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
|
||||||
|
// -1 if the string is null terminated.
|
||||||
|
int MB_WC_count(const char* mb, int mb_length)
|
||||||
|
{
|
||||||
|
return MultiByteToWideChar(932, 0, mb, mb_length, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unicode->SJIS. Analogous to MB_WC.
|
||||||
|
int WC_MB(const wchar_t *wc, char* mb, int mb_length)
|
||||||
|
{
|
||||||
|
return WideCharToMultiByte(932, 0, wc, -1, mb, mb_length, NULL, NULL);
|
||||||
|
}
|
105
i18n/gui_korean/utility.h
Normal file
105
i18n/gui_korean/utility.h
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ITH.h"
|
||||||
|
|
||||||
|
struct HookParam;
|
||||||
|
struct ProcessRecord;
|
||||||
|
|
||||||
|
DWORD ProcessCommand(const std::wstring& cmd, DWORD pid);
|
||||||
|
std::wstring GetProcessPath(DWORD pid);
|
||||||
|
void ConsoleOutput(LPCWSTR);
|
||||||
|
void ConsoleOutput(LPCSTR text);
|
||||||
|
std::wstring GetProcessTitle(DWORD pid);
|
||||||
|
std::wstring GetCode(const HookParam& hp, DWORD pid = 0);
|
||||||
|
|
||||||
|
// http://codesequoia.wordpress.com/2012/08/26/stdunique_ptr-for-windows-handles/
|
||||||
|
struct HandleDeleter
|
||||||
|
{
|
||||||
|
typedef HANDLE pointer;
|
||||||
|
void operator() (HANDLE h)
|
||||||
|
{
|
||||||
|
if (h != INVALID_HANDLE_VALUE) {
|
||||||
|
CloseHandle(h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::unique_ptr<HANDLE, HandleDeleter> UniqueHandle;
|
||||||
|
|
||||||
|
class FileWriter : public pugi::xml_writer
|
||||||
|
{
|
||||||
|
HANDLE hFile;
|
||||||
|
public:
|
||||||
|
FileWriter(HANDLE hFile) : hFile(hFile) {};
|
||||||
|
~FileWriter() {};
|
||||||
|
|
||||||
|
virtual void write(const void* data, size_t size)
|
||||||
|
{
|
||||||
|
DWORD dwNumberOfBytesWritten;
|
||||||
|
WriteFile(hFile, data, size, &dwNumberOfBytesWritten, NULL);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class WindowsError : public std::exception
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::string msg;
|
||||||
|
DWORD error_code;
|
||||||
|
public:
|
||||||
|
WindowsError(DWORD error_code);
|
||||||
|
virtual const char *what() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
HANDLE IthCreateThread(LPVOID start_addr, DWORD param);
|
||||||
|
bool IthCreateDirectory(LPCWSTR name);
|
||||||
|
HANDLE IthCreateFile(LPCWSTR name, DWORD option, DWORD share, DWORD disposition);
|
||||||
|
int MB_WC(const char* mb, wchar_t* wc, int wc_length);
|
||||||
|
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);
|
||||||
|
|
||||||
|
// http://jrdodds.blogs.com/blog/2004/08/raii_in_c.html
|
||||||
|
class CriticalSection
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CriticalSection()
|
||||||
|
{
|
||||||
|
::InitializeCriticalSection(&m_rep);
|
||||||
|
}
|
||||||
|
~CriticalSection()
|
||||||
|
{
|
||||||
|
::DeleteCriticalSection(&m_rep);
|
||||||
|
}
|
||||||
|
void Enter()
|
||||||
|
{
|
||||||
|
::EnterCriticalSection(&m_rep);
|
||||||
|
}
|
||||||
|
void Leave()
|
||||||
|
{
|
||||||
|
::LeaveCriticalSection(&m_rep);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
CriticalSection(const CriticalSection&);
|
||||||
|
CriticalSection& operator=(const CriticalSection&);
|
||||||
|
|
||||||
|
CRITICAL_SECTION m_rep;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CSLock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CSLock(CriticalSection& a_section)
|
||||||
|
: m_section(a_section)
|
||||||
|
{
|
||||||
|
m_section.Enter();
|
||||||
|
}
|
||||||
|
~CSLock()
|
||||||
|
{
|
||||||
|
m_section.Leave();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
CSLock(const CSLock&);
|
||||||
|
CSLock& operator=(const CSLock&);
|
||||||
|
|
||||||
|
CriticalSection& m_section;
|
||||||
|
};
|
2
i18n/gui_korean/version.h.in
Normal file
2
i18n/gui_korean/version.h.in
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
const wchar_t* build_date=L"27.01.2013";
|
||||||
|
const WCHAR program_version[] = L"@CPACK_PACKAGE_VERSION_MAJOR@.@CPACK_PACKAGE_VERSION_MINOR@.@CPACK_PACKAGE_VERSION_PATCH@";
|
866
i18n/gui_korean/window.cpp
Normal file
866
i18n/gui_korean/window.cpp
Normal file
@ -0,0 +1,866 @@
|
|||||||
|
/* 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 "window.h"
|
||||||
|
#include "ProcessWindow.h"
|
||||||
|
#include "resource.h"
|
||||||
|
#include "language.h"
|
||||||
|
#include "host/host.h"
|
||||||
|
#include "host/hookman.h"
|
||||||
|
#include "vnrhook/include/const.h"
|
||||||
|
#include "version.h"
|
||||||
|
#include "ProfileManager.h"
|
||||||
|
#include "host/settings.h"
|
||||||
|
#include "CustomFilter.h"
|
||||||
|
#include "profile/Profile.h"
|
||||||
|
#include "TextBuffer.h"
|
||||||
|
#include "profile/misc.h"
|
||||||
|
|
||||||
|
#define CMD_SIZE 512
|
||||||
|
|
||||||
|
static WNDPROC proc, proccmd, procChar;
|
||||||
|
static WCHAR last_cmd[CMD_SIZE];
|
||||||
|
extern HINSTANCE hIns; // main.cpp
|
||||||
|
|
||||||
|
HWND hMainWnd, hwndCombo, hwndProcessComboBox, hwndEdit, hwndCmd;
|
||||||
|
HWND hwndProcess;
|
||||||
|
HWND hwndOption, hwndTop, hwndClear, hwndSave, hwndRemoveLink, hwndRemoveHook;
|
||||||
|
HWND hProcDlg, hOptionDlg;
|
||||||
|
HBRUSH hWhiteBrush;
|
||||||
|
DWORD background;
|
||||||
|
ProcessWindow* pswnd;
|
||||||
|
TextBuffer* texts;
|
||||||
|
extern ProfileManager* pfman; // ProfileManager.cpp
|
||||||
|
extern HookManager* man; // main.cpp
|
||||||
|
extern CustomFilter* mb_filter; // main.cpp
|
||||||
|
extern CustomFilter* uni_filter; // main.cpp
|
||||||
|
extern Settings* setman; // main.cpp
|
||||||
|
#define COMMENT_BUFFER_LENGTH 512
|
||||||
|
static WCHAR comment_buffer[COMMENT_BUFFER_LENGTH];
|
||||||
|
|
||||||
|
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
|
||||||
|
void SaveSettings(); // main.cpp
|
||||||
|
extern LONG split_time, process_time, inject_delay, insert_delay,
|
||||||
|
auto_inject, auto_insert, clipboard_flag, cyclic_remove, global_filter; //main.cpp
|
||||||
|
static int last_select, last_edit;
|
||||||
|
|
||||||
|
ATOM MyRegisterClass(HINSTANCE hInstance)
|
||||||
|
{
|
||||||
|
WNDCLASSEX wcex;
|
||||||
|
wcex.cbSize = sizeof(WNDCLASSEX);
|
||||||
|
wcex.style = CS_HREDRAW | CS_VREDRAW;
|
||||||
|
wcex.lpfnWndProc = WndProc;
|
||||||
|
wcex.cbClsExtra = 0;
|
||||||
|
wcex.cbWndExtra = 0;
|
||||||
|
wcex.hInstance = hInstance;
|
||||||
|
wcex.hIcon = NULL;
|
||||||
|
wcex.hCursor = NULL;
|
||||||
|
wcex.hbrBackground = GetStockBrush(WHITE_BRUSH);
|
||||||
|
wcex.lpszMenuName = NULL;
|
||||||
|
wcex.lpszClassName = ClassName;
|
||||||
|
wcex.hIconSm = LoadIcon(hInstance, (LPWSTR)IDI_ICON1);
|
||||||
|
return RegisterClassEx(&wcex);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL InitInstance(HINSTANCE hInstance, DWORD nAdmin, RECT* rc)
|
||||||
|
{
|
||||||
|
hIns = hInstance;
|
||||||
|
LPCWSTR name = (nAdmin) ? ClassNameAdmin : ClassName;
|
||||||
|
hMainWnd = CreateWindow(ClassName, name, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
|
||||||
|
rc->left, rc->top, rc->right - rc->left, rc->bottom - rc->top, NULL, NULL, hInstance, 0);
|
||||||
|
if (!hMainWnd)
|
||||||
|
return FALSE;
|
||||||
|
ShowWindow(hMainWnd, SW_SHOWNORMAL);
|
||||||
|
UpdateWindow(hMainWnd);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD SaveProcessProfile(DWORD pid); // ProfileManager.cpp
|
||||||
|
|
||||||
|
BOOL CALLBACK OptionDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
switch (uMsg)
|
||||||
|
{
|
||||||
|
case WM_INITDIALOG:
|
||||||
|
{
|
||||||
|
SetWindowText(GetDlgItem(hDlg, IDC_EDIT1), std::to_wstring((long long)split_time).c_str());
|
||||||
|
SetWindowText(GetDlgItem(hDlg, IDC_EDIT2), std::to_wstring((long long)process_time).c_str());
|
||||||
|
SetWindowText(GetDlgItem(hDlg, IDC_EDIT3), std::to_wstring((long long)inject_delay).c_str());
|
||||||
|
SetWindowText(GetDlgItem(hDlg, IDC_EDIT4), std::to_wstring((long long)insert_delay).c_str());
|
||||||
|
CheckDlgButton(hDlg, IDC_CHECK1, auto_inject);
|
||||||
|
CheckDlgButton(hDlg, IDC_CHECK2, auto_insert);
|
||||||
|
CheckDlgButton(hDlg, IDC_CHECK3, clipboard_flag);
|
||||||
|
CheckDlgButton(hDlg, IDC_CHECK4, cyclic_remove);
|
||||||
|
CheckDlgButton(hDlg, IDC_CHECK5, global_filter);
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
case WM_COMMAND:
|
||||||
|
{
|
||||||
|
DWORD wmId = LOWORD(wParam);
|
||||||
|
DWORD wmEvent = HIWORD(wParam);
|
||||||
|
switch (wmId)
|
||||||
|
{
|
||||||
|
case IDOK:
|
||||||
|
{
|
||||||
|
WCHAR str[128];
|
||||||
|
GetWindowText(GetDlgItem(hDlg, IDC_EDIT1), str, 0x80);
|
||||||
|
DWORD st = std::stoul(str);
|
||||||
|
split_time = st > 100 ? st : 100;
|
||||||
|
GetWindowText(GetDlgItem(hDlg, IDC_EDIT2), str, 0x80);
|
||||||
|
DWORD pt = std::stoul(str);
|
||||||
|
process_time = pt > 50 ? pt : 50;
|
||||||
|
GetWindowText(GetDlgItem(hDlg, IDC_EDIT3), str, 0x80);
|
||||||
|
DWORD jd = std::stoul(str);
|
||||||
|
inject_delay = jd > 1000 ? jd : 1000;
|
||||||
|
GetWindowText(GetDlgItem(hDlg, IDC_EDIT4), str, 0x80);
|
||||||
|
DWORD sd = std::stoul(str);
|
||||||
|
insert_delay = sd > 200 ? sd : 200;
|
||||||
|
if (IsDlgButtonChecked(hDlg, IDC_CHECK6))
|
||||||
|
{
|
||||||
|
man->ResetRepeatStatus();
|
||||||
|
}
|
||||||
|
auto_inject = IsDlgButtonChecked(hDlg, IDC_CHECK1);
|
||||||
|
auto_insert = IsDlgButtonChecked(hDlg, IDC_CHECK2);
|
||||||
|
clipboard_flag = IsDlgButtonChecked(hDlg, IDC_CHECK3);
|
||||||
|
cyclic_remove = IsDlgButtonChecked(hDlg, IDC_CHECK4);
|
||||||
|
global_filter = IsDlgButtonChecked(hDlg, IDC_CHECK5);
|
||||||
|
setman->clipboardFlag = clipboard_flag;
|
||||||
|
setman->splittingInterval = split_time;
|
||||||
|
if (auto_inject == 0) auto_insert = 0;
|
||||||
|
}
|
||||||
|
case IDCANCEL:
|
||||||
|
EndDialog(hDlg, 0);
|
||||||
|
hOptionDlg = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL CALLBACK ProcessDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
switch (uMsg)
|
||||||
|
{
|
||||||
|
case WM_INITDIALOG:
|
||||||
|
{
|
||||||
|
pswnd = new ProcessWindow(hDlg);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
case WM_COMMAND:
|
||||||
|
{
|
||||||
|
DWORD wmId, wmEvent;
|
||||||
|
wmId = LOWORD(wParam);
|
||||||
|
wmEvent = HIWORD(wParam);
|
||||||
|
switch (wmId)
|
||||||
|
{
|
||||||
|
case WM_DESTROY:
|
||||||
|
case IDOK:
|
||||||
|
EndDialog(hDlg, NULL);
|
||||||
|
hProcDlg = NULL;
|
||||||
|
delete pswnd;
|
||||||
|
pswnd = NULL;
|
||||||
|
break;
|
||||||
|
case IDC_BUTTON1:
|
||||||
|
pswnd->RefreshProcess();
|
||||||
|
break;
|
||||||
|
case IDC_BUTTON2:
|
||||||
|
pswnd->AttachProcess();
|
||||||
|
break;
|
||||||
|
case IDC_BUTTON3:
|
||||||
|
pswnd->DetachProcess();
|
||||||
|
break;
|
||||||
|
case IDC_BUTTON5:
|
||||||
|
pswnd->CreateProfileForSelectedProcess();
|
||||||
|
break;
|
||||||
|
case IDC_BUTTON6:
|
||||||
|
pswnd->DeleteProfileForSelectedProcess();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
case WM_NOTIFY:
|
||||||
|
{
|
||||||
|
LPNMHDR dr = (LPNMHDR)lParam;
|
||||||
|
switch (dr->code)
|
||||||
|
{
|
||||||
|
case LVN_ITEMCHANGED:
|
||||||
|
if (dr->idFrom == IDC_LIST1)
|
||||||
|
{
|
||||||
|
NMLISTVIEW *nmlv = (LPNMLISTVIEW)lParam;
|
||||||
|
if (nmlv->uNewState & LVIS_SELECTED)
|
||||||
|
pswnd->RefreshThread(nmlv->iItem);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
default:
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT CALLBACK EditProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
|
||||||
|
switch (message)
|
||||||
|
{
|
||||||
|
case WM_CHAR: //Filter user input.
|
||||||
|
if (GetKeyState(VK_CONTROL) & 0x8000)
|
||||||
|
{
|
||||||
|
if (wParam == 1)
|
||||||
|
{
|
||||||
|
Edit_SetSel(hwndEdit, 0, -1);
|
||||||
|
SendMessage(hwndEdit, WM_COPY, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
case WM_LBUTTONUP:
|
||||||
|
if (hwndEdit)
|
||||||
|
SendMessage(hwndEdit, WM_COPY, 0, 0);
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
return proc(hWnd, message, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT CALLBACK EditCmdProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
switch (message)
|
||||||
|
{
|
||||||
|
case WM_KEYDOWN:
|
||||||
|
if (wParam == VK_UP)
|
||||||
|
{
|
||||||
|
SetWindowText(hWnd, last_cmd);
|
||||||
|
SetFocus(hWnd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WM_CHAR:
|
||||||
|
if (wParam == VK_RETURN)
|
||||||
|
{
|
||||||
|
DWORD s = 0, pid = 0;
|
||||||
|
WCHAR str[32];
|
||||||
|
if (GetWindowTextLength(hWnd) == 0)
|
||||||
|
break;
|
||||||
|
GetWindowText(hWnd, last_cmd, CMD_SIZE);
|
||||||
|
//IthBreak();
|
||||||
|
if (GetWindowText(hwndProcessComboBox, str, 32))
|
||||||
|
pid = std::stoul(str);
|
||||||
|
ProcessCommand(last_cmd, pid);
|
||||||
|
Edit_SetSel(hWnd, 0, -1);
|
||||||
|
Edit_ReplaceSel(hWnd, &s);
|
||||||
|
SetFocus(hWnd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return CallWindowProc(proccmd, hWnd, message, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateButtons(HWND hWnd)
|
||||||
|
{
|
||||||
|
hwndProcess = CreateWindow(L"Button", L"프로세스", WS_CHILD | WS_VISIBLE,
|
||||||
|
0, 0, 0, 0, hWnd, 0, hIns, NULL);
|
||||||
|
hwndOption = CreateWindow(L"Button", L"옵션", WS_CHILD | WS_VISIBLE,
|
||||||
|
0, 0, 0, 0, hWnd, 0, hIns, NULL);
|
||||||
|
hwndClear = CreateWindow(L"Button", L"지우기", WS_CHILD | WS_VISIBLE,
|
||||||
|
0, 0, 0, 0, hWnd, 0, hIns, NULL);
|
||||||
|
hwndSave = CreateWindow(L"Button", L"저장", WS_CHILD | WS_VISIBLE,
|
||||||
|
0, 0, 0, 0, hWnd, 0, hIns, NULL);
|
||||||
|
hwndRemoveLink = CreateWindow(L"Button", L"링크해제", WS_CHILD | WS_VISIBLE,
|
||||||
|
0, 0, 0, 0, hWnd, 0, hIns, NULL);
|
||||||
|
hwndRemoveHook = CreateWindow(L"Button", L"후킹해제", WS_CHILD | WS_VISIBLE,
|
||||||
|
0, 0, 0, 0, hWnd, 0, hIns, NULL);
|
||||||
|
hwndTop = CreateWindow(L"Button", L"항상위", WS_CHILD | WS_VISIBLE | BS_PUSHLIKE | BS_CHECKBOX,
|
||||||
|
0, 0, 0, 0, hWnd, 0, hIns, NULL);
|
||||||
|
hwndProcessComboBox = CreateWindow(L"ComboBox", NULL,
|
||||||
|
WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST |
|
||||||
|
CBS_SORT | WS_VSCROLL | WS_TABSTOP,
|
||||||
|
0, 0, 0, 0, hWnd, 0, hIns, NULL);
|
||||||
|
hwndCmd = CreateWindowEx(WS_EX_CLIENTEDGE, L"Edit", NULL,
|
||||||
|
WS_CHILD | WS_VISIBLE | ES_NOHIDESEL | ES_LEFT | ES_AUTOHSCROLL,
|
||||||
|
0, 0, 0, 0, hWnd, 0, hIns, NULL);
|
||||||
|
hwndEdit = CreateWindowEx(WS_EX_CLIENTEDGE, L"Edit", NULL,
|
||||||
|
WS_CHILD | WS_VISIBLE | ES_NOHIDESEL | WS_VSCROLL |
|
||||||
|
ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL,
|
||||||
|
0, 0, 0, 0, hWnd, 0, hIns, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClickButton(HWND hWnd, HWND h)
|
||||||
|
{
|
||||||
|
if (h == hwndProcess)
|
||||||
|
{
|
||||||
|
if (hProcDlg)
|
||||||
|
SetForegroundWindow(hProcDlg);
|
||||||
|
else
|
||||||
|
hProcDlg = CreateDialog(hIns, (LPWSTR)IDD_DIALOG2, 0, ProcessDlgProc);
|
||||||
|
}
|
||||||
|
else if (h == hwndOption)
|
||||||
|
{
|
||||||
|
if (hOptionDlg)
|
||||||
|
SetForegroundWindow(hOptionDlg);
|
||||||
|
else
|
||||||
|
hOptionDlg = CreateDialog(hIns, (LPWSTR)IDD_DIALOG4, 0, OptionDlgProc);
|
||||||
|
}
|
||||||
|
else if (h == hwndClear)
|
||||||
|
{
|
||||||
|
WCHAR pwcEntry[128] = {};
|
||||||
|
DWORD dwId = ComboBox_GetCurSel(hwndCombo);
|
||||||
|
int len = ComboBox_GetLBText(hwndCombo, dwId, pwcEntry);
|
||||||
|
dwId = std::stoul(pwcEntry, NULL, 16);
|
||||||
|
if (dwId == 0)
|
||||||
|
man->ClearCurrent();
|
||||||
|
else
|
||||||
|
man->RemoveSingleThread(dwId);
|
||||||
|
}
|
||||||
|
else if (h == hwndTop)
|
||||||
|
{
|
||||||
|
if (Button_GetCheck(h) == BST_CHECKED)
|
||||||
|
{
|
||||||
|
Button_SetCheck(h, BST_UNCHECKED);
|
||||||
|
SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
|
||||||
|
if (hProcDlg)
|
||||||
|
SetWindowPos(hProcDlg, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
|
||||||
|
if (hOptionDlg)
|
||||||
|
SetWindowPos(hOptionDlg, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Button_SetCheck(h, BST_CHECKED);
|
||||||
|
SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
|
||||||
|
if (hProcDlg)
|
||||||
|
SetWindowPos(hProcDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
|
||||||
|
if (hOptionDlg)
|
||||||
|
SetWindowPos(hOptionDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (h == hwndSave)
|
||||||
|
{
|
||||||
|
WCHAR str[32];
|
||||||
|
if (GetWindowText(hwndProcessComboBox, str, 32))
|
||||||
|
{
|
||||||
|
DWORD pid = std::stoul(str);
|
||||||
|
SaveProcessProfile(pid);
|
||||||
|
}
|
||||||
|
pfman->SaveProfiles();
|
||||||
|
}
|
||||||
|
else if (h == hwndRemoveLink)
|
||||||
|
{
|
||||||
|
WCHAR str[32];
|
||||||
|
if (GetWindowText(hwndCombo, str, 32))
|
||||||
|
{
|
||||||
|
DWORD from = std::stoul(str, NULL, 16);
|
||||||
|
if (from != 0)
|
||||||
|
Host_UnLink(from);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (h == hwndRemoveHook)
|
||||||
|
{
|
||||||
|
WCHAR str[32];
|
||||||
|
if (GetWindowText(hwndCombo, str, 32))
|
||||||
|
{
|
||||||
|
std::wstring entry(str);
|
||||||
|
std::size_t i;
|
||||||
|
DWORD threadNumber = std::stoul(entry, &i, 16);
|
||||||
|
entry = entry.substr(i + 1);
|
||||||
|
DWORD pid = std::stoul(entry, &i);
|
||||||
|
entry = entry.substr(i + 1);
|
||||||
|
DWORD addr = std::stoul(entry, NULL, 16);
|
||||||
|
if (threadNumber != 0)
|
||||||
|
Host_RemoveHook(pid, addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD ThreadFilter(TextThread* thread, BYTE* out, DWORD len, DWORD new_line, PVOID data, bool space)
|
||||||
|
{
|
||||||
|
DWORD status = thread->Status();
|
||||||
|
if (global_filter && !new_line && thread->Number() != 0)
|
||||||
|
{
|
||||||
|
if (status & USING_UNICODE)
|
||||||
|
{
|
||||||
|
DWORD i, j;
|
||||||
|
len /= 2;
|
||||||
|
LPWSTR str = (LPWSTR)out;
|
||||||
|
for (i = 0, j = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
WCHAR c = str[i];
|
||||||
|
if (!uni_filter->Find(c))
|
||||||
|
str[j++] = c;
|
||||||
|
}
|
||||||
|
memset(str + j, 0, (len - j) * 2);
|
||||||
|
len = j * 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DWORD i, j;
|
||||||
|
for (i = 0, j = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
WORD c = out[i];
|
||||||
|
if (!IsDBCSLeadByte(c & 0xFF))
|
||||||
|
{
|
||||||
|
if (!mb_filter->Find(c))
|
||||||
|
out[j++] = c & 0xFF;
|
||||||
|
}
|
||||||
|
else if (i + 1 < len)
|
||||||
|
{
|
||||||
|
|
||||||
|
c = out[i + 1];
|
||||||
|
c <<= 8;
|
||||||
|
c |= out[i];
|
||||||
|
if (!mb_filter->Find(c))
|
||||||
|
{
|
||||||
|
out[j++] = c & 0xFF;
|
||||||
|
out[j++] = c >> 8;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memset(out + j, 0, len - j);
|
||||||
|
len = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD ThreadOutput(TextThread* thread, BYTE* out, DWORD len, DWORD new_line, PVOID data, bool space)
|
||||||
|
{
|
||||||
|
if (len == 0)
|
||||||
|
return len;
|
||||||
|
DWORD status = thread->Status();
|
||||||
|
if (status & CURRENT_SELECT)
|
||||||
|
{
|
||||||
|
if (new_line)
|
||||||
|
{
|
||||||
|
if (thread->Number() == 0)
|
||||||
|
texts->AddText(L"\r\n", 2, true);
|
||||||
|
else
|
||||||
|
texts->AddText(L"\r\n\r\n", 4, true);
|
||||||
|
}
|
||||||
|
else if (status & USING_UNICODE)
|
||||||
|
{
|
||||||
|
texts->AddText((LPWSTR)out, len / 2, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int uni_len = MB_WC_count((char*)out, len);
|
||||||
|
LPWSTR str = new WCHAR[uni_len + 1];
|
||||||
|
MB_WC((char*)out, str, uni_len + 1);
|
||||||
|
str[uni_len] = L'\0';
|
||||||
|
texts->AddText(str, uni_len, false);
|
||||||
|
delete str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetHookParam(DWORD pid, DWORD hook_addr, HookParam& hp)
|
||||||
|
{
|
||||||
|
if (!pid)
|
||||||
|
return false;
|
||||||
|
ProcessRecord *pr = ::man->GetProcessRecord(pid);
|
||||||
|
if (!pr)
|
||||||
|
return false;
|
||||||
|
bool result = false;
|
||||||
|
WaitForSingleObject(pr->hookman_mutex, 0);
|
||||||
|
const Hook *hks = (Hook *)pr->hookman_map;
|
||||||
|
for (int i = 0; i < MAX_HOOK; i++)
|
||||||
|
{
|
||||||
|
if (hks[i].Address() == hook_addr)
|
||||||
|
{
|
||||||
|
hp = hks[i].hp;
|
||||||
|
result = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ReleaseMutex(pr->hookman_mutex);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring GetEntryString(TextThread& thread)
|
||||||
|
{
|
||||||
|
CHAR entry[512];
|
||||||
|
thread.GetEntryString(entry, 512);
|
||||||
|
return toUnicodeString(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring CreateEntryWithLink(TextThread& thread, std::wstring& entry)
|
||||||
|
{
|
||||||
|
std::wstring entryWithLink = entry;
|
||||||
|
if (thread.Link())
|
||||||
|
entryWithLink += L"->" + ToHexString(thread.LinkNumber());
|
||||||
|
if (thread.PID() == 0)
|
||||||
|
entryWithLink += L"ConsoleOutput";
|
||||||
|
HookParam hp = {};
|
||||||
|
if (GetHookParam(thread.PID(), thread.Addr(), hp))
|
||||||
|
entryWithLink += L" (" + GetCode(hp, thread.PID()) + L")";
|
||||||
|
return entryWithLink;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddToCombo(TextThread& thread, bool replace)
|
||||||
|
{
|
||||||
|
std::wstring entry = GetEntryString(thread);
|
||||||
|
std::wstring entryWithLink = CreateEntryWithLink(thread, entry);
|
||||||
|
int i = ComboBox_FindString(hwndCombo, -1, entry.c_str());
|
||||||
|
if (replace)
|
||||||
|
{
|
||||||
|
int sel = ComboBox_GetCurSel(hwndCombo);
|
||||||
|
if (i != CB_ERR)
|
||||||
|
ComboBox_DeleteString(hwndCombo, i);
|
||||||
|
ComboBox_AddString(hwndCombo, entryWithLink.c_str());
|
||||||
|
ComboBox_SetCurSel(hwndCombo, sel);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (i == CB_ERR)
|
||||||
|
ComboBox_AddString(hwndCombo, entryWithLink.c_str());
|
||||||
|
// Why set current selection to 0 when the new thread is selected?
|
||||||
|
if (thread.Status() & CURRENT_SELECT)
|
||||||
|
ComboBox_SetCurSel(hwndCombo, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveFromCombo(TextThread* thread)
|
||||||
|
{
|
||||||
|
CHAR entry[512];
|
||||||
|
thread->GetEntryString(entry, 512);
|
||||||
|
std::wstring unicodeEntry = toUnicodeString(entry);
|
||||||
|
if (thread->PID() == 0)
|
||||||
|
unicodeEntry += L"ConsoleOutput";
|
||||||
|
int i = ComboBox_FindString(hwndCombo, 0, unicodeEntry.c_str());
|
||||||
|
if (i != CB_ERR)
|
||||||
|
{
|
||||||
|
if (ComboBox_DeleteString(hwndCombo, i) == CB_ERR)
|
||||||
|
ConsoleOutput(ErrorDeleteCombo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComboSelectCurrent(TextThread* thread)
|
||||||
|
{
|
||||||
|
ComboBox_SetCurSel(hwndCombo, thread->Number());
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD SetEditText(LPWSTR wc)
|
||||||
|
{
|
||||||
|
DWORD line;
|
||||||
|
Edit_SetText(hwndEdit, wc);
|
||||||
|
line = Edit_GetLineCount(hwndEdit);
|
||||||
|
SendMessage(hwndEdit, EM_LINESCROLL, 0, line);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD ThreadReset(TextThread* thread)
|
||||||
|
{
|
||||||
|
texts->ClearBuffer();
|
||||||
|
man->SetCurrent(thread);
|
||||||
|
thread->LockVector();
|
||||||
|
DWORD uni = thread->Status() & USING_UNICODE;
|
||||||
|
if (uni)
|
||||||
|
{
|
||||||
|
DWORD len = 0;
|
||||||
|
LPWSTR wc = (LPWSTR)thread->GetStore(&len);
|
||||||
|
len /= 2;
|
||||||
|
wc[len] = L'\0';
|
||||||
|
SetEditText(wc);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DWORD len = MB_WC_count((char*)thread->Storage(), thread->Used());
|
||||||
|
LPWSTR wc = new WCHAR[len + 1];
|
||||||
|
MB_WC((char*)thread->Storage(), wc, len + 1);
|
||||||
|
wc[len] = L'\0';
|
||||||
|
SetEditText(wc);
|
||||||
|
delete wc;
|
||||||
|
}
|
||||||
|
WCHAR buffer[16];
|
||||||
|
std::swprintf(buffer, L"%04X", thread->Number());
|
||||||
|
DWORD tmp = ComboBox_FindString(hwndCombo, 0, buffer);
|
||||||
|
if (tmp != CB_ERR)
|
||||||
|
ComboBox_SetCurSel(hwndCombo, tmp);
|
||||||
|
thread->UnlockVector();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD AddRemoveLink(TextThread* thread)
|
||||||
|
{
|
||||||
|
AddToCombo(*thread, true);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsUnicodeHook(const ProcessRecord& pr, DWORD hook);
|
||||||
|
void AddLinksToHookManager(const Profile* pf, size_t thread_index, const TextThread* thread);
|
||||||
|
|
||||||
|
DWORD ThreadCreate(TextThread* thread)
|
||||||
|
{
|
||||||
|
thread->RegisterOutputCallBack(ThreadOutput, 0);
|
||||||
|
thread->RegisterFilterCallBack(ThreadFilter, 0);
|
||||||
|
AddToCombo(*thread, false);
|
||||||
|
const auto& tp = thread->GetThreadParameter();
|
||||||
|
auto pr = man->GetProcessRecord(tp->pid);
|
||||||
|
if (pr == NULL)
|
||||||
|
return 0;
|
||||||
|
if (IsUnicodeHook(*pr, tp->hook))
|
||||||
|
thread->Status() |= USING_UNICODE;
|
||||||
|
auto pf = pfman->GetProfile(tp->pid);
|
||||||
|
if (!pf)
|
||||||
|
return 0;
|
||||||
|
const std::wstring& hook_name = GetHookNameByAddress(*pr, thread->GetThreadParameter()->hook);
|
||||||
|
auto thread_profile = pf->FindThread(thread->GetThreadParameter(), hook_name);
|
||||||
|
if (thread_profile != pf->Threads().end())
|
||||||
|
{
|
||||||
|
(*thread_profile)->HookManagerIndex() = thread->Number();
|
||||||
|
auto thread_index = thread_profile - pf->Threads().begin();
|
||||||
|
AddLinksToHookManager(pf, thread_index, thread);
|
||||||
|
if (pf->IsThreadSelected(thread_profile))
|
||||||
|
ThreadReset(thread);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsUnicodeHook(const ProcessRecord& pr, DWORD hook)
|
||||||
|
{
|
||||||
|
bool res = false;
|
||||||
|
WaitForSingleObject(pr.hookman_mutex, 0);
|
||||||
|
auto hooks = (const Hook*)pr.hookman_map;
|
||||||
|
for (DWORD i = 0; i < MAX_HOOK; i++)
|
||||||
|
{
|
||||||
|
if (hooks[i].Address() == hook)
|
||||||
|
{
|
||||||
|
res = hooks[i].Type() & USING_UNICODE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ReleaseMutex(pr.hookman_mutex);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddLinksToHookManager(const Profile* pf, size_t thread_index, const TextThread* thread)
|
||||||
|
{
|
||||||
|
for (auto lp = pf->Links().begin(); lp != pf->Links().end(); ++lp)
|
||||||
|
{
|
||||||
|
if ((*lp)->FromIndex() == thread_index)
|
||||||
|
{
|
||||||
|
WORD to_index = pf->Threads()[(*lp)->ToIndex()]->HookManagerIndex();
|
||||||
|
if (to_index != 0)
|
||||||
|
man->AddLink(thread->Number(), to_index);
|
||||||
|
}
|
||||||
|
if ((*lp)->ToIndex() == thread_index)
|
||||||
|
{
|
||||||
|
WORD from_index = pf->Threads()[(*lp)->FromIndex()]->HookManagerIndex();
|
||||||
|
if (from_index != 0)
|
||||||
|
man->AddLink(from_index, thread->Number());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD ThreadRemove(TextThread* thread)
|
||||||
|
{
|
||||||
|
RemoveFromCombo(thread);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD RegisterProcessList(DWORD pid)
|
||||||
|
{
|
||||||
|
auto path = GetProcessPath(pid);
|
||||||
|
if (!path.empty())
|
||||||
|
{
|
||||||
|
WCHAR str[MAX_PATH];
|
||||||
|
std::swprintf(str, L"%04d:%s", pid, path.substr(path.rfind(L'\\') + 1).c_str());
|
||||||
|
ComboBox_AddString(hwndProcessComboBox, str);
|
||||||
|
if (ComboBox_GetCount(hwndProcessComboBox) == 1)
|
||||||
|
ComboBox_SetCurSel(hwndProcessComboBox, 0);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD RemoveProcessList(DWORD pid)
|
||||||
|
{
|
||||||
|
WCHAR str[MAX_PATH];
|
||||||
|
std::swprintf(str, L"%04d", pid);
|
||||||
|
DWORD i = ComboBox_FindString(hwndProcessComboBox, 0, str);
|
||||||
|
DWORD j = ComboBox_GetCurSel(hwndProcessComboBox);
|
||||||
|
if (i != CB_ERR)
|
||||||
|
{
|
||||||
|
DWORD k = ComboBox_DeleteString(hwndProcessComboBox, i);
|
||||||
|
if (i == j)
|
||||||
|
ComboBox_SetCurSel(hwndProcessComboBox, 0);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD RefreshProfileOnNewHook(DWORD pid)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
switch (message)
|
||||||
|
{
|
||||||
|
case WM_CREATE:
|
||||||
|
CreateButtons(hWnd);
|
||||||
|
// Add text to the window.
|
||||||
|
Edit_LimitText(hwndEdit, -1);
|
||||||
|
SendMessage(hwndEdit, WM_INPUTLANGCHANGEREQUEST, 0, 0x411);
|
||||||
|
proc = (WNDPROC)SetWindowLong(hwndEdit, GWL_WNDPROC, (LONG)EditProc);
|
||||||
|
proccmd = (WNDPROC)SetWindowLong(hwndCmd, GWL_WNDPROC, (LONG)EditCmdProc);
|
||||||
|
hwndCombo = CreateWindow(L"ComboBox", NULL,
|
||||||
|
WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST |
|
||||||
|
CBS_SORT | WS_VSCROLL | WS_TABSTOP,
|
||||||
|
0, 0, 0, 0, hWnd, 0, hIns, NULL);
|
||||||
|
{
|
||||||
|
HDC hDC = GetDC(hWnd);
|
||||||
|
int nHeight = -MulDiv(12, GetDeviceCaps(hDC, LOGPIXELSY), 72);
|
||||||
|
ReleaseDC(hWnd, hDC);
|
||||||
|
HFONT hf = CreateFont(nHeight, 0, 0, 0, FW_LIGHT, FALSE, FALSE, FALSE, SHIFTJIS_CHARSET,
|
||||||
|
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
|
||||||
|
L"MS Gothic");
|
||||||
|
hWhiteBrush = GetStockBrush(WHITE_BRUSH);
|
||||||
|
SendMessage(hwndCmd, WM_SETFONT, (WPARAM)hf, 0);
|
||||||
|
SendMessage(hwndEdit, WM_SETFONT, (WPARAM)hf, 0);
|
||||||
|
SendMessage(hwndCombo, WM_SETFONT, (WPARAM)hf, 0);
|
||||||
|
SendMessage(hwndProcessComboBox, WM_SETFONT, (WPARAM)hf, 0);
|
||||||
|
texts = new TextBuffer(hwndEdit);
|
||||||
|
man->RegisterThreadCreateCallback(ThreadCreate);
|
||||||
|
man->RegisterThreadRemoveCallback(ThreadRemove);
|
||||||
|
man->RegisterThreadResetCallback(ThreadReset);
|
||||||
|
TextThread* console = man->FindSingle(0);
|
||||||
|
console->RegisterOutputCallBack(ThreadOutput, NULL);
|
||||||
|
AddToCombo(*console, false);
|
||||||
|
man->RegisterProcessAttachCallback(RegisterProcessList);
|
||||||
|
man->RegisterProcessDetachCallback(RemoveProcessList);
|
||||||
|
man->RegisterProcessNewHookCallback(RefreshProfileOnNewHook);
|
||||||
|
man->RegisterAddRemoveLinkCallback(AddRemoveLink);
|
||||||
|
man->RegisterConsoleCallback(ConsoleOutput);
|
||||||
|
Host_Start();
|
||||||
|
{
|
||||||
|
static const WCHAR program_name[] = L"Interactive Text Hooker";
|
||||||
|
//static const WCHAR program_version[] = L"3.0";
|
||||||
|
static WCHAR version_info[256];
|
||||||
|
std::swprintf(version_info, L"%s %s (%s)", program_name, program_version, build_date);
|
||||||
|
man->AddConsoleOutput(version_info);
|
||||||
|
man->AddConsoleOutput(InitMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (background == 0)
|
||||||
|
man->AddConsoleOutput(BackgroundMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
case WM_COMMAND:
|
||||||
|
{
|
||||||
|
DWORD wmId, wmEvent, dwId;
|
||||||
|
wmId = LOWORD(wParam);
|
||||||
|
wmEvent = HIWORD(wParam);
|
||||||
|
switch (wmEvent)
|
||||||
|
{
|
||||||
|
case EN_VSCROLL:
|
||||||
|
{
|
||||||
|
SCROLLBARINFO info = { sizeof(info) };
|
||||||
|
GetScrollBarInfo(hwndEdit, OBJID_VSCROLL, &info);
|
||||||
|
InvalidateRect(hwndEdit, 0, 1);
|
||||||
|
ValidateRect(hwndEdit, &info.rcScrollBar);
|
||||||
|
RedrawWindow(hwndEdit, 0, 0, RDW_ERASE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CBN_SELENDOK:
|
||||||
|
{
|
||||||
|
if ((HWND)lParam == hwndProcessComboBox)
|
||||||
|
return 0;
|
||||||
|
dwId = ComboBox_GetCurSel(hwndCombo);
|
||||||
|
int len = ComboBox_GetLBTextLen(hwndCombo, dwId);
|
||||||
|
if (len > 0)
|
||||||
|
{
|
||||||
|
LPWSTR pwcEntry = new WCHAR[len + 1];
|
||||||
|
len = ComboBox_GetLBText(hwndCombo, dwId, pwcEntry);
|
||||||
|
DWORD num = std::stoul(pwcEntry, NULL, 16);
|
||||||
|
man->SelectCurrent(num);
|
||||||
|
delete[] pwcEntry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
case BN_CLICKED:
|
||||||
|
ClickButton(hWnd, (HWND)lParam);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WM_SETFOCUS:
|
||||||
|
SetFocus(hwndEdit);
|
||||||
|
return 0;
|
||||||
|
case WM_SIZE:
|
||||||
|
{
|
||||||
|
WORD width = LOWORD(lParam);
|
||||||
|
WORD height = HIWORD(lParam);
|
||||||
|
DWORD l = width / 7;
|
||||||
|
WORD h = HIWORD(GetDialogBaseUnits()); // height of the system font
|
||||||
|
h = h + (h / 2);
|
||||||
|
HDC hDC = GetDC(hWnd);
|
||||||
|
RECT rc;
|
||||||
|
GetClientRect(hWnd, &rc);
|
||||||
|
FillRect(hDC, &rc, hWhiteBrush);
|
||||||
|
ReleaseDC(hWnd, hDC);
|
||||||
|
MoveWindow(hwndProcess, 0, 0, l, h, TRUE);
|
||||||
|
MoveWindow(hwndOption, l * 1, 0, l, h, TRUE);
|
||||||
|
MoveWindow(hwndTop, l * 2, 0, l, h, TRUE);
|
||||||
|
MoveWindow(hwndClear, l * 3, 0, l, h, TRUE);
|
||||||
|
MoveWindow(hwndRemoveLink, l * 4, 0, l, h, TRUE);
|
||||||
|
MoveWindow(hwndRemoveHook, l * 5, 0, l, h, TRUE);
|
||||||
|
MoveWindow(hwndSave, l * 6, 0, width - 6 * l, h, TRUE);
|
||||||
|
l *= 2;
|
||||||
|
MoveWindow(hwndProcessComboBox, 0, h, l, 200, TRUE);
|
||||||
|
MoveWindow(hwndCmd, l, h, width - l, h, TRUE);
|
||||||
|
MoveWindow(hwndCombo, 0, h * 2, width, 200, TRUE);
|
||||||
|
h *= 3;
|
||||||
|
MoveWindow(hwndEdit, 0, h, width, height - h, TRUE);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
case WM_DESTROY:
|
||||||
|
man->RegisterThreadCreateCallback(0);
|
||||||
|
man->RegisterThreadRemoveCallback(0);
|
||||||
|
man->RegisterThreadResetCallback(0);
|
||||||
|
man->RegisterProcessAttachCallback(0);
|
||||||
|
man->RegisterProcessDetachCallback(0);
|
||||||
|
//delete texts;
|
||||||
|
SaveSettings();
|
||||||
|
PostQuitMessage(0);
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD WINAPI FlushThread(LPVOID lParam)
|
||||||
|
{
|
||||||
|
TextBuffer* t = (TextBuffer*)lParam;
|
||||||
|
while (t->Running())
|
||||||
|
{
|
||||||
|
t->Flush();
|
||||||
|
Sleep(10);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
20
i18n/gui_korean/window.h
Normal file
20
i18n/gui_korean/window.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/* 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 "ITH.h"
|
Loading…
Reference in New Issue
Block a user