弄了个在ring0下方便用的KMessAgeBox()

该博客介绍了如何在Ring0级别创建一个名为`KMessAgeBox`的函数,用于在内核模式下显示用户界面消息框。函数首先检查操作系统版本,然后通过创建系统线程、分配内存、映射页面并设置APC,实现在用户模式下显示消息框。文章详细展示了源代码实现,包括如何查找正确的线程、初始化APC等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/KernelMessAgeBox.h
 uty@uaty
#include <ntddk.h>

//CAllers of KMessAgeBox must be running At IRQL = PASSIVE_LEVEL :>
BOOLEAN
KMessAgeBox(
	PCHAR	lpText,
	PCHAR	lpCAption,
	ULONG	ulType
	);
//--------------------------------------------------------------------
/KernelMessAgeBox.c
 uty@uaty
#include <ntddk.h>

#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;

typedef	struct _messAgepArA{
	PCHAR	lpText;
	PCHAR	lpCAption;
	ULONG	ulType;
}MESSAGEPARA,*PMESSAGEPARA;
//--------------------------------------------------------------------
NTSTATUS
uSetTheApc(
	ULONG			process,
	ULONG			threAd,
	ULONG			MAppedAddress,
	PKEVENT			pEvent,
	PMESSAGEPARA	pPArA
	);

VOID 
WorkThreAd(
	IN PVOID pContext
	);

VOID
KernelApcCAllBAck(
	PKAPC Apc,
	PKNORMAL_ROUTINE *NormalRoutine,
	PVOID *NormalContext,
	PVOID *SystemArgument1,
	PVOID *SystemArgument2
	);

VOID
OnUnloAd(
	IN PDRIVER_OBJECT DriverObject
	);

BOOLEAN
find_threAd(
	OUT	ULONG	*process,
	OUT	ULONG	*threAd
	);

UserMessAgeBox(
	PCHAR	MessAgeText,
	PCHAR	MessAgeCAption,
	ULONG	ulType
	);

UserMessAgeBox_end(
	VOID
	);

BOOLEAN
CheckVersion(
	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
	);

//--------------------------------------------------------------------
ULONG		THREADLISTHEAD_OFFSET;
ULONG		THREADLISTENTRY_OFFSET;
ULONG		IMAGEFILENAME_OFFSET;
ULONG		ACTIVEPROCESSLINKS_OFFSET;
ULONG		USERAPCPENDING_OFFSET;
ULONG		TCB_TEB_OFFSET;

BOOLEAN
KMessAgeBox(
	PCHAR	lpText,
	PCHAR	lpCAption,
	ULONG	ulType
	)
{
	PMESSAGEPARA		pPArA	= NULL;
	HANDLE				hThreAd = NULL;
	NTSTATUS			dwStAtus;
	if(strlen(lpText)+strlen(lpCAption) > 98){		//two bytes for '/0'
		DbgPrint("Text And CAption is too long,At most 100 bytes/n");
		return FALSE;
	}

	pPArA = ExAllocatePool(PagedPool,sizeof(MESSAGEPARA));
	if(pPArA == NULL){
		DbgPrint("ExAllocAtePool fAiled/n");
		return FALSE;
	}

	pPArA->lpText			= lpText;
	pPArA->lpCAption		= lpCAption;
	pPArA->ulType			= ulType;

	if(FALSE == CheckVersion()){
		DbgPrint("os version not supported/n");
		return FALSE;
	}

	dwStAtus = PsCreateSystemThread(&hThreAd,
									(ACCESS_MASK)0,
									NULL,
									(HANDLE)0,
									NULL,
									WorkThreAd,
									pPArA
									);
									
	if (!NT_SUCCESS(dwStAtus)){
		DbgPrint("error when creAte the threAd/n");
		ExFreePool(pPArA);
		return FALSE;
	}
	return TRUE;
}
//--------------------------------------------------------------------
BOOLEAN
CheckVersion(
	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.dwBuildNumber == 2600)
		&&	(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;
	}
	return FALSE;
}

