// ithsys.cc // 8/21/2013 jichi // Branch: ITH_SYS/SYS.cpp, rev 126 // // 8/24/2013 TODO: // - Clean up the code // - Move my old create remote thread for ITH2 here #include "ithsys/ithsys.h" //#include "vnrhook/src/util/growl.h" //#define ITH_SYS_SECTION L"ITH_SysSection" #define ITH_THREADMAN_SECTION L"VNR_SYS_THREAD" // jichi 9/28/2013: Weither use NtThread or RemoteThread // RemoteThread works on both Windows 7 or Wine, while NtThread does not work on wine #define ITH_ENABLE_THREADMAN (!IthIsWindows8OrGreater() && !IthIsWine()) //#define ITH_ENABLE_THREADMAN true //#define ITH_ENABLE_WINAPI // jichi: prefer Win32 API to NTDLL API // Helpers // jichi 2/3/2015: About GetVersion // Windows XP SP3: 5.1 // Windows 7: 6.1, 0x1db10106 // Windows 8: 6.2, 0x23f00206 // Windows 10: 6.2, 0x23f00206 (build 9926): BOOL IthIsWindowsXp() { static BOOL ret = -1; // cached if (ret < 0) { // http://msdn.microsoft.com/en-us/library/windows/desktop/ms724439%28v=vs.85%29.aspx DWORD v = ::GetVersion(); BYTE major = LOBYTE(LOWORD(v)); //DWORD minor = (DWORD)(HIBYTE(LOWORD(v))); // Windows XP = 5.1 //ret = major < 6 ? 1 : 0; ret = major < 6; } return ret; } // https://msdn.microsoft.com/en-us/library/windows/desktop/dn424972%28v=vs.85%29.aspx // The same as IsWindows8OrGreater, which I don't know if the function is available to lower Windows. static BOOL IthIsWindows8OrGreater() // this function is not exported { static BOOL ret = -1; // cached if (ret < 0) { // http://msdn.microsoft.com/en-us/library/windows/desktop/ms724439%28v=vs.85%29.aspx DWORD v = ::GetVersion(); BYTE major = LOBYTE(LOWORD(v)), minor = HIBYTE(LOWORD(v)); //DWORD minor = (DWORD)(HIBYTE(LOWORD(v))); // Windows 8/10 = 6.2 ret = major > 6 || (major == 6 && minor >= 2); } return ret; } BOOL IthIsWine() { static BOOL ret = -1; // cached if (ret < 0) { const wchar_t *path; wchar_t buffer[MAX_PATH]; if (UINT sz = ::GetSystemDirectoryW(buffer, MAX_PATH)) { path = buffer; ::wcscpy(buffer + sz, L"\\winecfg.exe"); } else path = L"C:\\Windows\\System32\\winecfg.exe"; //ITH_MSG(path); ret = ::GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES ? TRUE : FALSE; } return ret; } // jichi 9/28/2013: prevent parallelization in wine void IthCoolDown() { // http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/Thread/NtDelayExecution.html //const LONGLONG timeout = -10000; // in 100ns, i.e. 1ms //NtDelayExecution(FALSE, (PLARGE_INTEGER)&timeout); //NtFlushInstructionCache(NtCurrentProcess(), (LPVOID)hp.addr, hp.recover_len); // Flush the instruction cache line, and prevent wine from rending things in parallel if (IthIsWine()) IthSleep(1); // sleep for 1 ms //__asm //{ // //mov eax,0x2710 // = 10000 // mov ecx,time // mul ecx // neg eax // adc edx,0 // neg edx // push edx // push eax // push esp // push 0 // call dword ptr [NtDelayExecution] // add esp,8 //} } // jichi 9/23/2013: wine deficenciy on mapping sections // Whe set to false, do not map sections. //static bool ith_has_section = true; //#ifdef ITH_WINE //# include "winddk/winddk.h" //#endif // ITH_WINE //#define SEC_BASED 0x200000 // jichi 8/24/2013: emoved // jichi 10/6/2013 // See: http://stackoverflow.com/questions/557081/how-do-i-get-the-hmodule-for-the-currently-executing-code // See: http://www.codeproject.com/Articles/16598/Get-Your-DLL-s-Path-Name EXTERN_C IMAGE_DOS_HEADER __ImageBase; #define CURRENT_MODULE_HANDLE ((HINSTANCE)&__ImageBase) size_t IthGetCurrentModulePath(wchar_t *buf, size_t len) { return ::GetModuleFileNameW(CURRENT_MODULE_HANDLE, buf, len); } // - Global variables - #ifdef ITH_HAS_HEAP HANDLE hHeap; // used in ith/common/memory.h #endif // ITH_HAS_HEAP DWORD current_process_id; DWORD debug; BYTE launch_time[0x10]; LPVOID page; // jichi 6/12/2015: https://en.wikipedia.org/wiki/Shift_JIS // Leading table for SHIFT-JIS encoding BYTE LeadByteTable[0x100] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1 }; namespace { // unnamed WCHAR file_path[MAX_PATH] = L"\\??\\"; LPWSTR current_dir; DWORD page_locale; HANDLE root_obj, dir_obj, codepage_section, thread_man_section; BYTE file_info[0x1000]; // - Helper functions - inline DWORD GetShareMemory() { __asm { mov eax,fs:[0x30] mov eax,[eax+0x4C] } } inline LARGE_INTEGER *GetTimeBias() { __asm mov eax,0x7ffe0020 } //Get full path of current process. //inline LPWSTR GetModulePath() //{ // __asm // { // mov eax,fs:[0x30] // mov eax,[eax+0xC] // mov eax,[eax+0xC] // mov eax,[eax+0x28] // } //} // - Singleton classes - BYTE normal_routine[0x14] = { 0x51,0x52,0x64,0x89,0x23,0x55,0xff,0xd0,0x50,0x6a,0xfe,0xff,0x15,0x14,0x00,0x00,0x00 }; BYTE except_routine[0xe0] = { 0xba,0x08,0x00,0x00,0x00,0x8b,0xc1,0x83,0xe0,0x0f,0x83,0xf8,0x0a,0x72,0x02,0x04, 0x07,0x04,0x30,0x66,0xab,0xc1,0xc9,0x04,0x4a,0x75,0xea,0xc3,0x00,0x00,0x00,0x00, 0x8b,0x44,0xe4,0x04,0x31,0xf6,0x8b,0x28,0x8b,0x4c,0xe4,0x0c,0x8b,0x99,0xb8,0x00, 0x00,0x00,0x81,0xec,0x40,0x02,0x00,0x00,0x8d,0x7c,0xe4,0x40,0x89,0xe0,0x56,0x6a, 0x1c,0x50,0x56,0x53,0x6a,0xff,0xff,0x15,0x18,0x00,0x00,0x00,0x85,0xc0,0x75,0x98, 0x89,0xe0,0x50,0x68,0x00,0x02,0x00,0x00,0x57,0x6a,0x02,0x53,0x6a,0xff,0xff,0x15, 0x18,0x00,0x00,0x00,0x85,0xc0,0x75,0xe6,0x5e,0x0f,0xc1,0xf7,0xfd,0xb0,0x5c,0x66, 0xf2,0xaf,0x66,0xc7,0x47,0x02,0x3a,0x00,0x89,0xd9,0x2b,0x0c,0xe4,0xe8,0x7e,0xff, 0xff,0xff,0x47,0x47,0x87,0xfe,0x89,0xe9,0xe8,0x73,0xff,0xff,0xff,0x47,0x47,0x31, 0xc0,0x89,0x47,0x10,0x6a,0x00,0x57,0x56,0x6a,0x00,0xfc,0xff,0x15,0x1c,0x00,0x00, 0x00,0x83,0xc8,0xff,0xeb,0xbe }; // jichi 8/24/2013: Could be initialized using NtMapViewOfSection/ZwMapViewOfSection // This class cannot have constructor / destructor struct _ThreadView { UINT_PTR mutex, count; DWORD proc_record[1]; }; class : private _ThreadView { // ThreadStartManager enum { ADDR0 = 0xD , ADDR1 = 0x48 , ADDR2 = 0x60 , ADDR3 = 0x9D }; public: LPVOID GetProcAddr(HANDLE hProc) { AcquireLock(); DWORD pid,addr,len; if (hProc == NtCurrentProcess()) pid = ::current_process_id; else { PROCESS_BASIC_INFORMATION info; NtQueryInformationProcess(hProc, ProcessBasicInformation, &info, sizeof(info), &len); pid=info.uUniqueProcessId; } pid >>= 2; for (UINT_PTR i = 0; i < count; i++) if (pid == (proc_record[i] & 0xfff)) { addr = proc_record[i] & ~0xfff; ReleaseLock(); return (LPVOID)addr; } len = 0x1000; NtAllocateVirtualMemory(hProc, (PVOID *)(proc_record + count), 0, &len, MEM_COMMIT,PAGE_EXECUTE_READWRITE); DWORD base = proc_record[count]; proc_record[count] |= pid; union { LPVOID buffer; DWORD b; }; b = base; LPVOID fun_table[3]; *(DWORD *)(normal_routine + ADDR0) += base; NtWriteVirtualMemory(hProc, buffer, normal_routine, 0x14, 0); *(DWORD *)(normal_routine + ADDR0) -= base; b += 0x14; fun_table[0] = NtTerminateThread; fun_table[1] = NtQueryVirtualMemory; fun_table[2] = MessageBoxW; NtWriteVirtualMemory(hProc, buffer, fun_table, 0xC, 0); b += 0xc; *(DWORD *)(except_routine + ADDR1) += base; *(DWORD *)(except_routine + ADDR2) += base; *(DWORD *)(except_routine + ADDR3) += base; NtWriteVirtualMemory(hProc, buffer, except_routine, 0xE0, 0); *(DWORD *)(except_routine + ADDR1) -= base; *(DWORD *)(except_routine + ADDR2) -= base; *(DWORD *)(except_routine + ADDR3) -= base; count++; ReleaseLock(); return (LPVOID)base; } void ReleaseProcessMemory(HANDLE hProc) { DWORD pid,addr,len; AcquireLock(); if (hProc==NtCurrentProcess()) pid = ::current_process_id; else { PROCESS_BASIC_INFORMATION info; NtQueryInformationProcess(hProc,ProcessBasicInformation,&info,sizeof(info),&len); pid = info.uUniqueProcessId; } pid >>= 2; //NtWaitForSingleObject(thread_man_mutex,0,0); for (UINT_PTR i = 0; i < count; i++) { if ((proc_record[i]&0xfff) == pid) { addr = proc_record[i] & ~0xfff; DWORD size=0x1000; NtFreeVirtualMemory(hProc, (PVOID *)&addr, &size, MEM_RELEASE); count--; for (UINT_PTR j = i; j < count; j++) proc_record[j] = proc_record[j + 1]; proc_record[count] = 0; ReleaseLock(); //NtReleaseMutant(thread_man_mutex,0); return; } } ReleaseLock(); //NtReleaseMutant(thread_man_mutex,0); } void CheckProcessMemory() { UINT_PTR i, j, flag, addr; DWORD len; CLIENT_ID id; OBJECT_ATTRIBUTES oa = {}; HANDLE hProc; BYTE buffer[8]; AcquireLock(); id.UniqueThread = 0; oa.uLength = sizeof(oa); for (i = 0; i < count ; i++) { id.UniqueProcess = (proc_record[i]&0xfff)<<2; addr = proc_record[i] & ~0xfff; flag = 0; if (NT_SUCCESS(NtOpenProcess(&hProc, PROCESS_VM_OPERATION|PROCESS_VM_READ, &oa, &id))) { if (NT_SUCCESS(NtReadVirtualMemory(hProc, (PVOID)addr, buffer, 8, &len))) if (::memcmp(buffer, normal_routine, 4) == 0) flag = 1; NtClose(hProc); } if (flag == 0) { for (j = i; j < count; j++) proc_record[j] = proc_record[j + 1]; count--; i--; } } ReleaseLock(); } void AcquireLock() { LONG *p = (LONG *)&mutex; while (_interlockedbittestandset(p,0)) YieldProcessor(); } void ReleaseLock() { LONG *p = (LONG*)&mutex; _interlockedbittestandreset(p, 0); } } *thread_man_ = nullptr; // global singleton } // unnamed namespace // - API functions - extern "C" { void FreeThreadStart(HANDLE hProc) { if (thread_man_) ::thread_man_->ReleaseProcessMemory(hProc); } void CheckThreadStart() { if (thread_man_) ::thread_man_->CheckProcessMemory(); // jichi 2/2/2015: This function is only used to wait for injected threads vnrhost. // Sleep for 100 ms to wait for remote thread to start //IthSleep(100); //IthCoolDown(); } void IthSleep(int time) { __asm { mov eax,0x2710 // jichi = 10000 mov ecx,time mul ecx neg eax adc edx,0 neg edx push edx push eax push esp push 0 call dword ptr [NtDelayExecution] add esp,8 } } void IthSystemTimeToLocalTime(LARGE_INTEGER *time) { time->QuadPart -= GetTimeBias()->QuadPart; } int FillRange(LPCWSTR name, DWORD *lower, DWORD *upper) { PLDR_DATA_TABLE_ENTRY it; LIST_ENTRY *begin; __asm { mov eax,fs:[0x30] mov eax,[eax+0xc] mov eax,[eax+0xc] mov it,eax mov begin,eax } while (it->SizeOfImage) { if (::_wcsicmp(it->BaseDllName.Buffer, name) == 0) { *lower = *upper = (DWORD)it->DllBase; MEMORY_BASIC_INFORMATION info = {}; DWORD l,size; size = 0; do { NtQueryVirtualMemory(NtCurrentProcess(), (LPVOID)(*upper), MemoryBasicInformation, &info, sizeof(info), &l); if (info.Protect&PAGE_NOACCESS) { it->SizeOfImage=size; break; } size += info.RegionSize; *upper += info.RegionSize; } while (size < it->SizeOfImage); return 1; } it = (PLDR_DATA_TABLE_ENTRY)it->InLoadOrderModuleList.Flink; if (it->InLoadOrderModuleList.Flink == begin) break; } return 0; } DWORD SearchPattern(DWORD base, DWORD base_length, LPCVOID search, DWORD search_length) // KMP { __asm { mov eax,search_length alloc: push 0 sub eax,1 jnz alloc mov edi,search mov edx,search_length mov ecx,1 xor esi,esi build_table: mov al,byte ptr [edi+esi] cmp al,byte ptr [edi+ecx] sete al test esi,esi jz pre test al,al jnz pre mov esi,[esp+esi*4-4] jmp build_table pre: test al,al jz write_table inc esi write_table: mov [esp+ecx*4],esi inc ecx cmp ecx,edx jb build_table mov esi,base xor edx,edx mov ecx,edx matcher: mov al,byte ptr [edi+ecx] cmp al,byte ptr [esi+edx] sete al test ecx,ecx jz match test al,al jnz match mov ecx, [esp+ecx*4-4] jmp matcher match: test al,al jz pre2 inc ecx cmp ecx,search_length je finish pre2: inc edx cmp edx,base_length // search_length jb matcher mov edx,search_length dec edx finish: mov ecx,search_length sub edx,ecx lea eax,[edx+1] lea ecx,[ecx*4] add esp,ecx } } // jichi 2/5/2014: '?' = 0xff // See: http://sakuradite.com/topic/124 DWORD SearchPatternEx(DWORD base, DWORD base_length, LPCVOID search, DWORD search_length, BYTE wildcard) // KMP { __asm { // jichi 2/5/2014 BEGIN mov bl,wildcard // jichi 2/5/2014 END mov eax,search_length alloc: push 0 sub eax,1 jnz alloc // jichi 2/5/2014: this will also set %eax to zero mov edi,search mov edx,search_length mov ecx,1 xor esi,esi build_table: mov al,byte ptr [edi+esi] cmp al,byte ptr [edi+ecx] sete al test esi,esi jz pre test al,al jnz pre mov esi,[esp+esi*4-4] jmp build_table pre: test al,al jz write_table inc esi write_table: mov [esp+ecx*4],esi inc ecx cmp ecx,edx jb build_table mov esi,base xor edx,edx mov ecx,edx matcher: mov al,byte ptr [edi+ecx] // search // jichi 2/5/2014 BEGIN mov bh,al // save loaded byte to reduce cache access. %ah is not used and always zero cmp al,bl // %bl is the wildcard byte sete al test al,al jnz wildcard_matched mov al,bh // restore the loaded byte // jichi 2/5/2014 END cmp al,byte ptr [esi+edx] // base sete al // jichi 2/5/2014 BEGIN wildcard_matched: // jichi 2/5/2014 END test ecx,ecx jz match test al,al jnz match mov ecx, [esp+ecx*4-4] jmp matcher match: test al,al jz pre2 inc ecx cmp ecx,search_length je finish pre2: inc edx cmp edx,base_length // search_length jb matcher mov edx,search_length dec edx finish: mov ecx,search_length sub edx,ecx lea eax,[edx+1] lea ecx,[ecx*4] add esp,ecx } } DWORD IthGetMemoryRange(LPCVOID mem, DWORD *base, DWORD *size) { DWORD r; MEMORY_BASIC_INFORMATION info; NtQueryVirtualMemory(NtCurrentProcess(), const_cast(mem), MemoryBasicInformation, &info, sizeof(info), &r); if (base) *base = (DWORD)info.BaseAddress; if (size) *size = info.RegionSize; return (info.Type&PAGE_NOACCESS) == 0; } // jichi 9/25/2013 // See: http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.nls/doc/nlsgdrf/multi-byte_widechar_subr.htm // SJIS->Unicode. 'mb' must be null-terminated. 'wc' should have enough space ( 2*strlen(mb) is safe). //#ifdef ITH_WINE //int MB_WC(char *mb, wchar_t *wc) //{ return mbstowcs(wc, mb, 0x100); } // //#else int MB_WC(char *mb, wchar_t *wc) { __asm { mov esi,mb mov edi,wc mov edx,page lea ebx,LeadByteTable add edx,0x220 push 0 _mb_translate: movzx eax,word ptr [esi] test al,al jz _mb_fin movzx ecx,al xlat test al,1 cmovnz cx, word ptr [ecx*2+edx-0x204] jnz _mb_next mov cx,word ptr [ecx*2+edx] mov cl,ah mov cx, word ptr [ecx*2+edx] _mb_next: mov [edi],cx add edi,2 movzx eax,al add esi,eax inc dword ptr [esp] jmp _mb_translate _mb_fin: pop eax } } // Count characters of 'mb' string. 'mb_length' is max length. // jichi 9/25/2013: This function is not used //int MB_WC_count(char *mb, int mb_length) //{ // __asm // { // xor eax,eax // xor edx,edx // mov esi,mb // mov edi,mb_length // lea ebx,LeadByteTable //_mbc_count: // mov dl,byte ptr [esi] // test dl,dl // jz _mbc_finish // movzx ecx, byte ptr [ebx+edx] // add esi,ecx // inc eax // sub edi,ecx // ja _mbc_count //_mbc_finish: // } //} // jichi 9/25/2013 // See: http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.nls/doc/nlsgdrf/multi-byte_widechar_subr.htm // Unicode->SJIS. Analogous to MB_WC. //#ifdef ITH_WINE //int WC_MB(wchar_t *wc, char *mb) //{ return wcstombs(mb, wc, 0x100); } // //#else int WC_MB(wchar_t *wc, char *mb) { __asm { mov esi,wc mov edi,mb mov edx,page add edx,0x7c22 xor ebx,ebx _wc_translate: movzx eax,word ptr [esi] test eax,eax jz _wc_fin mov cx,word ptr [eax*2+edx] test ch,ch jz _wc_single mov [edi+ebx],ch inc ebx _wc_single: mov [edi+ebx],cl inc ebx add esi,2 jmp _wc_translate _wc_fin: mov eax,ebx } } //Initialize environment for NT native calls. Not thread safe so only call it once in one module. //1. Create new heap. Future memory requests are handled by this heap. //Destroying this heap will completely release all dynamically allocated memory, thus prevent memory leaks on unload. //2. Create handle to root directory of process objects (section/event/mutex/semaphore). //NtCreate* calls will use this handle as base directory. //3. Load SJIS code page. First check for Japanese locale. If not then load from 'C_932.nls' in system folder. //MB_WC & WC_MB use this code page for translation. //4. Locate current NT path (start with \??\). //NtCreateFile requires full path or a root handle. But this handle is different from object. //5. Map shared memory for ThreadStartManager into virtual address space. //This will allow IthCreateThread function properly. BOOL IthInitSystemService() { PPEB peb; //NTSTATUS status; DWORD size; ULONG LowFragmentHeap; UNICODE_STRING us; OBJECT_ATTRIBUTES oa = {sizeof(oa), 0, &us, OBJ_CASE_INSENSITIVE, 0, 0}; IO_STATUS_BLOCK ios; HANDLE codepage_file; LARGE_INTEGER sec_size = {0x1000, 0}; __asm { mov eax,fs:[0x18] mov ecx,[eax+0x20] mov eax,[eax+0x30] mov peb,eax mov current_process_id,ecx } debug = peb->BeingDebugged; LowFragmentHeap = 2; #ifdef ITH_HAS_HEAP ::hHeap = RtlCreateHeap(0x1002, 0, 0, 0, 0, 0); RtlSetHeapInformation(::hHeap, HeapCompatibilityInformation, &LowFragmentHeap, sizeof(LowFragmentHeap)); #endif // ITH_HAS_HEAP LPWSTR t = nullptr, // jichi: path to system32, such as "c:\windows\system32" obj = nullptr; // jichi: path to current kernel session, such as "Sessions\\1\\BaseNamedObjects" // jichi 9/22/2013: This would crash wine with access violation exception. if (!IthIsWine()) { // jichi 9/22/2013: For ChuSingura46+1 on Windows 7 // t = L"C:\\Windows\\system32"; // obj = L"\\Sessions\\1\\BaseNamedObjects"; // On Windows XP // t = L"C:\\WINDOWS\\system32"; // obj = L"\\BaseNamedObjects"; MEMORY_BASIC_INFORMATION info; if (!NT_SUCCESS(NtQueryVirtualMemory(NtCurrentProcess(), peb->ReadOnlySharedMemoryBase, MemoryBasicInformation, &info, sizeof(info), &size))) return FALSE; DWORD base = (DWORD)peb->ReadOnlySharedMemoryBase; DWORD end = base + info.RegionSize - 0x40; // 일본어 코드 페이지 C_932 이 SysWow64에 없음 // 64bit에서 (32bit) 로 실행할 경우 SysWow64로 리다이렉트 되는 것 해제 PVOID OldValue; Wow64DisableWow64FsRedirection(&OldValue); static WCHAR system32[] = L"system32"; for (;base < end; base += 2) if (::memcmp((PVOID)base, system32, 0x10) == 0) { t = (LPWSTR)base; while (*t-- != L':'); obj = (LPWSTR)base; while (*obj != L'\\') obj++; break; } if (base == end) return FALSE; } //ITH_MSG(t); //ITH_MSG(obj); LDR_DATA_TABLE_ENTRY *ldr_entry = (LDR_DATA_TABLE_ENTRY*)peb->Ldr->InLoadOrderModuleList.Flink; // jichi 7/12/2015: This will fail when the file path is a remote path such as: // Original remote file path: \\??\\\\\\psf\\Host\\Local\\Windows\\Games\\ShinaRio\\Ayakashibito_trial\\"); // Correct UNC path: \\??\\\\UNC\\psf\\Host\\Local\\Windows\\Games\\ShinaRio\\Ayakashibito_trial\\"); //RtlInitUnicodeString(&us, L"\\??\\UNC\\psf\\Host\\Local\\Windows\\Games\\ShinaRio\\Ayakashibito_trial\\"); //WCHAR file_path[MAX_PATH] = L"\\??\\"; LPCWSTR modulePath = ldr_entry->FullDllName.Buffer; if (modulePath[0] == '\\' && modulePath[1] == '\\') { // This is a remote path ::file_path[4] = 'U'; ::file_path[5] = 'N'; ::file_path[6] = 'C'; ::wcscpy(::file_path + 7, modulePath + 1); } else ::wcscpy(::file_path + 4, modulePath); current_dir = ::wcsrchr(::file_path, L'\\') + 1; *current_dir = 0; //GROWL(::file_path); RtlInitUnicodeString(&us, ::file_path); if (!NT_SUCCESS(NtOpenFile(&dir_obj,FILE_LIST_DIRECTORY|FILE_TRAVERSE|SYNCHRONIZE, &oa,&ios,FILE_SHARE_READ|FILE_SHARE_WRITE,FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT))) return FALSE; // jichi 9/22/2013: Get kernel object session ID // See: http://www.brianbondy.com/blog/id/100/ // It seems that on sessionId is 0 on Windows XP, and 1 on Windows Vista and later // I assume that sessionId is in [0,9] // For ChuSingura46+1 on Windows 7 // obj = L"\\Sessions\\1\\BaseNamedObjects"; // On Windows XP // obj = L"\\BaseNamedObjects"; //ITH_MSG(obj); { if (obj) RtlInitUnicodeString(&us, obj); else { // jichi ITH is on Wine // Get session ID in PEB // See: http://msdn.microsoft.com/en-us/library/bb432286%28v=vs.85%29.aspx DWORD sessionId = peb->SessionId; if (!sessionId) // Windows XP RtlInitUnicodeString(&us, L"\\BaseNamedObjects"); else { // Windows Vista + wchar_t path[] = L"\\Sessions\\0\\BaseNamedObjects"; path[10] += (wchar_t)sessionId; // replace 0 with the session ID RtlInitUnicodeString(&us, path); } } } if (!NT_SUCCESS(NtOpenDirectoryObject(&::root_obj, READ_CONTROL|0xf, &oa))) return FALSE; ::page = peb->InitAnsiCodePageData; enum { CP932 = 932 }; // jichi 9/23/2013: Access violation on Wine if (IthIsWine()) // One wine, there is no C_932.nls //page_locale = 0x4e4; // 1252, English //page_locale = GetACP(); // This will return 932 when LC_ALL=ja_JP.UTF-8 on wine // Always set locale to CP932 on Wine, since C_932.nls could be missing. ::page_locale = CP932; else ::page_locale = *(DWORD *)page >> 16; if (::page_locale == CP932) { oa.hRootDirectory = ::root_obj; oa.uAttributes |= OBJ_OPENIF; } else { // Unreachable or wine //#ifdef ITH_WINE // // jichi 9/22/2013: For ChuSingura46+1 on Windows 7 // //t = L"C:\\Windows\\system32"; // wchar_t buffer[MAX_PATH]; // if (!t) { // jichi 9/22/2013: ITH is one wine // if (UINT sz = ::GetSystemDirectoryW(buffer, MAX_PATH)) { // buffer[sz] = 0; // t = buffer; // } else // t = L"C:\\Windows\\System32"; // jichi 9/29/2013: sth is wrong here // } //#endif // ITH_WINE ::wcscpy(::file_path + 4, t); t = ::file_path; while(*++t); if (*(t-1)!=L'\\') *t++=L'\\'; ::wcscpy(t,L"C_932.nls"); RtlInitUnicodeString(&us, ::file_path); if (!NT_SUCCESS(NtOpenFile(&codepage_file, FILE_READ_DATA, &oa, &ios,FILE_SHARE_READ,0))) return FALSE; oa.hRootDirectory = ::root_obj; oa.uAttributes |= OBJ_OPENIF; RtlInitUnicodeString(&us, L"JPN_CodePage"); if (!NT_SUCCESS(NtCreateSection(&codepage_section, SECTION_MAP_READ, &oa,0, PAGE_READONLY, SEC_COMMIT, codepage_file))) return FALSE; NtClose(codepage_file); size = 0; ::page = nullptr; if (!NT_SUCCESS(NtMapViewOfSection(::codepage_section, NtCurrentProcess(), &::page, 0, 0, 0, &size, ViewUnmap, 0, PAGE_READONLY))) return FALSE; } if (ITH_ENABLE_THREADMAN) { RtlInitUnicodeString(&us, ITH_THREADMAN_SECTION); if (!NT_SUCCESS(NtCreateSection(&thread_man_section, SECTION_ALL_ACCESS, &oa, &sec_size, PAGE_EXECUTE_READWRITE, SEC_COMMIT, 0))) return FALSE; size = 0; // http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/Section/NtMapViewOfSection.html thread_man_ = nullptr; if (!NT_SUCCESS(NtMapViewOfSection(thread_man_section, NtCurrentProcess(), (LPVOID *)&thread_man_, 0,0,0, &size, ViewUnmap, 0, PAGE_EXECUTE_READWRITE))) return FALSE; } return TRUE; } //Release resources allocated by IthInitSystemService. //After destroying the heap, all memory allocated by ITH module is returned to system. void IthCloseSystemService() { if (::page_locale != 0x3a4) { NtUnmapViewOfSection(NtCurrentProcess(), ::page); NtClose(::codepage_section); } if (ITH_ENABLE_THREADMAN) { NtUnmapViewOfSection(NtCurrentProcess(), ::thread_man_); NtClose(::thread_man_section); } NtClose(::root_obj); #ifdef ITH_HAS_HEAP RtlDestroyHeap(::hHeap); #endif // ITH_HAS_HEAP } //Check for existence of a file in current folder. Thread safe after init. //For ITH main module, it's ITH folder. For target process it's the target process's current folder. BOOL IthCheckFile(LPCWSTR file) { //return PathFileExistsW(file); // jichi: need Shlwapi.lib //return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); //return GetFileAttributesW(file) != INVALID_FILE_ATTRIBUTES; // jichi: does not consider the current app's path // jichi 9/22/2013: Following code does not work in Wine // See: http://stackoverflow.com/questions/3828835/how-can-we-check-if-a-file-exists-or-not-using-win32-program //WIN32_FIND_DATA FindFileData; //HANDLE handle = FindFirstFileW(file, &FindFileData); //if (handle != INVALID_HANDLE_VALUE) { // FindClose(handle); // return TRUE; //} //return FALSE; if (IthIsWine()) { HANDLE hFile = CreateFileW(file, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, 0); if (hFile != INVALID_HANDLE_VALUE) { CloseHandle(hFile); return TRUE; } else if (!wcschr(file, L':')) { // jichi: this is relative path // jichi 9/22/2013: Change current directory to the same as main module path // Otherwise NtFile* would not work for files with relative paths. if (const wchar_t *path = GetMainModulePath()) // path to VNR's python exe if (const wchar_t *base = wcsrchr(path, L'\\')) { size_t dirlen = base - path + 1; if (dirlen + wcslen(file) < MAX_PATH) { wchar_t buf[MAX_PATH]; wcsncpy(buf, path, dirlen); wcscpy(buf + dirlen, file); return IthCheckFile(buf); } } } } else { // not wine HANDLE hFile; IO_STATUS_BLOCK isb; UNICODE_STRING us; RtlInitUnicodeString(&us, file); OBJECT_ATTRIBUTES oa = { sizeof(oa), dir_obj, &us, 0, 0, 0}; // jichi 9/22/2013: Following code does not work in Wine if (NT_SUCCESS(NtCreateFile(&hFile, FILE_READ_DATA, &oa, &isb, 0, 0, FILE_SHARE_READ, FILE_OPEN, 0, 0, 0))) { NtClose(hFile); return TRUE; } } return FALSE; //return IthGetFileInfo(file,file_info); //wcscpy(current_dir,file); } //Check for existence of files in current folder. //Unlike IthCheckFile, this function allows wildcard character. BOOL IthFindFile(LPCWSTR file) { NTSTATUS status; HANDLE h; UNICODE_STRING us; OBJECT_ATTRIBUTES oa = {sizeof(oa), dir_obj, &us, OBJ_CASE_INSENSITIVE, 0, 0}; us.Buffer = const_cast(file); LPCWSTR path = wcsrchr(file, L'\\'); if (path) { us.Length = (path - file) << 1; us.MaximumLength = us.Length; } else { us.Length = 0; us.MaximumLength = 0; } IO_STATUS_BLOCK ios; if (NT_SUCCESS(NtOpenFile(&h,FILE_LIST_DIRECTORY|SYNCHRONIZE, &oa,&ios,FILE_SHARE_READ,FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT))) { BYTE info[0x400]; if (path) RtlInitUnicodeString(&us, path + 1); else RtlInitUnicodeString(&us, file); status = NtQueryDirectoryFile(h,0,0,0,&ios,info,0x400,FileBothDirectoryInformation,TRUE,&us,TRUE); NtClose(h); return NT_SUCCESS(status); } return FALSE; } //Analogous to IthFindFile, but return detail information in 'info'. BOOL IthGetFileInfo(LPCWSTR file, LPVOID info, DWORD size) { NTSTATUS status; HANDLE h; UNICODE_STRING us; LPCWSTR path = wcsrchr(file, L'\\'); us.Buffer = const_cast(file); if (path) { us.Length = (path - file) << 1; us.MaximumLength = us.Length; } else { us.Length = 0; us.MaximumLength = 0; } //RtlInitUnicodeString(&us,file); OBJECT_ATTRIBUTES oa = {sizeof(oa), dir_obj, &us, OBJ_CASE_INSENSITIVE, 0, 0}; IO_STATUS_BLOCK ios; if (NT_SUCCESS(NtOpenFile(&h,FILE_LIST_DIRECTORY|SYNCHRONIZE, &oa,&ios,FILE_SHARE_READ,FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT))) { RtlInitUnicodeString(&us,file); status = NtQueryDirectoryFile(h,0,0,0,&ios,info,size,FileBothDirectoryInformation,0,&us,0); status = NT_SUCCESS(status); NtClose(h); } else status = FALSE; return status; } //Check for existence of a file with full NT path(start with \??\). BOOL IthCheckFileFullPath(LPCWSTR file) { UNICODE_STRING us; RtlInitUnicodeString(&us, file); OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &us, OBJ_CASE_INSENSITIVE, 0, 0}; HANDLE hFile; IO_STATUS_BLOCK isb; if (NT_SUCCESS(NtCreateFile(&hFile,FILE_READ_DATA,&oa,&isb,0,0,FILE_SHARE_READ,FILE_OPEN,0,0,0))) { NtClose(hFile); return TRUE; } else return FALSE; } //Create or open file in current folder. Analogous to Win32 CreateFile. //option: GENERIC_READ / GENERIC_WRITE. //share: FILE_SHARE_READ / FILE_SHARE_WRITE / FILE_SHARE_DELETE. 0 for exclusive access. //disposition: FILE_OPEN / FILE_OPEN_IF. //Use FILE_OPEN instead of OPEN_EXISTING and FILE_OPEN_IF for CREATE_ALWAYS. HANDLE IthCreateFile(LPCWSTR name, DWORD option, DWORD share, DWORD disposition) { UNICODE_STRING us; RtlInitUnicodeString(&us, name); OBJECT_ATTRIBUTES oa = { sizeof(oa), dir_obj, &us, OBJ_CASE_INSENSITIVE, 0, 0 }; HANDLE hFile; IO_STATUS_BLOCK isb; return NT_SUCCESS(NtCreateFile(&hFile, option|FILE_READ_ATTRIBUTES|SYNCHRONIZE, &oa,&isb,0,0,share,disposition, FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE,0,0)) ? hFile : INVALID_HANDLE_VALUE; } //Create a directory file in current folder. HANDLE IthCreateDirectory(LPCWSTR name) { UNICODE_STRING us; RtlInitUnicodeString(&us,name); OBJECT_ATTRIBUTES oa = {sizeof(oa), dir_obj, &us, OBJ_CASE_INSENSITIVE, 0, 0}; HANDLE hFile; IO_STATUS_BLOCK isb; return NT_SUCCESS(NtCreateFile(&hFile,FILE_LIST_DIRECTORY|FILE_TRAVERSE|SYNCHRONIZE,&oa,&isb,0,0, FILE_SHARE_READ|FILE_SHARE_WRITE,FILE_OPEN_IF,FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT,0,0)) ? hFile : INVALID_HANDLE_VALUE; } HANDLE IthCreateFileInDirectory(LPCWSTR name, HANDLE dir, DWORD option, DWORD share, DWORD disposition) { UNICODE_STRING us; RtlInitUnicodeString(&us,name); if (dir == 0) dir = dir_obj; OBJECT_ATTRIBUTES oa = {sizeof(oa), dir, &us, OBJ_CASE_INSENSITIVE, 0, 0}; HANDLE hFile; IO_STATUS_BLOCK isb; return NT_SUCCESS(NtCreateFile(&hFile, option|FILE_READ_ATTRIBUTES|SYNCHRONIZE, &oa,&isb,0,0,share,disposition, FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE,0,0)) ? hFile : INVALID_HANDLE_VALUE; } //Analogous to IthCreateFile, but with full NT path. HANDLE IthCreateFileFullPath(LPCWSTR path, DWORD option, DWORD share, DWORD disposition) { UNICODE_STRING us; RtlInitUnicodeString(&us,path); OBJECT_ATTRIBUTES oa = {sizeof(oa), 0, &us, OBJ_CASE_INSENSITIVE, 0, 0}; HANDLE hFile; IO_STATUS_BLOCK isb; return NT_SUCCESS(NtCreateFile(&hFile, option|FILE_READ_ATTRIBUTES|SYNCHRONIZE, &oa,&isb,0,0,share,disposition, FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE,0,0)) ? hFile : INVALID_HANDLE_VALUE; } //Create section object for sharing memory between processes. //Similar to CreateFileMapping. HANDLE IthCreateSection(LPCWSTR name, DWORD size, DWORD right) { // jichi 9/25/2013: GENERIC_ALL does NOT work one wine // See ZwCreateSection: http://msdn.microsoft.com/en-us/library/windows/hardware/ff566428%28v=vs.85%29.aspx //#ifdef ITH_WINE enum { DesiredAccess = SECTION_ALL_ACCESS }; //#else // enum { DesiredAccess = GENERIC_ALL }; // jichi 9/25/2013: not sure whhy ITH is usin GENERIC_ALL //#endif // ITH_WINE #define eval (NT_SUCCESS(NtCreateSection(&hSection, DesiredAccess, poa, &s, \ right, SEC_COMMIT, 0)) ? hSection : INVALID_HANDLE_VALUE) HANDLE hSection; LARGE_INTEGER s = {size, 0}; OBJECT_ATTRIBUTES *poa = nullptr; // jichi 9/25/2013: What the fxxx?! poa in the orignal source code of ITH // is pointed to freed object on the stack?! This will crash wine! if (name) { UNICODE_STRING us; RtlInitUnicodeString(&us, name); OBJECT_ATTRIBUTES oa = {sizeof(oa), root_obj, &us,OBJ_OPENIF,0,0}; poa = &oa; return eval; } else return eval; #undef retval } //Create event object. Similar to CreateEvent. HANDLE IthCreateEvent(LPCWSTR name, DWORD auto_reset, DWORD init_state) { #define eval (NT_SUCCESS(NtCreateEvent(&hEvent, EVENT_ALL_ACCESS, poa, auto_reset, init_state)) ? \ hEvent : INVALID_HANDLE_VALUE) HANDLE hEvent; OBJECT_ATTRIBUTES *poa = nullptr; // jichi 9/25/2013: What the fxxx?! poa in the orignal source code of ITH // is pointed to freed object on the stack?! This will crash wine! if (name) { UNICODE_STRING us; RtlInitUnicodeString(&us,name); OBJECT_ATTRIBUTES oa = {sizeof(oa), root_obj, &us, OBJ_OPENIF, 0, 0}; poa = &oa; return eval; } else return eval; #undef eval } HANDLE IthOpenEvent(LPCWSTR name) { UNICODE_STRING us; RtlInitUnicodeString(&us, name); OBJECT_ATTRIBUTES oa = { sizeof(oa), root_obj, &us, 0, 0, 0 }; HANDLE hEvent; return NT_SUCCESS(NtOpenEvent(&hEvent, EVENT_ALL_ACCESS, &oa)) ? hEvent : INVALID_HANDLE_VALUE; } void IthSetEvent(HANDLE hEvent) { NtSetEvent(hEvent, 0); } void IthResetEvent(HANDLE hEvent) { NtClearEvent(hEvent); } //Create mutex object. Similar to CreateMutex. //If 'exist' is not null, it will be written 1 if mutex exist. HANDLE IthCreateMutex(LPCWSTR name, BOOL InitialOwner, DWORD *exist) { #ifdef ITH_ENABLE_WINAPI HANDLE ret = ::CreateMutexW(nullptr, InitialOwner, name); if (exist) *exist = ret == INVALID_HANDLE_VALUE || ::GetLastError() == ERROR_ALREADY_EXISTS; return ret; #else #define eval NtCreateMutant(&hMutex, MUTEX_ALL_ACCESS, poa, InitialOwner) UNICODE_STRING us; HANDLE hMutex; NTSTATUS status; OBJECT_ATTRIBUTES *poa = nullptr; // jichi 9/25/2013: What the fxxx?! poa in the orignal source code of ITH // is pointed to freed object on the stack?! This will crash wine! if (name) { //GROWL(name); RtlInitUnicodeString(&us, name); OBJECT_ATTRIBUTES oa = {sizeof(oa), root_obj, &us, OBJ_OPENIF, 0, 0}; poa = &oa; status = eval; //GROWL_DWORD(status); } else status = eval; if (NT_SUCCESS(status)) { if (exist) *exist = status == STATUS_OBJECT_NAME_EXISTS; return hMutex; } else return INVALID_HANDLE_VALUE; #undef eval #endif // ITH_ENABLE_WINAPI } HANDLE IthOpenMutex(LPCWSTR name) { #ifdef ITH_ENABLE_WINAPI return ::OpenMutexW(MUTEX_ALL_ACCESS, FALSE, name); #else UNICODE_STRING us; RtlInitUnicodeString(&us, name); OBJECT_ATTRIBUTES oa = {sizeof(oa), root_obj, &us, 0, 0, 0}; HANDLE hMutex; if (NT_SUCCESS(NtOpenMutant(&hMutex, MUTEX_ALL_ACCESS, &oa))) return hMutex; else return INVALID_HANDLE_VALUE; #endif // ITH_ENABLE_WINAPI } BOOL IthReleaseMutex(HANDLE hMutex) { return NT_SUCCESS(NtReleaseMutant(hMutex, 0)); } //Create new thread. 'hProc' must have following right. //PROCESS_CREATE_THREAD, PROCESS_VM_OPERATION, PROCESS_VM_READ, PROCESS_VM_WRITE. HANDLE IthCreateThread(LPCVOID start_addr, DWORD param, HANDLE hProc) { HANDLE hThread; // jichi 9/27/2013: NtCreateThread is not implemented in Wine 1.7 if (thread_man_) { // Windows XP // jichi 9/29/2013: Reserved && commit stack size // See: http://msdn.microsoft.com/en-us/library/windows/desktop/aa366803%28v=vs.85%29.aspx // See: http://msdn.microsoft.com/en-us/library/ms810627.aspx enum { DEFAULT_STACK_LIMIT = 0x400000 }; enum { DEFAULT_STACK_COMMIT = 0x10000 }; enum { PAGE_SIZE = 0x1000 }; CLIENT_ID id; LPVOID protect; USER_STACK stack = {}; CONTEXT ctx = {CONTEXT_FULL}; DWORD size = DEFAULT_STACK_LIMIT, commit = DEFAULT_STACK_COMMIT; if (!NT_SUCCESS(NtAllocateVirtualMemory(hProc, &stack.ExpandableStackBottom, 0, &size, MEM_RESERVE, PAGE_READWRITE))) return INVALID_HANDLE_VALUE; stack.ExpandableStackBase = (char *)stack.ExpandableStackBottom + size; stack.ExpandableStackLimit = (char *)stack.ExpandableStackBase - commit; size = PAGE_SIZE; commit += size; protect = (char *)stack.ExpandableStackBase - commit; NtAllocateVirtualMemory(hProc, &protect, 0, &commit, MEM_COMMIT, PAGE_READWRITE); DWORD oldAccess; // jichi 9/29/2013: unused NtProtectVirtualMemory(hProc, &protect, &size, PAGE_READWRITE|PAGE_GUARD, &oldAccess); ctx.SegGs = 0; ctx.SegFs = 0x38; ctx.SegEs = 0x20; ctx.SegDs = 0x20; ctx.SegSs = 0x20; ctx.SegCs = 0x18; ctx.EFlags = 0x3000; ctx.Eip = (DWORD)thread_man_->GetProcAddr(hProc); ctx.Eax = (DWORD)start_addr; ctx.Ecx = ctx.Eip + 0x40; ctx.Edx = 0xffffffff; ctx.Esp = (DWORD)stack.ExpandableStackBase - 0x10; ctx.Ebp = param; // NTSYSAPI // NTSTATUS // NTAPI // NtCreateThread( // _Out_ PHANDLE ThreadHandle, // _In_ ACCESS_MASK DesiredAccess, // _In_ POBJECT_ATTRIBUTES ObjectAttributes, // _In_ HANDLE ProcessHandle, // _Out_ PCLIENT_ID ClientId, // _In_ PCONTEXT ThreadContext, // _In_ PUSER_STACK UserStack, // _In_ BOOLEAN CreateSuspended // ); if (NT_SUCCESS(NtCreateThread( &hThread, // _Out_ PHANDLE ThreadHandle, THREAD_ALL_ACCESS, // _In_ ACCESS_MASK DesiredAccess, nullptr, // _In_ POBJECT_ATTRIBUTES ObjectAttributes, hProc, // _In_ HANDLE ProcessHandle, &id, // _Out_ PCLIENT_ID ClientId, &ctx, // _In_ PCONTEXT ThreadContext, &stack, // _In_ PUSER_STACK UserStack, TRUE // _In_ BOOLEAN CreateSuspended ))) { // On x64 Windows, NtCreateThread in ntdll calls NtCreateThread in ntoskrnl via WOW64, // which maps 32-bit system call to the correspond 64-bit version. // This layer doesn't correctly copy whole CONTEXT structure, so we must set it manually // after the thread is created. // On x86 Windows, this step is not necessary. NtSetContextThread(hThread, &ctx); NtResumeThread(hThread, 0); } else hThread = INVALID_HANDLE_VALUE; } else { // jichi 9/27/2013: CreateRemoteThread works on both Wine and Windows 7 // Use CreateRemoteThread instead // FIXME 10/5/2031: Though sometimes works, CreateRemoteThread randomly crashes on wine. // See: // - http://www.unknowncheats.me/forum/c-and-c/64775-createremotethread-dll-injection.html // - http://source.winehq.org/WineAPI/CreateRemoteThread.html // - http://msdn.microsoft.com/en-us/library/windows/desktop/ms682437%28v=vs.85%29.aspx // HANDLE WINAPI CreateRemoteThread( // _In_ HANDLE hProcess, // _In_ LPSECURITY_ATTRIBUTES lpThreadAttributes, // _In_ SIZE_T dwStackSize, // _In_ LPTHREAD_START_ROUTINE lpStartAddress, // _In_ LPVOID lpParameter, // _In_ DWORD dwCreationFlags, // _Out_ LPDWORD lpThreadId // ); //ITH_TRY { if (hProc == INVALID_HANDLE_VALUE) hProc = GetCurrentProcess(); //DWORD dwThreadId; hThread = CreateRemoteThread( hProc, // _In_ HANDLE hProcess, nullptr, // _In_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 0, // _In_ SIZE_T dwStackSize, (LPTHREAD_START_ROUTINE)start_addr, // _In_ LPTHREAD_START_ROUTINE lpStartAddress, (LPVOID)param, // _In_ LPVOID lpParameter, 0, //STACK_SIZE_PARAM_IS_A_RESERVATION // _In_ DWORD dwCreationFlags, nullptr // _Out_ LPDWORD lpThreadId ); if (!hThread) // jichi: this function returns nullptr instead of -1 hThread = INVALID_HANDLE_VALUE; //} ITH_EXCEPT { // ITH_WARN(L"exception"); // hThread = INVALID_HANDLE_VALUE; //} } /* else { // jichi 9/29/2013: Also work on Wine and Windows 7 // See: http://waleedassar.blogspot.com/2012/06/createremotethread-vs.html CLIENT_ID id; //DWORD size = DEFAULT_STACK_LIMIT, // commit = DEFAULT_STACK_COMMIT; DWORD reserve = 0, commit = 0; // http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Executable%20Images/RtlCreateUserThread.html // NTSYSAPI // NTSTATUS // NTAPI // RtlCreateUserThread( // IN HANDLE ProcessHandle, // IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL, // IN BOOLEAN CreateSuspended, // IN ULONG StackZeroBits, // IN OUT PULONG StackReserved, // IN OUT PULONG StackCommit, // IN PVOID StartAddress, // IN PVOID StartParameter OPTIONAL, // OUT PHANDLE ThreadHandle, // OUT PCLIENT_ID ClientID); if (!NT_SUCCESS(RtlCreateUserThread( hProc, // HANDLE hProcess, nullptr, // IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL, FALSE, // IN BOOLEAN CreateSuspended, 0, // IN ULONG StackZeroBits, &reserve, // IN OUT PULONG StackReserved, &commit, // IN OUT PULONG StackCommit, (LPVOID)start_addr, // IN PVOID StartAddress, (LPVOID)param,// IN PVOID StartParameter OPTIONAL, &hThread, // OUT PHANDLE ThreadHandle, &id // OUT PCLIENT_ID ClientID ))) hThread = INVALID_HANDLE_VALUE; } */ return hThread; } //Query module export table. Return function address if found. //Similar to GetProcAddress DWORD GetExportAddress(DWORD hModule,DWORD hash) { IMAGE_DOS_HEADER *DosHdr; IMAGE_NT_HEADERS *NtHdr; IMAGE_EXPORT_DIRECTORY *ExtDir; UINT uj; char* pcExportAddr,*pcFuncPtr,*pcBuffer; DWORD dwReadAddr,dwFuncAddr,dwFuncName; WORD wOrd; DosHdr = (IMAGE_DOS_HEADER*)hModule; if (IMAGE_DOS_SIGNATURE==DosHdr->e_magic) { dwReadAddr=hModule+DosHdr->e_lfanew; NtHdr=(IMAGE_NT_HEADERS*)dwReadAddr; if (IMAGE_NT_SIGNATURE == NtHdr->Signature) { pcExportAddr = (char*)((DWORD)hModule+ (DWORD)NtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); if (!pcExportAddr) return 0; ExtDir = (IMAGE_EXPORT_DIRECTORY*)pcExportAddr; pcExportAddr = (char*)((DWORD)hModule+(DWORD)ExtDir->AddressOfNames); for (uj = 0; uj < ExtDir->NumberOfNames; uj++) { dwFuncName = *(DWORD *)pcExportAddr; pcBuffer = (char*)((DWORD)hModule+dwFuncName); if (GetHash(pcBuffer) == hash) { pcFuncPtr = (char*)((DWORD)hModule+(DWORD)ExtDir->AddressOfNameOrdinals+(uj*sizeof(WORD))); wOrd = *(WORD*)pcFuncPtr; pcFuncPtr = (char*)((DWORD)hModule+(DWORD)ExtDir->AddressOfFunctions+(wOrd*sizeof(DWORD))); dwFuncAddr = *(DWORD *)pcFuncPtr; return hModule+dwFuncAddr; } pcExportAddr += sizeof(DWORD); } } } return 0; } } // extern "C" // EOF /*__declspec(naked) void normal_asm() { __asm { push ecx push edx mov fs:[0],esp push ebp call eax _terminate: push eax push -2 call dword ptr [NtTerminateThread] } }*/ /* __declspec(naked) void RegToStrAsm() { __asm { mov edx, 8 _cvt_loop: mov eax, ecx and eax, 0xF cmp eax, 0xA jb _below_ten add al,7 _below_ten: add al,0x30 stosw ror ecx,4 dec edx jne _cvt_loop retn } } __declspec(naked) void except_asm() { __asm { mov eax,[esp + 4] xor esi,esi mov ebp,[eax] mov ecx,[esp + 0xC] mov ebx,[ecx + 0xB8] sub esp,0x240 lea edi,[esp + 0x40] mov eax,esp push esi push 0x1C push eax push esi push ebx push -1 call dword ptr [NtQueryVirtualMemory] test eax,eax jne _terminate mov eax,esp push eax push 0x200 push edi push 2 push ebx push -1 call dword ptr [NtQueryVirtualMemory] test eax,eax jne _terminate pop esi xadd edi,esi std mov al,0x5C repen scasw mov word ptr [edi + 2], 0x3A mov ecx,ebx sub ecx,[esp] call RegToStrAsm inc edi inc edi xchg esi,edi mov ecx,ebp call RegToStrAsm inc edi inc edi xor eax,eax mov [edi + 0x10], eax push 0 push edi push esi push 0 call dword ptr [MessageBoxW] or eax, -1 jmp _terminate } } //Prompt for file name. HANDLE IthPromptCreateFile(DWORD option, DWORD share, DWORD disposition) { OPENFILENAME ofn = {sizeof(ofn)}; // common dialog box structure WCHAR szFile[MAX_PATH]; // buffer for file name wcscpy(current_dir,L"ITH_export.txt"); wcscpy(szFile,file_path); //szFile[0]=0; ofn.lpstrFile = szFile + 4; ofn.nMaxFile = MAX_PATH; ofn.lpstrFilter = L"Text\0*.txt"; BOOL result; if (disposition==FILE_OPEN) result=GetOpenFileName(&ofn); else result=GetSaveFileName(&ofn); if (result) { LPWSTR s=szFile+wcslen(szFile) - 4; if (_wcsicmp(s,L".txt")!=0) wcscpy(s + 4,L".txt"); return IthCreateFileFullPath(szFile,option,share,disposition); } else return INVALID_HANDLE_VALUE; } */