pid_t fork(void) { NTSTATUS nErrCode; CONTEXT ctxThreadContext; HANDLE hProcess; HANDLE hThread; INITIAL_TEB itInitialTeb; CLIENT_ID ciClientId; MEMORY_BASIC_INFORMATION mbiStackInfo; THREAD_BASIC_INFORMATION tbiThreadInfo; struct __tagcsrmsg{ PORT_MESSAGE PortMessage; struct CSRSS_MESSAGE CsrssMessage; PROCESS_INFORMATION ProcessInformation; CLIENT_ID Debugger; ULONG CreationFlags; ULONG VdmInfo[2]; } csrmsg; /* STEP 1: Duplicate current process */ nErrCode = NtCreateProcess ( &hProcess, PROCESS_ALL_ACCESS, NULL, NtCurrentProcess(), TRUE, 0, 0, 0 ); /* failure */ if(!NT_SUCCESS(nErrCode)) { ERR("NtCreateProcess() failed with status 0x%08X\n", nErrCode); goto fail; } /* STEP 2: Duplicate current thread */ /* 2.1: duplicate registers */ ctxThreadContext.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS | CONTEXT_FLOATING_POINT; /* get the current thread's registers */ nErrCode = NtGetContextThread(NtCurrentThread(), &ctxThreadContext); /* failure */ if(!NT_SUCCESS(nErrCode)) { ERR("NtGetContextThread() failed with status 0x%08X\n", nErrCode); goto cleanup_and_fail; } /* redirect the child process to the child_branch label (see 4.3 below) */ ctxThreadContext.Eip = (ULONG)&&child_branch; /* 2.2: duplicate stack */ /* get stack base and size */ nErrCode = NtQueryVirtualMemory ( NtCurrentProcess(), (PVOID)ctxThreadContext.Esp, MemoryBasicInformation, &mbiStackInfo, sizeof(mbiStackInfo), 0 ); /* failure */ if(!NT_SUCCESS(nErrCode)) { ERR("NtQueryVirtualMemory() failed with status 0x%08X\n", nErrCode); goto cleanup_and_fail; } itInitialTeb.StackCommit = 0; itInitialTeb.StackReserve = 0; itInitialTeb.StackBase = (PVOID)((ULONG)(mbiStackInfo.BaseAddress) + mbiStackInfo.RegionSize); itInitialTeb.StackLimit = mbiStackInfo.BaseAddress; itInitialTeb.StackAllocate = mbiStackInfo.AllocationBase; /* 2.3: create duplicate thread */ nErrCode = NtCreateThread ( &hThread, THREAD_ALL_ACCESS, NULL, hProcess, (CLIENT_ID *)&ciClientId, &ctxThreadContext, &itInitialTeb, TRUE ); /* failure */ if(!NT_SUCCESS(nErrCode)) { ERR("NtCreateThread() failed with status 0x%08X\n", nErrCode); goto cleanup_and_fail; } /* 2.4: duplicate the TEB */ /* store the client id in the child thread's stack (see 4.3b) */ nErrCode = NtWriteVirtualMemory ( hProcess, &ciClientId, &ciClientId, sizeof(ciClientId), 0 ); /* failure */ if(!NT_SUCCESS(nErrCode)) { ERR("NtWriteVirtualMemory() failed with status 0x%08X\n", nErrCode); goto cleanup_and_fail; } /* get the child thread's TEB base */ nErrCode = NtQueryInformationThread ( hThread, ThreadBasicInformation, &tbiThreadInfo, sizeof(tbiThreadInfo), 0 ); /* failure */ if(!NT_SUCCESS(nErrCode)) { ERR("NtQueryInformationThread() failed with status 0x%08X\n", nErrCode); goto cleanup_and_fail; } /* copy the TEB */ nErrCode = NtWriteVirtualMemory ( hProcess, tbiThreadInfo.TebBaseAddress, NtCurrentTeb(), sizeof(TEB), 0 ); /* failure */ if(!NT_SUCCESS(nErrCode)) { ERR("NtWriteVirtualMemory() failed with status 0x%08X\n", nErrCode); goto cleanup_and_fail; } /* STEP 3: Call Win32 subsystem */ memset(&csrmsg, 0, sizeof(csrmsg)); csrmsg.ProcessInformation.hProcess = hProcess; csrmsg.ProcessInformation.hThread = hThread; csrmsg.ProcessInformation.dwProcessId = (DWORD)ciClientId.UniqueProcess; csrmsg.ProcessInformation.dwThreadId = (DWORD)ciClientId.UniqueThread; nErrCode = CsrClientCallServer(&csrmsg, 0, 0x10000, 0x24); /* failure */ if(!NT_SUCCESS(nErrCode)) { ERR("CsrClientCallServer() failed with status 0x%08X\n", nErrCode); goto cleanup_and_fail; } /* STEP 4: Finalization */ /* 4.1: resume thread */ nErrCode = NtResumeThread(hThread, 0); /* 4.2: close superfluous handles */ NtClose(hProcess); NtClose(hThread); /* 4.3: (parent) return the child process id */ return ((pid_t)(ciClientId.UniqueProcess)); /* 4.3b: (child) cleanup and return 0 */ child_branch: /* restore the thread and process id in the TEB */ memcpy(&NtCurrentTeb()->Cid, &ciClientId, sizeof(ciClientId)); /* return 0 */ return (0); cleanup_and_fail: NtTerminateProcess(hProcess, nErrCode); fail: errno = __status_to_errno(nErrCode); return (-1); }
/*********************************************************************** * GetThreadContext [KERNEL32.@] Retrieves context of thread. * * RETURNS * Success: TRUE * Failure: FALSE */ BOOL WINAPI GetThreadContext( HANDLE handle, /* [in] Handle to thread with context */ CONTEXT *context ) /* [out] Address of context structure */ { NTSTATUS status = NtGetContextThread( handle, context ); if (status) SetLastError( RtlNtStatusToDosError(status) ); return !status; }
NTSTATUS ModifySelfSizeOfImage(LPWSTR ExeFullPath, LPWSTR CommandLine, ULONG SizeOfImage) { BOOL Result; ULONG Length; PVOID FakeCPInfoBuffer; WCHAR CmdFullPath[MAX_NTPATH]; PWCHAR CmdLineBuffer; NTSTATUS Status; PLDR_MODULE LdrModule; PIMAGE_DOS_HEADER DosHeader; PIMAGE_NT_HEADERS NtHeader; PIMAGE_SECTION_HEADER SectionHeader; FAKE_CREATE_PROCESS_INFO *fcpi; PROCESS_INFORMATION ProcessInformation; CONTEXT Context; NtFileDisk file; UNICODE_STRING ExeNtPath, *ProcessCommandLine; UNREFERENCED_PARAMETER(CommandLine); LdrModule = Nt_FindLdrModuleByName(NULL); DosHeader = (PIMAGE_DOS_HEADER)&__ImageBase; NtHeader = (PIMAGE_NT_HEADERS)((ULONG_PTR)DosHeader + DosHeader->e_lfanew); fcpi = (FAKE_CREATE_PROCESS_INFO *)AllocStack(0x2000); fcpi->PeHeaderSize = (ULONG_PTR)(IMAGE_FIRST_SECTION(NtHeader) + NtHeader->FileHeader.NumberOfSections) - (ULONG_PTR)DosHeader; Status = file.Open(LdrModule->FullDllName.Buffer); if (!NT_SUCCESS(Status)) return Status; Status = file.Read(fcpi->PeHeader, fcpi->PeHeaderSize); if (!NT_SUCCESS(Status)) return Status; CmdLineBuffer = (PWCHAR)((ULONG_PTR)fcpi->PeHeader + fcpi->PeHeaderSize); fcpi->CommandLine.Buffer = CmdLineBuffer; fcpi->CommandLine.Length = (USHORT)(StrLengthW(ExeFullPath) * sizeof(WCHAR)); ProcessCommandLine = &Nt_CurrentPeb()->ProcessParameters->CommandLine; CopyMemory(CmdLineBuffer, ProcessCommandLine->Buffer, ProcessCommandLine->Length); *(PULONG_PTR)&CmdLineBuffer += ProcessCommandLine->Length; CmdLineBuffer[0] = 0; fcpi->CommandLine.Length = ProcessCommandLine->Length; fcpi->CommandLine.MaximumLength = fcpi->CommandLine.Length + sizeof(WCHAR); ++CmdLineBuffer; CmdLineBuffer = (PWCHAR)ROUND_UP((ULONG_PTR)CmdLineBuffer, 16); RtlDosPathNameToNtPathName_U(LdrModule->FullDllName.Buffer, &ExeNtPath, NULL, NULL); fcpi->ExeNtPath.Buffer = CmdLineBuffer; CopyMemory(CmdLineBuffer, ExeNtPath.Buffer, ExeNtPath.Length); *(PULONG_PTR)&CmdLineBuffer += ExeNtPath.Length; CmdLineBuffer[0] = 0; fcpi->ExeNtPath.Length = ExeNtPath.Length; fcpi->ExeNtPath.MaximumLength = fcpi->ExeNtPath.Length + sizeof(WCHAR); *CmdLineBuffer++ = 0; RtlFreeUnicodeString(&ExeNtPath); DosHeader = (PIMAGE_DOS_HEADER)fcpi->PeHeader; NtHeader = (PIMAGE_NT_HEADERS)((ULONG_PTR)DosHeader + DosHeader->e_lfanew); SectionHeader = IMAGE_FIRST_SECTION(NtHeader); SectionHeader += NtHeader->FileHeader.NumberOfSections - 1; SizeOfImage -= LdrModule->SizeOfImage; SizeOfImage = ROUND_UP(SizeOfImage, MEMORY_PAGE_SIZE); SectionHeader->Misc.VirtualSize = ROUND_UP(SectionHeader->Misc.VirtualSize, MEMORY_PAGE_SIZE) + SizeOfImage; if (NtHeader->FileHeader.SizeOfOptionalHeader > FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, SizeOfImage) + RTL_FIELD_SIZE(IMAGE_OPTIONAL_HEADER, SizeOfImage)) NtHeader->OptionalHeader.SizeOfImage += SizeOfImage; Length = Nt_GetSystemDirectory(CmdFullPath, countof(CmdFullPath)); StrCopyW(CmdFullPath + Length, L"cmd.exe"); ProcessInformation.hProcess = NtCurrentProcess(); ProcessInformation.hThread = NtCurrentThread(); #if 1 Result = Nt_CreateProcess(NULL, CmdFullPath, NULL, CREATE_SUSPENDED, NULL, &ProcessInformation); if (!Result) return STATUS_UNSUCCESSFUL; #endif FakeCPInfoBuffer = NULL; LOOP_ONCE { ULONG_PTR Offset; Status = NtDuplicateObject( NtCurrentProcess(), NtCurrentProcess(), ProcessInformation.hProcess, &fcpi->ProcessHandle, 0, 0, DUPLICATE_SAME_ACCESS ); if (!NT_SUCCESS(Status)) break; /* Status = NtDuplicateObject( NtCurrentProcess(), file, ProcessInformation.hProcess, &fcpi->FileHandle, 0, 0, DUPLICATE_SAME_ACCESS ); if (!NT_SUCCESS(Status)) break; */ Status = Nt_AllocateMemory(ProcessInformation.hProcess, &FakeCPInfoBuffer, MEMORY_PAGE_SIZE); if (!NT_SUCCESS(Status)) break; fcpi->CreateProcessInternalW = CreateProcessInternalW; fcpi->NtTerminateProcess = NtTerminateProcess; fcpi->LdrShutdownProcess = LdrShutdownProcess; fcpi->NtCreateFile = NtCreateFile; fcpi->NtWriteFile = NtWriteFile; fcpi->NtClose = NtClose; fcpi->NtWaitForSingleObject = NtWaitForSingleObject; fcpi->InitialDirectory.Buffer = NULL; Offset = (ULONG_PTR)FakeCPInfoBuffer - (ULONG_PTR)fcpi; *(PULONG_PTR)&fcpi->CommandLine.Buffer += Offset; *(PULONG_PTR)&fcpi->ExeNtPath.Buffer += Offset; Status = Nt_WriteMemory( ProcessInformation.hProcess, FakeCPInfoBuffer, fcpi, (ULONG_PTR)CmdLineBuffer - (ULONG_PTR)fcpi, &Length ); if (!NT_SUCCESS(Status)) break; Context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; Status = NtGetContextThread(ProcessInformation.hThread, &Context); if (!NT_SUCCESS(Status)) break; Context.Eip = (ULONG_PTR)FakeCPInfoBuffer + Length; Context.Eip = ROUND_UP(Context.Eip, 16); Context.Ecx = (ULONG_PTR)FakeCPInfoBuffer; Status = Nt_WriteMemory( ProcessInformation.hProcess, (PVOID)Context.Eip, ModifySizeOfImage, (ULONG_PTR)ModifySizeOfImageEnd - (ULONG_PTR)ModifySizeOfImage, &Length ); if (!NT_SUCCESS(Status)) break; #if 1 Status = NtSetContextThread(ProcessInformation.hThread, &Context); if (!NT_SUCCESS(Status)) break; Status = NtResumeThread(ProcessInformation.hThread, NULL); #else INLINE_ASM jmp Context.Eip; #endif } if (!NT_SUCCESS(Status)) { if (FakeCPInfoBuffer != NULL) Nt_FreeMemory(ProcessInformation.hProcess, FakeCPInfoBuffer); NtTerminateProcess(ProcessInformation.hProcess, 0); } NtClose(ProcessInformation.hProcess); NtClose(ProcessInformation.hThread); return Status; }
ULONG fork () { LONG i; PULONG Foo; NTSTATUS status; HANDLE CurrentProcessHandle; HANDLE ProcessHandle; CONTEXT ThreadContext; CLIENT_ID Cid1; HANDLE Thread1; LARGE_INTEGER DelayTime; INITIAL_TEB Teb; CurrentProcessHandle = NtCurrentProcess(); DbgPrint("creating new process\n"); status = NtCreateProcess( &ProcessHandle, PROCESS_ALL_ACCESS, //DesiredAccess, NULL, //ObjectAttributes, CurrentProcessHandle, //ParentProcess TRUE, //InheritObjectTable, NULL, //SectionHandle NULL, //DebugPort OPTIONAL, NULL //ExceptionPort OPTIONAL ); DbgPrint("status from create process %lx\n",status); if (!NT_SUCCESS(status)) { return 0; } ThreadContext.ContextFlags = CONTEXT_FULL; status = NtGetContextThread (NtCurrentThread(), &ThreadContext); DbgPrint("status from get context %lx\n",status); if (status == 0) { #ifdef i386 ThreadContext.Eax = 0x7777; ThreadContext.Esp -= 0x18; Foo = (PULONG)ThreadContext.Esp; DbgPrint("stack value is %lx\n",*Foo); #endif #ifdef MIPS ThreadContext.IntV0 = 0x7777; #endif status = NtCreateThread( &Thread1, THREAD_ALL_ACCESS, NULL, ProcessHandle, &Cid1, &ThreadContext, &Teb, FALSE ); // DelayTime.HighPart = -1; // DelayTime.LowPart = 0; // NtDelayExecution (FALSE, &DelayTime); return 0; } else { ProcessNumber += ProcessNumber; return ProcessNumber; } }
int GetContext( VDMCONTEXT* lpContext ) { #ifndef i386 // int mode; ULONG pTmp; NT_CPU_INFO nt_cpu_info; BOOL b; BOOL bInNano; ULONG UMask; pTmp = (ULONG)EXPRESSION("ntvdm!nt_cpu_info"); if ( pTmp ) { b = READMEM((LPVOID) pTmp, &nt_cpu_info, sizeof(NT_CPU_INFO)); if ( !b ) { PRINTF("Could not read IntelRegisters context out of process\n"); return( -1 ); } bInNano = ReadDwordSafe((ULONG) nt_cpu_info.in_nano_cpu); UMask = ReadDwordSafe((ULONG) nt_cpu_info.universe); lpContext->Eax = GetRegValue(nt_cpu_info.eax, bInNano, UMask); lpContext->Ecx = GetRegValue(nt_cpu_info.ecx, bInNano, UMask); lpContext->Edx = GetRegValue(nt_cpu_info.edx, bInNano, UMask); lpContext->Ebx = GetRegValue(nt_cpu_info.ebx, bInNano, UMask); lpContext->Ebp = GetRegValue(nt_cpu_info.ebp, bInNano, UMask); lpContext->Esi = GetRegValue(nt_cpu_info.esi, bInNano, UMask); lpContext->Edi = GetRegValue(nt_cpu_info.edi, bInNano, UMask); lpContext->Esp = GetEspValue(nt_cpu_info, bInNano); lpContext->EFlags = ReadDwordSafe(nt_cpu_info.flags); lpContext->Eip = ReadDwordSafe(nt_cpu_info.eip); lpContext->SegEs = ReadWordSafe(nt_cpu_info.es); lpContext->SegCs = ReadWordSafe(nt_cpu_info.cs); lpContext->SegSs = ReadWordSafe(nt_cpu_info.ss); lpContext->SegDs = ReadWordSafe(nt_cpu_info.ds); lpContext->SegFs = ReadWordSafe(nt_cpu_info.fs); lpContext->SegGs = ReadWordSafe(nt_cpu_info.gs); } else { PRINTF("Could not find the symbol 'ntvdm!nt_cpu_info'\n"); return( -1 ); } if ( !(ReadDwordSafe(nt_cpu_info.cr0) & 1) ) { mode = V86_MODE; } else { mode = PROT_MODE; } return( mode ); #else // NTSTATUS rc; BOOL b; ULONG EFlags; WORD cs; int mode; ULONG lpVdmTib; lpContext->ContextFlags = CONTEXT_FULL; rc = NtGetContextThread( hCurrentThread, lpContext ); if ( NT_ERROR(rc) ) { PRINTF( "bde.k: Could not get current threads context - status = %08lX\n", rc ); return( -1 ); } /* ** Get the 16-bit registers from the context */ cs = (WORD)lpContext->SegCs; EFlags = lpContext->EFlags; // BUGBUG We don't seem to be setting v86 mode correctly on x86. // if ( EFlags & V86_BITS ) { /* ** V86 Mode */ mode = V86_MODE; } else { if ( (cs & RPL_MASK) != KGDT_R3_CODE ) { mode = PROT_MODE; } else { /* ** We are in flat 32-bit address space! */ lpVdmTib = (ULONG)EXPRESSION("ntvdm!VdmTib"); if ( !lpVdmTib ) { PRINTF("Could not find the symbol 'VdmTib'\n"); return( -1 ); } b = READMEM((LPVOID)(lpVdmTib+FIELD_OFFSET(VDM_TIB,VdmContext)), lpContext, sizeof(VDMCONTEXT)); if ( !b ) { PRINTF("Could not read IntelRegisters context out of process\n"); return( -1 ); } EFlags = lpContext->EFlags; if ( EFlags & V86_BITS ) { mode = V86_MODE; } else { mode = PROT_MODE; } } } return( mode ); #endif }
VOID SetThreadFields( PSYSTEM_THREAD_INFORMATION ThreadInfo, HWND hwnd ) { TIME_FIELDS UserTime; TIME_FIELDS KernelTime; TIME_FIELDS RunTime; LARGE_INTEGER Time; CHAR TimeString[15]; CHAR StartString[32]; HANDLE hThread; CONTEXT ThreadContext; NTSTATUS Status; OBJECT_ATTRIBUTES Obja; ULONG PcValue; // // Display the selected thread information // // // Compute runtimes // RtlTimeToTimeFields ( &ThreadInfo->UserTime, &UserTime); RtlTimeToTimeFields ( &ThreadInfo->KernelTime, &KernelTime); RtlTimeToTimeFields ( &ThreadInfo->UserTime, &UserTime); RtlTimeToTimeFields ( &ThreadInfo->KernelTime, &KernelTime); Time.QuadPart = RefreshTimeOfDayInfo.CurrentTime.QuadPart - ThreadInfo->CreateTime.QuadPart; RtlTimeToTimeFields ( &Time, &RunTime); wsprintf(TimeString,"%3ld:%02ld:%02ld.%03ld", RunTime.Hour, RunTime.Minute, RunTime.Second, RunTime.Milliseconds ); SetDlgItemText( hwnd, PXPLODE_THREADELAPSED_TIME, TimeString ); wsprintf(TimeString,"%3ld:%02ld:%02ld.%03ld", UserTime.Hour, UserTime.Minute, UserTime.Second, UserTime.Milliseconds ); SetDlgItemText( hwnd, PXPLODE_THREADUSER_TIME, TimeString ); wsprintf(TimeString,"%3ld:%02ld:%02ld.%03ld", KernelTime.Hour, KernelTime.Minute, KernelTime.Second, KernelTime.Milliseconds ); SetDlgItemText( hwnd, PXPLODE_THREADKERNEL_TIME, TimeString ); wsprintf(StartString,"0x%08lx", ThreadInfo->StartAddress ); SetDlgItemText( hwnd, PXPLODE_THREAD_START, StartString ); // // Do the priority Group // SetDlgItemInt( hwnd, PXPLODE_THREAD_DYNAMIC, ThreadInfo->Priority, FALSE ); switch ( ThreadInfo->BasePriority - DlgProcessInfo->BasePriority ) { case 2: CheckRadioButton( hwnd, PXPLODE_THREAD_HIGHEST, PXPLODE_THREAD_LOWEST, PXPLODE_THREAD_HIGHEST ); break; case 1: CheckRadioButton( hwnd, PXPLODE_THREAD_HIGHEST, PXPLODE_THREAD_LOWEST, PXPLODE_THREAD_ABOVE ); break; case -1: CheckRadioButton( hwnd, PXPLODE_THREAD_HIGHEST, PXPLODE_THREAD_LOWEST, PXPLODE_THREAD_BELOW ); break; case -2: CheckRadioButton( hwnd, PXPLODE_THREAD_HIGHEST, PXPLODE_THREAD_LOWEST, PXPLODE_THREAD_LOWEST ); break; case 0: default: CheckRadioButton( hwnd, PXPLODE_THREAD_HIGHEST, PXPLODE_THREAD_LOWEST, PXPLODE_THREAD_NORMAL ); break; } // // Complete thread information // SetDlgItemInt( hwnd, PXPLODE_THREAD_SWITCHES, ThreadInfo->ContextSwitches, FALSE ); PcValue = 0; InitializeObjectAttributes(&Obja, NULL, 0, NULL, NULL); Status = NtOpenThread( &hThread, THREAD_GET_CONTEXT, &Obja, &ThreadInfo->ClientId ); if ( NT_SUCCESS(Status) ) { ThreadContext.ContextFlags = CONTEXT_CONTROL; Status = NtGetContextThread(hThread,&ThreadContext); NtClose(hThread); if ( NT_SUCCESS(Status) ) { PcValue = (ULONG) CONTEXT_TO_PROGRAM_COUNTER(&ThreadContext); } } if ( PcValue ) { wsprintf(StartString,"0x%08lx", PcValue ); SetDlgItemText( hwnd, PXPLODE_THREAD_PC, StartString ); } else { SetDlgItemText( hwnd, PXPLODE_THREAD_PC, "Unknown" ); } // // Disable the thread buttons if we can't get at the thread or it's token // { HANDLE Thread; HANDLE Token; BOOL ThreadOK = FALSE; BOOL GotToken = FALSE; Thread = OpenThread(MAXIMUM_ALLOWED, FALSE, (DWORD)ThreadInfo->ClientId.UniqueThread); if (Thread != NULL) { ThreadOK = TRUE; if (OpenThreadToken(Thread, MAXIMUM_ALLOWED, TRUE, &Token)) { GotToken = TRUE; CloseHandle(Token); } CloseHandle(Thread); } EnableWindow(GetDlgItem(hwnd, PXPLODE_THREAD_ACL), ThreadOK); EnableWindow(GetDlgItem(hwnd, PXPLODE_THREAD_TOKEN), GotToken); EnableWindow(GetDlgItem(hwnd, PXPLODE_THREAD_TOKEN_ACL), GotToken); } }
NTSTATUS InjectSelfToRemoteProcess(HANDLE hProcess, HANDLE hThread) { NTSTATUS Status; PVOID pvBuffer; DWORD Length; WCHAR szSelfPath[MAX_PATH]; CONTEXT ThreadContext; LARGE_INTEGER TimeOut; INJECT_DLL_CURRENT_THREAD inj; ThreadContext.ContextFlags = CONTEXT_CONTROL; Status = NtGetContextThread(hThread, &ThreadContext); if (!NT_SUCCESS(Status)) { // BaseSetLastNTError(Status); // PrintError(RtlGetLastWin32Error()); return Status; } // PrintConsoleW(L"Eip = %08X\n", ThreadContext.Eip); // getch(); Length = Nt_GetExeDirectory(szSelfPath, countof(szSelfPath)); if (Length == NULL) return STATUS_UNSUCCESSFUL; static WCHAR szDll[] = L"LocaleEmulator.dll"; StrCopyW(szSelfPath + Length, szDll); Length += CONST_STRLEN(szDll); pvBuffer = NULL; Status = Nt_AllocateMemory(hProcess, &pvBuffer, MEMORY_PAGE_SIZE); if (!NT_SUCCESS(Status)) { // BaseSetLastNTError(Status); // PrintError(RtlGetLastWin32Error()); return Status; } Length *= sizeof(WCHAR); inj.pfLdrLoadDll = LdrLoadDll; inj.ReturnAddr = ThreadContext.Eip; inj.ModuleFileName.Length = Length; inj.ModuleFileName.MaximumLength = Length + sizeof(WCHAR); inj.ModuleFileName.Buffer = (LPWSTR)((ULONG_PTR)pvBuffer + sizeof(inj)); Status = STATUS_UNSUCCESSFUL; LOOP_ONCE { Status = Nt_WriteMemory(hProcess, pvBuffer, &inj, sizeof(inj)); if (!NT_SUCCESS(Status)) break; Length += sizeof(WCHAR); Status = Nt_WriteMemory(hProcess, (PVOID)((ULONG_PTR)pvBuffer + sizeof(inj)), szSelfPath, Length); if (!NT_SUCCESS(Status)) break; ThreadContext.Eip = (DWORD)(PBYTE)pvBuffer + sizeof(inj) + Length; Status = Nt_WriteMemory( hProcess, (PVOID)ThreadContext.Eip, LoadExternDll, (ULONG_PTR)_LoadExternDllEnd - (ULONG_PTR)LoadExternDll ); if (!NT_SUCCESS(Status)) break; Status = NtSetContextThread(hThread, &ThreadContext); if (!NT_SUCCESS(Status)) break; Status = NtResumeThread(hThread, NULL); if (!NT_SUCCESS(Status)) break; BaseFormatTimeOut(&TimeOut, 500); for (DWORD TryTimes = 30; TryTimes; --TryTimes) { DWORD Val; Status = Nt_ReadMemory(hProcess, pvBuffer, &Val, sizeof(Val)); if (!NT_SUCCESS(Status)) break; if (Val != 0) { NtDelayExecution(FALSE, &TimeOut); continue; } break; } if (!NT_SUCCESS(Status)) break; NtDelayExecution(FALSE, &TimeOut); Status = NtGetContextThread(hThread, &ThreadContext); if (!NT_SUCCESS(Status)) break; if ((ULONG_PTR)ThreadContext.Eip < (ULONG_PTR)pvBuffer || (ULONG_PTR)ThreadContext.Eip > (ULONG_PTR)pvBuffer + MEMORY_PAGE_SIZE) { Status = STATUS_SUCCESS; } else { Status = STATUS_UNSUCCESSFUL; } } // BaseSetLastNTError(Status); // PrintError(RtlGetLastWin32Error()); // Nt_FreeMemory(hProcess, pvBuffer); return Status; }