windows下shellcode注入注意事项

2025-01-04 18:30:18 ctf

参考文章: 1.12 进程注入ShellCode套接字 | LyShark®


注入shellcode调用messagebox正常,调用NtAllocateVirtualMemory目标程序崩溃,发现调大SizeOfMyShell一千倍之后程序可以正常运行,查看注入的代码发现跳转到了shellcode以外的区域

跳转到这个地址发现没看出什么有用的线索


我们查看负责注入程序的函数指令,发现call了一个TestShellCode.__security_check_cookie这个东西

上网搜索得知TestShellCode.__security_check_cookie是vistual studio为了防止栈溢出的一个编译选项

我们在项目属性 --> c/c++ --> 代码生成 --> 安全检查 中关闭gs安全检查

恢复SizeOfMyShell ,程序正常注入运行


附上完整代码:


test.cpp:

#include
#include
using namespace std;


const int js_start=1;


int js(int a,int b) {
	return a+b;
} 


void js_end_func() {
	return ;
}


const int js_end=1;


int main() {
	printf("js_start address: %p     js_end address: %p\n",&js_start,&js_end);
	printf("js_address: %p\n      js_end_func_address%p\n",&js,&js_end_func);
	printf("sizeof js : %d\n",(uintptr_t)&js_end_func-(uintptr_t)&js); 
	printf("%p\n",&js_end-&js_start);
	while(true) {
		printf("1\n");
		Sleep(1000); 
	}
	return 0;
} 

TestShellCode.cpp

#include 
#include 
#include 


// 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);


// NtDll 调用约定定义
typedef NTSTATUS(WINAPI* NTALLOCATEVIRTUALMEMORY)(IN HANDLE ProcessHandle, IN OUT PVOID* BaseAddress, IN ULONG ZeroBits, IN OUT PSIZE_T RegionSize, IN ULONG AllocationType, IN ULONG Protect);


//typedef NTSTATUS(WINAPI* NTALLOCATEVIRTUALMEMORY)(
//    HANDLE    ProcessHandle,
//    PVOID* BaseAddress,
//    ULONG_PTR ZeroBits,
//    PSIZE_T   RegionSize,
//    ULONG     AllocationType,
//    ULONG     Protect
//);


typedef struct _ShellBase
{
    // 针对Kernel32的操作
    HANDLE Kernel32Base;
    char KernelString[20]; // kernel32.dll


    LOADLIBRARY Kernel_LoadLibrary;
    GETPROCADDRESS Kernel_GetProcAddress;
    NTALLOCATEVIRTUALMEMORY Func_NtAllocateVirtualMemory;


    // 针对User32的操作
    HANDLE User32Base;
    char UserString[20];   // 存储 user32.dll 字符串
    char User_MsgBox[20];  // 存储 MessageBoxA 字符串


    HANDLE NtDllBase;
    char NtDllString[20]; // 存储 ntdll.dll 字符串
    char NtAllocateVirtualMemoryString[40];


    // 输出一段话
    char Text[32];


}ShellParametros;




void __stdcall MyShell(ShellParametros*);


// 定义远程线程函数
void __stdcall MyShell(ShellParametros* ptr)
{
    /*ptr->Kernel32Base = (HANDLE)(*ptr->Kernel_LoadLibrary)((const TCHAR*)ptr->KernelString);
    ptr->User32Base = (HANDLE)(*ptr->Kernel_LoadLibrary)((const TCHAR*)ptr->UserString);
    ptr->NtDllBase = (HANDLE)(*ptr->Kernel_LoadLibrary)((const TCHAR*)ptr->NtDllString);*/


     //printf("动态获取到Kernel32基地址 = %x \n", ptr->Kernel32Base);
     //printf("动态获取到User32基地址 = %x \n", ptr->User32Base);
    // printf("动态获取到NtDll基地址 = %x \n", ptr->NtDllBase);


    //// 调用NtDll中的NtAllocateVirtualMemory函数
    //NTALLOCATEVIRTUALMEMORY NtAllocateVirtualMemory = (NTALLOCATEVIRTUALMEMORY)GetProcAddress((HINSTANCE)ptr->NtDllBase, ptr->NtAllocateVirtualMemoryString);
    PVOID BaseAddress = NULL;
    SIZE_T RegionSize = 4096;
    //while (true);
    NTALLOCATEVIRTUALMEMORY NtAllocateVirtualMemory = ptr->Func_NtAllocateVirtualMemory;
    void* p = NtAllocateVirtualMemory;
    NTSTATUS status = NtAllocateVirtualMemory((HANDLE)-1, &BaseAddress, 0, &RegionSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    //printf("NtAllocateVirtualMemory Address %p \r\n", NtAllocateVirtualMemory);
    //printf("NtAllocateVirtualMemory 调用结果 = %d \n", status);


    // MESSAGEBOX msgbox = (MESSAGEBOX)(*ptr->KernelGetProcAddress)((HINSTANCE)ptr->UserHandle, "MessageBoxA");
    //MESSAGEBOX msgbox = (MESSAGEBOX)(*ptr->Kernel_GetProcAddress)((HINSTANCE)ptr->User32Base, ptr->User_MsgBox);
    //MESSAGEBOX msgbox = ptr->Func_MessageBox;


    //printf("MessageBox 基地址 = %x \n", msgbox);
    //msgbox(0, ptr->Text, 0, 0);
}


void __stdcall MyShell_end(ShellParametros* ptr)
{
    ;
}


// 通过进程名获取进程ID
DWORD GetProcessId(const char* processName)
{
    DWORD processId = 0;
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);


    if (snapshot != INVALID_HANDLE_VALUE)
    {
        PROCESSENTRY32 processEntry;
        processEntry.dwSize = sizeof(processEntry);


        if (Process32First(snapshot, &processEntry))
        {
            do
            {
                // 将宽字符转换为多字节字符
                char exeName[MAX_PATH];
                WideCharToMultiByte(CP_ACP, 0, processEntry.szExeFile, -1,
                    exeName, MAX_PATH, NULL, NULL);


                if (_stricmp(exeName, processName) == 0)
                {
                    processId = processEntry.th32ProcessID;
                    break;
                }
                //printf("Process Name: %s, Process ID: %d\n", exeName, processEntry.th32ProcessID);
            } while (Process32Next(snapshot, &processEntry));
        }
        CloseHandle(snapshot);
    }
    return processId;
}