//PMDL	pMdl = NULL;
VOID
WorkThreAd(
	IN PVOID pContext
	)
{
	ULONG			process,threAd;
	PKEVENT			pEvent = NULL;
	PMDL			pMdl = NULL;
	PVOID			MAppedAddress = NULL;
	ULONG			size;
	KAPC_STATE		ApcStAte;
	PMESSAGEPARA	pPArA = NULL;

	pPArA = (PMESSAGEPARA)pContext;
	if (!find_threAd(&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);
	}
	memcpy((UCHAR*)UserMessAgeBox_end,pPArA->lpText,strlen(pPArA->lpText));
	memset((UCHAR*)((ULONG)UserMessAgeBox_end+strlen(pPArA->lpText)),0,1);
	memcpy((UCHAR*)((ULONG)UserMessAgeBox_end+strlen(pPArA->lpText) + 1),pPArA->lpCAption,strlen(pPArA->lpCAption));
	memset((UCHAR*)((ULONG)UserMessAgeBox_end+strlen(pPArA->lpText) + 1 + strlen(pPArA->lpCAption)),0,1);

	
	size = (UCHAR*)UserMessAgeBox_end - (UCHAR*)UserMessAgeBox + 100;//最多100个字节的MessAge
	u_DbgPrint(("size: %d/n",size));
	pMdl = IoAllocateMdl(
				UserMessAgeBox,
				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 his pPArAm,freed in APC->KernelRoutine
	(ULONG)pPArA->lpText		= (ULONG)MAppedAddress + (ULONG)((UCHAR*)UserMessAgeBox_end - (UCHAR*)UserMessAgeBox);
	(ULONG)pPArA->lpCAption		= (ULONG)MAppedAddress + (ULONG)((UCHAR*)UserMessAgeBox_end - (UCHAR*)UserMessAgeBox) + strlen(pPArA->lpText) + 1 ; 
	
	KeUnstackDetachProcess(&ApcStAte);
	KeInitializeEvent(pEvent,NotificationEvent,FALSE);

	uSetTheApc(process,threAd,(ULONG)MAppedAddress,pEvent,pPArA);

	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(
	ULONG			process,
	ULONG			threAd,
	ULONG			MAppedAddress,
	PKEVENT			pEvent,
	PMESSAGEPARA	pPArA
	)
{
	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;
	}
	u_DbgPrint(("MessAgeText: 0x%x/n",pPArA->lpText));
	KeInitializeApc(
		pkApc,
		(PKTHREAD)threAd,
		OriginalApcEnvironment,
		(PKKERNEL_ROUTINE)KernelApcCAllBAck,
		NULL,
		(PKNORMAL_ROUTINE)MAppedAddress,//UserApcCAllBAck,
		UserMode,
		(PVOID)pPArA
		);
	bBool = KeInsertQueueApc(pkApc,pEvent,(PVOID)pPArA->ulType,0);		//ticky
	if(bBool == FALSE){
		DbgPrint("error:KeInsertQueueApc/n");
	}

	return STATUS_SUCCESS;
}
//--------------------------------------------------------------------
VOID
KernelApcCAllBAck(
	PKAPC Apc, 
	PKNORMAL_ROUTINE *NormAlRoutine,
	IN OUT PVOID *NormAlContext,
	IN OUT PVOID *SystemArgument1,
	IN OUT PVOID *SystemArgument2
	)
{
	PKEVENT			pEvent;
	PMESSAGEPARA	pPArA;

	u_DbgPrint(("NormAlContext: 0x%x/n",(ULONG)*NormAlContext));
	pEvent	= (PKEVENT)*SystemArgument1;
	KeSetEvent(pEvent,IO_NO_INCREMENT,FALSE);
	pPArA	= (PMESSAGEPARA)*NormAlContext;
	*SystemArgument1	= (PVOID)pPArA->lpCAption;
	*SystemArgument2	= (PVOID)pPArA->ulType;
	*NormAlContext		= (PVOID)pPArA->lpText;
	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(
	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 == strcmp((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)
UserMessAgeBox(
	PCHAR	MessAgeText,
	PCHAR	MessAgeCAption,
	ULONG	ulType
	)
{
	__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
		// -------------加载user32.dll------------------------
		add		esi, 0xd					// 0xd即"user32"前面那个字符串的长度,硬编码可以节省两个字节
        push	edx							// edx是GetProcAddress 地址
        push    esi							// 字符"user32"地址
        call    dword ptr [edi-4]			// LoadLibraryA/????

		 // ============ 解决user32中的函数地址 ============
        pop		edx
        mov		ebx, eax					// 将user32起始地址存放在ebx                    
        push    0x1							// 函数个数
        pop		ecx							// 函数个数 <-这种方式省两个字节 
        call    locator_api_addr

        
		add		esi, 0xB					// MessAgeBoxA 的长度为0xB		
//--------------------------------------------------------------------
//		
		push	ulType
		push	MessAgeCAption
		push	MessAgeText;
		push	0
		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 'L'
		__emit 'o'
		__emit 'a'
		__emit 'd'
		__emit 'L'
		__emit 'i'
		__emit 'b'
		__emit 'r'
		__emit 'a'
		__emit 'r'
		__emit 'y'
		__emit 'A'
		__emit 0
		__emit 'u'
		__emit 's'
		__emit 'e'
		__emit 'r'
		__emit '3'
		__emit '2'
		__emit 0
		__emit 'M'
		__emit 'e'
		__emit 's'
		__emit 's'
		__emit 'a'
		__emit 'g'
		__emit 'e'
		__emit 'B'
		__emit 'o'
		__emit 'x'
		__emit 'A'
		__emit 0

end_func:
		add esp,20
		popad
	}
	__asm{
		mov esp,ebp
		pop ebp
		ret			//don't forget this :>
	}
}
//--------------------------------------------------------------------
__declspec(naked) UserMessAgeBox_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
	}


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值