home *** CD-ROM | disk | FTP | other *** search
Wrap
;------------------------------------------------------------------------------- ;Creates remote thread in the process specified by procID and which handle ;is in EBX register. ;Returns ApiHooks ErrorCodes. RemoteExecNT PROC USES ESI, procID, ExpTime, lpBlock, BlockSize, lpCodeEnd LOCAL ThreadStack: DWORD LOCAL tbi :THREAD_BASIC_INFORMATION LOCAL hThreadTIDField[MAX_HTIDTHREAD*2+1] :HANDLE ;Suspend all threads in the target --- AND ThreadStack, 0 LEA ESI, hThreadTIDField ;of course there's no need to find a suitable thread ;just suspend all threads sWin32 FindThread, THREAD_SUSPEND_RESUME OR THREAD_GET_CONTEXT OR \ THREAD_SET_CONTEXT OR \ ; THREAD_SET_INFORMATION OR \ THREAD_QUERY_INFORMATION,\ FALSE,\ procID,\ ESI TEST EAX, EAX PUSH ErrorRemoteExec JE REFailed ;------------------------------------- PUSH EDI MOV ESI, NTThreadExit MOV EDI, lpCodeEnd MOVSD ;copy end sequence at CodeEnd MOVSD MOVSD POP EDI ;write it to the process iWin32 WriteProcessMemory, EBX, EDI, lpBlock, BlockSize, NULL TEST EAX, EAX JE REFailure ;can't write ;I'm not using CreateRemoteThread because it is too hilevel. It requires ;KERNEL32.dll to be present in the target. Moreover when are all csrss.exe's ;threads suspended, CRT never returns (hangs OS). PUSH EAX ;place for thread handle MOV EDX, ESP sWin32 RtlCreateUserThread, EBX, NULL, TRUE,\ ;TRUE == suspended NULL, NULL, NULL,\ EDI, NULL, EDX, NULL TEST EAX, EAX POP ESI ;hThread JL REFailure ;native api returned NTSTATUS -> check for signum bit if failed ;get remote thread's stack memory LEA ECX, tbi sWin32 NtQueryInformationThread, ESI, ThreadBasicInformation, ECX, SIZEOF tbi, 0 TEST EAX, EAX JL @F ;native api returned NTSTATUS MOV EAX, tbi.TebBaseAddress TEST EAX, EAX JE @F LEA ECX, ThreadStack ;read it here ADD EAX, TEB.ThreadStack iWin32 ReadProcessMemory, EBX, EAX, ECX, 4, NULL @@: iWin32 ResumeThread, ESI ;go on iWin32 WaitForSingleObject, ESI, ExpTime CMP EAX, WAIT_TIMEOUT JNE @F oMOV [ESP], ErrorTimeOut JMP REFailureClose @@: LEA ECX, tbi ;do GetExitCodeThread: sWin32 NtQueryInformationThread, ESI, ThreadBasicInformation, ECX, SIZEOF tbi, 0 oMOV [ESP], tbi.ExitStatus REFailureClose: iWin32 CloseHandle, ESI REFailure: ;Desuspend and close all threads --- LEA ESI, hThreadTIDField PUSH ESI sWin32 DeSuspend, ESI, -1 POP ESI REFailed: LODSD TEST EAX, EAX JE ThreadsClosed iWin32 CloseHandle, EAX LODSD JMP REFailed ThreadsClosed: ;----------------------------------- CMP DWORD PTR [ESP], ErrorTimeOut ;if there was timeout let it be JE @F ;and don't free anything MOV ECX, ThreadStack JECXZ DontFree sWin32 RemoteFreeNT, ECX ;free remote thread stack in target DontFree: RemFree: sWin32 RemoteFreeNT, EDI ;free allocated memory in target TEST EAX, EAX JNE @F CMP DWORD PTR [ESP], ErrorSuccess ;evaluate error code JNE @F oMOV [ESP], ErrorRemoteFree @@: POP EAX RET RemoteExecNT ENDP ;------------------------------------------------------------------------------- ;structure shorter than CONTEXT for saving memory: _CONTEXT STRUCT ContextFlags DWORD ? iDr0 DWORD ? iDr1 DWORD ? iDr2 DWORD ? iDr3 DWORD ? iDr6 DWORD ? iDr7 DWORD ? FloatSave FLOATING_SAVE_AREA <> regGs DWORD ? regFs DWORD ? regEs DWORD ? regDs DWORD ? regEdi DWORD ? regEsi DWORD ? regEbx DWORD ? regEdx DWORD ? regEcx DWORD ? regEax DWORD ? regEbp DWORD ? regEip DWORD ? regCs DWORD ? regFlag DWORD ? regEsp DWORD ? regSs DWORD ? ;ExtendedRegisters BYTE MAXIMUM_SUPPORTED_EXTENSION DUP (?) _CONTEXT ENDS ;------------------------------------------------------------------------------- ;Performs 'riding on the thread' of process specified by procID and which handle ;is in EBX register. ;Returns ApiHooks ErrorCodes. RemoteExec9x PROC USES ESI, procID, ExpTime, lpBlock, BlockSize, lpCodeEnd LOCAL ErrVal :DWORD LOCAL SuspCnt:DWORD LOCAL TID :DWORD LOCAL MyTime :DWORD LOCAL MyProcessPriority :DWORD LOCAL MyThreadPriority :DWORD LOCAL hThreadTIDField[MAX_HTIDTHREAD*2+1] :HANDLE ;array of handles and tids LOCAL mcontext :_CONTEXT LOCAL context :_CONTEXT ;initialize local variables SUB EAX, EAX oMOV ErrVal, ErrorRemoteExec AND MyProcessPriority, EAX MOV MyThreadPriority, THREAD_PRIORITY_ERROR_RETURN oMOV MyTime, ExpTime LEA ESI, hThreadTIDField sWin32 FindThread, THREAD_SUSPEND_RESUME OR THREAD_GET_CONTEXT OR \ THREAD_SET_CONTEXT OR THREAD_QUERY_INFORMATION,\ EAX,\ ;null inheritance procID,\ ESI ;array TEST EAX, EAX JE Re9xFailed ;can't find thread suitable for riding on -> fail MOV TID, ECX ;returned thread id in ECX MOV ESI, EAX ;thread handle iWin32 SuspendThread, EAX ;get suspend count MOV SuspCnt, EAX INC EAX JNE @F oMOV SuspCnt, MAXIMUM_SUSPEND_COUNT ;if suspension fails, assume max_susp_count @@: iWin32 ResumeThread, ESI ;restore suspend count MOV EAX, lpCodeEnd MOV WORD PTR [EAX], 0FEEBH ;put JMP $ at the end of remote code ;in EBX is target process handle ;write remote block to the process iWin32 WriteProcessMemory, EBX, EDI, lpBlock, BlockSize, NULL TEST EAX, EAX JE @F ;===================================== ;JMP $ at the end of remote code requires my and target process and ;thread priorities to be equal. If my prioirities would be less I ;couldn't control the target thread ;adjust my process priority according to target process' priority iWin32 GetPriorityClass, EBX ;get target's priority TEST EAX, EAX JE @F ;can't get priority -> fail PUSH EAX iWin32 GetPriorityClass, CurrentProcess ;get this process priority TEST EAX, EAX POP EDX ;TargetProcessPriority JE @F ;can't get priority -> fail CMP EAX, EDX ;compare process priorities JE ThrPri ;if equal compare thread priorities MOV MyProcessPriority, EAX iWin32 SetPriorityClass, CurrentProcess, EDX TEST EAX, EAX @@: JE Re9xClose ;adjust my thread priority according to target thread's priority ThrPri: iWin32 GetThreadPriority, ESI CMP EAX, MyThreadPriority ;== THREAD_PRIORITY_ERROR_RETURN JE @F ;can't get priority -> fail PUSH EAX iWin32 GetThreadPriority, CurrentThread CMP EAX, MyThreadPriority ;== THREAD_PRIORITY_ERROR_RETURN POP EDX ;TargetThreadPriority JE @F ;can't get priority -> fail CMP EAX, EDX JE WakeUp MOV MyThreadPriority, EAX iWin32 SetThreadPriority, CurrentThread, EDX TEST EAX, EAX @@: JE RetProcessPriority ;if failed return process priority ;===================================== ;wake up target thread (affects GUI threads only) WakeUp: iWin32i PostThreadMessage, TID, WM_NCACTIVATE, TRUE, EAX ;save target thread's context LEA EAX, context ;original context PUSHp ESI, EDI MOV (_CONTEXT PTR [EAX]).ContextFlags, CONTEXT_INTEGER OR CONTEXT_CONTROL ;CONTEXT_FULL OR CONTEXT_EXTENDED_REGISTERS OR CONTEXT_FLOATING_POINT OR CONTEXT_DEBUG_REGISTERS PUSH EAX iWin32 GetThreadContext, ESI, EAX POP ESI LEA EDI, mcontext ;working context oMOV ECX, _CONTEXT/4 ;copy context MOV EDX, EDI REP MOVSD TEST EAX, EAX POPc ESI, EDI JE RetThreadPriority ;if failed return thread and process priorities ASSUME EDX: PTR _CONTEXT SUB [EDX].regEsp, 50H ;for sure eat some target stack XOR [EDX].ContextFlags, CONTEXT_INTEGER XOR CONTEXT_i386 ;INTEGER OFF MOV [EDX].regEip, EDI iWin32 SetThreadContext, ESI, EDX ASSUME EDX: NOTHING XOR mcontext.ContextFlags, CONTEXT_INTEGER XOR CONTEXT_i386 ;INTEGER ON TEST EAX, EAX JE RetThreadPriority ;if failed return my priorities MOV EAX, lpBlock ADD lpCodeEnd, EDI SUB lpCodeEnd, EAX ;EIP of CodeEnd in the target PUSH EDI LEA EDI, mcontext ASSUME EDI: PTR _CONTEXT @@: iWin32 ResumeThread, ESI DEC EAX JG @B ;resume until suspend count == 0 iWin32 Sleep, 256 ;run the thread for 256 ms iWin32 SuspendThread, ESI ;and suspend it for the next analysis iWin32 GetThreadContext, ESI, EDI NeverEnding: MOV EAX, [EDI].regEip CMP EAX, lpCodeEnd ;is EIP at CodeEnd (JMP $) ? JE WorkEnd ;yes done CMP ExpTime, INFINITE ;user gave us time? JE @B ;yes -> go on SUB MyTime, 256 ;subtract 256 ms from time counter JNLE @B ;still some ms? yes-> go on JMP RetContext ;no -> return all WorkEnd: MOV EAX, [EDI].regEax ;update thread's EAX according returned ECX MOV ECX, [EDI].regEcx ;ECX == original EAX (at thread entry) MOV ErrVal, EAX ;return value MOV context.regEax, ECX ;important for the thread which was awaked RetContext: LEA EAX, context POP EDI ASSUME EDI: NOTHING iWin32 SetThreadContext, ESI, EAX ;return original context RetThreadPriority: MOV EAX, MyThreadPriority CMP EAX, THREAD_PRIORITY_ERROR_RETURN JE RetProcessPriority iWin32 SetThreadPriority, CurrentThread, EAX ;return my thread priority RetProcessPriority: MOV EAX, MyProcessPriority TEST EAX, EAX JE Re9xClose iWin32 SetPriorityClass, CurrentProcess , EAX ;return my process priority Re9xClose: ;evaluate error code INC MyTime JE NotExpired DEC MyTime JNL NotExpired oMOV ErrVal, ErrorTimeOut NotExpired: @@: DEC SuspCnt JLE Re9xClThr iWin32 SuspendThread, ESI ;return original suspend count JMP @B Re9xClThr: LEA ESI, hThreadTIDField sWin32 DeSuspend, ESI, -1 ;desuspend all threads in target Re9xFailed: @@: LODSD TEST EAX, EAX JE ClDone iWin32 CloseHandle, EAX ;close all threads LODSD JMP @B ClDone: sWin32 RemoteFree, EDI ;free memory allocated in target TEST EAX, EAX JNE @F CMP ErrVal, ErrorSuccess ;evaluate error code JNE @F oMOV ErrVal, ErrorRemoteFree @@: MOV EAX, ErrVal ;return it RET RemoteExec9x ENDP ;------------------------------------------------------------------------------- ;Tries to find thread suitable for executing remote code. ;Such a thread must be 32bit and FS must not be null. ;Returns thread handle if all went OK and NULL if there was an error. ;Returns thread id in ECX. FindThread PROC USES EBX ESI EDI, fdwAccess, fInherit, IDProcess, hThreadTIDField LOCAL context :_CONTEXT MOV ESI, hThreadTIDField LEA EDI, context ASSUME EDI: PTR _CONTEXT sWin32 OpenAllThreads, fdwAccess, fInherit, IDProcess, ESI TEST EAX, EAX JNE Unsuccess ;can't open all IDProcess' threads ;watch thread CS and FS values MOV [EDI].ContextFlags, CONTEXT_CONTROL OR CONTEXT_SEGMENTS ;1st suspend all the threads Susp: LODSD TEST EAX, EAX JE ChooseCandidate MOV EBX, EAX LODSD iWin32 SuspendThread, EBX INC EAX JNE Susp SUB ESI, 8 ;cut this thread (handle+tid) from array DesuspIt: ;desuspend all threads in array, which were suspended above sWin32 DeSuspend, hThreadTIDField, ESI Unsuccess: SUB EAX, EAX ;return NULL JMP Success DesuspAll: OR ESI, -1 ;till the end of array JMP DesuspIt ;2nd now select first thread with suitable CS and FS ChooseCandidate: MOV ESI, hThreadTIDField ;start @@: LODSD MOV EBX, EAX ;save handle TEST EAX, EAX JE DesuspAll ;at the end and none was chosen LODSD PUSH EAX iWin32 GetThreadContext, EBX, EDI TEST EAX, EAX POP ECX JE @B ;can't get context -> explore next thread MOV EDX, CS CMP WORD PTR context.regFs, 0 ;thread FS != 0 JE @B CMP DX, WORD PTR context.regCs ;thread CS == myCS JNE @B MOV EAX, EBX ;return thread handle Success: RET ASSUME EDI: NOTHING FindThread ENDP ;------------------------------------------------------------------------------- ;Tries to open all threads of given 9x process. ;Fills StoreHandlesIDs array with handle, id, handle, id, ... and terminates ;the chain with NULL handle. ;Returns -1 if there was an error. OpenAllThreads9x PROC USES EBX ESI EDI, fdwAccess, fInherit, IDProcess, StoreHandlesIDs LOCAL ThrCnt :DWORD LOCAL thread :THREADENTRY32 MOV EDI, StoreHandlesIDs ;make thread snapshot sWin32 CreateToolhelp32Snapshot, TH32CS_SNAPTHREAD, IDProcess MOV EBX, EAX CMP EAX, -1 JE ThrExit oMOV ThrCnt, MAX_HTIDTHREAD ;initialize thread counter (array size) ASSUME ESI: PTR THREADENTRY32 LEA ESI, thread oMOV [ESI].dwSize, SIZEOF THREADENTRY32 sWin32 Thread32First, EBX, ESI @@: TEST EAX, EAX JE ThrClose MOV EAX, [ESI].th32OwnerProcessID CMP EAX, IDProcess JNE ThrNext sWin32 OpenThread9x, fdwAccess, fInherit, [ESI].th32ThreadID TEST EAX, EAX JE ThrCloseFail ;if can't open any of ps' threads -> fin STOSD MOV EAX, [ESI].th32ThreadID STOSD SUB EAX, EAX DEC ThrCnt ;Too many threads JLE ThrClose ;quit but don't fail ThrNext: sWin32 Thread32Next, EBX, ESI JMP @B ThrCloseFail: OR EAX, -1 ;failed -> return -1 ThrClose: PUSH EAX iWin32 CloseHandle, EBX ;close snapshot POP EAX ThrExit: AND DWORD PTR [EDI], 0 ;NULL handle at the end of OPENED thread handles in the array RET OpenAllThreads9x ENDP ;------------------------------------------------------------------------------- ;Tries to open all threads of given NT process. ;Fills StoreHandlesIDs array with handle, id, handle, id, ... and terminates ;the chain with NULL handle. ;Returns -1 if there was an error. OpenAllThreadsNT PROC USES EBX ESI EDI, fdwAccess, fInherit, IDProcess, StoreHandlesIDs LOCAL ThrCnt :DWORD oMOV ThrCnt, MAX_HTIDTHREAD ;initialize thread counter (array size) oMOV EBX, START_SIZE_FOR_NTQUERY @@: MOV EDI, StoreHandlesIDs ;array: handle, id, handle, id, ... sWin32 RemoteAlloc9x, EBX, NULL ;allocate memory for ntquery MOV ESI, EAX DEC EAX ;return -1 if alloc failed JL ThrExit sWin32 NtQuerySystemInformation, SystemProcessInformation, ESI, EBX, NULL CMP EAX, STATUS_INFO_LENGTH_MISMATCH JNE @F ;native api returned NTSTATUS sWin32 RemoteFree9x, ESI ;free allocated memory and allocate ADD EBX, DELTA_SIZE_FOR_NTQUERY ;more memory JMP @B @@: TEST EAX, EAX JL ThrExit0 ;ntquery failed -> return -1 ;there are too many processes and no memory MOV ECX, ESI ASSUME ECX :PTR SYSTEM_PROCESS_INFORMATION MOV EBX, IDProcess JMP ThreadFirst ;assume that there is at least 1 (this) process in the system NextProc: CMP [ECX].SizeOfBlock, 0 ;info ends? JE ProcInfoEnd ADD ECX, [ECX].SizeOfBlock ;ECX points to the next block ThreadFirst: CMP EBX, [ECX].ProcessId ;block.pid == parameter IDProcess ? JNE NextProc MOV EDX, SYSTEM_PROCESS_INFORMATION.ThreadInformation + SYSTEM_THREAD_INFORMATION.ClientId.UniqueThread ThreadInfoStart EQU BYTE PTR $-4 ;This is patched in DllMain if running in NT4 ThreadNext: DEC [ECX].ThreadCount JL ProcInfoEnd ASSUME ECX :NOTHING MOV EAX, [ECX+EDX] ;ThreadId STOSD ;store it in the array STOSD DEC ThrCnt JLE ProcInfoEnd ADD EDX, SIZEOF SYSTEM_THREAD_INFORMATION JMP ThreadNext ProcInfoEnd: SUB EAX, EAX STOSD ;store NULL handle (end of array) MOV EDI, StoreHandlesIDs @@: MOV EAX, [EDI] ;get TID TEST EAX, EAX ; == NULL end JE ThrExit0 sWin32 OpenThreadNT, fdwAccess, fInherit, EBX, EAX TEST EAX, EAX JE ThrExit1 ;if can't open any of ps' threads -> fin STOSD ;store thread handle ADD EDI, 4 ;skip TID JMP @B ThrExit1: OR EAX, -1 ;failed -> return -1 ThrExit0: PUSH EAX sWin32 RemoteFree9x, ESI ;free ntquery memo POP EAX ThrExit: AND DWORD PTR [EDI], 0 ;NULL handle at the end of OPENED thread handles in the array RET OpenAllThreadsNT ENDP ;------------------------------------------------------------------------------- ;Desuspends opened threads. Handles are in hthreadTIDField array (handle, id, ;handle, id,...). Last is NULL handle. ;Returns void. DeSuspend PROC USES ESI, hFrom, hTo MOV ESI, hFrom ;start here @@: CMP ESI, hTo ;end here JAE DeSuspended LODSD TEST EAX, EAX ;if hThread == NULL end JE DeSuspended iWin32 ResumeThread, EAX LODSD JMP @B DeSuspended: RET DeSuspend ENDP ;------------------------------------------------------------------------------- ;Opens Windows 9x thread represented by thread id. Used is routine at ;OpenProcess+24H. OpenThread API is present in Windows Millenium only. ;Returns thread handle if all went OK, NULL if there was an error. ;Based on ATM method (c) Enrico Del Fante. OpenThread9x PROC fdwAccess, fInherit, IDThread SUB EAX, EAX ;NULL MOV EDX, 0 ;Was "OpenThread" routine found? W9xOpenThread EQU DWORD PTR $-4 TEST EDX, EDX JE @F ;No -> return NULL MOV EAX, 0 Obsfucator EQU DWORD PTR $-4 XOR EAX, IDThread ;Thread Database = ThreadId ^ Obsfucator ;must be in EAX sWin32 EDX, fdwAccess, fInherit, IDThread @@: RET OpenThread9x ENDP ;------------------------------------------------------------------------- ;Opens Windows NT thread represented by client id. ;Inheritance is not handled (if fInherit is TRUE, put 2 into oa.Attributes). ;Client id == process id & thread id. ;However, thread can opened by thread id only when is process id part ;of client id = 0. ;Returns thread handle if all went OK, NULL if there was an error. OpenThreadNT PROC USES EDI, fdwAccess, fInherit, CID :CLIENT_ID LOCAL hThread :HANDLE LOCAL oa :OBJECT_ATTRIBUTES LEA EDX, CID LEA EDI, oa PUSHc fdwAccess, EDI, EDX ;push parameters for NtOpenThread oMOV EAX, SIZEOF oa ;initialize object attributes STOSD SUB EAX, EAX ZeroBlockSize = (SIZEOF oa - SIZEOF oa.Length_)/4 oMOV ECX, ZeroBlockSize REP STOSD PUSH EDI ;push 1st parameter: address of hThread STOSD ;hThread = 0 sWin32 NtOpenThread MOV EAX, hThread ;here is no check for error RET ;hThread == 0 is assumed if there was an error OpenThreadNT ENDP ;-------------------------------------------------------------------------------