BOOL AdjustPrivilege()
{
    HANDLE hToken = NULL;
    TOKEN_PRIVILEGES priv = { 0 };


    //提权操作
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
    {
        return FALSE;
    }


    priv.PrivilegeCount = 1;
    priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;


    if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &priv.Privileges[0].Luid))
        AdjustTokenPrivileges(hToken, FALSE, &priv, 0, NULL, NULL);


    CloseHandle(hToken);
    return TRUE;
}






int main()
{
    AdjustPrivilege();
    ShellParametros Param, * remote = NULL;
    HANDLE hProcess;
    void* p = NULL;


    // 进程PID
    int ProcessID = GetProcessId("test.exe");


    printf("notepad.exe PID = %d\n", ProcessID);


    // 得到加载基地址的工具函数
    Param.Kernel32Base = LoadLibraryA("kernel32.dll");
    printf("Kernel32Base: %p\r\n", Param.Kernel32Base);
    Param.Kernel_LoadLibrary = (LOADLIBRARY)GetProcAddress((HINSTANCE)Param.Kernel32Base, "LoadLibraryA");
    printf("Kernel_LoadLibrary: %p\r\n", Param.Kernel_LoadLibrary);
    Param.Kernel_GetProcAddress = (GETPROCADDRESS)GetProcAddress((HINSTANCE)Param.Kernel32Base, "GetProcAddress");
    // printf("获取到Kernel32.dll = %x", Param.KernelHandle);


    Param.User32Base = LoadLibraryA("User32.dll");
    // printf("获取到User32.dll = %x", Param.UserHandle);


    Param.NtDllBase = LoadLibraryA("ntdll.dll");
    // printf("获取到NtDll.dll = %x", Param.NtDllHandle);


    // 得到NtDll中的NtAllocateVirtualMemory函数
    Param.Func_NtAllocateVirtualMemory = (NTALLOCATEVIRTUALMEMORY)GetProcAddress((HINSTANCE)Param.NtDllBase, "NtAllocateVirtualMemory");


    SIZE_T SizeOfMyShell = (uintptr_t)MyShell_end - (uintptr_t)MyShell;
    SizeOfMyShell *= 1000;
    printf("address of MyShell: %p\n", MyShell);
    printf("address of MyShell_end: %p\n", MyShell_end);
    printf("sizeofmyshell: %d\n", SizeOfMyShell);
    printf("myshell address: %p\n", &MyShell);


    // 分别获取Kernel32与User32的对应字符串
    strcpy_s(Param.KernelString, "kernel32.dll");
    strcpy_s(Param.UserString, "user32.dll");
    strcpy_s(Param.NtDllString, "ntdll.dll");


    strcpy_s(Param.User_MsgBox, "MessageBoxA");
    strcpy_s(Param.Text, "hello lyshark");
    strcpy_s(Param.NtAllocateVirtualMemoryString, "NtAllocateVirtualMemory");


    NTALLOCATEVIRTUALMEMORY NtAllocateVirtualMemory = (NTALLOCATEVIRTUALMEMORY)GetProcAddress((HINSTANCE)Param.NtDllBase, Param.NtAllocateVirtualMemoryString);
    PVOID BaseAddress = NULL;
    SIZE_T RegionSize = 4096;
    NTSTATUS status = NtAllocateVirtualMemory(GetCurrentProcess(), &BaseAddress, 0, &RegionSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    printf("NtAllocateVirtualMemory Address %p \r\n", NtAllocateVirtualMemory);
    printf("NtAllocateVirtualMemory 调用结果 = %d \n", status);
    printf("BaseAddress 地址 = %p \n", BaseAddress);


    // 根据PID注入代码到指定进程中
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessID);
    p = VirtualAllocEx(hProcess, 0, SizeOfMyShell, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    remote = (ShellParametros*)VirtualAllocEx(hProcess, 0, sizeof(ShellParametros), MEM_COMMIT, PAGE_READWRITE);


    printf("shellcode address: %p\r\n", p);




    WriteProcessMemory(hProcess, p, &MyShell, SizeOfMyShell, 0);
    WriteProcessMemory(hProcess, remote, &Param, sizeof(ShellParametros), 0);
    CreateRemoteThread(hProcess, 0, 0, (DWORD(__stdcall*)(void*)) p, remote, 0, 0);
    //MyShell(&Param);


    // MyShell(&Param);
    system("pause");
    return 0;
}